From 58c0f11fe2f23a1be2dec768f9ac02107301a634 Mon Sep 17 00:00:00 2001
From: riku <risaku@163.com>
Date: 星期五, 19 九月 2025 17:30:36 +0800
Subject: [PATCH] 2025.9.19 数据产品(待完成)

---
 src/views/fysp/data-product/base-data-product/ProdMonitorDataInfo.vue        |   98 +++++
 src/views/fysp/data-product/base-data-product/ProdInspectionInfo.vue         |   40 +
 src/components/search-option/FYOptionTopTask.vue                             |   84 ++++
 src/views/fysp/data-product/components/ProdQueryOpt.vue                      |    0 
 src/components.d.ts                                                          |    2 
 src/constants/menu.js                                                        |    5 
 src/router/index copy.js                                                     |    4 
 src/components/search-option/FYOptionLocation.vue                            |    2 
 src/views/fysp/data-product/ProdLawEnforceList.vue                           |   14 
 src/views/fysp/data-product/components/ProdQueryOptCompare.vue               |  102 +++++
 src/utils/echart-util.js                                                     |  208 ++++------
 src/views/fysp/data-product/middle-data-product/ProdEvaluationSummary.vue    |   28 +
 src/views/fysp/data-product/middle-data-product/ProdProblemCountSummary.vue  |   33 +
 src/views/fysp/data-product/components/BaseProdProcess.vue                   |    4 
 src/views/fysp/data-product/components/CompProdManage.vue                    |   50 +-
 src/views/fysp/data-product/base-data-product/ProdSceneInfo.vue              |    7 
 src/views/fysp/data-product/components/ProdDownload.vue                      |    0 
 src/views/fysp/data-product/middle-data-product/ProdProblemTypeSummary.vue   |  127 ++++++
 src/views/fysp/data-product/middle-data-product/ProdMonitorDeviceSummary.vue |   28 +
 src/views/fysp/data-product/base-data-product/ManageBaseProd.vue             |   27 +
 src/views/fysp/data-product/base-data-product/ProdEvaluationInfo.vue         |    2 
 src/router/index.js                                                          |   83 +++
 src/components/table/FYTable.vue                                             |    8 
 src/main.js                                                                  |    4 
 src/views/fysp/data-product/middle-data-product/ProdInspectionSummary.vue    |   75 +++
 src/views/fysp/support/JingAnNightConstruction.vue                           |   24 +
 src/utils/excel.js                                                           |    4 
 src/views/fysp/data-product/middle-data-product/ManageMiddleProd.vue         |   31 +
 src/views/fysp/data-product/components/CompProdTextGenerator.vue             |   25 +
 29 files changed, 927 insertions(+), 192 deletions(-)

diff --git a/src/components.d.ts b/src/components.d.ts
index 3d570e1..61329ff 100644
--- a/src/components.d.ts
+++ b/src/components.d.ts
@@ -13,6 +13,7 @@
     CompGenericWrapper: typeof import('./components/CompGenericWrapper.vue')['default']
     CompQuickSet: typeof import('./components/search-option/CompQuickSet.vue')['default']
     Content: typeof import('./components/core/Content.vue')['default']
+    copy: typeof import('./components/search-option/FYOptionScene copy.vue')['default']
     ElAffix: typeof import('element-plus/es')['ElAffix']
     ElAside: typeof import('element-plus/es')['ElAside']
     ElAvatar: typeof import('element-plus/es')['ElAvatar']
@@ -92,6 +93,7 @@
     FYOptionSupervisionStatus: typeof import('./components/search-option/FYOptionSupervisionStatus.vue')['default']
     FYOptionText: typeof import('./components/search-option/base/FYOptionText.vue')['default']
     FYOptionTime: typeof import('./components/search-option/FYOptionTime.vue')['default']
+    FYOptionTopTask: typeof import('./components/search-option/FYOptionTopTask.vue')['default']
     FYOptionUserType: typeof import('./components/search-option/FYOptionUserType.vue')['default']
     FYPageHeader: typeof import('./components/head/FYPageHeader.vue')['default']
     FYReconfrimButton: typeof import('./components/button/FYReconfrimButton.vue')['default']
diff --git a/src/components/search-option/FYOptionLocation.vue b/src/components/search-option/FYOptionLocation.vue
index cf5cee9..3a0aabb 100644
--- a/src/components/search-option/FYOptionLocation.vue
+++ b/src/components/search-option/FYOptionLocation.vue
@@ -1,13 +1,13 @@
 <template>
   <el-form-item :label="placeholder" :prop="prop">
     <el-cascader
+      v-bind="$attrs"
       :model-value="formatedValue"
       @change="handleChange"
       :options="locations"
       :placeholder="placeholder"
       :props="optionProps"
       style="width: 320px"
-      v-bind="$attrs"
     />
   </el-form-item>
 </template>
diff --git a/src/components/search-option/FYOptionTopTask.vue b/src/components/search-option/FYOptionTopTask.vue
new file mode 100644
index 0000000..291094b
--- /dev/null
+++ b/src/components/search-option/FYOptionTopTask.vue
@@ -0,0 +1,84 @@
+<template>
+  <el-form-item :label="label" :prop="prop">
+    <el-select
+      :model-value="formatedValue"
+      @update:model-value="handleChange"
+      placeholder="鎬讳换鍔�"
+      style="width: 260px"
+    >
+      <el-option
+        v-for="s in topTasks"
+        :key="s.value"
+        :label="s.label"
+        :value="s.value"
+      />
+    </el-select>
+  </el-form-item>
+</template>
+
+<script>
+import taskApi from '@/api/fysp/taskApi';
+
+export default {
+  props: {
+    label: {
+      type: String,
+      default: '鎬讳换鍔�'
+    },
+    // 杩斿洖缁撴灉
+    value: Object,
+    // 鏄惁榛樿杩斿洖鍒濆閫夐」
+    initValue: {
+      type: Boolean,
+      default: true
+    },
+    // form琛ㄥ崟缁戝畾灞炴�у悕
+    prop: {
+      type: String,
+      default: 'topTaskId'
+    },
+  },
+  emits: ['update:value'],
+  data() {
+    return {
+      selected: {},
+      topTasks: [],
+    };
+  },
+  computed: {
+    formatedValue() {
+      return this.value.tguid;
+    }
+  },
+  methods: {
+    //鑾峰彇鏌ヨ鏉′欢
+    getOptions() {
+      taskApi.getTopTask().then((res) => {
+        const list = res.map((r) => {
+          return {
+            value: r.tguid,
+            label: r.name,
+            data: r
+          };
+        });
+        this.topTasks = list;
+        if (this.initValue) {
+          this.handleChange(list[0].value);
+        }
+      });
+    },
+    //鏌ヨ瀛愪换鍔$粺璁′俊鎭�
+    handleChange(value) {
+      const task = this.topTasks.find(
+        (t) => t.data.tguid == value
+      );
+      const param = task ? task.data : {}
+
+      this.$emit('update:value', param);
+    },
+  },
+  mounted() {
+    this.getOptions();
+  }
+};
+</script>
diff --git a/src/components/table/FYTable.vue b/src/components/table/FYTable.vue
index a85de22..2590983 100644
--- a/src/components/table/FYTable.vue
+++ b/src/components/table/FYTable.vue
@@ -90,6 +90,10 @@
       type: Number,
       default: 0
     },
+    defaultPageSize: {
+      type: Number,
+      default: 20
+    },
     // 棰濆鐨勯珮搴︼紝鐢ㄤ簬璁$畻琛ㄦ牸楂樺害
     extraHeight: {
       type: Number,
@@ -102,7 +106,7 @@
       tableData: [],
       total: 0,
       currentPage: 1,
-      pageSize: 20,
+      pageSize: this.defaultPageSize,
       loading: false,
       fontSize: 'default'
     };
@@ -142,7 +146,7 @@
         if (nValue != oValue) {
           this.tableHeight = this.calcTableHeight();
         }
-      },
+      }
     }
   },
   computed: {},
diff --git a/src/constants/menu.js b/src/constants/menu.js
index 767b029..136fcc1 100644
--- a/src/constants/menu.js
+++ b/src/constants/menu.js
@@ -74,6 +74,11 @@
     name: '涓棿鏁版嵁浜у搧',
     children: [
       {
+        path: '/fysp/data-product/middle/home/inspectionSummary',
+        icon: 'Document',
+        name: '鏈堝害宸℃煡绠�鎶�'
+      },
+      {
         path: '/fysp/data-product/profollow',
         icon: 'Document',
         name: '闂鍔ㄦ�佽窡韪�'
diff --git a/src/main.js b/src/main.js
index ceb52d6..175bb60 100644
--- a/src/main.js
+++ b/src/main.js
@@ -20,9 +20,6 @@
 import isSameOrAfter from 'dayjs/plugin/isSameOrAfter';
 import isSameOrBefore from 'dayjs/plugin/isSameOrBefore';
 
-// echarts
-import * as echarts from 'echarts'
-
 
 dayjs.extend(isSameOrAfter);
 dayjs.extend(isSameOrBefore);
@@ -30,7 +27,6 @@
 const app = createApp(App);
 
 app.config.globalProperties.$fm = timeUtil;
-app.config.globalProperties.$echarts = echarts
 app.config.globalProperties.$message = ElMessage
 app.config.globalProperties.$notification = ElNotification
 app.config.globalProperties.$messageBox = ElMessageBox
diff --git a/src/router/index copy.js b/src/router/index copy.js
index fa7bcf8..2ff6cb5 100644
--- a/src/router/index copy.js
+++ b/src/router/index copy.js
@@ -181,10 +181,10 @@
       },
       {
         // 鍩虹浜у搧-绠$悊
-        name: 'ProdManage',
+        name: 'ManageBaseProd',
         path: 'fysp/data-product/base/home',
         component: () =>
-          import('@/views/fysp/data-product/base-data-product/ProdManage.vue'),
+          import('@/views/fysp/data-product/base-data-product/ManageBaseProd.vue'),
         children: [
           {
             // 鍩虹浜у搧-鍦烘櫙娓呭崟
diff --git a/src/router/index.js b/src/router/index.js
index c229675..ba8f36f 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -70,7 +70,7 @@
                   import('@/views/fysp/data-product/ProdSceneReport.vue')
               },
               {
-                //鍦烘櫙鎶ュ憡
+                //鑱斿悎鎵ф硶娓呭崟
                 name: 'lawenforcelist',
                 path: 'lawenforcelist',
                 component: () =>
@@ -82,18 +82,18 @@
                 children: [
                   {
                     // 鍩虹浜у搧-绠$悊
-                    name: 'ProdManage',
+                    name: 'ManageBaseProd',
                     path: 'home',
                     component: () =>
                       import(
-                        '@/views/fysp/data-product/base-data-product/ProdManage.vue'
+                        '@/views/fysp/data-product/base-data-product/ManageBaseProd.vue'
                       ),
                     children: [
                       {
                         // 鍩虹浜у搧-鍦烘櫙娓呭崟
                         path: 'scene',
                         name: 'ProdSceneInfo',
-                        meta: { keepAlive: true, key: 'ProdManage' },
+                        meta: { keepAlive: false, key: 'ManageBaseProd' },
                         component: () =>
                           import(
                             '@/views/fysp/data-product/base-data-product/ProdSceneInfo.vue'
@@ -103,17 +103,17 @@
                         // 鍩虹浜у搧-瑙勮寖鎬ц瘎浼�
                         path: 'evaluate',
                         name: 'ProdEvaluationInfo',
-                        meta: { keepAlive: true, key: 'ProdManage' },
+                        meta: { keepAlive: false, key: 'ManageBaseProd' },
                         component: () =>
                           import(
                             '@/views/fysp/data-product/base-data-product/ProdEvaluationInfo.vue'
                           )
                       },
                       {
-                        // 鍩虹浜у搧-宸℃煡淇℃伅
+                        // 鍩虹浜у搧-鏁存敼娓呭崟
                         path: 'inspection',
                         name: 'ProdInspectionInfo',
-                        meta: { keepAlive: true, key: 'ProdManage' },
+                        meta: { keepAlive: false, key: 'ManageBaseProd' },
                         component: () =>
                           import(
                             '@/views/fysp/data-product/base-data-product/ProdInspectionInfo.vue'
@@ -123,7 +123,7 @@
                         // 鍩虹浜у搧-鐩戞祴鏁版嵁
                         path: 'monitordata',
                         name: 'ProdMonitorDataInfo',
-                        meta: { keepAlive: true, key: 'ProdManage' },
+                        meta: { keepAlive: false, key: 'ManageBaseProd' },
                         component: () =>
                           import(
                             '@/views/fysp/data-product/base-data-product/ProdMonitorDataInfo.vue'
@@ -141,6 +141,73 @@
                       )
                   }
                 ]
+              },
+              {
+                name: 'dataProdMiddle',
+                path: 'middle',
+                children: [
+                  {
+                    // 涓棿浜у搧-绠$悊
+                    name: 'ManageMiddleProd',
+                    path: 'home',
+                    component: () =>
+                      import(
+                        '@/views/fysp/data-product/middle-data-product/ManageMiddleProd.vue'
+                      ),
+                    children: [
+                      {
+                        // 涓棿浜у搧-鏈堝害宸℃煡鎯呭喌姹囨��
+                        path: 'inspectionSummary',
+                        name: 'ProdInspectionSummary',
+                        meta: { keepAlive: false, key: 'ManageMiddleProd' },
+                        component: () =>
+                          import(
+                            '@/views/fysp/data-product/middle-data-product/ProdInspectionSummary.vue'
+                          )
+                      },
+                      {
+                        // 涓棿浜у搧-鏈堝害闂姹囨��
+                        path: 'problemTypeSummary',
+                        name: 'ProdProblemTypeSummary',
+                        meta: { keepAlive: false, key: 'ManageMiddleProd' },
+                        component: () =>
+                          import(
+                            '@/views/fysp/data-product/middle-data-product/ProdProblemTypeSummary.vue'
+                          )
+                      },
+                      {
+                        // 涓棿浜у搧-鍒嗚闀囧崟鍦烘櫙闂鏁板潎鍊�
+                        path: 'problemCountSummary',
+                        name: 'ProdProblemCountSummary',
+                        meta: { keepAlive: false, key: 'ManageMiddleProd' },
+                        component: () =>
+                          import(
+                            '@/views/fysp/data-product/middle-data-product/ProdProblemCountSummary.vue'
+                          )
+                      },
+                      {
+                        // 涓棿浜у搧-鐩戞祴璁惧姹囨��
+                        path: 'monitorDeviceSummary',
+                        name: 'ProdMonitorDeviceSummary',
+                        meta: { keepAlive: false, key: 'ManageMiddleProd' },
+                        component: () =>
+                          import(
+                            '@/views/fysp/data-product/middle-data-product/ProdMonitorDeviceSummary.vue'
+                          )
+                      },
+                      {
+                        // 涓棿浜у搧-璇勪及鎯呭喌
+                        path: 'evaluationSummary',
+                        name: 'ProdEvaluationSummary',
+                        meta: { keepAlive: false, key: 'ManageMiddleProd' },
+                        component: () =>
+                          import(
+                            '@/views/fysp/data-product/middle-data-product/ProdEvaluationSummary.vue'
+                          )
+                      },
+                    ]
+                  },
+                ]
               }
             ]
           },
diff --git a/src/utils/echart-util.js b/src/utils/echart-util.js
index 0934d69..ad12e65 100644
--- a/src/utils/echart-util.js
+++ b/src/utils/echart-util.js
@@ -1,123 +1,95 @@
-// 閫掑綊鐨勮幏鍙杘bj涓殑prop灞炴�� 瑙e喅鏈夋椂闇�瑕佸彇val.obj.prop鐨勬儏鍐�
-function getPropValueLoop(obj, prop) {
-  if (typeof prop !== 'string') {
-    return obj;
-  }
-  const props = prop.split('.');
-  let result = obj;
-  props.forEach((item) => {
-    result = result[item];
-  });
-  return result;
-}
-function getCount(array, element) {
-  let count = 0;
-  array.forEach((e) => {
-    if (e == element) {
-      count++;
-    }
-  });
-  return count;
-}
-export default {
-  /** 灏哻hart鍥捐〃杞寲涓哄浘鐗噓rl
-   * @param chart锛� chart鍥捐〃鐨勫疄渚�
-   *  */
-  chartToImageUrl(chart) {
-    const dataURL = chart.getDataURL({
-      pixelRatio: 5, // 鎻愰珮鍥剧墖璐ㄩ噺
-      backgroundColor: '#FFFFFF', // 璁剧疆鑳屾櫙棰滆壊
-      excludeComponents: ['toolbox'], // 鎺掗櫎宸ュ叿绠辩粍浠�
-      type: 'png' // 杈撳嚭鍥剧墖绫诲瀷涓篜NG
-    });
-    return dataURL;
-  },
-  // 灞曠ず data 鏁扮粍涓璞$殑 prop 灞炴�х殑楗煎浘, title 鏄ゼ鍥剧殑鏍囬
-  getPieChartByDataAndProp(data, prop, label) {
-    let chartData = [];
-    function hasThisName(name) {
-      for (let index = 0; index < chartData.length; index++) {
-        const element = chartData[index];
-        if (element.name === name) {
-          return true;
+function pieChartOption() {
+  return {
+    color: [
+      '#5470c6',
+      '#91cc75',
+      '#fac858',
+      '#ee6666',
+      '#73c0de',
+      '#3ba272',
+      '#fc8452',
+      '#9a60b4',
+      '#ea7ccc',
+      '#514a9d',
+      '#2ec7c9',
+      '#b6a2de'
+    ],
+    title: {
+      text: `楗煎浘榛樿鍚嶇О`,
+      left: 'center' // 鏍囬灞呬腑鏄剧ず
+    },
+    // 娣诲姞宸ュ叿鏍忛厤缃紝鍖呭惈涓嬭浇鍔熻兘
+    toolbox: {
+      show: true,
+      feature: {
+        saveAsImage: {
+          show: true,
+          title: '涓嬭浇鍥捐〃',
+          type: 'png',
+          pixelRatio: 2 // 鎻愰珮鍥剧墖娓呮櫚搴�
         }
       }
-      return false;
-    }
-
-    data.map((item) => {
-      const name = getPropValueLoop(item, prop);
-      if (hasThisName(name)) {
-        chartData.map((item) => {
-          if (item.name === name) {
-            item.value++;
+    },
+    tooltip: {
+      trigger: 'item', // 楗煎浘浣跨敤item瑙﹀彂tooltip
+      formatter: '{a} <br/>{b}: {c} ({d}%)' // 鏄剧ず鏍煎紡锛氬悕绉�: 鏁伴噺 (鐧惧垎姣�)
+    },
+    legend: {
+      show: false,
+      orient: 'vertical',
+      left: 'right', // 鍥句緥灞呭乏鍨傜洿鎺掑垪
+      data: ['sample1', 'sample2', 'sample3'] // 鍥句緥鏁版嵁涓洪棶棰樼被鍨嬪悕绉�
+    },
+    series: [
+      {
+        name: 'sample',
+        type: 'pie', // 鍥捐〃绫诲瀷鏀逛负楗煎浘
+        radius: '60%', // 楗煎浘鍗婂緞
+        center: ['50%', '55%'], // 楗煎浘涓績浣嶇疆
+        data: [
+          {
+            name: 'sample1',
+            value: 100
+          },
+          {
+            name: 'sample2',
+            value: 200
+          },
+          {
+            name: 'sample3',
+            value: 300
           }
-        });
-      } else {
-        chartData.push({
-          name: name,
-          value: 1
-        });
+        ],
+        label: {
+          show: true,
+          formatter: '{b}: {c} ({d}%)' // 鎵囧尯鏍囩鏄剧ず锛氬悕绉�: 鏁伴噺 (鐧惧垎姣�)
+        }
       }
-    });
+    ]
+  };
+}
 
-    return {
-      title: {
-        text: label,
-        left: 'center'
-      },
-      tooltip: {
-        trigger: 'item'
-      },
-      legend: {
-        orient: 'vertical',
-        left: 'left'
-      },
-      series: [
-        {
-          type: 'pie',
-          radius: '50%',
-          data: chartData,
-          emphasis: {
-            itemStyle: {
-              shadowBlur: 10,
-              shadowOffsetX: 0,
-              shadowColor: 'rgba(0, 0, 0, 0.5)'
-            }
-          }
-        }
-      ]
-    };
-  },
-  // 灞曠ず data 鏁扮粍涓璞$殑 prop 灞炴�х殑鐩存柟鍥�, title 鏄洿鏂瑰浘鐨勬爣棰�
-  getBarChartByDataAndProp(data, prop, title) {
-    let series = data.map((item) => getPropValueLoop(item, prop));
-    const option = {
-      title: {
-        text: title //璁剧疆鏍囬
-      },
-      xAxis: {
-        type: 'category',
-        data: Array.from(new Set(series)),
-        axisLabel: {
-          rotate: 45, // 鏃嬭浆鏍囩锛岄伩鍏嶉噸鍙�
-          // 鎴栬��
-          interval: 0 // 鏄剧ず鎵�鏈夋爣绛撅紝鍙兘瀵艰嚧閲嶅彔锛屾牴鎹渶姹傝皟鏁�
-        }
-      },
-      yAxis: {
-        type: 'value'
-      },
-      series: [
-        {
-          data: Array.from(new Set(series)).map((item) =>
-            getCount(series, item)
-          ),
-          type: 'bar',
-          smooth: true
-        }
-      ]
-    };
-    return option;
-  }
-};
+// 閫氳繃 ECharts API 涓嬭浇鍥剧墖鐨勫嚱鏁�
+function downloadChartImage(chart, fileName) {
+  if (!chart) return; // 纭繚鍥捐〃宸插垵濮嬪寲
+
+  // 鑾峰彇鍥捐〃鍥剧墖鏁版嵁锛堟敮鎸� png/jpeg 鏍煎紡锛宲ixelRatio 鎺у埗娓呮櫚搴︼級
+  const dataURL = chart.getDataURL({
+    type: 'png', // 鍥剧墖鏍煎紡
+    pixelRatio: 2, // 鍍忕礌姣旓紝鍊艰秺澶у浘鐗囪秺娓呮櫚
+    backgroundColor: '#fff', // 鑳屾櫙鑹诧紙榛樿閫忔槑锛�
+    excludeComponents: ['toolbox']
+  });
+  // 鍒涘缓涓嬭浇閾炬帴
+  const link = document.createElement('a');
+  link.href = dataURL;
+  // 璁剧疆涓嬭浇鏂囦欢鍚嶏紙鍙牴鎹疄闄呴渶姹傝皟鏁达級
+  link.download = `${fileName}.png`;
+  // 娣诲姞鍒版枃妗e苟瑙﹀彂涓嬭浇
+  document.body.appendChild(link);
+  link.click();
+  // 娓呯悊閾炬帴鍏冪礌
+  document.body.removeChild(link);
+}
+
+export { pieChartOption, downloadChartImage };
diff --git a/src/utils/excel.js b/src/utils/excel.js
index 07a0cc2..9caa91c 100644
--- a/src/utils/excel.js
+++ b/src/utils/excel.js
@@ -1,5 +1,7 @@
 import * as XLSX from 'xlsx';
 import FileSaver from 'file-saver';
+import { ElMessage } from 'element-plus';
+
 
 function conversionFromTable(elementId, title) {
   // 鑾峰彇琛ㄦ牸鍏冪礌
@@ -38,7 +40,7 @@
       `${title}.xlsx` //淇敼鍚嶅瓧
     );
     //杩欓噷鍙互鏀惧叆浣犵殑鍥炶皟鍑芥暟
-    alert('寮�濮嬩笅杞�');
+    ElMessage.success('寮�濮嬩笅杞�');
   } catch (e) {
     if (typeof console !== 'undefined') console.log(e, table_write);
   }
diff --git a/src/views/fysp/data-product/ProdLawEnforceList.vue b/src/views/fysp/data-product/ProdLawEnforceList.vue
index 940d70d..caed506 100644
--- a/src/views/fysp/data-product/ProdLawEnforceList.vue
+++ b/src/views/fysp/data-product/ProdLawEnforceList.vue
@@ -76,15 +76,11 @@
           <el-icon class="is-loading" v-if="row._loading">
             <Loading color="#409eff" />
           </el-icon>
-          <div v-else>
-            <template v-if="row._problems.length > 0">
-              <div v-for="(p, i) in row._problems" :key="p.guid">
-                <el-text>{{ i + 1 }}銆�</el-text>
-                <el-text>{{ p.problemname }}</el-text>
-              </div>
+          <template v-else-if="row._problems.length > 0">
+            <template v-for="(p, i) in row._problems" :key="p.guid">
+              <br v-if="i > 0" />{{ i + 1 + '銆�' + p.problemname }}
             </template>
-            <el-text v-else>/</el-text>
-          </div>
+          </template>
         </template>
       </el-table-column>
       <!-- <el-table-column
@@ -325,7 +321,7 @@
     filterHandler(value, row, column) {
       const property = column['property'];
       return row[property] === value;
-    },
+    }
   },
   mounted() {
     this.addRefreshEvent(this.$refs.tableRef.doLayout);
diff --git a/src/views/fysp/data-product/base-data-product/ManageBaseProd.vue b/src/views/fysp/data-product/base-data-product/ManageBaseProd.vue
new file mode 100644
index 0000000..d956404
--- /dev/null
+++ b/src/views/fysp/data-product/base-data-product/ManageBaseProd.vue
@@ -0,0 +1,27 @@
+<template>
+  <CompProdManage :menu="menu" />
+</template>
+<script setup>
+import { ref } from 'vue';
+import CompProdManage from '@/views/fysp/data-product/components/CompProdManage.vue';
+
+const menu = ref([
+  {
+    name: '鍦烘櫙娓呭崟',
+    path: 'scene',
+  },
+  {
+    name: '璇勪及娓呭崟',
+    path: 'evaluate'
+  },
+  {
+    name: '鏁存敼娓呭崟',
+    path: 'inspection'
+  },
+  {
+    name: '鐩戞祴鏁版嵁',
+    path: 'monitorData'
+  }
+]);
+</script>
+<style scoped></style>
diff --git a/src/views/fysp/data-product/base-data-product/ProdEvaluationInfo.vue b/src/views/fysp/data-product/base-data-product/ProdEvaluationInfo.vue
index c9c31d5..b64f367 100644
--- a/src/views/fysp/data-product/base-data-product/ProdEvaluationInfo.vue
+++ b/src/views/fysp/data-product/base-data-product/ProdEvaluationInfo.vue
@@ -56,7 +56,7 @@
 <script setup>
 import { ref, inject } from 'vue';
 import dayjs from 'dayjs';
-import BaseProdProcess from '@/views/fysp/data-product/base-data-product/components/BaseProdProcess.vue';
+import BaseProdProcess from '@/views/fysp/data-product/components/BaseProdProcess.vue';
 import dataprodbaseApi from '@/api/fysp/dataprodbaseApi.js';
 import { conversionFromTable } from '@/utils/excel';
 import { useProdStepChange } from '@/views/fysp/data-product/prod-step-change.js';
diff --git a/src/views/fysp/data-product/base-data-product/ProdInspectionInfo.vue b/src/views/fysp/data-product/base-data-product/ProdInspectionInfo.vue
index 10bd091..0e8db25 100644
--- a/src/views/fysp/data-product/base-data-product/ProdInspectionInfo.vue
+++ b/src/views/fysp/data-product/base-data-product/ProdInspectionInfo.vue
@@ -37,24 +37,35 @@
         <el-table-column prop="cityname" label="甯�" width="90" />
         <el-table-column prop="districtname" label="鍖哄幙" width="90" /> -->
         <el-table-column prop="subTask.townname" label="琛楅亾" width="80" />
+        <el-table-column prop="problems.length" label="闂鏁�" width="60" />
+        <el-table-column label="闂鎽樿" width="300">
+          <template #default="{ row }">
+            <template v-for="(value, index) in row.problems" :key="value.guid">
+              <br v-if="index > 0" />{{ index + 1 + '銆�' + value.problemname }}
+            </template>
+          </template>
+        </el-table-column>
         <el-table-column
-          prop="problems.length"
-          label="闂鏁�"
-          width="60"
-        />
-        <el-table-column prop="scoreLevel" label="闂鎽樿" width="70" />
-        <el-table-column
-          prop="evaluate.resultscorebef"
+          prop="unChangeProblems.length"
           label="鏈暣鏀规暟"
           width="60"
         />
-        <el-table-column prop="scoreLevel" label="鏈暣鏀归棶棰�" width="70" />
-        <el-table-column
+        <el-table-column label="鏈暣鏀归棶棰�" width="300">
+          <template #default="{ row }">
+            <template
+              v-for="(value, index) in row.unChangeProblems"
+              :key="value.guid"
+            >
+              <br v-if="index > 0" />{{ index + 1 + '銆�' + value.problemname }}
+            </template>
+          </template>
+        </el-table-column>
+        <!-- <el-table-column
           prop="evaluate.updatedate"
           label="鏇存柊鏃堕棿"
           width="140"
           :formatter="timeFormat"
-        />
+        /> -->
       </el-table>
     </template>
   </BaseProdProcess>
@@ -62,7 +73,7 @@
 <script setup>
 import { ref, inject } from 'vue';
 import dayjs from 'dayjs';
-import BaseProdProcess from '@/views/fysp/data-product/base-data-product/components/BaseProdProcess.vue';
+import BaseProdProcess from '@/views/fysp/data-product/components/BaseProdProcess.vue';
 import dataprodbaseApi from '@/api/fysp/dataprodbaseApi.js';
 import { conversionFromTable } from '@/utils/excel';
 import { useProdStepChange } from '@/views/fysp/data-product/prod-step-change.js';
@@ -77,7 +88,12 @@
     .fetchProdInspectionInfo(opt)
     .then((res) => {
       if (res.success) {
-        tableData.value = res.data;
+        tableData.value = res.data.map((item) => {
+          return {
+            ...item,
+            unChangeProblems: item.problems.filter((p) => !p.ischanged)
+          };
+        });
       }
       changeActive();
     })
diff --git a/src/views/fysp/data-product/base-data-product/ProdMonitorDataInfo.vue b/src/views/fysp/data-product/base-data-product/ProdMonitorDataInfo.vue
index 91bfefa..cc5e097 100644
--- a/src/views/fysp/data-product/base-data-product/ProdMonitorDataInfo.vue
+++ b/src/views/fysp/data-product/base-data-product/ProdMonitorDataInfo.vue
@@ -1,4 +1,98 @@
 <template>
-  1
+  <BaseProdProcess
+    v-model:active="active"
+    @onStep1="onStep1"
+    @onStep2="onStep2"
+    @onStep3="onStep3"
+    :loading="loading"
+  >
+    <template #step2="{ contentHeight }">
+      <el-table
+        id="prod-scene-table"
+        :data="tableData"
+        v-loading="loading"
+        :height="contentHeight + 'px'"
+        table-layout="fixed"
+        :show-overflow-tooltip="true"
+        size="small"
+        border
+      >
+        <el-table-column fixed="left" prop="index" label="鎺掑悕" width="50">
+        </el-table-column>
+        <el-table-column
+          fixed="left"
+          prop="scene.name"
+          label="鍚嶇О"
+          :show-overflow-tooltip="true"
+          min-width="200"
+        >
+        </el-table-column>
+        <el-table-column prop="data.drAvg" label="骞冲潎鍊�(mg/m鲁)" width="100" />
+        <el-table-column
+          prop="data.drOverAvgPer"
+          label="瓒呭尯鍧囧��"
+          width="80"
+          :formatter="ratioFormat"
+        />
+        <el-table-column label="瓒呭競鍧囧��" width="80" />
+        <!-- <el-table-column prop="provincename" label="鐪�" width="90" />
+        <el-table-column prop="cityname" label="甯�" width="90" />
+        <el-table-column prop="districtname" label="鍖哄幙" width="90" /> -->
+        <el-table-column prop="scene.townname" label="灞炲湴" width="110" />
+      </el-table>
+    </template>
+    <!-- <template #step3></template> -->
+  </BaseProdProcess>
 </template>
-<script setup></script>
\ No newline at end of file
+<script setup>
+import { ref, inject } from 'vue';
+import dayjs from 'dayjs';
+import BaseProdProcess from '@/views/fysp/data-product/components/BaseProdProcess.vue';
+import dataprodbaseApi from '@/api/fysp/dataprodbaseApi.js';
+import { conversionFromTable } from '@/utils/excel';
+import { useProdStepChange } from '@/views/fysp/data-product/prod-step-change.js';
+
+const { active, changeActive } = useProdStepChange();
+const loading = ref(false);
+const tableData = ref([]);
+
+function onStep1(opt) {
+  loading.value = true;
+  dataprodbaseApi
+    .fetchProdMonitorDataInfo(opt)
+    .then((res) => {
+      if (res.success) {
+        tableData.value = res.data
+          .sort((a, b) => {
+            return b.data.drAvg - a.data.drAvg;
+          })
+          .map((item, index) => {
+            return {
+              ...item,
+              index: index + 1
+            };
+          });
+      }
+      changeActive();
+    })
+    .finally(() => {
+      loading.value = false;
+    });
+}
+
+function onStep2() {
+  changeActive();
+}
+
+function onStep3(val) {
+  if (val.downloadType == '1') {
+    loading.value = true;
+    conversionFromTable('prod-scene-table', '鍦ㄧ嚎鐩戞祴鏁版嵁娓呭崟');
+    loading.value = false;
+  }
+}
+
+function ratioFormat(row, column, cellValue, index) {
+  return Math.round(cellValue * 1000) / 10 + '%';
+}
+</script>
diff --git a/src/views/fysp/data-product/base-data-product/ProdSceneInfo.vue b/src/views/fysp/data-product/base-data-product/ProdSceneInfo.vue
index ef1323e..1bc9117 100644
--- a/src/views/fysp/data-product/base-data-product/ProdSceneInfo.vue
+++ b/src/views/fysp/data-product/base-data-product/ProdSceneInfo.vue
@@ -6,9 +6,6 @@
     @onStep3="onStep3"
     :loading="loading"
   >
-    <!-- <template #step1>
-      <ProdQueryOpt :loading="loading" @submit="onSearch"> </ProdQueryOpt>
-    </template> -->
     <template #step2="{ contentHeight }">
       <el-table
         id="prod-scene-table"
@@ -50,14 +47,12 @@
         /> -->
       </el-table>
     </template>
-    <!-- <template #step3></template> -->
   </BaseProdProcess>
 </template>
 <script setup>
 import { ref, inject } from 'vue';
 import dayjs from 'dayjs';
-import BaseProdProcess from '@/views/fysp/data-product/base-data-product/components/BaseProdProcess.vue';
-import ProdQueryOpt from '@/views/fysp/data-product/base-data-product/components/ProdQueryOpt.vue';
+import BaseProdProcess from '@/views/fysp/data-product/components/BaseProdProcess.vue';
 import dataprodbaseApi from '@/api/fysp/dataprodbaseApi.js';
 import { conversionFromTable } from '@/utils/excel';
 import { useProdStepChange } from '@/views/fysp/data-product/prod-step-change.js';
diff --git a/src/views/fysp/data-product/base-data-product/components/BaseProdProcess.vue b/src/views/fysp/data-product/components/BaseProdProcess.vue
similarity index 97%
rename from src/views/fysp/data-product/base-data-product/components/BaseProdProcess.vue
rename to src/views/fysp/data-product/components/BaseProdProcess.vue
index 8d533e7..699d958 100644
--- a/src/views/fysp/data-product/base-data-product/components/BaseProdProcess.vue
+++ b/src/views/fysp/data-product/components/BaseProdProcess.vue
@@ -111,8 +111,8 @@
 <script setup>
 import { computed, inject, ref, watch, onMounted, onUnmounted } from 'vue';
 import { unCalc } from '@/utils/css-util';
-import ProdQueryOpt from '@/views/fysp/data-product/base-data-product/components/ProdQueryOpt.vue';
-import ProdDownload from '@/views/fysp/data-product/base-data-product/components/ProdDownload.vue';
+import ProdQueryOpt from '@/views/fysp/data-product/components/ProdQueryOpt.vue';
+import ProdDownload from '@/views/fysp/data-product/components/ProdDownload.vue';
 
 const props = defineProps({
   active: {
diff --git a/src/views/fysp/data-product/base-data-product/ProdManage.vue b/src/views/fysp/data-product/components/CompProdManage.vue
similarity index 72%
rename from src/views/fysp/data-product/base-data-product/ProdManage.vue
rename to src/views/fysp/data-product/components/CompProdManage.vue
index e04d292..e7d3397 100644
--- a/src/views/fysp/data-product/base-data-product/ProdManage.vue
+++ b/src/views/fysp/data-product/components/CompProdManage.vue
@@ -2,7 +2,7 @@
   <el-affix>
     <el-menu
       ref="menuRef"
-      default-active="scene"
+      :default-active="menu.length > 0 ? menu[0].path : ''"
       ellipsis
       mode="horizontal"
     >
@@ -28,35 +28,41 @@
 </template>
 <script setup>
 import { ref, onMounted, provide, inject, computed } from 'vue';
-import { useRouter, useRoute } from 'vue-router';
+import { useRouter } from 'vue-router';
 
 const contentMaxHeight = inject('contentMaxHeight');
 
+const props = defineProps({
+  menu: {
+    type: Array,
+    default: () => []
+  }
+})
+
 const router = useRouter();
-const route = useRoute();
 
 const menuRef = ref(null);
 const height = ref(contentMaxHeight.value);
 
-const menu = ref([
-  {
-    name: '鍦烘櫙娓呭崟',
-    path: 'scene',
-    selected: true
-  },
-  {
-    name: '璇勪及娓呭崟',
-    path: 'evaluate'
-  },
-  {
-    name: '鏁存敼娓呭崟',
-    path: 'inspection'
-  },
-  {
-    name: '鐩戞祴鏁版嵁',
-    path: 'monitorData'
-  }
-]);
+// const menu = ref([
+//   {
+//     name: '鍦烘櫙娓呭崟',
+//     path: 'scene',
+//     selected: true
+//   },
+//   {
+//     name: '璇勪及娓呭崟',
+//     path: 'evaluate'
+//   },
+//   {
+//     name: '鏁存敼娓呭崟',
+//     path: 'inspection'
+//   },
+//   {
+//     name: '鐩戞祴鏁版嵁',
+//     path: 'monitorData'
+//   }
+// ]);
 
 const navPage = (item) => {
   if (item.index) {
diff --git a/src/views/fysp/data-product/components/CompProdTextGenerator.vue b/src/views/fysp/data-product/components/CompProdTextGenerator.vue
new file mode 100644
index 0000000..43d4f90
--- /dev/null
+++ b/src/views/fysp/data-product/components/CompProdTextGenerator.vue
@@ -0,0 +1,25 @@
+<template>
+  <el-input v-model="textarea" autosize type="textarea" placeholder="" />
+</template>
+<script setup>
+import { computed, ref } from 'vue';
+
+const props = defineProps({
+  // 妯℃澘
+  template: {
+    type: String,
+    default: ''
+  },
+  // 鍙傛暟
+  params: {
+    type: Object,
+    default: () => {}
+  }
+});
+
+const textarea = computed(() => {
+  return props.template.replace(/{(\w+)}/g, (match, p1) => {
+    return props.params[p1] || '';
+  });
+});
+</script>
diff --git a/src/views/fysp/data-product/base-data-product/components/ProdDownload.vue b/src/views/fysp/data-product/components/ProdDownload.vue
similarity index 100%
rename from src/views/fysp/data-product/base-data-product/components/ProdDownload.vue
rename to src/views/fysp/data-product/components/ProdDownload.vue
diff --git a/src/views/fysp/data-product/base-data-product/components/ProdQueryOpt.vue b/src/views/fysp/data-product/components/ProdQueryOpt.vue
similarity index 100%
rename from src/views/fysp/data-product/base-data-product/components/ProdQueryOpt.vue
rename to src/views/fysp/data-product/components/ProdQueryOpt.vue
diff --git a/src/views/fysp/data-product/components/ProdQueryOptCompare.vue b/src/views/fysp/data-product/components/ProdQueryOptCompare.vue
new file mode 100644
index 0000000..0935f07
--- /dev/null
+++ b/src/views/fysp/data-product/components/ProdQueryOptCompare.vue
@@ -0,0 +1,102 @@
+<template>
+  <el-card shadow="never">
+    <template #header>
+      <div><el-text tag="b" size="large">浜у搧鐢熸垚閫夐」</el-text></div>
+    </template>
+    <el-form :inline="true" :model="formSearch">
+      <FYOptionTopTask v-model:value="formSearch.topTask"></FYOptionTopTask>
+      <FYOptionScene
+        :allOption="false"
+        :type="2"
+        v-model:value="formSearch.scenetype"
+      ></FYOptionScene>
+    </el-form>
+    <el-form :inline="true" :model="formSearch2">
+      <FYOptionTopTask v-model:value="formSearch2.topTask"></FYOptionTopTask>
+    </el-form>
+    <template #footer>
+      <el-row v-show="active" justify="end">
+        <el-button
+          type="primary"
+          size="default"
+          :loading="loading"
+          @click="submit"
+          >鐢熸垚</el-button
+        >
+      </el-row>
+    </template>
+  </el-card>
+</template>
+<script setup>
+import { ref, computed } from 'vue';
+import dayjs from 'dayjs';
+
+const props = defineProps({
+  loading: {
+    type: Boolean,
+    default: false
+  },
+  active: {
+    type: Boolean,
+    default: true
+  }
+});
+const emit = defineEmits(['submit']);
+
+const formSearch = ref({
+  topTask: {},
+  scenetype: {}
+});
+
+const formSearch2 = ref({
+  topTask: {}
+});
+
+const submit = () => {
+  const opt1 = {
+    topTaskId: formSearch.value.topTask.tguid,
+    topTaskName: formSearch.value.topTask.name,
+    provinceCode: formSearch.value.topTask.provincecode,
+    provinceName: formSearch.value.topTask.provincename,
+    cityCode: formSearch.value.topTask.citycode,
+    cityName: formSearch.value.topTask.cityname,
+    districtCode: formSearch.value.topTask.districtcode,
+    districtName: formSearch.value.topTask.districtname,
+    townCode: formSearch.value.topTask.towncode,
+    townName: formSearch.value.topTask.townname,
+    startTime: dayjs(formSearch.value.topTask.starttime).format(
+      'YYYY-MM-DD HH:mm:ss'
+    ),
+    endTime: dayjs(formSearch.value.topTask.endtime)
+      .add(1, 'day')
+      .add(-1, 'second')
+      .format('YYYY-MM-DD HH:mm:ss'),
+    sceneTypeId: formSearch.value.scenetype.value,
+    sceneTypeName: formSearch.value.scenetype.label,
+    needCache: true
+  };
+  const opt2 = {
+    topTaskId: formSearch2.value.topTask.tguid,
+    topTaskName: formSearch2.value.topTask.name,
+    provinceCode: formSearch2.value.topTask.provincecode,
+    provinceName: formSearch2.value.topTask.provincename,
+    cityCode: formSearch2.value.topTask.citycode,
+    cityName: formSearch2.value.topTask.cityname,
+    districtCode: formSearch2.value.topTask.districtcode,
+    districtName: formSearch2.value.topTask.districtname,
+    townCode: formSearch2.value.topTask.towncode,
+    townName: formSearch2.value.topTask.townname,
+    startTime: dayjs(formSearch2.value.topTask.starttime).format(
+      'YYYY-MM-DD HH:mm:ss'
+    ),
+    endTime: dayjs(formSearch2.value.topTask.endtime)
+      .add(1, 'day')
+      .add(-1, 'second')
+      .format('YYYY-MM-DD HH:mm:ss'),
+    sceneTypeId: formSearch.value.scenetype.value,
+    sceneTypeName: formSearch.value.scenetype.label,
+    needCache: true
+  };
+  emit('submit', [opt1, opt2]);
+};
+</script>
diff --git a/src/views/fysp/data-product/middle-data-product/ManageMiddleProd.vue b/src/views/fysp/data-product/middle-data-product/ManageMiddleProd.vue
new file mode 100644
index 0000000..cb2ee56
--- /dev/null
+++ b/src/views/fysp/data-product/middle-data-product/ManageMiddleProd.vue
@@ -0,0 +1,31 @@
+<template>
+  <CompProdManage :menu="menu" />
+</template>
+<script setup>
+import { ref } from 'vue';
+import CompProdManage from '@/views/fysp/data-product/components/CompProdManage.vue';
+
+const menu = ref([
+  {
+    name: '鏈堝害宸℃煡鎯呭喌姹囨��',
+    path: 'inspectionSummary',
+  },
+  {
+    name: '鏈堝害闂姹囨��',
+    path: 'problemTypeSummary'
+  },
+  {
+    name: '鍒嗚闀囧崟鍦烘櫙闂鏁板潎鍊�',
+    path: 'problemCountSummary'
+  },
+  {
+    name: '鐩戞祴璁惧姹囨��',
+    path: 'monitorDeviceSummary'
+  },
+  {
+    name: '璇勪及鎯呭喌姹囨��',
+    path: 'evaluationSummary'
+  }
+]);
+</script>
+<style scoped></style>
diff --git a/src/views/fysp/data-product/middle-data-product/ProdEvaluationSummary.vue b/src/views/fysp/data-product/middle-data-product/ProdEvaluationSummary.vue
new file mode 100644
index 0000000..21ce1c9
--- /dev/null
+++ b/src/views/fysp/data-product/middle-data-product/ProdEvaluationSummary.vue
@@ -0,0 +1,28 @@
+<template>
+  <BaseProdProcess
+    v-model:active="active"
+    @onStep1="onStep1"
+    @onStep2="onStep2"
+    @onStep3="onStep3"
+    :loading="loading"
+  >
+  </BaseProdProcess>
+</template>
+<script setup>
+import { ref } from 'vue';
+import BaseProdProcess from '@/views/fysp/data-product/components/BaseProdProcess.vue';
+import dataprodmiddleApi from '@/api/fysp/dataprodmiddleApi.js';
+import { conversionFromTable } from '@/utils/excel';
+import { useProdStepChange } from '@/views/fysp/data-product/prod-step-change.js';
+
+const { active, changeActive } = useProdStepChange();
+const loading = ref(false);
+
+function onStep1(opt) {}
+
+function onStep2() {
+  changeActive();
+}
+
+function onStep3(val) {}
+</script>
diff --git a/src/views/fysp/data-product/middle-data-product/ProdInspectionSummary.vue b/src/views/fysp/data-product/middle-data-product/ProdInspectionSummary.vue
new file mode 100644
index 0000000..3738cda
--- /dev/null
+++ b/src/views/fysp/data-product/middle-data-product/ProdInspectionSummary.vue
@@ -0,0 +1,75 @@
+<template>
+  <BaseProdProcess
+    v-model:active="active"
+    @onStep1="onStep1"
+    @onStep2="onStep2"
+    @onStep3="onStep3"
+    :loading="loading"
+  >
+    <template #step2="{ contentHeight }">
+      <el-scrollbar :height="contentHeight">
+        <el-card shadow="never">
+          <el-form :inline="false" label-position="left" label-width="150px">
+            <el-form-item label="宸℃煡鍦烘櫙鎬绘暟">
+              <el-text>{{ data.sceneCount }}</el-text>
+            </el-form-item>
+            <el-form-item label="宸℃煡鐐规">
+              <el-text>{{ data.pointCount }}</el-text>
+            </el-form-item>
+            <el-form-item label="澶嶆牳鐐规">
+              <el-text>{{ data.reviewPointCount }}</el-text>
+            </el-form-item>
+            <el-form-item label="鍋滃伐鍦烘櫙鏁�">
+              <el-text>{{ data.stopSceneCount }}</el-text>
+            </el-form-item>
+            <el-form-item label="瀹屽伐鍦烘櫙鏁�">
+              <el-text>{{ data.completeSceneCount }}</el-text>
+            </el-form-item>
+          </el-form>
+          <!-- <CompProdTextGenerator
+            :template="template"
+            :params="params"
+          /> -->
+        </el-card>
+      </el-scrollbar>
+    </template>
+  </BaseProdProcess>
+</template>
+<script setup>
+import { ref } from 'vue';
+import BaseProdProcess from '@/views/fysp/data-product/components/BaseProdProcess.vue';
+import CompProdTextGenerator from '@/views/fysp/data-product/components/CompProdTextGenerator.vue';
+import dataprodmiddleApi from '@/api/fysp/dataprodmiddleApi.js';
+import { conversionFromTable } from '@/utils/excel';
+import { useProdStepChange } from '@/views/fysp/data-product/prod-step-change.js';
+import { ElMessage } from 'element-plus';
+
+const { active, changeActive } = useProdStepChange();
+const loading = ref(false);
+const data = ref({});
+
+const template = ref('2025骞�7鏈堬紝绗笁鏂瑰湪鍖虹敓鎬佺幆澧冨眬鎸囧涓嬪杈栧尯鍐�72瀹跺伐鍦板紑灞曚簡鎵皹姹℃煋闃叉不鐜板満宸℃煡銆傚闂杈冧弗閲嶆垨鎵皹绠℃帶涓嶅埌浣嶅伐鍦拌繘琛�4瀹舵澶嶆牳锛屾湰杞叡璁″贰鏌�76瀹舵锛�7鏈堥厤鍚堣仈鍚堟墽娉曟垨鏂板伐鍦颁氦搴曞璐叡鍑哄姩6缁�7浜烘銆�');
+const params = ref({});
+
+function onStep1(opt) {
+  loading.value = true;
+  dataprodmiddleApi
+    .fetchInspectionSummary(opt)
+    .then((res) => {
+      if (res.success) {
+        data.value = res.data;
+      }
+      changeActive();
+    })
+    .finally(() => {
+      loading.value = false;
+    });
+}
+
+function onStep2() {
+  // changeActive();
+  ElMessage.error('鏆備笉鎻愪緵涓嬭浇');
+}
+
+function onStep3(val) {}
+</script>
diff --git a/src/views/fysp/data-product/middle-data-product/ProdMonitorDeviceSummary.vue b/src/views/fysp/data-product/middle-data-product/ProdMonitorDeviceSummary.vue
new file mode 100644
index 0000000..21ce1c9
--- /dev/null
+++ b/src/views/fysp/data-product/middle-data-product/ProdMonitorDeviceSummary.vue
@@ -0,0 +1,28 @@
+<template>
+  <BaseProdProcess
+    v-model:active="active"
+    @onStep1="onStep1"
+    @onStep2="onStep2"
+    @onStep3="onStep3"
+    :loading="loading"
+  >
+  </BaseProdProcess>
+</template>
+<script setup>
+import { ref } from 'vue';
+import BaseProdProcess from '@/views/fysp/data-product/components/BaseProdProcess.vue';
+import dataprodmiddleApi from '@/api/fysp/dataprodmiddleApi.js';
+import { conversionFromTable } from '@/utils/excel';
+import { useProdStepChange } from '@/views/fysp/data-product/prod-step-change.js';
+
+const { active, changeActive } = useProdStepChange();
+const loading = ref(false);
+
+function onStep1(opt) {}
+
+function onStep2() {
+  changeActive();
+}
+
+function onStep3(val) {}
+</script>
diff --git a/src/views/fysp/data-product/middle-data-product/ProdProblemCountSummary.vue b/src/views/fysp/data-product/middle-data-product/ProdProblemCountSummary.vue
new file mode 100644
index 0000000..fe5212f
--- /dev/null
+++ b/src/views/fysp/data-product/middle-data-product/ProdProblemCountSummary.vue
@@ -0,0 +1,33 @@
+<template>
+  <BaseProdProcess
+    v-model:active="active"
+    @onStep2="onStep2"
+    @onStep3="onStep3"
+    :loading="loading"
+  >
+    <template #step1>
+      <ProdQueryOptCompare @submit="onStep1"></ProdQueryOptCompare>
+    </template>
+  </BaseProdProcess>
+</template>
+<script setup>
+import { ref } from 'vue';
+import BaseProdProcess from '@/views/fysp/data-product/components/BaseProdProcess.vue';
+import dataprodmiddleApi from '@/api/fysp/dataprodmiddleApi.js';
+import { conversionFromTable } from '@/utils/excel';
+import { useProdStepChange } from '@/views/fysp/data-product/prod-step-change.js';
+import ProdQueryOptCompare from '@/views/fysp/data-product/components/ProdQueryOptCompare.vue';
+
+const { active, changeActive } = useProdStepChange();
+const loading = ref(false);
+
+function onStep1(opts) {
+  console.log('onStep1', opts);
+}
+
+function onStep2() {
+  changeActive();
+}
+
+function onStep3(val) {}
+</script>
diff --git a/src/views/fysp/data-product/middle-data-product/ProdProblemTypeSummary.vue b/src/views/fysp/data-product/middle-data-product/ProdProblemTypeSummary.vue
new file mode 100644
index 0000000..181450a
--- /dev/null
+++ b/src/views/fysp/data-product/middle-data-product/ProdProblemTypeSummary.vue
@@ -0,0 +1,127 @@
+<template>
+  <BaseProdProcess
+    v-model:active="active"
+    @onStep1="onStep1"
+    @onStep2="onStep2"
+    @onStep3="onStep3"
+    :loading="loading"
+  >
+    <template #step2="{ contentHeight }">
+      <el-scrollbar :height="contentHeight">
+        <el-row>
+          <el-col :span="24">
+            <el-table
+              id="prod-problem-type-table"
+              :data="tableData"
+              v-loading="loading"
+              table-layout="fixed"
+              :show-overflow-tooltip="true"
+              size="small"
+              border
+            >
+              <el-table-column
+                fixed="left"
+                type="index"
+                label="缂栧彿"
+                width="50"
+              >
+              </el-table-column>
+              <el-table-column
+                fixed="left"
+                prop="typeName"
+                label="闂绫诲瀷"
+                min-width="200"
+              >
+              </el-table-column>
+              <el-table-column prop="count" label="鏁伴噺" min-width="50" />
+              <el-table-column
+                prop="ratio"
+                label="鏈湀鍗犳瘮"
+                min-width="70"
+                :formatter="ratioFormat"
+              />
+              <el-table-column
+                prop="ratioDiff"
+                label="杈冧笂鏈堝崰姣斿彉鍖�"
+                min-width="70"
+                :formatter="ratioFormat"
+              />
+            </el-table>
+          </el-col>
+          <el-col :span="24">
+            <el-row justify="center">
+              <div ref="chartRef" style="height: 400px; width: 100%;max-width: 800px;"></div>
+            </el-row>
+          </el-col>
+        </el-row>
+      </el-scrollbar>
+    </template>
+  </BaseProdProcess>
+</template>
+<script setup>
+import { ref } from 'vue';
+import * as echarts from 'echarts';
+import BaseProdProcess from '@/views/fysp/data-product/components/BaseProdProcess.vue';
+import dataprodmiddleApi from '@/api/fysp/dataprodmiddleApi.js';
+import { conversionFromTable } from '@/utils/excel';
+import { useProdStepChange } from '@/views/fysp/data-product/prod-step-change.js';
+import dayjs from 'dayjs';
+import { pieChartOption, downloadChartImage } from '@/utils/echart-util.js';
+
+const { active, changeActive } = useProdStepChange();
+const loading = ref(false);
+const tableData = ref([]);
+const chartRef = ref(null);
+let chart;
+
+function onStep1(opt) {
+  loading.value = true;
+  dataprodmiddleApi
+    .fetchProblemTypeSummary(opt)
+    .then((res) => {
+      if (res.success) {
+        tableData.value = res.data;
+      }
+      changeActive();
+      setTimeout(() => {
+        genChart(opt);
+      }, 500);
+    })
+    .finally(() => {
+      loading.value = false;
+    });
+}
+
+function onStep2() {
+  changeActive();
+}
+
+function onStep3(val) {
+  if (val.downloadType == '1') {
+    loading.value = true;
+    // conversionFromTable('prod-problem-type-table', '鎵皹姹℃煋闂绫诲瀷鍗犳瘮娓呭崟');
+    downloadChartImage(chart, '鎵皹姹℃煋闂绫诲瀷鍗犳瘮');
+    loading.value = false;
+  }
+}
+
+function genChart(opt) {
+  if (chart == undefined) {
+    chart = echarts.init(chartRef.value);
+  }
+  const startTime = dayjs(opt.startTime).format('YYYY骞碝M鏈�');
+  const option = pieChartOption();
+  option.title.text = `${startTime}鎵皹姹℃煋闂绫诲瀷鍗犳瘮`;
+  option.legend.data = tableData.value.map((item) => item.typeName);
+  option.series[0].name = '闂绫诲瀷';
+  option.series[0].data = tableData.value.map((item) => ({
+    name: item.typeName,
+    value: item.count
+  }));
+  chart.setOption(option);
+}
+
+function ratioFormat(row, column, cellValue, index) {
+  return Math.round(cellValue * 1000) / 10 + '%';
+}
+</script>
diff --git a/src/views/fysp/support/JingAnNightConstruction.vue b/src/views/fysp/support/JingAnNightConstruction.vue
index c4066bf..c610f63 100644
--- a/src/views/fysp/support/JingAnNightConstruction.vue
+++ b/src/views/fysp/support/JingAnNightConstruction.vue
@@ -4,9 +4,19 @@
     :total-count="total"
     @search="onSearch"
     :extraHeight="tabsHeaderHeight"
+    :defaultPageSize="10"
   >
-    <!-- <template #options> </template>
-    <template #buttons> </template> -->
+    <template #options>
+      <FYOptionLocation
+        :disabled="true"
+        :checkStrictly="false"
+        :initValue="false"
+        :allOption="false"
+        :level="3"
+        v-model:value="formSearch._locations"
+      ></FYOptionLocation>
+    </template>
+    <!-- <template #buttons> </template> -->
     <template #table-column>
       <el-table-column
         fixed="left"
@@ -97,6 +107,16 @@
 
 const tabsHeaderHeight = inject('tabsHeaderHeight', 0);
 
+const formSearch = ref({
+  _locations: {
+    pCode: '31',
+    pName: '涓婃捣甯�',
+    cCode: '3100',
+    cName: '涓婃捣甯�',
+    dCode: '310106',
+    dName: '闈欏畨鍖�'
+  }
+});
 // 澶滈棿鏂藉伐璁板綍鍙婃�绘暟
 const data = ref([]);
 const total = ref(0);

--
Gitblit v1.9.3