|
@@ -0,0 +1,172 @@
|
|
|
+<template>
|
|
|
+ <el-dialog v-model="visible" :title="`指标数据 - ${title}`" width="1100px" :close-on-click-modal="false" destroy-on-close>
|
|
|
+ <div v-if="visible">
|
|
|
+ <el-form :inline="true" class="toolbar">
|
|
|
+ <el-form-item>
|
|
|
+ <el-input v-model="query.searchValue" placeholder="输入指标值或原始值" clearable style="width: 160px" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="时间范围">
|
|
|
+ <el-date-picker v-model="query.dateRange" type="datetimerange" range-separator="至" start-placeholder="开始时间" end-placeholder="结束时间" format="YYYY-MM-DD HH:mm:ss" value-format="YYYY-MM-DD HH:mm:ss" style="width: 380px" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="维度筛选">
|
|
|
+ <el-select v-model="dimensionSelectedText" style="width: 120px" placeholder="全部维度" />
|
|
|
+ </el-form-item>
|
|
|
+ <el-form-item label="">
|
|
|
+ <el-button type="primary" :icon="Filter" @click="fetchList(1)">筛选</el-button>
|
|
|
+ <!-- <el-button @click="exportData">导出</el-button> -->
|
|
|
+ </el-form-item>
|
|
|
+ </el-form>
|
|
|
+
|
|
|
+ <el-table :data="list" style="width: 100%; margin-top: 8px" v-loading="loading">
|
|
|
+ <el-table-column label="时间" align="left" min-width="160">
|
|
|
+ <template #default="scope">{{ scope.row.time || scope.row.createdAt || scope.row.createTime || "-" }}</template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column :label="`指标值${detail.unit ? ' (' + detail.unit + ')' : ''}`" min-width="140" align="left">
|
|
|
+ <template #default="scope">
|
|
|
+ <el-link type="primary" :underline="false">{{ scope.row.value ?? scope.row.indicatorValue ?? "-" }}</el-link>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="原始值" width="120" align="left">
|
|
|
+ <template #default="scope">{{ scope.row.rawValue ?? scope.row.originValue ?? "-" }}</template>
|
|
|
+ </el-table-column>
|
|
|
+ <el-table-column label="监测点" prop="monitorPoint" width="120" align="left"> </el-table-column>
|
|
|
+ <el-table-column label="深度" prop="depth" width="120" align="left"> </el-table-column>
|
|
|
+ <el-table-column label="设备" prop="device" width="120" align="left"> </el-table-column>
|
|
|
+ <el-table-column v-for="k in dimKeys" :key="k" :label="dimNameMap[k] || k" min-width="120" show-overflow-tooltip>
|
|
|
+ <template #default="scope">{{ (scope.row.dimensions && scope.row.dimensions[k]) ?? scope.row[k] ?? "-" }}</template>
|
|
|
+ </el-table-column>
|
|
|
+ </el-table>
|
|
|
+
|
|
|
+ <div class="pager">
|
|
|
+ <el-pagination background layout="prev, pager, next, ->, total, sizes" :page-sizes="[20, 50, 100, 200]" :total="total" :page-size="query.pageSize" :current-page="query.pageNum" @current-change="(p:number)=>fetchList(p)" @size-change="(s:number)=>{query.pageSize=s;fetchList(1)}" />
|
|
|
+ </div>
|
|
|
+ </div>
|
|
|
+ </el-dialog>
|
|
|
+</template>
|
|
|
+
|
|
|
+<script lang="ts" setup>
|
|
|
+import { reactive, ref, computed } from "vue";
|
|
|
+import { ElMessage } from "element-plus";
|
|
|
+import { Filter } from "@element-plus/icons-vue";
|
|
|
+import api from "/@/api/datahub";
|
|
|
+
|
|
|
+const visible = ref(false);
|
|
|
+const loading = ref(false);
|
|
|
+const code = ref("");
|
|
|
+const title = ref("");
|
|
|
+const detail = reactive<any>({}); // 详情含 unit/维度等
|
|
|
+const list = ref<any[]>([]);
|
|
|
+const total = ref(0);
|
|
|
+
|
|
|
+// 查询参数(对应后端文档)
|
|
|
+const query = reactive({
|
|
|
+ searchValue: "",
|
|
|
+ keyWord: "",
|
|
|
+ year: "",
|
|
|
+ accurate: "h",
|
|
|
+ dateRange: [],
|
|
|
+ pageNum: 1,
|
|
|
+ pageSize: 20,
|
|
|
+});
|
|
|
+
|
|
|
+const dimensionFilters = reactive<Record<string, any>>({});
|
|
|
+
|
|
|
+const dimKeys = computed(() => {
|
|
|
+ const set = new Set<string>();
|
|
|
+ list.value.forEach((row: any) => {
|
|
|
+ if (row?.dimensions && typeof row.dimensions === "object") {
|
|
|
+ Object.keys(row.dimensions).forEach((k) => set.add(k));
|
|
|
+ }
|
|
|
+ });
|
|
|
+ return Array.from(set);
|
|
|
+});
|
|
|
+const dimNameMap = computed<Record<string, string>>(() => {
|
|
|
+ const map: Record<string, string> = {};
|
|
|
+ (detail.dimensions || []).forEach((d: any) => {
|
|
|
+ map[d.key || d.name] = d.name || d.key;
|
|
|
+ });
|
|
|
+ return map;
|
|
|
+});
|
|
|
+const dimensionSelectedText = computed(() => {
|
|
|
+ const entries = Object.entries(dimensionFilters).filter(([, v]) => v !== "" && v !== undefined && v !== null);
|
|
|
+ if (!entries.length) return "全部维度";
|
|
|
+ return entries.map(([k, v]) => `${dimNameMap.value[k] || k}:${v}`).join(";");
|
|
|
+});
|
|
|
+
|
|
|
+function buildParams() {
|
|
|
+ const params: any = {
|
|
|
+ ...query,
|
|
|
+ code: code.value,
|
|
|
+ };
|
|
|
+ // 维度 JSON 字符串
|
|
|
+ const dims: Record<string, any> = {};
|
|
|
+ Object.entries(dimensionFilters).forEach(([k, v]) => {
|
|
|
+ if (v !== "" && v !== undefined && v !== null) dims[k] = v;
|
|
|
+ });
|
|
|
+ if (Object.keys(dims).length) params.dimensions = JSON.stringify(dims);
|
|
|
+ return params;
|
|
|
+}
|
|
|
+
|
|
|
+function fetchDetail() {
|
|
|
+ const getDetail = (api.indicator as any).detail || (api.indicator as any).data;
|
|
|
+ return getDetail(code.value).then((res: any) => {
|
|
|
+ const data = res?.data || res?.Info || res || {};
|
|
|
+ Object.assign(detail, data);
|
|
|
+ });
|
|
|
+}
|
|
|
+
|
|
|
+function fetchList(p?: number) {
|
|
|
+ if (typeof p === "number") query.pageNum = p;
|
|
|
+ loading.value = true;
|
|
|
+ const params = buildParams();
|
|
|
+ api.indicator
|
|
|
+ .getData(params)
|
|
|
+ .then((res: any) => {
|
|
|
+ // 兼容不同返回格式
|
|
|
+ const data = res?.data ?? res?.Info ?? res ?? {};
|
|
|
+ const rows = data?.list ?? data?.rows ?? data?.records ?? data ?? [];
|
|
|
+ list.value = Array.isArray(rows) ? rows : [];
|
|
|
+ total.value = res?.total ?? data?.total ?? data?.count ?? list.value.length ?? 0;
|
|
|
+ })
|
|
|
+ .finally(() => (loading.value = false));
|
|
|
+}
|
|
|
+
|
|
|
+function open(row: any) {
|
|
|
+ code.value = row?.code || "";
|
|
|
+ title.value = `${row?.name || "-"} (${code.value})`;
|
|
|
+ visible.value = true;
|
|
|
+ // 清空筛选
|
|
|
+ Object.assign(query, { searchValue: "", keyWord: "", year: "", startTime: "", endTime: "", accurate: "", accurateRanges: "", orderBy: "", pageNum: 1, pageSize: 20 });
|
|
|
+ Object.keys(dimensionFilters).forEach((k) => delete (dimensionFilters as any)[k]);
|
|
|
+ fetchDetail().then(() => fetchList(1));
|
|
|
+}
|
|
|
+
|
|
|
+function exportData() {
|
|
|
+ ElMessage.info("导出功能请在接口确定后接入");
|
|
|
+}
|
|
|
+
|
|
|
+defineExpose({ open });
|
|
|
+</script>
|
|
|
+
|
|
|
+<style lang="scss" scoped>
|
|
|
+.sub-title {
|
|
|
+ color: var(--el-text-color-secondary);
|
|
|
+}
|
|
|
+.toolbar {
|
|
|
+ margin-top: 10px;
|
|
|
+ display: flex;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 8px;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+.pager {
|
|
|
+ margin-top: 12px;
|
|
|
+ display: flex;
|
|
|
+ justify-content: space-between;
|
|
|
+ align-items: center;
|
|
|
+}
|
|
|
+.empty-tip {
|
|
|
+ color: var(--el-text-color-secondary);
|
|
|
+ text-align: center;
|
|
|
+}
|
|
|
+</style>
|