Просмотр исходного кода

[Feat 0000]密闭监测-历史数据监测页面搭建

wangkeyi 4 месяцев назад
Родитель
Сommit
67ecef5c7d

+ 2 - 2
src/views/dashboard/basicInfo/dataQuality/components/DataQualityModal.vue

@@ -22,12 +22,12 @@
         </div>
       </div>
       <!-- 动态渲染topFormSchema字段(查看模式) -->
-      <div class="mine-info">
+      <!-- <div class="mine-info">
         <div class="mine-field" v-for="schema in topFormSchema" :key="schema.field">
           <span class="que-label">{{ schema.label }}:</span>
           <span class="que-value">{{ currentRecord?.[schema.field] || mockFormdData[schema.field] }}</span>
         </div>
-      </div>
+      </div> -->
       <div 
         class="que-item" 
         v-for="(item, index) in queList" 

+ 374 - 0
src/views/dashboard/sealedMonitoring/historicalData/components/MonitoringDetailsModal.vue

@@ -0,0 +1,374 @@
+<template>
+  <Modal
+    v-model:open="visible"
+    title="密闭监测详情"
+    width="1200px"
+    @ok="handleOk"
+    @cancel="handleCancel"
+    prefixCls="custom-modal"
+  >
+    <div class="filter-area">
+      <!-- 时间选择 -->
+      <div class="filter-section">
+        <span class="filter-label">时间选择:</span>
+        <RangePicker
+          v-model="dateRange"
+          format="YYYY-MM-DD HH:mm:ss"
+          :placeholder="['开始时间','结束时间']"
+          style="width: 320px"
+          :show-time="{ format: 'HH:mm:ss' }"
+        />
+      </div>
+      <!-- 参数选择 -->
+      <div class="filter-section param-section">
+        <span class="filter-label">参数选择:</span>
+        <div class="param-selector">
+          <Input
+            v-model="selectedParamsText"
+            placeholder="请选择监测参数"
+            readonly
+            style="width: 300px"
+          />
+          <Button type="primary" @click="showTree = !showTree">+</Button>
+          <!-- 树形选择器 -->
+          <div class="tree-popup" v-if="showTree">
+            <BasicTree
+              :treeData="treeData"
+              :checkable="true"
+              defaultExpandAll
+              @check="handleTreeCheck"
+              :checkedKeys="checkedTreeKeys"
+            />
+          </div>
+        </div>
+      </div>
+      <!-- 生成按钮 -->
+      <div class="filter-section">
+        <Button type="primary" @click="generateChart">生成</Button>
+      </div>
+    </div>
+    <!-- 动态图表区域-->
+    <div class="chart-area">
+      <div class="chart-item" style="flex: 1 1 100%;">
+        <div class="chart-placeholder">
+          <template v-if="generatedChartData.length">
+            <CustomChart 
+              :chart-data="generatedChartData" 
+              :chart-config="generatedChartConfig" 
+              style="height: 100%; width: 100%"
+            />
+          </template>
+          <template v-else-if="isChartGenerated">
+            <div class="empty-chart">暂无匹配数据,请调整筛选条件</div>
+          </template>
+          <template v-else>
+            <div class="empty-chart">请选择时间范围和参数,点击"生成"查看数据</div>
+          </template>
+        </div>
+      </div>
+    </div>
+  </Modal>
+</template>
+<script setup>
+import { ref, computed } from 'vue';
+import { Modal, DatePicker, Button, message, Input } from 'ant-design-vue';
+import { BasicTree } from '/@/components/Tree/index';
+import CustomChart from '/@/components/Configurable/detail/CustomChart.vue';
+import { treeData, mockChartData } from '../historicalData.data'; // 引入模拟数据
+import dayjs from 'dayjs';
+import isBetween from 'dayjs/plugin/isBetween'; // 引入 isBetween 插件
+
+// 关键:使用 dayjs 插件
+dayjs.extend(isBetween);
+
+// 组件注册
+const RangePicker = DatePicker.RangePicker;
+
+// 弹框控制
+const visible = ref(false);
+const showModal = () => (visible.value = true);
+const hideModal = () => (visible.value = false);
+const handleOk = () => hideModal();
+const handleCancel = () => hideModal();
+
+// 筛选相关响应式数据
+const dateRange = ref([dayjs().subtract(1, 'day').toDate(), dayjs().toDate()]); // 默认时间范围(近1天)
+const selectedParams = ref([]); // 选中的参数(实际用于图表)
+const selectedParamsText = ref(''); // 参数选择框显示文本
+const showTree = ref(false); // 控制树形选择器显示/隐藏
+const checkedTreeKeys = ref([]); // 树形选中的key
+const generatedChartData = ref([]); // 生成的图表数据
+const generatedChartConfig = ref({}); // 生成的图表配置
+const isChartGenerated = ref(false); // 是否已点击生成
+
+// Tree Key 与参数名映射(关键:关联树形节点和实际参数)
+const treeKeyToParamMap = computed(() => ({
+  '0-0-0': 'CO',
+  '0-0-1': 'CH4',
+  '0-0-2': 'C2H4',
+  '0-0-3': 'C2H2',
+  '0-0-4': 'CO2',
+  '0-0-5': 'O2',
+  '1-1-0': 'innerPressure',
+  '1-1-1': 'outerPressure',
+  '1-1-2': 'pressureDiff',
+  '2-2': 'temperature',
+}));
+
+// 参数名反向映射到 Tree Key
+const paramToTreeKeyMap = computed(() => {
+  return Object.fromEntries(
+    Object.entries(treeKeyToParamMap.value).map(([key, val]) => [val, key])
+  );
+});
+
+// 树形选择事件处理
+const handleTreeCheck = (checkedKeys) => {
+  checkedTreeKeys.value = checkedKeys;
+  // 转换为实际参数名
+  const params = checkedKeys
+    .map(key => treeKeyToParamMap.value[key])
+    .filter(param => param); // 过滤无效参数
+  selectedParams.value = params;
+  
+  // 更新输入框显示文本
+  const paramLabels = params.map(param => paramLabelMap.value[param]);
+  selectedParamsText.value = paramLabels.join('、');
+};
+
+// 参数颜色映射
+const paramColorMap = computed(() => ({
+  'CO': '#f5222d',    // 红色
+  'CH4': '#1890ff',   // 蓝色
+  'C2H4': '#faad14',  // 橙色
+  'C2H2': '#52c41a',  // 绿色
+  'CO2': '#722ed1',   // 紫色
+  'O2': '#13c2c2',    // 青色
+  'innerPressure': '#ff4d4f', // 浅红
+  'outerPressure': '#40a9ff',// 浅蓝
+  'pressureDiff': '#fa8c16', // 浅橙
+  'temperature': '#9254de',  // 浅紫
+}));
+
+// 参数标签映射(图表系列名称)
+const paramLabelMap = computed(() => ({
+  'CO': 'CO浓度(ppm)',
+  'CH4': 'CH4浓度(%)',
+  'C2H4': 'C2H4浓度(ppm)',
+  'C2H2': 'C2H2浓度(ppm)',
+  'CO2': 'CO2浓度(%)',
+  'O2': 'O2浓度(%)',
+  'innerPressure': '内压力(kPa)',
+  'outerPressure': '外压力(kPa)',
+  'pressureDiff': '压差(kPa)',
+  'temperature': '温度(℃)',
+}));
+
+// 生成折线图核心逻辑
+const generateChart = () => {
+  // 校验筛选条件
+  if (!dateRange.value[0] || !dateRange.value[1]) {
+    message.warning('请选择完整的时间范围');
+    return;
+  }
+  if (selectedParams.value.length === 0) {
+    message.warning('请至少选择一个监测参数');
+    return;
+  }
+
+  isChartGenerated.value = true;
+  const start = dayjs(dateRange.value[0]); // 转为 dayjs 实例
+  const end = dayjs(dateRange.value[1]);   // 转为 dayjs 实例
+
+  // 1. 筛选时间范围内的模拟数据(修复核心漏洞)
+  const filteredData = mockChartData.filter(item => {
+    const itemTime = dayjs(item.time); // 解析 item.time 为 dayjs 实例
+    // 修复 isBetween 用法:明确指定 unit 为 'second',包容性为 '[]'
+    return itemTime.isBetween(start, end, 'second', '[]');
+  });
+
+  // 2. 构建图表数据结构(适配 CustomChart 的 line 类型)
+  const timeMap = new Map();
+  // 修复变量名:filteredRawData → filteredData(之前未定义)
+  filteredData.forEach((item) => {
+    const timeStr = dayjs(item.time).format('YYYY-MM-DD HH:mm:ss');
+    if (!timeMap.has(timeStr)) {
+      timeMap.set(timeStr, { time: timeStr });
+    }
+    // 只保留选中的参数数据
+    selectedParams.value.forEach(param => {
+      if (item[param] !== undefined) {
+        timeMap.get(timeStr)[param] = item[param];
+      }
+    });
+  });
+
+  // 转换为数组并按时间排序
+  const chartData = Array.from(timeMap.values()).sort((a, b) => {
+    return dayjs(a.time).valueOf() - dayjs(b.time).valueOf();
+  });
+  generatedChartData.value = chartData;
+
+  // 3. 构建图表配置(折线图类型,完善适配逻辑)
+  generatedChartConfig.value = {
+    type: 'line', // 折线图
+    clear: true, // 每次生成清空之前的图表
+    legend: { show: true, top: 10, right: 10 },
+    xAxis: [
+      {
+        type: 'category',
+        axisLabel: {
+          rotate: 30,
+          formatter: (value) => dayjs(value).format('HH:mm:ss'),
+          interval: Math.max(1, Math.floor(chartData.length / 10)) // 控制x轴标签密度
+        }
+      }
+    ],
+    yAxis: selectedParams.value.map(param => ({
+      type: 'value',
+      name: paramLabelMap.value[param].split('(')[1].replace(')', ''), // 显示单位
+      nameTextStyle: { color: paramColorMap.value[param] },
+      axisLine: { lineStyle: { color: paramColorMap.value[param] } },
+      splitLine: { lineStyle: { opacity: 0.1 } }
+    })),
+    series: selectedParams.value.map((param, index) => ({
+      name: paramLabelMap.value[param],
+      type: 'line',
+      readFrom: '', // 适配 CustomChart 的 baseSeries 读取逻辑
+      label: paramLabelMap.value[param],
+      xprop: 'time', // 对应图表数据的 x 字段(时间)
+      yprop: param, // 对应图表数据的 y 字段(参数值)
+      color: paramColorMap.value[param],
+      smooth: true,
+      symbol: 'circle',
+      symbolSize: 4,
+      yAxisIndex: index,
+    })),
+    tooltip: {
+      trigger: 'axis',
+      axisPointer: { type: 'cross' },
+      formatter: (params) => {
+        let tooltipHtml = `<div>${dayjs(params[0].axisValue).format('YYYY-MM-DD HH:mm:ss')}</div>`;
+        params.forEach(param => {
+          tooltipHtml += `<div style="color: ${param.color}">${param.seriesName}: ${param.value[1]} ${param.seriesName.split('(')[1].replace(')', '')}</div>`;
+        });
+        return tooltipHtml;
+      }
+    },
+    grid: { left: 60, top: 40, right: 60, bottom: 60 }
+  };
+
+  // 无数据提示
+  if (chartData.length === 0) {
+    message.info('当前筛选条件下无数据');
+  }
+};
+
+// 暴露方法给父组件
+defineExpose({
+  showModal,
+  hideModal
+});
+</script>
+<style scoped>
+.param-selector {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+  position: relative;
+}
+.tree-popup {
+  position: absolute;
+  top: 100%;
+  left: 0;
+  margin-top: 8px;
+  width: 300px;
+  max-height: 300px;
+  overflow-y: auto;
+  background: #fff;
+  border: 1px solid #e8e8e8;
+  border-radius: 4px;
+  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+  z-index: 100;
+  padding: 8px;
+}
+.filter-area {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 16px;
+  margin-bottom: 20px;
+  padding: 20px;
+  border: 1px solid #f0f0f0;
+  border-radius: 10px;
+  background: #f8f9fc;
+  align-items: center;
+}
+.filter-section {
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+.filter-label {
+  color: #666;
+  min-width: 80px;
+  flex-shrink: 0;
+  font-weight: 500;
+}
+.param-section {
+  flex: 1;
+  min-width: 300px;
+}
+.chart-area {
+  display: flex;
+  flex-wrap: wrap;
+  gap: 16px;
+  padding: 20px;
+  border: 1px solid #f0f0f0;
+  border-radius: 10px;
+  background: #f8f9fc;
+}
+.chart-item {
+  flex: 1;
+  min-width: 200px;
+}
+.chart-title {
+  font-size: 16px;
+  font-weight: 500;
+  margin-bottom: 12px;
+  color: #333;
+  display: flex;
+  align-items: center;
+  gap: 8px;
+}
+.chart-desc {
+  font-size: 12px;
+  color: #666;
+  font-weight: normal;
+}
+.chart-placeholder {
+  width: 100%;
+  height: 300px;
+  border-radius: 4px;
+  overflow: hidden;
+  background: #333;
+  border: 1px solid #eee;
+}
+.empty-chart {
+  width: 100%;
+  height: 100%;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  color: #999;
+  font-size: 14px;
+}
+@media (max-width: 1200px) {
+  .param-section {
+    min-width: 100%;
+    margin-top: 8px;
+  }
+  .filter-area {
+    gap: 12px;
+  }
+}
+</style>

+ 259 - 0
src/views/dashboard/sealedMonitoring/historicalData/historicalData.data.ts

@@ -0,0 +1,259 @@
+import { BasicColumn } from '/@/components/Table';
+import { FormSchema } from '/@/components/Table';
+import { TreeItem } from '/@/components/Tree/index';
+import { h } from 'vue';
+import { Tag } from 'ant-design-vue';
+
+export const columns: BasicColumn[] = [
+  {
+    title: '序号',
+    dataIndex: 'orderNo',
+  },
+  {
+    title: '区域',
+    dataIndex: 'enforcement',
+  },
+  {
+    title: '煤矿名称',
+    dataIndex: 'mineName',
+  },
+  {
+    title: '密闭名称',
+    dataIndex: 'sealedName',
+  },
+  {
+    title: '所属煤层',
+    dataIndex: 'coalSeam',
+  },
+  {
+    title: '自燃倾向性',
+    dataIndex: 'riskLevel',
+  },
+  {
+    title: 'CO(ppm)',
+    dataIndex: 'COVal',
+  },
+  {
+    title: 'CH4(%)',
+    dataIndex: 'CH4Val',
+  },
+  {
+    title: 'C2H2(ppm)',
+    dataIndex: 'C2H2Val',
+  },
+  {
+    title: 'O2(%)',
+    dataIndex: 'O2Val',
+  },
+  {
+    title: '温度(℃)',
+    dataIndex: 'temperature',
+  },
+  {
+    title: '压差(Pa)',
+    dataIndex: 'pressureDiff',
+  },
+  {
+    title: '是否漏风',
+    dataIndex: 'leakage',
+  },
+  {
+    title: '自然发火隐患',
+    dataIndex: 'fireHazard',
+  },
+  {
+    title: '密闭启封判定',
+    dataIndex: 'unsealing',
+  },
+  {
+    title: '爆炸危险性',
+    dataIndex: 'explosionHazard',
+  },
+  {
+    title: '更新时间',
+    dataIndex: 'updateTime',
+  },
+];
+
+export const searchFormSchema: FormSchema[] = [
+  {
+    field: 'mineName',
+    label: '煤矿名称',
+    component: 'Input',
+    colProps: { span: 6 },
+  },
+  {
+    field: 'mineNameAbbr',
+    label: '煤矿简称',
+    component: 'Input',
+    colProps: { span: 6 },
+  },
+  {
+    field: 'productStatus',
+    label: '生产状态',
+    component: 'Select',
+    componentProps: {
+      options: [
+        { label: '拟建矿井', value: '0' },
+        { label: '正常生产矿井', value: '1' },
+        { label: '长期停产矿井', value: '1' },
+      ],
+    },
+    colProps: { span: 6 },
+  },
+  {
+    field: 'riskLevel',
+    label: '自燃情况',
+    component: 'Select',
+    componentProps: {
+      options: [
+        { label: 'Ⅰ类容易自燃', value: '0' },
+        { label: 'Ⅱ类自燃', value: '1' },
+        { label: 'Ⅲ类不易自燃', value: '2' },
+      ],
+    },
+    colProps: { span: 6 },
+  },
+  {
+    field: 'coalSeam',
+    label: '所属煤层',
+    component: 'Select',
+    componentProps: {
+      options: [
+        { label: '煤层1', value: '0' },
+        { label: '煤层2', value: '1' },
+        { label: '煤层3', value: '2' },
+      ],
+    },
+    colProps: { span: 6 },
+  },
+  {
+    field: 'sealedName',
+    label: '密闭名称',
+    component: 'Select',
+    componentProps: {
+      options: [
+        { label: '密闭1', value: '0' },
+        { label: '密闭2', value: '1' },
+        { label: '密闭3', value: '2' },
+      ],
+    },
+    colProps: { span: 6 },
+  },
+];
+
+export const minesData = [
+  {
+    orderNo: 101, // 序号
+    enforcement: '执法一处', // 区域
+    mineName: '神木市三江', // 煤矿名称
+    sealedName: '采空区密闭', // 密闭名称
+    coalSeam: 'XX煤层', // 所属煤层
+    riskLevel: 'Ⅰ类容易自燃', // 自燃倾向性(与搜索框选项label一致)
+    COVal: 24, // CO浓度(ppm)
+    CH4Val: 0, // CH4浓度(%)
+    C2H2Val: 0, // C2H2浓度(ppm)
+    O2Val: 20, // O2浓度(%)
+    temperature: 35, // 温度(℃)
+    pressureDiff: 50, // 压差(Pa)
+    leakage: '气体涌出', // 是否漏风
+    fireHazard: '低风险', // 自然发火隐患
+    unsealing: '不可启封', // 密闭启封判定
+    explosionHazard: '低风险', // 爆炸危险性
+    updateTime: '2025-12-22 15:00:40', // 更新时间
+  },
+  {
+    orderNo: 102, // 序号
+    enforcement: '执法一处', // 区域
+    mineName: '神木市三江', // 煤矿名称
+    sealedName: '采空区密闭', // 密闭名称
+    coalSeam: 'XX煤层', // 所属煤层
+    riskLevel: 'Ⅰ类容易自燃', // 自燃倾向性(与搜索框选项label一致)
+    COVal: 24, // CO浓度(ppm)
+    CH4Val: 0, // CH4浓度(%)
+    C2H2Val: 0, // C2H2浓度(ppm)
+    O2Val: 20, // O2浓度(%)
+    temperature: 35, // 温度(℃)
+    pressureDiff: 50, // 压差(Pa)
+    leakage: '气体涌出', // 是否漏风
+    fireHazard: '低风险', // 自然发火隐患
+    unsealing: '不可启封', // 密闭启封判定
+    explosionHazard: '低风险', // 爆炸危险性
+    updateTime: '2025-12-22 15:00:40', // 更新时间
+  },
+  {
+    orderNo: 103, // 序号
+    enforcement: '执法一处', // 区域
+    mineName: '神木市三江', // 煤矿名称
+    sealedName: '采空区密闭', // 密闭名称
+    coalSeam: 'XX煤层', // 所属煤层
+    riskLevel: 'Ⅰ类容易自燃', // 自燃倾向性(与搜索框选项label一致)
+    COVal: 24, // CO浓度(ppm)
+    CH4Val: 0, // CH4浓度(%)
+    C2H2Val: 0, // C2H2浓度(ppm)
+    O2Val: 20, // O2浓度(%)
+    temperature: 35, // 温度(℃)
+    pressureDiff: 50, // 压差(Pa)
+    leakage: '气体涌出', // 是否漏风
+    fireHazard: '低风险', // 自然发火隐患
+    unsealing: '不可启封', // 密闭启封判定
+    explosionHazard: '低风险', // 爆炸危险性
+    updateTime: '2025-12-22 15:00:40', // 更新时间
+  },
+]
+
+export const treeData: TreeItem[] = [
+  {
+    title: '气体参数 ',
+    key: '0-0',
+    children: [
+      { title: 'CO', key: '0-0-0' },
+      { title: 'CH4', key: '0-0-1' },
+      { title: 'C2H4', key: '0-0-2' },
+      { title: 'C2H2', key: '0-0-3' },
+      { title: 'CO2', key: '0-0-4' },
+      { title: 'O2', key: '0-0-5' },
+    ],
+  },
+  {
+    title: '内外压力及压差',
+    key: '1-1',
+    children: [
+      { title: '内压力', key: '1-1-0' },
+      { title: '外压力', key: '1-1-1' },
+      { title: '压差', key: '1-1-2' },
+    ],
+  },
+  {
+    title: '温度',
+    key: '2-2',
+  },
+];
+
+export const mockChartData = [
+  { time: '2025-12-22 00:00:00', CO: 22.3, CH4: 0.12, C2H4: 0.35, C2H2: 0.10, CO2: 0.85, O2: 19.5, innerPressure: 101.32, outerPressure: 101.10, pressureDiff: 0.22, temperature: 33.2 },
+  { time: '2025-12-22 01:00:00', CO: 23.1, CH4: 0.15, C2H4: 0.42, C2H2: 0.12, CO2: 0.92, O2: 19.7, innerPressure: 101.38, outerPressure: 101.15, pressureDiff: 0.23, temperature: 33.5 },
+  { time: '2025-12-22 02:00:00', CO: 22.8, CH4: 0.13, C2H4: 0.38, C2H2: 0.09, CO2: 0.88, O2: 19.6, innerPressure: 101.41, outerPressure: 101.18, pressureDiff: 0.23, temperature: 33.3 },
+  { time: '2025-12-22 03:00:00', CO: 21.9, CH4: 0.11, C2H4: 0.31, C2H2: 0.08, CO2: 0.81, O2: 19.4, innerPressure: 101.35, outerPressure: 101.12, pressureDiff: 0.21, temperature: 33.1 },
+  { time: '2025-12-22 04:00:00', CO: 22.5, CH4: 0.14, C2H4: 0.36, C2H2: 0.11, CO2: 0.86, O2: 19.5, innerPressure: 101.39, outerPressure: 101.16, pressureDiff: 0.22, temperature: 33.4 },
+  { time: '2025-12-22 05:00:00', CO: 23.4, CH4: 0.16, C2H4: 0.45, C2H2: 0.13, CO2: 0.95, O2: 19.8, innerPressure: 101.43, outerPressure: 101.20, pressureDiff: 0.24, temperature: 33.7 },
+  { time: '2025-12-22 06:00:00', CO: 24.2, CH4: 0.18, C2H4: 0.51, C2H2: 0.15, CO2: 1.02, O2: 20.0, innerPressure: 101.47, outerPressure: 101.23, pressureDiff: 0.25, temperature: 34.0 },
+  { time: '2025-12-22 07:00:00', CO: 25.3, CH4: 0.21, C2H4: 0.58, C2H2: 0.17, CO2: 1.08, O2: 20.2, innerPressure: 101.52, outerPressure: 101.27, pressureDiff: 0.26, temperature: 34.3 },
+  { time: '2025-12-22 08:00:00', CO: 26.1, CH4: 0.23, C2H4: 0.65, C2H2: 0.19, CO2: 1.15, O2: 20.4, innerPressure: 101.56, outerPressure: 101.30, pressureDiff: 0.27, temperature: 34.6 },
+  { time: '2025-12-22 09:00:00', CO: 27.4, CH4: 0.25, C2H4: 0.72, C2H2: 0.22, CO2: 1.23, O2: 20.6, innerPressure: 101.60, outerPressure: 101.33, pressureDiff: 0.28, temperature: 35.0 },
+  { time: '2025-12-22 10:00:00', CO: 28.2, CH4: 0.27, C2H4: 0.78, C2H2: 0.24, CO2: 1.29, O2: 20.8, innerPressure: 101.63, outerPressure: 101.35, pressureDiff: 0.29, temperature: 35.3 },
+  { time: '2025-12-22 11:00:00', CO: 27.8, CH4: 0.26, C2H4: 0.75, C2H2: 0.23, CO2: 1.26, O2: 20.7, innerPressure: 101.61, outerPressure: 101.34, pressureDiff: 0.28, temperature: 35.2 },
+  { time: '2025-12-22 12:00:00', CO: 26.9, CH4: 0.24, C2H4: 0.69, C2H2: 0.21, CO2: 1.19, O2: 20.5, innerPressure: 101.58, outerPressure: 101.32, pressureDiff: 0.27, temperature: 34.9 },
+  { time: '2025-12-22 13:00:00', CO: 26.3, CH4: 0.22, C2H4: 0.64, C2H2: 0.19, CO2: 1.14, O2: 20.3, innerPressure: 101.55, outerPressure: 101.30, pressureDiff: 0.26, temperature: 34.7 },
+  { time: '2025-12-22 14:00:00', CO: 25.7, CH4: 0.20, C2H4: 0.59, C2H2: 0.18, CO2: 1.09, O2: 20.1, innerPressure: 101.53, outerPressure: 101.28, pressureDiff: 0.25, temperature: 34.5 },
+  { time: '2025-12-22 15:00:00', CO: 24.9, CH4: 0.18, C2H4: 0.53, C2H2: 0.16, CO2: 1.03, O2: 19.9, innerPressure: 101.49, outerPressure: 101.25, pressureDiff: 0.24, temperature: 34.2 },
+  { time: '2025-12-22 16:00:00', CO: 24.3, CH4: 0.17, C2H4: 0.49, C2H2: 0.15, CO2: 0.98, O2: 19.8, innerPressure: 101.46, outerPressure: 101.22, pressureDiff: 0.23, temperature: 34.0 },
+  { time: '2025-12-22 17:00:00', CO: 23.8, CH4: 0.16, C2H4: 0.46, C2H2: 0.14, CO2: 0.94, O2: 19.7, innerPressure: 101.44, outerPressure: 101.21, pressureDiff: 0.23, temperature: 33.8 },
+  { time: '2025-12-22 18:00:00', CO: 23.5, CH4: 0.15, C2H4: 0.43, C2H2: 0.13, CO2: 0.91, O2: 19.6, innerPressure: 101.42, outerPressure: 101.19, pressureDiff: 0.22, temperature: 33.7 },
+  { time: '2025-12-22 19:00:00', CO: 24.1, CH4: 0.17, C2H4: 0.48, C2H2: 0.15, CO2: 0.97, O2: 19.8, innerPressure: 101.45, outerPressure: 101.22, pressureDiff: 0.24, temperature: 33.9 },
+  { time: '2025-12-22 20:00:00', CO: 24.7, CH4: 0.19, C2H4: 0.52, C2H2: 0.16, CO2: 1.01, O2: 20.0, innerPressure: 101.48, outerPressure: 101.24, pressureDiff: 0.25, temperature: 34.1 },
+  { time: '2025-12-22 21:00:00', CO: 25.2, CH4: 0.20, C2H4: 0.56, C2H2: 0.18, CO2: 1.05, O2: 20.1, innerPressure: 101.51, outerPressure: 101.26, pressureDiff: 0.26, temperature: 34.3 },
+  { time: '2025-12-22 22:00:00', CO: 24.5, CH4: 0.18, C2H4: 0.50, C2H2: 0.16, CO2: 0.99, O2: 19.9, innerPressure: 101.47, outerPressure: 101.23, pressureDiff: 0.24, temperature: 34.0 },
+  { time: '2025-12-22 23:00:00', CO: 23.7, CH4: 0.16, C2H4: 0.45, C2H2: 0.14, CO2: 0.93, O2: 19.7, innerPressure: 101.43, outerPressure: 101.20, pressureDiff: 0.23, temperature: 33.8 },
+  { time: '2025-11-18 00:00:00', CO: 22.9, CH4: 0.14, C2H4: 0.39, C2H2: 0.11, CO2: 0.89, O2: 19.6, innerPressure: 101.37, outerPressure: 101.17, pressureDiff: 0.22, temperature: 33.4 },
+];

+ 58 - 0
src/views/dashboard/sealedMonitoring/historicalData/index.vue

@@ -0,0 +1,58 @@
+<template>
+  <div>
+    <BasicTable @register="registerTable" :scroll="{ x: 'max-content' }" >
+      <template #action="{ record }">
+        <div class="action-buttons">
+          <button @click="openModal(record)" class="action-btn">
+            <img src="@/assets/images/common/icon-details.svg" class="action-icon" />
+          </button>
+        </div>
+      </template>
+    </BasicTable>
+    
+    <!-- 监测详情弹框 -->
+    <MonitoringDetailsModal ref="monitoringModalRef" />
+  </div>
+</template>
+
+<script setup lang="ts">
+  import { ref } from 'vue';
+  import { BasicTable, useTable } from '/@/components/Table';
+  import { columns, searchFormSchema, minesData } from './historicalData.data';
+  import MonitoringDetailsModal from './components/MonitoringDetailsModal.vue';
+
+  // 注册表格并获取相关方法
+  const [registerTable] = useTable({
+    dataSource: minesData,
+    columns,
+    formConfig: {
+      labelWidth: 120,
+      schemas: searchFormSchema,
+      showAdvancedButton: false,
+    },
+    pagination: false,
+    striped: false,
+    useSearchForm: true,
+    bordered: true,
+    showIndexColumn: false,
+    canResize: false,
+    actionColumn: {
+      width: 60,
+      title: '操作',
+      dataIndex: 'action',
+      slots: { customRender: 'action' },
+      fixed: undefined,
+    },
+  });
+
+  const monitoringModalRef = ref(null);
+  const openModal = (record) => {
+    monitoringModalRef.value?.showModal();
+  };
+
+</script>
+<style lang="less" scoped>
+  .action-btn {
+    cursor: pointer;
+  }
+</style>