1. 新增自动评估监测数据统计导入功能
2. 修改问题审核界面巡查点次统计没有根据场景类型切换的问题
已修改6个文件
已添加1个文件
257 ■■■■ 文件已修改
public/扬尘监测数据月度统计模板.xlsx 补丁 | 查看 | 原始文档 | blame | 历史
src/api/index.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/components/SearchBar.vue 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/utils/time-util.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/check/ProCheck.vue 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/check/components/CompSubTaskStatistic.vue 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/views/fysp/evaluation/components/CompDataResultEdit.vue 232 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
public/Ñï³¾¼à²âÊý¾ÝÔ¶Èͳ¼ÆÄ£°å.xlsx
Binary files differ
src/api/index.js
@@ -1,7 +1,7 @@
import axios from 'axios';
import { ElMessage } from 'element-plus';
const debug = true;
const debug = false;
let ip1 = 'http://47.100.191.150:9005/';
let ip1_file = 'http://47.100.191.150:9005/';
src/components/SearchBar.vue
@@ -18,7 +18,7 @@
          </el-select>
        </el-form-item>
        <FYOptionScene
          :allOption="true"
          :allOption="false"
          :type="2"
          v-model:value="formSearch.scenetype"
        ></FYOptionScene>
src/utils/time-util.js
@@ -44,7 +44,7 @@
    const year = time.getFullYear();
    const month = time.getMonth() + 1;
    const date = time.getDate();
    return (
    return dayjs(
      year +
      format +
      (month < 10 ? '0' + month : month) +
src/views/fysp/check/ProCheck.vue
@@ -5,6 +5,7 @@
        <template #summary>
          <CompSubTaskStatistic
            :loading="sideLoading"
            :sceneType="sceneTypeId"
            :subtasks="subtasks"
            :monitorObjList="curMonitorObjList"
          />
@@ -103,6 +104,8 @@
      mainLoading: false,
      // æ€»ä»»åŠ¡
      topTask: {},
      // åœºæ™¯ç±»åž‹id
      sceneTypeId: undefined,
      // æ€»ä»»åŠ¡å·¡æŸ¥è®¡åˆ’æ¸…å•
      curMonitorObjList: [],
      //子任务列表
@@ -165,6 +168,7 @@
      this.mainLoading = true;
      this.curProList = [];
      this.curSubtask = {};
      this.sceneTypeId = formSearch.sceneTypeId
      const param = {
        topTaskId: formSearch.topTask.tguid,
        sceneTypeId: formSearch.sceneTypeId
src/views/fysp/check/components/CompSubTaskStatistic.vue
@@ -195,6 +195,7 @@
export default {
  props: {
    loading: Boolean,
    sceneType: Number,
    subtasks: {
      type: Array,
      default: () => []
@@ -269,12 +270,14 @@
        reviewTimes: 0
      };
      this.monitorObjList.forEach((m) => {
        _res.total++;
        const times = parseInt(m.extension1);
        if (times) {
          _res.completedScenes++;
          _res.completedTimes += times;
          _res.reviewTimes += times - 1;
        if (this.sceneType == undefined || m.sceneTypeId == this.sceneType) {
          _res.total++;
          const times = parseInt(m.extension1);
          if (times) {
            _res.completedScenes++;
            _res.completedTimes += times;
            _res.reviewTimes += times - 1;
          }
        }
      });
      return _res;
src/views/fysp/evaluation/components/CompDataResultEdit.vue
@@ -1,27 +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"
@@ -57,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">
@@ -82,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.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"
@@ -97,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"
@@ -107,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"
@@ -117,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"
@@ -127,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"
@@ -137,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"
@@ -147,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"
@@ -164,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
@@ -174,6 +209,7 @@
                  text
                  bg
                  size="small"
                  class="m-b-2"
                  @click="handleRadioChange(v, row)"
                >
                  {{ v.name }}
@@ -193,20 +229,25 @@
            </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
@@ -214,10 +255,12 @@
</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;
@@ -264,6 +307,11 @@
  upload.value.handleStart(file);
}
/**
 * å¤„理上传文件解析
 * @param uploadFile
 * @param uploadFiles
 */
function handleChange(uploadFile, uploadFiles) {
  expandRowKeys.value = [];
  tableLoading.value = true;
@@ -280,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['超标次数'],
@@ -293,8 +343,9 @@
        drOverAvgPer: v['超区均值百分比'],
        drDataNum: v['数据量'],
        drEffectiveRate: v['有效率']
      });
      };
    });
    data.value = combineSameScene(_data);
    // console.log(tableData);
    setTimeout(() => {
      tableLoading.value = false;
@@ -307,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;
@@ -351,6 +467,7 @@
function handleRadioChange(value, row) {
  const scene = value;
  row.sceneIndex = scene.index;
  row.drSceneId = scene.guid;
  row.drSceneName = scene.name;
  searchScene(row);
@@ -358,7 +475,30 @@
// ä¸Šä¼ ç»Ÿè®¡ç»“果文档
function uploadFile() {
  monitordataApi.uploadDustDataResult(data.value).then((res) => {});
  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(() => {