riku
2025-09-16 5ad61d6ad3a0ce12c7fe0808527069b09a7c9c0d
src/views/fysp/evaluation/components/CompDataResultEdit.vue
@@ -1,29 +1,32 @@
<template>
  <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"
  <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" :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-table
    ref="tableRef"
@@ -59,19 +62,49 @@
      </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"
      label="场景名称"
    >
      <template #default="{ row }">
        <el-input
          v-if="isUploadNewFile && !row.isFound"
          size="small"
          v-model="row.drSceneName"
          @change="(e) => handleSceneNameChange(e, row)"
        />
        <span v-else>{{ row.drSceneName }}</span>
      </template>
    </el-table-column>
    <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">
@@ -84,12 +117,12 @@
        <span v-else>{{ row.drDeviceCode }}</span>
      </template>
    </el-table-column>
    <el-table-column prop="drTime" label="时间" width="100">
    <el-table-column prop="drTime" label="时间" width="70">
      <template #default="{ row }">
        <span>{{ $fm.formatYMD(row.drTime) }}</span>
        <span>{{ $fm.formatYM(row.drTime) }}</span>
      </template>
    </el-table-column>
    <el-table-column prop="drExceedTimes" label="超标次数">
    <el-table-column prop="drExceedTimes" label="超标次数" width="50">
      <template #default="{ row }">
        <el-input
          v-if="isUploadNewFile && !row.isFound"
@@ -99,7 +132,7 @@
        <span v-else>{{ row.drExceedTimes }}</span>
      </template>
    </el-table-column>
    <el-table-column prop="drAvg" label="平均值">
    <el-table-column prop="drAvg" label="平均值" width="65">
      <template #default="{ row }">
        <el-input
          v-if="isUploadNewFile && !row.isFound"
@@ -109,7 +142,7 @@
        <span v-else>{{ row.drAvg }}</span>
      </template>
    </el-table-column>
    <el-table-column prop="drMax" label="最大值">
    <el-table-column prop="drMax" label="最大值" width="65">
      <template #default="{ row }">
        <el-input
          v-if="isUploadNewFile && !row.isFound"
@@ -119,7 +152,7 @@
        <span v-else>{{ row.drMax }}</span>
      </template>
    </el-table-column>
    <el-table-column prop="drMin" label="最小值">
    <el-table-column prop="drMin" label="最小值" width="65">
      <template #default="{ row }">
        <el-input
          v-if="isUploadNewFile && !row.isFound"
@@ -129,7 +162,7 @@
        <span v-else>{{ row.drMin }}</span>
      </template>
    </el-table-column>
    <el-table-column prop="drOverAvgPer" label="超区均值百分比">
    <el-table-column prop="drOverAvgPer" label="超区均值百分比" width="70">
      <template #default="{ row }">
        <el-input
          v-if="isUploadNewFile && !row.isFound"
@@ -139,7 +172,7 @@
        <span v-else>{{ row.drOverAvgPer }}</span>
      </template>
    </el-table-column>
    <el-table-column prop="drDataNum" label="数据量">
    <el-table-column prop="drDataNum" label="数据量" width="65">
      <template #default="{ row }">
        <el-input
          v-if="isUploadNewFile && !row.isFound"
@@ -149,7 +182,7 @@
        <span v-else>{{ row.drDataNum }}</span>
      </template>
    </el-table-column>
    <el-table-column prop="drEffectiveRate" label="有效率">
    <el-table-column prop="drEffectiveRate" label="有效率" width="65">
      <template #default="{ row }">
        <el-input
          v-if="isUploadNewFile && !row.isFound"
@@ -166,7 +199,7 @@
          <div v-if="!row.isFound" class="p-h-16">
            <div v-if="row.notSure">
              <el-text type="warning" size="small"
                >未找到该场景,但找到了有相似名称的场景,请确定是哪个场景</el-text
                >根据唯一编号及行政区划找到了相关场景,但与已有场景名称不匹配,请确定是哪个场景</el-text
              >
              <div class="m-t-8">
                <el-button
@@ -176,6 +209,7 @@
                  text
                  bg
                  size="small"
                  class="m-b-2"
                  @click="handleRadioChange(v, row)"
                >
                  {{ v.name }}
@@ -195,24 +229,38 @@
            </div>
            <div v-else>
              <el-text type="danger" size="small"
                >未找到该场景,也没有任何相似名称的场景,请修改场景名称或去除该场景</el-text
                >根据唯一编号及行政区划未找到相关场景,请修改唯一编号</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, 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;
@@ -229,6 +277,7 @@
const tableLoading = ref(false);
const loadTxt = ref('');
const tips = ref('');
const uploadLoading = ref(false);
const tableRowClassName = ({ row, rowIndex }) => {
  if (row.loading) {
@@ -258,6 +307,11 @@
  upload.value.handleStart(file);
}
/**
 * 处理上传文件解析
 * @param uploadFile
 * @param uploadFiles
 */
function handleChange(uploadFile, uploadFiles) {
  expandRowKeys.value = [];
  tableLoading.value = true;
@@ -274,10 +328,12 @@
    }
    const worksheet = workbook.Sheets[workbook.SheetNames[0]];
    const tableData = XLSX.utils.sheet_to_json(worksheet);
    data.value = tableData.map((v, i) => {
      return reactive({
    const _data = tableData.map((v, i) => {
      return {
        id: i,
        drSceneName: v['名称'],
        sceneIndex: v['唯一编号'],
        drSceneName: v['场景名称'],
        deviceName: v['设备名称'],
        drDeviceCode: v['设备号'],
        drTime: $fm.formatDateFromExcel(v['时间'], '-'),
        drExceedTimes: v['超标次数'],
@@ -287,8 +343,9 @@
        drOverAvgPer: v['超区均值百分比'],
        drDataNum: v['数据量'],
        drEffectiveRate: v['有效率']
      });
      };
    });
    data.value = combineSameScene(_data);
    // console.log(tableData);
    setTimeout(() => {
      tableLoading.value = false;
@@ -301,31 +358,96 @@
  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.drSceneName) {
  // 根据场景的唯一编号、行政区划和场景类型进行查找
  if (!d.sceneIndex) {
    d.isFound = false;
    d.loading = false;
    return Promise;
  } else {
    sceneApi
      .findScene({ name: d.drSceneName })
      .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) {
            const findRes = res.find((v) => v.name == d.drSceneName);
            if (findRes) {
              d.drSceneId = res[0].guid;
              d.isFound = true;
            // 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;
@@ -345,13 +467,39 @@
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();