|
|
@@ -1,6 +1,7 @@
|
|
|
<template>
|
|
|
<div class="page-container">
|
|
|
<div class="page-content">
|
|
|
+ <!-- 搜索栏 -->
|
|
|
<div class="search-bar">
|
|
|
<div class="search-left">
|
|
|
<el-select v-model="selectedUnit" placeholder="请选择共享单位" @change="handleUnitChange" class="unit-select">
|
|
|
@@ -9,8 +10,8 @@
|
|
|
</div>
|
|
|
<div class="search-center">
|
|
|
<div class="biz-buttons">
|
|
|
- <el-button
|
|
|
- v-for="biz in bizList"
|
|
|
+ <el-button
|
|
|
+ v-for="biz in bizList"
|
|
|
:key="biz.bizCode"
|
|
|
:class="{ active: selectedBiz === biz.bizCode }"
|
|
|
@click="handleBizClick(biz.bizCode)"
|
|
|
@@ -22,42 +23,36 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
<div class="search-right">
|
|
|
- <el-input v-model="searchKeyword" placeholder="请输入站名/行政区名" @keyup.enter="loadData" clearable style="width: 200px">
|
|
|
+ <el-input v-model="searchKeyword" placeholder="请输入站名/站码/行政区名" @keyup.enter="loadData" clearable style="width: 240px">
|
|
|
<template #prefix>
|
|
|
<el-icon><Search /></el-icon>
|
|
|
</template>
|
|
|
</el-input>
|
|
|
</div>
|
|
|
</div>
|
|
|
-
|
|
|
+
|
|
|
+ <!-- 数据表格 -->
|
|
|
<div class="table-container">
|
|
|
- <el-table :data="tableData" stripe border v-loading="loading" @row-click="handleRowClick">
|
|
|
- <template v-if="isWryType">
|
|
|
- <el-table-column type="index" label="序号" width="60" align="center" />
|
|
|
- <el-table-column prop="stnm" label="行政区" width="250" />
|
|
|
- <el-table-column prop="year" label="年份" width="80" />
|
|
|
- <el-table-column prop="cod" label="化学需氧量排放总量(吨)" width="200" />
|
|
|
- <el-table-column prop="nh3" label="氨氮排放总量(吨)" width="200" />
|
|
|
- <el-table-column prop="tn" label="总氮排放总量(吨)" width="200" />
|
|
|
- <el-table-column prop="tp" label="总磷排放总量(吨)" width="200" />
|
|
|
- </template>
|
|
|
- <template v-else>
|
|
|
- <el-table-column type="index" label="序号" width="60" align="center" />
|
|
|
- <el-table-column prop="stcd" label="站码" width="100" />
|
|
|
- <el-table-column prop="stnm" label="站名" width="150" />
|
|
|
- <el-table-column prop="rvnm" label="河流名称" width="200" />
|
|
|
- <el-table-column prop="latestDataTime" label="最新数据时间" width="170" />
|
|
|
- <el-table-column prop="wt" label="水温(℃)" width="100" />
|
|
|
- <el-table-column prop="ph" label="pH" width="80" />
|
|
|
- <el-table-column prop="do" label="溶解氧(mg/L)" width="110" />
|
|
|
- <el-table-column prop="nh3n" label="氨氮(mg/L)" width="100" />
|
|
|
- <el-table-column prop="tp" label="总磷(mg/L)" width="100" />
|
|
|
- <el-table-column prop="tn" label="总氮(mg/L)" width="100" />
|
|
|
- <el-table-column prop="cod" label="COD(mg/L)" width="100" />
|
|
|
- <el-table-column prop="bod" label="BOD(mg/L)" width="100" />
|
|
|
+ <el-table :data="tableData" stripe border v-loading="loading" @row-click="handleRowClick" height="100%" max-height="100%">
|
|
|
+ <el-table-column type="index" label="序号" width="60" align="center" fixed="left" />
|
|
|
+ <template v-for="col in currentColumns" :key="col.prop">
|
|
|
+ <el-table-column
|
|
|
+ :prop="col.prop"
|
|
|
+ :label="col.label"
|
|
|
+ :width="col.width || 140"
|
|
|
+ :min-width="col.minWidth"
|
|
|
+ :formatter="col.formatter"
|
|
|
+ :align="col.align || 'center'"
|
|
|
+ show-overflow-tooltip
|
|
|
+ />
|
|
|
</template>
|
|
|
+ <el-table-column label="操作" width="90" fixed="right" align="center">
|
|
|
+ <template #default="{ row }">
|
|
|
+ <el-button type="primary" link @click.stop="handleRowClick(row)">历史数据</el-button>
|
|
|
+ </template>
|
|
|
+ </el-table-column>
|
|
|
</el-table>
|
|
|
-
|
|
|
+
|
|
|
<div v-if="tableData.length === 0 && !loading" class="empty-state">
|
|
|
<el-icon class="empty-icon"><DataAnalysis /></el-icon>
|
|
|
<p>暂无数据</p>
|
|
|
@@ -65,18 +60,33 @@
|
|
|
</div>
|
|
|
</div>
|
|
|
|
|
|
- <el-dialog :title="historyDialogTitle" v-model="historyDialogVisible" width="900px" append-to-body>
|
|
|
+ <!-- 历史数据弹框 -->
|
|
|
+ <el-dialog :title="historyDialogTitle" v-model="historyDialogVisible" width="85%" append-to-body top="5vh">
|
|
|
<div class="history-dialog-content">
|
|
|
<div class="history-table">
|
|
|
- <el-table :data="historyTableData" stripe border>
|
|
|
- <el-table-column prop="year" label="年份" width="100" />
|
|
|
- <el-table-column prop="cod" label="化学需氧量排放总量(吨)" width="200" />
|
|
|
- <el-table-column prop="nh3" label="氨氮排放总量(吨)" width="200" />
|
|
|
- <el-table-column prop="tn" label="总氮排放总量(吨)" width="200" />
|
|
|
- <el-table-column prop="tp" label="总磷排放总量(吨)" width="200" />
|
|
|
+ <el-table :data="historyTableData" stripe border height="100%" max-height="560">
|
|
|
+ <el-table-column type="index" label="序号" width="60" align="center" fixed="left" />
|
|
|
+ <template v-for="col in historyColumns" :key="col.prop">
|
|
|
+ <el-table-column
|
|
|
+ :prop="col.prop"
|
|
|
+ :label="col.label"
|
|
|
+ :width="col.width || 140"
|
|
|
+ :formatter="col.formatter"
|
|
|
+ :align="col.align || 'center'"
|
|
|
+ show-overflow-tooltip
|
|
|
+ />
|
|
|
+ </template>
|
|
|
</el-table>
|
|
|
</div>
|
|
|
<div class="history-chart">
|
|
|
+ <div class="chart-title">
|
|
|
+ <span>历史趋势图</span>
|
|
|
+ <el-select v-model="chartMetrics" multiple collapse-tags collapse-tags-tooltip
|
|
|
+ placeholder="请选择指标" style="width: 420px; display: inline-block; vertical-align: middle; margin-left: 15px;"
|
|
|
+ @change="renderChart()">
|
|
|
+ <el-option v-for="m in chartableMetrics" :key="m.prop" :label="m.label" :value="m.prop" />
|
|
|
+ </el-select>
|
|
|
+ </div>
|
|
|
<div ref="chartRef" class="chart-container"></div>
|
|
|
</div>
|
|
|
</div>
|
|
|
@@ -85,13 +95,14 @@
|
|
|
</template>
|
|
|
|
|
|
<script setup>
|
|
|
-import { ref, onMounted, computed, nextTick, watch } from 'vue'
|
|
|
+import { ref, onMounted, nextTick, watch, computed } from 'vue'
|
|
|
import { Search, DataAnalysis } from '@element-plus/icons-vue'
|
|
|
import request from '@/utils/request'
|
|
|
import * as echarts from 'echarts'
|
|
|
|
|
|
+// ================ 基础变量 ================
|
|
|
const selectedUnit = ref('TBA')
|
|
|
-const selectedBiz = ref('TBA_SW_1H2H')
|
|
|
+const selectedBiz = ref('')
|
|
|
const searchKeyword = ref('')
|
|
|
const loading = ref(false)
|
|
|
|
|
|
@@ -103,14 +114,329 @@ const historyDialogVisible = ref(false)
|
|
|
const historyDialogTitle = ref('')
|
|
|
const historyTableData = ref([])
|
|
|
const chartRef = ref(null)
|
|
|
+const chartMetrics = ref([])
|
|
|
let chartInstance = null
|
|
|
|
|
|
-const WRY_TYPES = ['JS_ST_WRY', 'ZJ_ST_WRY', 'SH_ST_WRY']
|
|
|
+// ================ 业务域字段配置 ================
|
|
|
+// 按业务域配置:表格列、图表可选项(注意 prop 对应 HashMap 默认小写 key)
|
|
|
+const BIZ_COLUMN_CONFIG = {
|
|
|
+ // ========== 1. 水位流量类 - RIVER_H 表 ==========
|
|
|
+ TBA_SW_1H2H: {
|
|
|
+ type: 'RIVER_H',
|
|
|
+ columns: [
|
|
|
+ { prop: 'stcd', label: '站码', width: 100 },
|
|
|
+ { prop: 'stnm', label: '站点名称', width: 160 },
|
|
|
+ { prop: 'rvnm', label: '河流名称', width: 160 },
|
|
|
+ { prop: 'spt', label: '监测时间', width: 170, formatter: fmtDateTime },
|
|
|
+ { prop: 'upz', label: '上水位(m)', width: 110 },
|
|
|
+ { prop: 'dwz', label: '下水位(m)', width: 110 },
|
|
|
+ { prop: 'q', label: '流量(m³/s)', width: 120 }
|
|
|
+ ],
|
|
|
+ historyChart: ['upz', 'dwz', 'q']
|
|
|
+ },
|
|
|
+ TBA_SLDD_GC: {
|
|
|
+ type: 'RIVER_H',
|
|
|
+ columns: [
|
|
|
+ { prop: 'stcd', label: '站码', width: 100 },
|
|
|
+ { prop: 'stnm', label: '工程(口门)', width: 180 },
|
|
|
+ { prop: 'spt', label: '监测时间', width: 170, formatter: fmtDateTime },
|
|
|
+ { prop: 'upz', label: '闸上水位(m)', width: 120 },
|
|
|
+ { prop: 'dwz', label: '闸下水位(m)', width: 120 },
|
|
|
+ { prop: 'q', label: '流量', width: 100 },
|
|
|
+ { prop: 'ysl', label: '引水量', width: 100 },
|
|
|
+ { prop: 'psl', label: '排水量', width: 100 },
|
|
|
+ { prop: 'ddzl', label: '调度指令', width: 160 },
|
|
|
+ { prop: 'yxzt', label: '运行状态', width: 100 }
|
|
|
+ ],
|
|
|
+ historyChart: ['upz', 'dwz', 'ysl', 'psl']
|
|
|
+ },
|
|
|
+ TBA_STSW_TH: {
|
|
|
+ type: 'RIVER_H',
|
|
|
+ columns: [
|
|
|
+ { prop: 'rvnm', label: '河流名称', width: 160 },
|
|
|
+ { prop: 'stcd', label: '站码', width: 100 },
|
|
|
+ { prop: 'stnm', label: '测站名称', width: 160 },
|
|
|
+ { prop: 'spt', label: '监测时间', width: 170, formatter: fmtDateTime },
|
|
|
+ { prop: 'upz', label: '上水位(m)', width: 110 },
|
|
|
+ { prop: 'dwz', label: '下水位(m)', width: 110 },
|
|
|
+ { prop: 'q', label: '流量(m³/s)', width: 120 }
|
|
|
+ ],
|
|
|
+ historyChart: ['upz', 'dwz', 'q']
|
|
|
+ },
|
|
|
+
|
|
|
+ // ========== 2. 水质基础类 - AWQMD (BASE + METAL + AMR) ==========
|
|
|
+ TBA_SZY_SJ_RIVER: {
|
|
|
+ type: 'AWQMD',
|
|
|
+ columns: [
|
|
|
+ { prop: 'stcd', label: '站码', width: 100 },
|
|
|
+ { prop: 'stnm', label: '测站名称', width: 160 },
|
|
|
+ { prop: 'rvnm', label: '河流', width: 140 },
|
|
|
+ { prop: 'spt', label: '采样时间', width: 170, formatter: fmtDateTime },
|
|
|
+ { prop: 'wt', label: '水温(℃)', width: 90 },
|
|
|
+ { prop: 'ph', label: 'PH值', width: 80 },
|
|
|
+ { prop: 'cond', label: '电导率', width: 90 },
|
|
|
+ { prop: 'dox', label: '溶解氧', width: 90 },
|
|
|
+ { prop: 'codmn', label: '高锰酸盐指数', width: 120 },
|
|
|
+ { prop: 'codcr', label: '化学需氧量', width: 110 },
|
|
|
+ { prop: 'bod5', label: '五日生化需氧量', width: 130 },
|
|
|
+ { prop: 'nh3n', label: '氨氮', width: 90 },
|
|
|
+ { prop: 'tp', label: '总磷', width: 90 },
|
|
|
+ { prop: 'tn', label: '总氮', width: 90 },
|
|
|
+ { prop: 'turb', label: '浊度', width: 90 },
|
|
|
+ { prop: 'cu', label: '铜', width: 70 },
|
|
|
+ { prop: 'zn', label: '锌', width: 70 },
|
|
|
+ { prop: 'f', label: '氟化物', width: 80 },
|
|
|
+ { prop: 'se', label: '硒', width: 70 },
|
|
|
+ { prop: 'ars', label: '砷', width: 70 },
|
|
|
+ { prop: 'hg', label: '汞', width: 70 },
|
|
|
+ { prop: 'cd', label: '镉', width: 70 },
|
|
|
+ { prop: 'cr6', label: '六价铬', width: 80 },
|
|
|
+ { prop: 'pb', label: '铅', width: 70 },
|
|
|
+ { prop: 'cn', label: '氰化物', width: 80 },
|
|
|
+ { prop: 'fe', label: '铁', width: 70 },
|
|
|
+ { prop: 'mn', label: '锰', width: 70 },
|
|
|
+ { prop: 'ni', label: '镍', width: 70 },
|
|
|
+ { prop: 'b', label: '硼', width: 70 },
|
|
|
+ { prop: 'mo', label: '钼', width: 70 },
|
|
|
+ { prop: 'co', label: '钴', width: 70 },
|
|
|
+ { prop: 'be', label: '铍', width: 70 },
|
|
|
+ { prop: 'sb', label: '锑', width: 70 },
|
|
|
+ { prop: 'ba', label: '钡', width: 70 },
|
|
|
+ { prop: 'v', label: '钒', width: 70 },
|
|
|
+ { prop: 'ti', label: '钛', width: 70 },
|
|
|
+ { prop: 'tl', label: '铊', width: 70 }
|
|
|
+ ],
|
|
|
+ historyChart: ['wt', 'ph', 'dox', 'codmn', 'codcr', 'bod5', 'nh3n', 'tp', 'tn', 'cond']
|
|
|
+ },
|
|
|
+ TBA_SZY_SJ_BASIN: {
|
|
|
+ type: 'AWQMD',
|
|
|
+ columns: [
|
|
|
+ { prop: 'stcd', label: '站码', width: 100 },
|
|
|
+ { prop: 'stnm', label: '测站名称', width: 160 },
|
|
|
+ { prop: 'rvnm', label: '河流', width: 140 },
|
|
|
+ { prop: 'spt', label: '采样时间', width: 170, formatter: fmtDateTime },
|
|
|
+ { prop: 'wt', label: '水温(℃)', width: 90 },
|
|
|
+ { prop: 'ph', label: 'PH值', width: 80 },
|
|
|
+ { prop: 'cond', label: '电导率', width: 90 },
|
|
|
+ { prop: 'dox', label: '溶解氧', width: 90 },
|
|
|
+ { prop: 'codmn', label: '高锰酸盐指数', width: 120 },
|
|
|
+ { prop: 'codcr', label: '化学需氧量', width: 110 },
|
|
|
+ { prop: 'bod5', label: '五日生化需氧量', width: 130 },
|
|
|
+ { prop: 'nh3n', label: '氨氮', width: 90 },
|
|
|
+ { prop: 'tp', label: '总磷', width: 90 },
|
|
|
+ { prop: 'tn', label: '总氮', width: 90 },
|
|
|
+ { prop: 'turb', label: '浊度', width: 90 },
|
|
|
+ { prop: 'cu', label: '铜', width: 70 },
|
|
|
+ { prop: 'zn', label: '锌', width: 70 },
|
|
|
+ { prop: 'f', label: '氟化物', width: 80 },
|
|
|
+ { prop: 'ars', label: '砷', width: 70 },
|
|
|
+ { prop: 'hg', label: '汞', width: 70 },
|
|
|
+ { prop: 'cd', label: '镉', width: 70 },
|
|
|
+ { prop: 'cr6', label: '六价铬', width: 80 },
|
|
|
+ { prop: 'pb', label: '铅', width: 70 },
|
|
|
+ { prop: 'fe', label: '铁', width: 70 },
|
|
|
+ { prop: 'mn', label: '锰', width: 70 },
|
|
|
+ { prop: 'ni', label: '镍', width: 70 }
|
|
|
+ ],
|
|
|
+ historyChart: ['wt', 'ph', 'dox', 'codmn', 'codcr', 'bod5', 'nh3n', 'tp', 'tn']
|
|
|
+ },
|
|
|
+ TBA_SZY_RH: {
|
|
|
+ type: 'AWQMD',
|
|
|
+ columns: [
|
|
|
+ { prop: 'stcd', label: '站码', width: 100 },
|
|
|
+ { prop: 'stnm', label: '测站名称', width: 160 },
|
|
|
+ { prop: 'rvnm', label: '河流', width: 140 },
|
|
|
+ { prop: 'spt', label: '采样时间', width: 170, formatter: fmtDateTime },
|
|
|
+ { prop: 'wt', label: '水温(℃)', width: 90 },
|
|
|
+ { prop: 'ph', label: 'PH值', width: 80 },
|
|
|
+ { prop: 'cond', label: '电导率', width: 90 },
|
|
|
+ { prop: 'dox', label: '溶解氧', width: 90 },
|
|
|
+ { prop: 'codmn', label: '高锰酸盐指数', width: 120 },
|
|
|
+ { prop: 'codcr', label: '化学需氧量', width: 110 },
|
|
|
+ { prop: 'bod5', label: '五日生化需氧量', width: 130 },
|
|
|
+ { prop: 'nh3n', label: '氨氮', width: 90 },
|
|
|
+ { prop: 'tp', label: '总磷', width: 90 },
|
|
|
+ { prop: 'tn', label: '总氮', width: 90 },
|
|
|
+ { prop: 'turb', label: '浊度', width: 90 }
|
|
|
+ ],
|
|
|
+ historyChart: ['wt', 'ph', 'dox', 'codmn', 'codcr', 'bod5', 'nh3n', 'tp', 'tn']
|
|
|
+ },
|
|
|
+ TBA_SZ_1H2H: {
|
|
|
+ type: 'AWQMD',
|
|
|
+ columns: [
|
|
|
+ { prop: 'stcd', label: '站码', width: 100 },
|
|
|
+ { prop: 'stnm', label: '测站(口门)', width: 180 },
|
|
|
+ { prop: 'rvnm', label: '河流', width: 140 },
|
|
|
+ { prop: 'spt', label: '监测时间', width: 170, formatter: fmtDateTime },
|
|
|
+ { prop: 'wt', label: '水温(℃)', width: 90 },
|
|
|
+ { prop: 'ph', label: 'PH值', width: 80 },
|
|
|
+ { prop: 'cond', label: '电导率', width: 90 },
|
|
|
+ { prop: 'dox', label: '溶解氧', width: 90 },
|
|
|
+ { prop: 'codmn', label: '高锰酸盐指数', width: 120 },
|
|
|
+ { prop: 'nh3n', label: '氨氮', width: 90 },
|
|
|
+ { prop: 'tp', label: '总磷', width: 90 },
|
|
|
+ { prop: 'tn', label: '总氮', width: 90 },
|
|
|
+ { prop: 'turb', label: '浊度', width: 90 }
|
|
|
+ ],
|
|
|
+ historyChart: ['wt', 'ph', 'cond', 'dox', 'codmn', 'nh3n', 'tp', 'tn', 'turb']
|
|
|
+ },
|
|
|
+
|
|
|
+ // ========== 3. 蓝藻监测类 - LZDC / LZJC (AMR表为主) ==========
|
|
|
+ TBA_SYD_LZDC: {
|
|
|
+ type: 'AWQMD',
|
|
|
+ columns: [
|
|
|
+ { prop: 'stcd', label: '站码', width: 100 },
|
|
|
+ { prop: 'stnm', label: '测站名称', width: 160 },
|
|
|
+ { prop: 'spt', label: '采样时间', width: 170, formatter: fmtDateTime },
|
|
|
+ { prop: 'wt', label: '水温(℃)', width: 90 },
|
|
|
+ { prop: 'ph', label: 'PH值', width: 80 },
|
|
|
+ { prop: 'cond', label: '电导率', width: 90 },
|
|
|
+ { prop: 'dox', label: '溶解氧', width: 90 },
|
|
|
+ { prop: 'codmn', label: '高锰酸盐指数', width: 120 },
|
|
|
+ { prop: 'nh3n', label: '氨氮', width: 90 },
|
|
|
+ { prop: 'tp', label: '总磷', width: 90 },
|
|
|
+ { prop: 'tn', label: '总氮', width: 90 },
|
|
|
+ { prop: 'wndv', label: '风速', width: 80 },
|
|
|
+ { prop: 'wndpwr', label: '风力', width: 70 },
|
|
|
+ { prop: 'windir', label: '风向', width: 70 },
|
|
|
+ { prop: 'physp', label: '浮游植物种类', width: 140 },
|
|
|
+ { prop: 'phyd', label: '浮游植物密度', width: 130 },
|
|
|
+ { prop: 'cyncd', label: '蓝藻门细胞密度', width: 140 },
|
|
|
+ { prop: 'crycd', label: '隐藻门细胞密度', width: 140 },
|
|
|
+ { prop: 'pyrcd', label: '甲藻门细胞密度', width: 140 },
|
|
|
+ { prop: 'chrcd', label: '金藻门细胞密度', width: 140 },
|
|
|
+ { prop: 'xntcd', label: '黄藻门细胞密度', width: 140 },
|
|
|
+ { prop: 'bclcd', label: '硅藻门细胞密度', width: 140 },
|
|
|
+ { prop: 'eugcd', label: '裸藻门细胞密度', width: 140 },
|
|
|
+ { prop: 'chlcd', label: '绿藻门细胞密度', width: 140 },
|
|
|
+ { prop: 'phys', label: '浮游植物优势种', width: 160 },
|
|
|
+ { prop: 'phydd', label: '优势种密度', width: 140 },
|
|
|
+ { prop: 'phydi', label: '多样性指数', width: 120 }
|
|
|
+ ],
|
|
|
+ historyChart: ['wt', 'ph', 'dox', 'codmn', 'nh3n', 'tp', 'tn',
|
|
|
+ 'phyd', 'cyncd', 'bclcd', 'chlcd', 'eugcd', 'crycd']
|
|
|
+ },
|
|
|
+ TBA_SZY_LZJC: {
|
|
|
+ type: 'AWQMD',
|
|
|
+ columns: [
|
|
|
+ { prop: 'stcd', label: '站码', width: 100 },
|
|
|
+ { prop: 'stnm', label: '测站名称', width: 160 },
|
|
|
+ { prop: 'spt', label: '采样时间', width: 170, formatter: fmtDateTime },
|
|
|
+ { prop: 'physp', label: '浮游植物种类', width: 140 },
|
|
|
+ { prop: 'phyd', label: '浮游植物密度', width: 130 },
|
|
|
+ { prop: 'phys', label: '主要优势种', width: 160 },
|
|
|
+ { prop: 'phydd', label: '优势种密度', width: 140 },
|
|
|
+ { prop: 'cyncd', label: '蓝藻门', width: 120 },
|
|
|
+ { prop: 'crycd', label: '隐藻门', width: 120 },
|
|
|
+ { prop: 'pyrcd', label: '甲藻门', width: 120 },
|
|
|
+ { prop: 'chrcd', label: '金藻门', width: 120 },
|
|
|
+ { prop: 'xntcd', label: '黄藻门', width: 120 },
|
|
|
+ { prop: 'bclcd', label: '硅藻门', width: 120 },
|
|
|
+ { prop: 'eugcd', label: '裸藻门', width: 120 },
|
|
|
+ { prop: 'chlcd', label: '绿藻门', width: 120 }
|
|
|
+ ],
|
|
|
+ historyChart: ['phyd', 'cyncd', 'crycd', 'pyrcd', 'chrcd', 'bclcd', 'eugcd', 'chlcd']
|
|
|
+ },
|
|
|
+
|
|
|
+ // ========== 4. 污染源类 - ST_WRY 表 ==========
|
|
|
+ JS_ST_WRY: {
|
|
|
+ type: 'WRY',
|
|
|
+ columns: [
|
|
|
+ { prop: 'stcd', label: '行政区编码', width: 120 },
|
|
|
+ { prop: 'stnm', label: '行政区名称', width: 200 },
|
|
|
+ { prop: 'year', label: '年份', width: 80 },
|
|
|
+ { prop: 'cod', label: 'COD排放量(吨)', width: 170 },
|
|
|
+ { prop: 'nh3', label: '氨氮排放量(吨)', width: 170 },
|
|
|
+ { prop: 'tn', label: '总氮排放量(吨)', width: 170 },
|
|
|
+ { prop: 'tp', label: '总磷排放量(吨)', width: 170 }
|
|
|
+ ],
|
|
|
+ historyChart: ['cod', 'nh3', 'tn', 'tp']
|
|
|
+ },
|
|
|
+ ZJ_ST_WRY: {
|
|
|
+ type: 'WRY',
|
|
|
+ columns: [
|
|
|
+ { prop: 'stcd', label: '行政区编码', width: 120 },
|
|
|
+ { prop: 'stnm', label: '行政区名称', width: 200 },
|
|
|
+ { prop: 'year', label: '年份', width: 80 },
|
|
|
+ { prop: 'cod', label: 'COD排放量(吨)', width: 170 },
|
|
|
+ { prop: 'nh3', label: '氨氮排放量(吨)', width: 170 },
|
|
|
+ { prop: 'tn', label: '总氮排放量(吨)', width: 170 },
|
|
|
+ { prop: 'tp', label: '总磷排放量(吨)', width: 170 }
|
|
|
+ ],
|
|
|
+ historyChart: ['cod', 'nh3', 'tn', 'tp']
|
|
|
+ },
|
|
|
+ SH_ST_WRY: {
|
|
|
+ type: 'WRY',
|
|
|
+ columns: [
|
|
|
+ { prop: 'stcd', label: '行政区编码', width: 120 },
|
|
|
+ { prop: 'stnm', label: '行政区名称', width: 200 },
|
|
|
+ { prop: 'year', label: '年份', width: 80 },
|
|
|
+ { prop: 'cod', label: 'COD排放量(吨)', width: 170 },
|
|
|
+ { prop: 'nh3', label: '氨氮排放量(吨)', width: 170 },
|
|
|
+ { prop: 'tn', label: '总氮排放量(吨)', width: 170 },
|
|
|
+ { prop: 'tp', label: '总磷排放量(吨)', width: 170 }
|
|
|
+ ],
|
|
|
+ historyChart: ['cod', 'nh3', 'tn', 'tp']
|
|
|
+ },
|
|
|
+
|
|
|
+ // ========== 5. 其他 / 降雨 ==========
|
|
|
+ TBA_JYL_FQ: {
|
|
|
+ type: 'DEFAULT',
|
|
|
+ columns: [
|
|
|
+ { prop: 'stnm', label: '测站名称', width: 160 },
|
|
|
+ { prop: 'spt', label: '时间', width: 170, formatter: fmtDateTime }
|
|
|
+ ],
|
|
|
+ historyChart: []
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// ================ 计算属性 ================
|
|
|
+const currentConfig = computed(() => BIZ_COLUMN_CONFIG[selectedBiz.value] || {
|
|
|
+ type: 'DEFAULT',
|
|
|
+ columns: [
|
|
|
+ { prop: 'stcd', label: '站码', width: 100 },
|
|
|
+ { prop: 'stnm', label: '站名', width: 160 },
|
|
|
+ { prop: 'rvnm', label: '河流', width: 140 },
|
|
|
+ { prop: 'spt', label: '最新数据时间', width: 170, formatter: fmtDateTime }
|
|
|
+ ],
|
|
|
+ historyChart: []
|
|
|
+})
|
|
|
+
|
|
|
+const currentColumns = computed(() => currentConfig.value.columns || [])
|
|
|
+const historyColumns = computed(() => currentColumns.value)
|
|
|
|
|
|
-const isWryType = computed(() => {
|
|
|
- return WRY_TYPES.includes(selectedBiz.value)
|
|
|
+const chartableMetrics = computed(() => {
|
|
|
+ const metrics = (currentConfig.value.historyChart || []).map(p => {
|
|
|
+ const col = currentColumns.value.find(c => c.prop === p)
|
|
|
+ return { prop: p, label: col ? col.label : p }
|
|
|
+ })
|
|
|
+ return metrics
|
|
|
})
|
|
|
|
|
|
+function fmtDate(row, col, val) {
|
|
|
+ if (!val) return '-'
|
|
|
+ const d = new Date(val)
|
|
|
+ if (isNaN(d)) return String(val).slice(0, 10)
|
|
|
+ return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())}`
|
|
|
+}
|
|
|
+function fmtYM(row, col, val) {
|
|
|
+ if (!val) return '-'
|
|
|
+ const d = new Date(val)
|
|
|
+ if (isNaN(d)) {
|
|
|
+ const s = String(val)
|
|
|
+ return s.length >= 7 ? s.slice(0, 7) : s
|
|
|
+ }
|
|
|
+ return `${d.getFullYear()}-${pad(d.getMonth()+1)}`
|
|
|
+}
|
|
|
+function fmtDateTime(row, col, val) {
|
|
|
+ if (!val) return '-'
|
|
|
+ const d = new Date(val)
|
|
|
+ if (isNaN(d)) return String(val)
|
|
|
+ return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`
|
|
|
+}
|
|
|
+function pad(n) { return n < 10 ? '0' + n : String(n) }
|
|
|
+
|
|
|
+// ================ 生命周期 ================
|
|
|
onMounted(() => {
|
|
|
loadUnits()
|
|
|
})
|
|
|
@@ -138,35 +464,32 @@ function loadBizList(unitCode) {
|
|
|
params: { bizUnit: unitCode }
|
|
|
}).then(res => {
|
|
|
const bizData = res.data || []
|
|
|
-
|
|
|
- Promise.all(bizData.map(biz => {
|
|
|
- if (WRY_TYPES.includes(biz.bizCode)) {
|
|
|
- return request({
|
|
|
- url: '/gx/stWry/front/latest/' + biz.bizCode,
|
|
|
- method: 'get'
|
|
|
- }).then(wryRes => {
|
|
|
- const data = wryRes.data || []
|
|
|
- return { ...biz, stationCount: data.length }
|
|
|
- })
|
|
|
- } else {
|
|
|
- return request({
|
|
|
- url: '/gx/station/front/listByBizCode/' + biz.bizCode,
|
|
|
- method: 'get'
|
|
|
- }).then(stationRes => {
|
|
|
- const stations = stationRes.data || []
|
|
|
- return { ...biz, stationCount: stations.length }
|
|
|
- })
|
|
|
+ if (bizData.length === 0) {
|
|
|
+ bizList.value = []
|
|
|
+ tableData.value = []
|
|
|
+ return
|
|
|
+ }
|
|
|
+ // 一次性批量查询所有业务域的站点数量
|
|
|
+ const bizCodes = bizData.map(b => b.bizCode)
|
|
|
+ request({
|
|
|
+ url: '/gx/station/front/countByBizCodes',
|
|
|
+ method: 'get',
|
|
|
+ params: { bizCodes: bizCodes.join(',') }
|
|
|
+ }).then(countRes => {
|
|
|
+ const countMap = countRes.data || {}
|
|
|
+ bizList.value = bizData.map(biz => ({
|
|
|
+ ...biz,
|
|
|
+ stationCount: countMap[biz.bizCode] || 0
|
|
|
+ }))
|
|
|
+ // 默认选中第一个业务域
|
|
|
+ if (bizList.value.length > 0) {
|
|
|
+ selectedBiz.value = bizList.value[0].bizCode
|
|
|
+ handleBizClick(selectedBiz.value)
|
|
|
}
|
|
|
- })).then(results => {
|
|
|
- bizList.value = results
|
|
|
-
|
|
|
+ }).catch(() => {
|
|
|
+ bizList.value = bizData.map(biz => ({ ...biz, stationCount: 0 }))
|
|
|
if (bizList.value.length > 0) {
|
|
|
- const defaultBiz = bizList.value.find(b => b.bizCode === selectedBiz.value)
|
|
|
- if (defaultBiz) {
|
|
|
- selectedBiz.value = defaultBiz.bizCode
|
|
|
- } else {
|
|
|
- selectedBiz.value = bizList.value[0].bizCode
|
|
|
- }
|
|
|
+ selectedBiz.value = bizList.value[0].bizCode
|
|
|
handleBizClick(selectedBiz.value)
|
|
|
}
|
|
|
})
|
|
|
@@ -175,108 +498,63 @@ function loadBizList(unitCode) {
|
|
|
|
|
|
function handleBizClick(bizCode) {
|
|
|
selectedBiz.value = bizCode
|
|
|
+ chartMetrics.value = []
|
|
|
loadData()
|
|
|
}
|
|
|
|
|
|
function loadData() {
|
|
|
+ if (!selectedBiz.value) return
|
|
|
loading.value = true
|
|
|
-
|
|
|
- if (isWryType.value) {
|
|
|
- request({
|
|
|
- url: '/gx/stWry/front/latest/' + selectedBiz.value,
|
|
|
- method: 'get'
|
|
|
- }).then(res => {
|
|
|
- let data = res.data || []
|
|
|
-
|
|
|
- if (searchKeyword.value) {
|
|
|
- const keyword = searchKeyword.value.toLowerCase()
|
|
|
- data = data.filter(item =>
|
|
|
- item.stnm.toLowerCase().includes(keyword)
|
|
|
- )
|
|
|
- }
|
|
|
-
|
|
|
- tableData.value = data
|
|
|
- loading.value = false
|
|
|
- }).catch(() => {
|
|
|
- tableData.value = []
|
|
|
- loading.value = false
|
|
|
- })
|
|
|
- } else {
|
|
|
- request({
|
|
|
- url: '/gx/station/front/listByBizCode/' + selectedBiz.value,
|
|
|
- method: 'get'
|
|
|
- }).then(res => {
|
|
|
- const stationList = res.data || []
|
|
|
-
|
|
|
- let filteredStations = stationList
|
|
|
- if (searchKeyword.value) {
|
|
|
- const keyword = searchKeyword.value.toLowerCase()
|
|
|
- filteredStations = filteredStations.filter(s =>
|
|
|
- s.stnm.toLowerCase().includes(keyword) ||
|
|
|
- s.stcd.toLowerCase().includes(keyword)
|
|
|
- )
|
|
|
- }
|
|
|
-
|
|
|
- Promise.all(filteredStations.map(station => {
|
|
|
- return request({
|
|
|
- url: '/gx/quality/front/list',
|
|
|
- method: 'get',
|
|
|
- params: { stcd: station.stcd, pageSize: 1 }
|
|
|
- }).then(qualityRes => {
|
|
|
- const qualityData = qualityRes.data || []
|
|
|
- const latestQuality = qualityData.length > 0 ? qualityData[0] : {}
|
|
|
- return {
|
|
|
- ...station,
|
|
|
- latestDataTime: latestQuality.uploadTime || '-',
|
|
|
- wt: latestQuality.wt || '-',
|
|
|
- ph: latestQuality.ph || '-',
|
|
|
- do: latestQuality.do || '-',
|
|
|
- nh3n: latestQuality.nh3n || '-',
|
|
|
- tp: latestQuality.tp || '-',
|
|
|
- tn: latestQuality.tn || '-',
|
|
|
- cod: latestQuality.cod || '-',
|
|
|
- bod: latestQuality.bod || '-'
|
|
|
- }
|
|
|
- })
|
|
|
- })).then(results => {
|
|
|
- tableData.value = results
|
|
|
- loading.value = false
|
|
|
- }).catch(() => {
|
|
|
- tableData.value = filteredStations.map(station => ({
|
|
|
- ...station,
|
|
|
- latestDataTime: '-',
|
|
|
- wt: '-',
|
|
|
- ph: '-',
|
|
|
- do: '-',
|
|
|
- nh3n: '-',
|
|
|
- tp: '-',
|
|
|
- tn: '-',
|
|
|
- cod: '-',
|
|
|
- bod: '-'
|
|
|
- }))
|
|
|
- loading.value = false
|
|
|
+ request({
|
|
|
+ url: '/gx/dataCommon/front/latest/' + selectedBiz.value,
|
|
|
+ method: 'get'
|
|
|
+ }).then(res => {
|
|
|
+ let data = res.data || []
|
|
|
+ if (searchKeyword.value) {
|
|
|
+ const kw = searchKeyword.value.toLowerCase()
|
|
|
+ data = data.filter(item => {
|
|
|
+ const name = (item.stnm || '').toLowerCase()
|
|
|
+ const code = (item.stcd || '').toLowerCase()
|
|
|
+ const rvnm = (item.rvnm || '').toLowerCase()
|
|
|
+ return name.includes(kw) || code.includes(kw) || rvnm.includes(kw)
|
|
|
})
|
|
|
- }).catch(() => {
|
|
|
- loading.value = false
|
|
|
- })
|
|
|
- }
|
|
|
+ }
|
|
|
+ tableData.value = data
|
|
|
+ loading.value = false
|
|
|
+ }).catch(err => {
|
|
|
+ console.error(err)
|
|
|
+ tableData.value = []
|
|
|
+ loading.value = false
|
|
|
+ })
|
|
|
}
|
|
|
|
|
|
+// ================ 历史数据弹框 ================
|
|
|
function handleRowClick(row) {
|
|
|
- if (isWryType.value) {
|
|
|
- historyDialogTitle.value = `${row.stnm} 历史数据`
|
|
|
- loadHistoryData(row.stnm)
|
|
|
- historyDialogVisible.value = true
|
|
|
+ const cfg = currentConfig.value
|
|
|
+ if (cfg.type === 'WRY') {
|
|
|
+ historyDialogTitle.value = `${row.stnm || ''} - 历史数据`
|
|
|
+ loadHistoryData(row.stcd, row.stnm)
|
|
|
+ } else {
|
|
|
+ const title = (row.stnm || row.STNM || '') + (row.stcd ? `(${row.stcd})` : '')
|
|
|
+ historyDialogTitle.value = `${title} - 历史数据`
|
|
|
+ loadHistoryData(row.stcd || row.STCD, row.stnm || row.STNM)
|
|
|
}
|
|
|
+ historyDialogVisible.value = true
|
|
|
}
|
|
|
|
|
|
-function loadHistoryData(stnm) {
|
|
|
+function loadHistoryData(stcd, stnm) {
|
|
|
request({
|
|
|
- url: '/gx/stWry/front/history',
|
|
|
+ url: '/gx/dataCommon/front/history',
|
|
|
method: 'get',
|
|
|
- params: { bizCode: selectedBiz.value, stnm: stnm }
|
|
|
+ params: {
|
|
|
+ bizCode: selectedBiz.value,
|
|
|
+ stcd: stcd || '',
|
|
|
+ stnm: stnm || ''
|
|
|
+ }
|
|
|
}).then(res => {
|
|
|
historyTableData.value = res.data || []
|
|
|
+ // 默认选择图表指标
|
|
|
+ chartMetrics.value = (currentConfig.value.historyChart || []).slice(0, 4)
|
|
|
nextTick(() => {
|
|
|
renderChart()
|
|
|
})
|
|
|
@@ -285,81 +563,90 @@ function loadHistoryData(stnm) {
|
|
|
|
|
|
function renderChart() {
|
|
|
if (!chartRef.value) return
|
|
|
-
|
|
|
if (chartInstance) {
|
|
|
chartInstance.dispose()
|
|
|
+ chartInstance = null
|
|
|
}
|
|
|
-
|
|
|
+ if (!chartMetrics.value || chartMetrics.value.length === 0) return
|
|
|
chartInstance = echarts.init(chartRef.value)
|
|
|
-
|
|
|
- const sortedData = [...historyTableData.value].sort((a, b) => a.year - b.year)
|
|
|
- const years = sortedData.map(item => item.year + '年')
|
|
|
- const codData = sortedData.map(item => item.cod || 0)
|
|
|
- const nh3Data = sortedData.map(item => item.nh3 || 0)
|
|
|
- const tnData = sortedData.map(item => item.tn || 0)
|
|
|
- const tpData = sortedData.map(item => item.tp || 0)
|
|
|
-
|
|
|
+
|
|
|
+ // 按时间正序排列
|
|
|
+ const sorted = [...historyTableData.value].sort((a, b) => {
|
|
|
+ const ta = getTimeVal(a.spt || a.SPT || a.year)
|
|
|
+ const tb = getTimeVal(b.spt || b.SPT || b.year)
|
|
|
+ return ta - tb
|
|
|
+ })
|
|
|
+ const xData = sorted.map(item => {
|
|
|
+ const v = item.spt || item.SPT || item.year
|
|
|
+ if (typeof v === 'number') return v + '年'
|
|
|
+ const d = new Date(v)
|
|
|
+ if (isNaN(d)) return String(v).slice(0, 10)
|
|
|
+ return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())}`
|
|
|
+ })
|
|
|
+ function getTimeVal(v) {
|
|
|
+ if (typeof v === 'number') return v
|
|
|
+ const d = new Date(v)
|
|
|
+ return isNaN(d) ? 0 : d.getTime()
|
|
|
+ }
|
|
|
+
|
|
|
+ const palette = ['#1c97e7', '#ffcc4d', '#93d347', '#ff8562', '#8d6cc7',
|
|
|
+ '#39c5c9', '#f46687', '#60a5fa', '#f59e0b', '#10b981',
|
|
|
+ '#ef4444', '#8b5cf6', '#06b6d4', '#f97316', '#84cc16']
|
|
|
+ const series = chartMetrics.value.map((mp, idx) => {
|
|
|
+ const col = chartableMetrics.value.find(m => m.prop === mp)
|
|
|
+ return {
|
|
|
+ name: col ? col.label : mp,
|
|
|
+ type: 'line',
|
|
|
+ smooth: true,
|
|
|
+ symbol: 'circle',
|
|
|
+ symbolSize: 5,
|
|
|
+ itemStyle: { color: palette[idx % palette.length] },
|
|
|
+ data: sorted.map(item => numOrNull(item[mp] || item[mp?.toUpperCase?.()] || item[(mp || '').toLowerCase?.()]))
|
|
|
+ }
|
|
|
+ })
|
|
|
+ function numOrNull(v) {
|
|
|
+ if (v === null || v === undefined || v === '') return null
|
|
|
+ const n = Number(v)
|
|
|
+ return isNaN(n) ? null : n
|
|
|
+ }
|
|
|
+
|
|
|
const option = {
|
|
|
tooltip: {
|
|
|
trigger: 'axis',
|
|
|
- axisPointer: {
|
|
|
- type: 'shadow'
|
|
|
- }
|
|
|
+ axisPointer: { type: 'cross' }
|
|
|
},
|
|
|
legend: {
|
|
|
- data: ['COD', '氨氮', '总氮', '总磷'],
|
|
|
- bottom: 10
|
|
|
+ bottom: 10,
|
|
|
+ data: series.map(s => s.name)
|
|
|
},
|
|
|
grid: {
|
|
|
- left: '3%',
|
|
|
- right: '4%',
|
|
|
- bottom: '15%',
|
|
|
- top: '10%',
|
|
|
- containLabel: true
|
|
|
+ left: '3%', right: '4%', bottom: '18%', top: '10%', containLabel: true
|
|
|
},
|
|
|
xAxis: {
|
|
|
type: 'category',
|
|
|
- data: years,
|
|
|
- axisLabel: {
|
|
|
- rotate: 45
|
|
|
- }
|
|
|
+ data: xData,
|
|
|
+ axisLabel: { rotate: 40, fontSize: 11 }
|
|
|
},
|
|
|
yAxis: {
|
|
|
- type: 'value'
|
|
|
+ type: 'value',
|
|
|
+ scale: true
|
|
|
},
|
|
|
- series: [
|
|
|
- {
|
|
|
- name: 'COD',
|
|
|
- type: 'bar',
|
|
|
- data: codData,
|
|
|
- itemStyle: { color: '#1c97e7' }
|
|
|
- },
|
|
|
- {
|
|
|
- name: '氨氮',
|
|
|
- type: 'bar',
|
|
|
- data: nh3Data,
|
|
|
- itemStyle: { color: '#ffcc4d' }
|
|
|
- },
|
|
|
- {
|
|
|
- name: '总氮',
|
|
|
- type: 'bar',
|
|
|
- data: tnData,
|
|
|
- itemStyle: { color: '#93d347' }
|
|
|
- },
|
|
|
- {
|
|
|
- name: '总磷',
|
|
|
- type: 'bar',
|
|
|
- data: tpData,
|
|
|
- itemStyle: { color: '#ff8562' }
|
|
|
- }
|
|
|
- ]
|
|
|
+ dataZoom: [
|
|
|
+ { type: 'inside', start: 0, end: 100 },
|
|
|
+ { type: 'slider', start: 0, end: 100, bottom: 50, height: 18 }
|
|
|
+ ],
|
|
|
+ series
|
|
|
}
|
|
|
-
|
|
|
chartInstance.setOption(option)
|
|
|
}
|
|
|
|
|
|
+// 窗口变化 resize
|
|
|
+window.addEventListener('resize', () => chartInstance && chartInstance.resize())
|
|
|
+
|
|
|
watch(historyDialogVisible, (val) => {
|
|
|
- if (!val && chartInstance) {
|
|
|
+ if (val) {
|
|
|
+ nextTick(() => chartInstance && chartInstance.resize())
|
|
|
+ } else if (chartInstance) {
|
|
|
chartInstance.dispose()
|
|
|
chartInstance = null
|
|
|
}
|
|
|
@@ -371,15 +658,19 @@ watch(historyDialogVisible, (val) => {
|
|
|
height: 100%;
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
+ padding: 16px;
|
|
|
+ box-sizing: border-box;
|
|
|
}
|
|
|
|
|
|
.page-content {
|
|
|
flex: 1;
|
|
|
background: #fff;
|
|
|
border-radius: 12px;
|
|
|
+ box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
|
|
|
display: flex;
|
|
|
flex-direction: column;
|
|
|
overflow: hidden;
|
|
|
+ min-height: 0;
|
|
|
}
|
|
|
|
|
|
.search-bar {
|
|
|
@@ -388,21 +679,19 @@ watch(historyDialogVisible, (val) => {
|
|
|
display: flex;
|
|
|
align-items: center;
|
|
|
justify-content: space-between;
|
|
|
+ flex-wrap: wrap;
|
|
|
+ gap: 12px;
|
|
|
}
|
|
|
|
|
|
-.search-left {
|
|
|
- flex-shrink: 0;
|
|
|
-}
|
|
|
-
|
|
|
-.unit-select {
|
|
|
- width: 220px;
|
|
|
-}
|
|
|
+.search-left { flex-shrink: 0; }
|
|
|
+.unit-select { width: 220px; }
|
|
|
|
|
|
.search-center {
|
|
|
flex: 1;
|
|
|
display: flex;
|
|
|
justify-content: center;
|
|
|
padding: 0 20px;
|
|
|
+ min-width: 0;
|
|
|
}
|
|
|
|
|
|
.biz-buttons {
|
|
|
@@ -424,42 +713,34 @@ watch(historyDialogVisible, (val) => {
|
|
|
align-items: center;
|
|
|
gap: 6px;
|
|
|
}
|
|
|
-
|
|
|
.biz-buttons :deep(.el-button:hover) {
|
|
|
background: #ecf5ff;
|
|
|
border-color: #b3d8ff;
|
|
|
color: #1c97e7;
|
|
|
}
|
|
|
-
|
|
|
.biz-buttons :deep(.el-button.active) {
|
|
|
background: #1c97e7;
|
|
|
color: #fff;
|
|
|
border-color: #1c97e7;
|
|
|
}
|
|
|
-
|
|
|
.station-count {
|
|
|
font-size: 12px;
|
|
|
background: rgba(255, 255, 255, 0.2);
|
|
|
padding: 2px 6px;
|
|
|
border-radius: 10px;
|
|
|
}
|
|
|
-
|
|
|
.biz-buttons :deep(.el-button.active) .station-count {
|
|
|
background: rgba(255, 255, 255, 0.3);
|
|
|
}
|
|
|
|
|
|
-.search-right {
|
|
|
- flex-shrink: 0;
|
|
|
-}
|
|
|
+.search-right { flex-shrink: 0; }
|
|
|
|
|
|
.table-container {
|
|
|
flex: 1;
|
|
|
- overflow-y: auto;
|
|
|
- padding: 20px;
|
|
|
-}
|
|
|
-
|
|
|
-.table-container :deep(.el-table) {
|
|
|
- width: 100%;
|
|
|
+ overflow: hidden;
|
|
|
+ padding: 12px 16px 16px;
|
|
|
+ position: relative;
|
|
|
+ min-height: 0;
|
|
|
}
|
|
|
|
|
|
.table-container :deep(.el-table tr:hover) {
|
|
|
@@ -472,38 +753,50 @@ watch(historyDialogVisible, (val) => {
|
|
|
flex-direction: column;
|
|
|
align-items: center;
|
|
|
justify-content: center;
|
|
|
- height: 300px;
|
|
|
+ height: 100%;
|
|
|
+ min-height: 300px;
|
|
|
color: #909399;
|
|
|
+ position: absolute;
|
|
|
+ top: 0; left: 0; right: 0; bottom: 0;
|
|
|
}
|
|
|
-
|
|
|
.empty-icon {
|
|
|
font-size: 64px;
|
|
|
margin-bottom: 16px;
|
|
|
opacity: 0.5;
|
|
|
}
|
|
|
+.empty-state p { font-size: 16px; margin: 0; }
|
|
|
|
|
|
-.empty-state p {
|
|
|
- font-size: 16px;
|
|
|
- margin: 0;
|
|
|
-}
|
|
|
-
|
|
|
+/* ========= 弹框布局 ========= */
|
|
|
.history-dialog-content {
|
|
|
display: flex;
|
|
|
gap: 20px;
|
|
|
- height: 500px;
|
|
|
+ height: 600px;
|
|
|
+ padding: 4px;
|
|
|
}
|
|
|
-
|
|
|
.history-table {
|
|
|
flex: 1;
|
|
|
- overflow-y: auto;
|
|
|
+ overflow: hidden;
|
|
|
+ border: 1px solid #ebeef5;
|
|
|
+ border-radius: 6px;
|
|
|
+ min-width: 0;
|
|
|
}
|
|
|
-
|
|
|
.history-chart {
|
|
|
flex: 1;
|
|
|
+ display: flex;
|
|
|
+ flex-direction: column;
|
|
|
+ min-width: 0;
|
|
|
+}
|
|
|
+.chart-title {
|
|
|
+ padding: 10px 4px 12px;
|
|
|
+ font-size: 15px;
|
|
|
+ font-weight: 600;
|
|
|
+ color: #303133;
|
|
|
+ border-bottom: 1px dashed #e4e7ed;
|
|
|
+ margin-bottom: 8px;
|
|
|
}
|
|
|
-
|
|
|
.chart-container {
|
|
|
+ flex: 1;
|
|
|
width: 100%;
|
|
|
- height: 100%;
|
|
|
+ min-height: 480px;
|
|
|
}
|
|
|
</style>
|