| | |
| | | <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" |
| | |
| | | </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"> |
| | |
| | | <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" |
| | |
| | | <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" |
| | |
| | | <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" |
| | |
| | | <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" |
| | |
| | | <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" |
| | |
| | | <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" |
| | |
| | | <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" |
| | |
| | | <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 |
| | |
| | | text |
| | | bg |
| | | size="small" |
| | | class="m-b-2" |
| | | @click="handleRadioChange(v, row)" |
| | | > |
| | | {{ v.name }} |
| | |
| | | </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; |
| | |
| | | const tableLoading = ref(false); |
| | | const loadTxt = ref(''); |
| | | const tips = ref(''); |
| | | const uploadLoading = ref(false); |
| | | |
| | | const tableRowClassName = ({ row, rowIndex }) => { |
| | | if (row.loading) { |
| | |
| | | upload.value.handleStart(file); |
| | | } |
| | | |
| | | /** |
| | | * 处理上传文件解析 |
| | | * @param uploadFile |
| | | * @param uploadFiles |
| | | */ |
| | | function handleChange(uploadFile, uploadFiles) { |
| | | expandRowKeys.value = []; |
| | | tableLoading.value = true; |
| | |
| | | } |
| | | 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['超标次数'], |
| | |
| | | drOverAvgPer: v['超区均值百分比'], |
| | | drDataNum: v['数据量'], |
| | | drEffectiveRate: v['有效率'] |
| | | }); |
| | | }; |
| | | }); |
| | | data.value = combineSameScene(_data); |
| | | // console.log(tableData); |
| | | setTimeout(() => { |
| | | tableLoading.value = false; |
| | |
| | | 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; |
| | |
| | | |
| | | 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(); |