From 9169a74e1d7b2d24d20d708b4498d7ca17eda9d8 Mon Sep 17 00:00:00 2001
From: riku <risaku@163.com>
Date: 星期一, 28 四月 2025 13:42:52 +0800
Subject: [PATCH] 1. 新增自动评估监测数据统计导入功能 2. 修改问题审核界面巡查点次统计没有根据场景类型切换的问题

---
 src/views/fysp/evaluation/components/CompDataResultEdit.vue |  515 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 483 insertions(+), 32 deletions(-)

diff --git a/src/views/fysp/evaluation/components/CompDataResultEdit.vue b/src/views/fysp/evaluation/components/CompDataResultEdit.vue
index 8837f56..8cb5a18 100644
--- a/src/views/fysp/evaluation/components/CompDataResultEdit.vue
+++ b/src/views/fysp/evaluation/components/CompDataResultEdit.vue
@@ -1,64 +1,297 @@
 <template>
-  <el-row align="top">
-    <el-upload
-      ref="upload"
-      class="upload-file"
-      :limit="1"
-      :on-change="handleChange"
-      :on-exceed="handleExceed"
-      :auto-upload="false"
+  <el-row align="top" justify="space-between">
+    <el-row align="top">
+      <el-upload
+        ref="upload"
+        class="upload-file"
+        :limit="1"
+        accept=".xls,.xlsx"
+        :on-change="handleChange"
+        :on-exceed="handleExceed"
+        :auto-upload="false"
+      >
+        <template #trigger>
+          <el-button type="success" :loading="tableLoading">瀵煎叆鏂囦欢</el-button>
+        </template>
+        <template #tip>
+          <div>
+            <el-text type="danger">{{ tips }}</el-text>
+          </div>
+        </template>
+      </el-upload>
+      <div v-if="tableLoading">
+        <el-icon class="is-loading"><Loading /></el-icon>
+        <el-text>{{ loadTxt }}</el-text>
+      </div>
+    </el-row>
+    <el-button type="default" icon="download" @click="downloadTemplate"
+      >涓嬭浇瀵煎叆妯℃澘</el-button
     >
-      <template #trigger>
-        <el-button type="primary">涓婁紶鐩戞祴鏁版嵁缁熻缁撴灉</el-button>
-      </template>
-    </el-upload>
-    <el-text>{{ loadTxt }}</el-text>
   </el-row>
   <el-table
     ref="tableRef"
     :data="data"
-    v-loading="loading"
+    v-loading="tableLoading"
     table-layout="fixed"
-    :stripe="true"
+    row-key="id"
+    :expand-row-keys="expandRowKeys"
+    :row-class-name="tableRowClassName"
     size="small"
     height="60vh"
     border
   >
+    <!-- <el-table-column type="expand">
+      <template #default="{ row }">
+        {{ row.drSceneName }}
+      </template>
+    </el-table-column> -->
+    <el-table-column
+      v-if="isUploadNewFile"
+      prop="isFound"
+      label="鍚堣"
+      width="30"
+    >
+      <template #default="{ row }">
+        <el-icon class="is-loading" v-if="row.loading">
+          <Loading color="#409eff" />
+        </el-icon>
+        <el-icon v-else>
+          <Check v-if="row.isFound" />
+          <Close v-else />
+        </el-icon>
+      </template>
+    </el-table-column>
+    <el-table-column
+      v-if="isUploadNewFile"
+      :show-overflow-tooltip="true"
+      prop="sceneIndex"
+      label="鍞竴缂栧彿"
+      width="70"
+    >
+      <template #default="{ row }">
+        <el-input
+          v-if="isUploadNewFile && !row.isFound"
+          size="small"
+          v-model="row.sceneIndex"
+          @change="(e) => handleSceneNameChange(e, row)"
+        />
+        <span v-else>{{ row.sceneIndex }}</span>
+      </template>
+    </el-table-column>
     <el-table-column
       :show-overflow-tooltip="true"
       prop="drSceneName"
-      label="鍚嶇О"
-      width="300"
-    />
-    <el-table-column prop="drDeviceCode" label="璁惧鍙�" width="130" />
-    <el-table-column prop="drTime" label="鏃堕棿" width="100">
+      label="鍦烘櫙鍚嶇О"
+    >
       <template #default="{ row }">
-        <span>{{ $fm.formatYMD(row.drTime) }}</span>
+        <el-input
+          v-if="isUploadNewFile && !row.isFound"
+          size="small"
+          v-model="row.drSceneName"
+        />
+        <span v-else>{{ row.drSceneName }}</span>
       </template>
     </el-table-column>
-    <el-table-column prop="drExceedTimes" label="瓒呮爣娆℃暟" />
-    <el-table-column prop="drAvg" label="骞冲潎鍊�" />
-    <el-table-column prop="drMax" label="鏈�澶у��" />
-    <el-table-column prop="drMin" label="鏈�灏忓��" />
-    <el-table-column prop="drOverAvgPer" label="瓒呭尯鍧囧�肩櫨鍒嗘瘮" />
-    <el-table-column prop="drDataNum" label="鏁版嵁閲�" />
-    <el-table-column prop="drEffectiveRate" label="鏈夋晥鐜�" />
+    <el-table-column
+      v-if="isUploadNewFile"
+      :show-overflow-tooltip="true"
+      prop="drDeviceCode"
+      label="璁惧鍚嶇О"
+    >
+      <template #default="{ row }">
+        <el-input
+          v-if="isUploadNewFile && !row.isFound"
+          size="small"
+          v-model="row.deviceName"
+        />
+        <span v-else>{{ row.deviceName }}</span>
+      </template>
+    </el-table-column>
+    <el-table-column prop="drDeviceCode" label="璁惧鍙�" width="130">
+      <template #default="{ row }">
+        <el-input
+          v-if="isUploadNewFile && !row.isFound"
+          size="small"
+          v-model="row.drDeviceCode"
+        />
+        <span v-else>{{ row.drDeviceCode }}</span>
+      </template>
+    </el-table-column>
+    <el-table-column prop="drTime" label="鏃堕棿" width="70">
+      <template #default="{ row }">
+        <span>{{ $fm.formatYM(row.drTime) }}</span>
+      </template>
+    </el-table-column>
+    <el-table-column prop="drExceedTimes" label="瓒呮爣娆℃暟" width="50">
+      <template #default="{ row }">
+        <el-input
+          v-if="isUploadNewFile && !row.isFound"
+          size="small"
+          v-model="row.drExceedTimes"
+        />
+        <span v-else>{{ row.drExceedTimes }}</span>
+      </template>
+    </el-table-column>
+    <el-table-column prop="drAvg" label="骞冲潎鍊�" width="65">
+      <template #default="{ row }">
+        <el-input
+          v-if="isUploadNewFile && !row.isFound"
+          size="small"
+          v-model="row.drAvg"
+        />
+        <span v-else>{{ row.drAvg }}</span>
+      </template>
+    </el-table-column>
+    <el-table-column prop="drMax" label="鏈�澶у��" width="65">
+      <template #default="{ row }">
+        <el-input
+          v-if="isUploadNewFile && !row.isFound"
+          size="small"
+          v-model="row.drMax"
+        />
+        <span v-else>{{ row.drMax }}</span>
+      </template>
+    </el-table-column>
+    <el-table-column prop="drMin" label="鏈�灏忓��" width="65">
+      <template #default="{ row }">
+        <el-input
+          v-if="isUploadNewFile && !row.isFound"
+          size="small"
+          v-model="row.drMin"
+        />
+        <span v-else>{{ row.drMin }}</span>
+      </template>
+    </el-table-column>
+    <el-table-column prop="drOverAvgPer" label="瓒呭尯鍧囧�肩櫨鍒嗘瘮" width="70">
+      <template #default="{ row }">
+        <el-input
+          v-if="isUploadNewFile && !row.isFound"
+          size="small"
+          v-model="row.drOverAvgPer"
+        />
+        <span v-else>{{ row.drOverAvgPer }}</span>
+      </template>
+    </el-table-column>
+    <el-table-column prop="drDataNum" label="鏁版嵁閲�" width="65">
+      <template #default="{ row }">
+        <el-input
+          v-if="isUploadNewFile && !row.isFound"
+          size="small"
+          v-model="row.drDataNum"
+        />
+        <span v-else>{{ row.drDataNum }}</span>
+      </template>
+    </el-table-column>
+    <el-table-column prop="drEffectiveRate" label="鏈夋晥鐜�" width="65">
+      <template #default="{ row }">
+        <el-input
+          v-if="isUploadNewFile && !row.isFound"
+          size="small"
+          v-model="row.drEffectiveRate"
+          placeholder="鍦烘櫙鍚嶇О"
+        />
+        <span v-else>{{ row.drEffectiveRate }}</span>
+      </template>
+    </el-table-column>
+    <el-table-column v-if="isUploadNewFile" type="expand">
+      <template #default="{ row }">
+        <div class="p-v-4">
+          <div v-if="!row.isFound" class="p-h-16">
+            <div v-if="row.notSure">
+              <el-text type="warning" size="small"
+                >鏍规嵁鍞竴缂栧彿鍙婅鏀垮尯鍒掓壘鍒颁簡鐩稿叧鍦烘櫙锛屼絾涓庡凡鏈夊満鏅悕绉颁笉鍖归厤锛岃纭畾鏄摢涓満鏅�</el-text
+              >
+              <div class="m-t-8">
+                <el-button
+                  v-for="(v, i) in row.sourceScene"
+                  :key="v.guid"
+                  type="primary"
+                  text
+                  bg
+                  size="small"
+                  class="m-b-2"
+                  @click="handleRadioChange(v, row)"
+                >
+                  {{ v.name }}
+                </el-button>
+                <!-- <el-radio-group v-model="row.radioValue">
+                <el-radio
+                  v-for="(v, i) in row.sourceScene"
+                  :key="v.guid"
+                  :value="i"
+                  size="small"
+                  border
+                  @change="handleRadioChange(v, row)"
+                  >{{ v.name }}</el-radio
+                >
+              </el-radio-group> -->
+              </div>
+            </div>
+            <div v-else>
+              <el-text type="danger" size="small"
+                >鏍规嵁鍞竴缂栧彿鍙婅鏀垮尯鍒掓湭鎵惧埌鐩稿叧鍦烘櫙锛岃淇敼鍞竴缂栧彿</el-text
+              >
+            </div>
+          </div>
+          <div v-else class="p-h-16">
+            <el-text type="success" size="small"> 宸叉纭尮閰嶅埌璇ュ満鏅� </el-text>
+            <el-text v-if="row.remark" type="success" size="small">
+              {{ '锛�' + row.remark }}
+            </el-text>
+          </div>
+        </div>
+      </template>
+    </el-table-column>
   </el-table>
+  <el-button
+    class="m-t-8"
+    type="primary"
+    :loading="uploadLoading"
+    :disabled="!isUploadNewFile"
+    icon="upload"
+    @click="uploadFile"
+    >涓婁紶缁熻缁撴灉</el-button
+  >
 </template>
 <script setup>
-import { ref, watch, onMounted } from 'vue';
+import { ref, reactive, watch, onMounted, getCurrentInstance } from 'vue';
+import { useMessageBoxTip, useMessageBox } from '@/composables/messageBox';
 import { genFileId } from 'element-plus';
 import monitordataApi from '@/api/fysp/monitordataApi';
+import sceneApi from '@/api/fysp/sceneApi';
 import * as XLSX from 'xlsx';
+import { exportDocx } from '@/utils/doc';
+
+const cns = getCurrentInstance();
+const $fm = cns.appContext.config.globalProperties.$fm;
 
 const props = defineProps({
   areaInfo: { type: Object }
 });
 
 let workbook;
+const isUploadNewFile = ref(false);
 const data = ref([]);
+const expandRowKeys = ref([]);
 const upload = ref();
+const tableLoading = ref(false);
 const loadTxt = ref('');
+const tips = ref('');
+const uploadLoading = ref(false);
+
+const tableRowClassName = ({ row, rowIndex }) => {
+  if (row.loading) {
+    return 'loading-row';
+  } else if (row.isFound == undefined) {
+    return '';
+  } else {
+    return row.isFound
+      ? 'success-row'
+      : row.notSure
+        ? 'warning-row'
+        : 'danger-row';
+  }
+};
 
 // 鑾峰彇鍘嗗彶缁熻缁撴灉
 function fetchDustDataResult() {
@@ -74,19 +307,199 @@
   upload.value.handleStart(file);
 }
 
+/**
+ * 澶勭悊涓婁紶鏂囦欢瑙f瀽
+ * @param uploadFile
+ * @param uploadFiles
+ */
 function handleChange(uploadFile, uploadFiles) {
+  expandRowKeys.value = [];
+  tableLoading.value = true;
+  loadTxt.value = '鏂囦欢瑙f瀽涓�...';
   // console.log(uploadFile, uploadFiles);
   const fileReader = new FileReader();
   fileReader.onload = (file) => {
-    const data = file.target.result;
-    workbook = XLSX.read(data, { type: 'array' });
+    const fileData = file.target.result;
+    workbook = XLSX.read(fileData, { type: 'array' });
     console.log(workbook.SheetNames);
+    if (workbook.SheetNames.length == 0) {
+      tips.value = 'excel鏂囦欢閿欒锛屾病鏈塻heet琛ㄥ崟';
+      return;
+    }
+    const worksheet = workbook.Sheets[workbook.SheetNames[0]];
+    const tableData = XLSX.utils.sheet_to_json(worksheet);
+    const _data = tableData.map((v, i) => {
+      return {
+        id: i,
+        sceneIndex: v['鍞竴缂栧彿'],
+        drSceneName: v['鍦烘櫙鍚嶇О'],
+        deviceName: v['璁惧鍚嶇О'],
+        drDeviceCode: v['璁惧鍙�'],
+        drTime: $fm.formatDateFromExcel(v['鏃堕棿'], '-'),
+        drExceedTimes: v['瓒呮爣娆℃暟'],
+        drAvg: v['骞冲潎鍊�'],
+        drMax: v['鏈�澶у��'],
+        drMin: v['鏈�灏忓��'],
+        drOverAvgPer: v['瓒呭尯鍧囧�肩櫨鍒嗘瘮'],
+        drDataNum: v['鏁版嵁閲�'],
+        drEffectiveRate: v['鏈夋晥鐜�']
+      };
+    });
+    data.value = combineSameScene(_data);
+    // console.log(tableData);
+    setTimeout(() => {
+      tableLoading.value = false;
+      isUploadNewFile.value = true;
+      data.value.forEach((d) => {
+        searchScene(d);
+      });
+    }, 1000);
   };
   fileReader.readAsArrayBuffer(uploadFile.raw);
 }
 
+/**
+ * 鍚堝苟鐩稿悓鍦烘櫙鐨勫鍙扮洃娴嬭澶囷紝榛樿鍙栧尯鍧囧�兼渶楂樼殑涓�鍙拌澶�
+ */
+function combineSameScene(dataList) {
+  // 鏍规嵁鍦烘櫙鍞竴缂栧彿杩涜鐩稿悓璁惧褰掔被
+  const tempMap = new Map();
+  dataList.forEach((d) => {
+    if (!tempMap.has(d.sceneIndex)) {
+      tempMap.set(d.sceneIndex, []);
+    }
+    tempMap.get(d.sceneIndex).push(d);
+  });
+  const res = [];
+  // 鐩稿悓鍦烘櫙涓嬶紝鍙栧尯鍧囧�兼渶楂樼殑涓�鍙拌澶囦綔涓虹粨鏋�
+  for (const [k, v] of tempMap) {
+    v.sort((a, b) => b.drAvg - a.drAvg);
+    if (v.length > 1) {
+      v[0].remark = `鏈満鏅叡鏈�${v.length}鍙拌澶囷紝宸茶嚜鍔ㄩ�夋嫨鍖哄潎鍊兼渶楂樼殑涓�鍙颁负缁熻缁撴灉`;      
+    }
+    res.push(reactive(v[0]));
+  }
+  return res;
+}
+
+// 鏌ヨ浠庢枃浠朵笂浼犵殑姣忎釜鍦烘櫙鏄惁鑳藉湪绯荤粺涓壘鍒板搴旂殑鍦烘櫙淇℃伅
+function searchScene(d) {
+  d.loading = true;
+  // 鏍规嵁鍦烘櫙鐨勫敮涓�缂栧彿銆佽鏀垮尯鍒掑拰鍦烘櫙绫诲瀷杩涜鏌ユ壘
+  if (!d.sceneIndex) {
+    d.isFound = false;
+    d.loading = false;
+    return Promise;
+  } else {
+    sceneApi
+      .findScene({
+        // name: d.drSceneName,
+        typeid: props.areaInfo.scensetypeid,
+        provincecode: props.areaInfo.provincecode,
+        citycode: props.areaInfo.citycode,
+        districtcode: props.areaInfo.districtcode,
+        towncode: props.areaInfo.towncode,
+        index: d.sceneIndex,
+        // 绛涢�夋煡璇㈠湪绾跨殑鍦烘櫙
+        extension1: '1'
+      })
+      .then((res) => {
+        setTimeout(() => {
+          if (res.length > 0) {
+            // 1. 鏍规嵁鍦烘櫙鍞竴缂栧彿杩涜鏌ヨ鏃讹紝涓�鑸儏鍐典笅搴旇鍙湁涓�涓敮涓�缁撴灉
+            // 2-1. 褰撲笂浼犳枃浠朵腑鍦烘櫙鍚嶇О涓虹┖鐧芥椂锛岃嚜鍔ㄥ尮閰嶆煡璇㈡墍寰楀満鏅�
+            // 2-2. 褰撲笂浼犳枃浠朵腑鍦烘櫙鍚嶇О涓嶄负绌虹櫧鏃讹紝姣斿涓よ�呯殑鍦烘櫙鍚嶇О锛岃嫢涓嶅悓鍒欒繘琛岃鍛婃彁绀�
+            if (res.length == 1) {
+              const findRes = res[0];
+              if (!d.drSceneName || d.drSceneName == '') {
+                d.drSceneId = findRes.guid;
+                d.drSceneName = findRes.name;
+                d.isFound = true;
+                d.notSure = false;
+                if (d.remark) expandRowKeys.value.push(d.id);
+              } else {
+                if (d.drSceneName == findRes.name) {
+                  d.drSceneId = findRes.guid;
+                  d.isFound = true;
+                  d.notSure = false;
+                } else {
+                  d.isFound = false;
+                  d.notSure = true;
+                  expandRowKeys.value.push(d.id);
+                }
+              }
+            } else {
+              d.isFound = false;
+              d.notSure = true;
+              expandRowKeys.value.push(d.id);
+            }
+            d.sourceScene = res;
+
+            // const findRes = res.find((v) => v.name == d.drSceneName);
+            // if (findRes) {
+            //   d.drSceneId = findRes.guid;
+            //   d.isFound = true;
+            // } else {
+            //   d.isFound = false;
+            //   d.notSure = true;
+            //   expandRowKeys.value.push(d.id);
+            // }
+            // d.sourceScene = res;
+          } else {
+            d.isFound = false;
+            d.notSure = false;
+            expandRowKeys.value.push(d.id);
+          }
+          d.loading = false;
+        }, 1000);
+      })
+      .finally(() => {
+        setTimeout(() => {
+          d.loading = false;
+        }, 1000);
+      });
+  }
+}
+
+function handleSceneNameChange(newName, row) {
+  searchScene(row);
+}
+
+function handleRadioChange(value, row) {
+  const scene = value;
+  row.sceneIndex = scene.index;
+  row.drSceneId = scene.guid;
+  row.drSceneName = scene.name;
+  searchScene(row);
+}
+
 // 涓婁紶缁熻缁撴灉鏂囨。
-function uploadFile() {}
+function uploadFile() {
+  useMessageBoxTip({
+    confirmMsg: `鏄惁纭涓婁紶锛焋,
+    confirmTitle: '涓婁紶',
+    onConfirm: () => {
+      uploadLoading.value = true;
+      return monitordataApi
+        .uploadDustDataResult(data.value)
+        .finally(() => (uploadLoading.value = false));
+    }
+  });
+}
+
+/**
+ * 涓嬭浇妯℃澘鏂囦欢
+ */
+function downloadTemplate() {
+  const fName = '鎵皹鐩戞祴鏁版嵁鏈堝害缁熻妯℃澘.xlsx';
+  const path = `/${fName}`;
+  const link = document.createElement('a');
+  link.href = path;
+  link.download = fName;
+  document.body.appendChild(link);
+  link.click();
+  document.body.removeChild(link);
+}
 
 onMounted(() => {
   fetchDustDataResult();
@@ -102,4 +515,42 @@
 :deep(.el-text) {
   align-self: auto;
 }
+
+:deep(.el-table__expanded-cell) {
+  padding: 0;
+  /* background-color: var(--el-bg-color-page); */
+}
+
+/* :deep(.el-table__body tr>td.hover-cell) {
+  background-color: red !important;
+} */
+/* .el-table--enable-row-hover
+  .el-table__body
+  tr:hover
+  > td
+  :deep(.el-table__cell) {
+  background-color: red !important;
+} */
+</style>
+<style>
+.el-table .warning-row {
+  --el-table-tr-bg-color: var(--el-color-warning-light-5);
+}
+.el-table .success-row {
+  --el-table-tr-bg-color: var(--el-color-success-light-7);
+}
+.el-table .danger-row {
+  --el-table-tr-bg-color: var(--el-color-danger-light-5);
+}
+.el-table .loading-row {
+  color: var(--el-text-color-disabled);
+  /* --el-table-tr-bg-color: var(--el-text-color-placeholder); */
+  --el-table-tr-bg-color: var(--el-bg-color);
+}
+/* .el-table__body tr>td.hover-cell {
+  background-color: red !important;
+} */
+/* .el-table--enable-row-hover .el-table__body tr:hover>td.el-table__cell {
+  background-color: unset;
+} */
 </style>

--
Gitblit v1.9.3