From 49e2b7ea866695957633855f71f9e2f943b11ec7 Mon Sep 17 00:00:00 2001
From: riku <risaku@163.com>
Date: 星期三, 04 三月 2026 17:29:03 +0800
Subject: [PATCH] 2026.3.4
---
src/components/head/FYPageHeader.vue | 25
components.d.ts | 2
src/views/analysis/evalution/components/CompReport.vue | 101 +
src/components/monitor/RealTimeData.vue | 543 ++++++++-
src/constants/envCreditCode.js | 26
src/router/index.js | 2
src/views/analysis/evalution/components/precheck/components/CompCheckConfirm.vue | 108 ++
src/views/monitor/DataDashboard.vue | 155 +
src/components/table/FYTable.vue | 95
src/components/monitor/DistrictRanking.vue | 67
src/views/analysis/evalution/components/CompDataResultEdit.vue | 556 ++++++++++
src/views/analysis/evalution/EvalutationRecord.vue | 451 ++++++++
src/views/analysis/evalution/EvalutationTask.vue | 34
src/views/analysis/evalution/components/precheck/components/CompCheckExemption.vue | 45
src/components/monitor/DeviceStatus.vue | 9
src/views/analysis/evalution/components/precheck/components/CompCheckSource.vue | 334 ++++++
src/views/analysis/evalution/EvalutationEdit.vue | 279 +++++
src/views/analysis/evalution/components/precheck/components/CompCheckArea.vue | 138 ++
src/views/analysis/evalution/components/CompEvaTask.vue | 144 ++
src/views/analysis/evalution/components/precheck/CompPreCheck.vue | 97 +
20 files changed, 2,981 insertions(+), 230 deletions(-)
diff --git a/components.d.ts b/components.d.ts
index cbb0eab..dac87af 100644
--- a/components.d.ts
+++ b/components.d.ts
@@ -99,6 +99,7 @@
FYOptionTime: typeof import('./src/components/search-option/FYOptionTime.vue')['default']
FYOptionTopTask: typeof import('./src/components/search-option/FYOptionTopTask.vue')['default']
FYOptionUserType: typeof import('./src/components/search-option/FYOptionUserType.vue')['default']
+ FYPageHeader: typeof import('./src/components/head/FYPageHeader.vue')['default']
FYReconfrimButton: typeof import('./src/components/button/FYReconfrimButton.vue')['default']
FYSearchBar: typeof import('./src/components/search-option/FYSearchBar.vue')['default']
FYTable: typeof import('./src/components/table/FYTable.vue')['default']
@@ -213,6 +214,7 @@
const FYOptionTime: typeof import('./src/components/search-option/FYOptionTime.vue')['default']
const FYOptionTopTask: typeof import('./src/components/search-option/FYOptionTopTask.vue')['default']
const FYOptionUserType: typeof import('./src/components/search-option/FYOptionUserType.vue')['default']
+ const FYPageHeader: typeof import('./src/components/head/FYPageHeader.vue')['default']
const FYReconfrimButton: typeof import('./src/components/button/FYReconfrimButton.vue')['default']
const FYSearchBar: typeof import('./src/components/search-option/FYSearchBar.vue')['default']
const FYTable: typeof import('./src/components/table/FYTable.vue')['default']
diff --git a/src/components/head/FYPageHeader.vue b/src/components/head/FYPageHeader.vue
new file mode 100644
index 0000000..f474776
--- /dev/null
+++ b/src/components/head/FYPageHeader.vue
@@ -0,0 +1,25 @@
+<template>
+ <el-page-header @back="onBack" class="page-header">
+ <template #content>
+ <span> {{ title }} </span>
+ </template>
+ </el-page-header>
+ <el-divider />
+</template>
+
+<script>
+export default {
+ props: {
+ title: {
+ type: String,
+ default: '褰撳墠涓洪粯璁ら〉闈㈡爣棰橈紝璇蜂紶鍏ユ爣棰樺悕瀛�'
+ }
+ },
+ methods: {
+ // 鍥為��椤甸潰
+ onBack() {
+ this.$router.back();
+ }
+ }
+};
+</script>
diff --git a/src/components/monitor/DeviceStatus.vue b/src/components/monitor/DeviceStatus.vue
index 20228aa..13c776e 100644
--- a/src/components/monitor/DeviceStatus.vue
+++ b/src/components/monitor/DeviceStatus.vue
@@ -6,9 +6,9 @@
<span>璁惧鍦ㄧ嚎鎯呭喌</span>
</div>
</template>
- <el-row :gutter="20">
+ <el-row :gutter="0">
<el-col :span="12">
- <el-row :gutter="20">
+ <el-row :gutter="10">
<el-col :span="12">
<el-card class="status-card online-card" shadow="hover">
<div class="status-content">
@@ -126,6 +126,7 @@
formatter: '{a} <br/>{b}: {c} ({d}%)',
},
legend: {
+ show: false,
bottom: '0%',
data: ['鍦ㄧ嚎璁惧', '绂荤嚎璁惧', '姝e父璁惧', '鏁呴殰璁惧'],
},
@@ -133,7 +134,7 @@
{
name: '鍦ㄧ嚎鐘舵��',
type: 'pie',
- radius: ['40%', '70%'],
+ radius: ['20%', '40%'],
center: ['48%', '50%'],
startAngle: 270,
endAngle: 90,
@@ -152,7 +153,7 @@
{
name: '杩愯鐘舵��',
type: 'pie',
- radius: ['40%', '70%'],
+ radius: ['30%', '50%'],
center: ['52%', '50%'],
startAngle: 90,
endAngle: 270,
diff --git a/src/components/monitor/DistrictRanking.vue b/src/components/monitor/DistrictRanking.vue
index f471c32..ea1c4e2 100644
--- a/src/components/monitor/DistrictRanking.vue
+++ b/src/components/monitor/DistrictRanking.vue
@@ -24,25 +24,31 @@
</el-radio-group>
</el-col>
</el-row>
- <div ref="rankingChart" class="chart-container"></div>
- <el-table :data="sortedRankingData" style="width: 100%" stripe class="ranking-table">
- <el-table-column label="鎺掑悕" type="index" width="80" />
- <el-table-column prop="name" label="鍖哄幙鍚嶇О" />
- <el-table-column prop="value" label="娴撳害鍧囧�� (mg/m鲁)" />
- <el-table-column label="鎺掑悕鍙樺寲" width="120">
- <template #default="scope">
- <div v-if="scope.row.rankChange > 0" class="rank-up">
- <el-icon><ArrowUp /></el-icon> {{ scope.row.rankChange }}
- </div>
- <div v-else-if="scope.row.rankChange < 0" class="rank-down">
- <el-icon><ArrowDown /></el-icon> {{ Math.abs(scope.row.rankChange) }}
- </div>
- <div v-else class="rank-no-change">
- <el-icon><Minus /></el-icon> 0
- </div>
- </template>
- </el-table-column>
- </el-table>
+ <el-row :gutter="20">
+ <el-col :span="10">
+ <div ref="rankingChart" class="chart-container"></div>
+ </el-col>
+ <el-col :span="14">
+ <el-table :data="sortedRankingData" size="small" stripe class="ranking-table">
+ <el-table-column label="鎺掑悕" type="index" width="80" />
+ <el-table-column prop="name" label="鍖哄幙鍚嶇О" />
+ <el-table-column prop="value" label="娴撳害鍧囧�� (mg/m鲁)" />
+ <el-table-column label="鎺掑悕鍙樺寲" width="120">
+ <template #default="scope">
+ <div v-if="scope.row.rankChange > 0" class="rank-up">
+ <el-icon><ArrowUp /></el-icon> {{ scope.row.rankChange }}
+ </div>
+ <div v-else-if="scope.row.rankChange < 0" class="rank-down">
+ <el-icon><ArrowDown /></el-icon> {{ Math.abs(scope.row.rankChange) }}
+ </div>
+ <div v-else class="rank-no-change">
+ <el-icon><Minus /></el-icon> 0
+ </div>
+ </template>
+ </el-table-column>
+ </el-table>
+ </el-col>
+ </el-row>
</el-card>
</template>
@@ -112,26 +118,29 @@
},
},
grid: {
- left: '3%',
+ left: '0%',
right: '4%',
- bottom: '3%',
+ bottom: '6%',
+ top: '4%',
containLabel: true,
},
xAxis: {
- type: 'category',
- data: this.sortedRankingData.map((item) => item.name),
+ type: 'value',
+ nameLocation: 'middle',
+ nameGap: 30,
+ name: this.rankingType === 'hourly' ? '灏忔椂鍧囧�� (mg/m鲁)' : '鏈堝潎鍊� (mg/m鲁)',
},
yAxis: {
- type: 'value',
- name: this.rankingType === 'hourly' ? '灏忔椂鍧囧�� (mg/m鲁)' : '鏈堝潎鍊� (mg/m鲁)',
+ type: 'category',
+ data: this.sortedRankingData.map((item) => item.name).reverse(),
},
series: [
{
name: '娴撳害鍧囧��',
type: 'bar',
- data: this.sortedRankingData.map((item) => parseFloat(item.value)),
+ data: this.sortedRankingData.map((item) => parseFloat(item.value)).reverse(),
itemStyle: {
- color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ color: new echarts.graphic.LinearGradient(1, 0, 0, 0, [
{ offset: 0, color: '#83bff6' },
{ offset: 0.5, color: '#188df0' },
{ offset: 1, color: '#188df0' },
@@ -153,7 +162,7 @@
}
</script>
-<style scoped>
+<style scoped lang="scss">
.section {
margin-bottom: 20px;
}
@@ -165,7 +174,7 @@
}
.chart-container {
- height: 300px;
+ height: 400px;
width: 100%;
}
diff --git a/src/components/monitor/RealTimeData.vue b/src/components/monitor/RealTimeData.vue
index f8aba0a..8e3e361 100644
--- a/src/components/monitor/RealTimeData.vue
+++ b/src/components/monitor/RealTimeData.vue
@@ -6,153 +6,313 @@
<span>璁惧瀹炴椂鏁版嵁</span>
</div>
</template>
- <el-row :gutter="20">
- <el-col :span="8">
- <el-card class="realtime-data" shadow="hover">
- <template #header>
- <span>瀹炴椂鍒嗛挓鏁版嵁</span>
- </template>
- <el-descriptions :column="1" v-if="currentDevice">
- <el-descriptions-item label="璁惧缂栧彿">{{
- currentDevice.deviceId
- }}</el-descriptions-item>
- <el-descriptions-item label="璁惧渚涘簲鍟�">{{
- currentDevice.supplier
- }}</el-descriptions-item>
- <el-descriptions-item label="娌圭儫娴撳害"
- >{{ currentDevice.娌圭儫娴撳害 }} mg/m鲁</el-descriptions-item
+ <el-space v-if="devices && devices.length > 0" justify="center" wrap>
+ <el-card
+ v-for="(device, index) in devices"
+ :key="device.deviceId"
+ class="device-card"
+ shadow="hover"
+ :class="{ 'abnormal-device': isDeviceAbnormal(device) }"
+ >
+ <template #header>
+ <div class="device-header">
+ <span class="device-id">{{ device.deviceId }}</span>
+ <div class="device-status">
+ <el-icon v-if="device.status === '姝e父'" class="status-icon normal-icon"
+ ><iconify-icon icon="mdi:check-circle"
+ /></el-icon>
+ <el-icon v-else class="status-icon abnormal-icon"
+ ><iconify-icon icon="mdi:alert-circle"
+ /></el-icon>
+ <span>{{ device.status }}</span>
+ </div>
+ </div>
+ </template>
+
+ <!-- 瀹炴椂鍒嗛挓鏁版嵁 -->
+ <div class="realtime-data">
+ <div class="basic-info">
+ <span class="supplier">{{ device.supplier }}</span>
+ <span class="monitor-time">{{
+ device.monitorTime || new Date().toLocaleString()
+ }}</span>
+ </div>
+ <div class="monitor-values">
+ <div
+ class="value-item"
+ :class="{ 'abnormal-value': isAbnormal('smokeDensity', device.smokeDensity) }"
>
- <el-descriptions-item label="椋庢満鐢垫祦"
- >{{ currentDevice.椋庢満鐢垫祦 }} A</el-descriptions-item
+ <span class="value-label">娌圭儫娴撳害</span>
+ <span class="value">{{ device.smokeDensity }} <span class="unit">mg/m鲁</span></span>
+ </div>
+ <div
+ class="value-item"
+ :class="{ 'abnormal-value': isAbnormal('fanCurrent', device.fanCurrent) }"
>
- <el-descriptions-item label="鍑�鍖栧櫒鐢垫祦"
- >{{ currentDevice.鍑�鍖栧櫒鐢垫祦 }} A</el-descriptions-item
+ <span class="value-label">椋庢満鐢垫祦</span>
+ <span class="value">{{ device.fanCurrent }} <span class="unit">A</span></span>
+ </div>
+ <div
+ class="value-item"
+ :class="{ 'abnormal-value': isAbnormal('purifierCurrent', device.purifierCurrent) }"
>
- </el-descriptions>
- </el-card>
- </el-col>
- <el-col :span="16">
- <el-card class="realtime-chart" shadow="hover">
- <template #header>
- <span>杩戜竴灏忔椂鏁版嵁</span>
- </template>
- <div ref="hourlyChart" class="chart-container"></div>
- </el-card>
- </el-col>
- </el-row>
+ <span class="value-label">鍑�鍖栧櫒鐢垫祦</span>
+ <span class="value">{{ device.purifierCurrent }} <span class="unit">A</span></span>
+ </div>
+ </div>
+ </div>
+
+ <!-- 杩戜竴灏忔椂鏁版嵁 -->
+ <div class="hourly-charts">
+ <el-popover
+ placement="left"
+ :width="600"
+ trigger="click"
+ @show="() => initDeviceCharts(device)"
+ >
+ <template #reference>
+ <div class="chart-header">
+ <span class="date">{{ new Date().toLocaleDateString() }}</span>
+ <el-button size="small" type="primary" link> 鏌ョ湅杩戜竴灏忔椂鏁版嵁 </el-button>
+ </div>
+ </template>
+ <div class="popover-content">
+ <div class="popover-header">
+ <h3>{{ device.deviceId }} 杩戜竴灏忔椂鏁版嵁</h3>
+ </div>
+ <div ref="charts" :key="device.deviceId" class="charts-container">
+ <div class="chart-item">
+ <div class="chart-title">娌圭儫娴撳害(mg/m鲁)</div>
+ <div ref="smokeChart" :data-device-id="device.deviceId" class="small-chart"></div>
+ </div>
+ <div class="chart-item">
+ <div class="chart-title">椋庢満鐢垫祦(A)</div>
+ <div ref="fanChart" :data-device-id="device.deviceId" class="small-chart"></div>
+ </div>
+ <div class="chart-item">
+ <div class="chart-title">鍑�鍖栧櫒鐢垫祦(A)</div>
+ <div
+ ref="purifierChart"
+ :data-device-id="device.deviceId"
+ class="small-chart"
+ ></div>
+ </div>
+ </div>
+ </div>
+ </el-popover>
+ </div>
+ </el-card>
+ </el-space>
+ <div v-else class="no-data">
+ <el-empty description="鏆傛棤璁惧鏁版嵁" />
+ </div>
</el-card>
</template>
<script>
import * as echarts from 'echarts'
+import { Icon } from '@iconify/vue'
export default {
name: 'RealTimeData',
+ components: {
+ IconifyIcon: Icon,
+ },
props: {
- currentDevice: {
- type: Object,
- default: null,
- },
- hourlyData: {
+ devices: {
type: Array,
default: () => [],
},
},
data() {
return {
- hourlyChart: null,
+ charts: {},
}
},
mounted() {
- this.initChart()
+ // 涓嶉渶瑕佽嚜鍔ㄥ垵濮嬪寲鍥捐〃锛屽彧鍦ㄥ脊鍑烘鏄剧ず鏃跺垵濮嬪寲
},
beforeUnmount() {
- if (this.hourlyChart) {
- this.hourlyChart.dispose()
- }
+ Object.values(this.charts).forEach((chart) => {
+ if (chart) {
+ chart.dispose()
+ }
+ })
},
watch: {
- hourlyData() {
- this.updateChart()
+ devices: {
+ handler(newDevices) {
+ // 娓呴櫎鏃у浘琛�
+ Object.values(this.charts).forEach((chart) => {
+ if (chart) {
+ chart.dispose()
+ }
+ })
+ this.charts = {}
+ },
+ deep: true,
},
},
methods: {
- initChart() {
- this.hourlyChart = echarts.init(this.$refs.hourlyChart)
- this.updateChart()
+ initDeviceCharts(device) {
+ const deviceId = device.deviceId
- window.addEventListener('resize', () => {
- this.hourlyChart.resize()
+ // 娓呴櫎璇ヨ澶囩殑鏃у浘琛�
+ Object.keys(this.charts).forEach((key) => {
+ if (key.startsWith(deviceId)) {
+ this.charts[key].dispose()
+ delete this.charts[key]
+ }
+ })
+
+ this.$nextTick(() => {
+ // 娌圭儫娴撳害鍥捐〃
+ const smokeChartEl = document.querySelector(`[data-device-id="${deviceId}"]`)
+ if (smokeChartEl) {
+ this.charts[`${deviceId}_smoke`] = echarts.init(smokeChartEl)
+ }
+
+ // 椋庢満鐢垫祦鍥捐〃
+ const fanChartEl = document.querySelectorAll(`[data-device-id="${deviceId}"]`)[1]
+ if (fanChartEl) {
+ this.charts[`${deviceId}_fan`] = echarts.init(fanChartEl)
+ }
+
+ // 鍑�鍖栧櫒鐢垫祦鍥捐〃
+ const purifierChartEl = document.querySelectorAll(`[data-device-id="${deviceId}"]`)[2]
+ if (purifierChartEl) {
+ this.charts[`${deviceId}_purifier`] = echarts.init(purifierChartEl)
+ }
+
+ this.updateDeviceCharts(device)
})
},
- updateChart() {
- if (!this.hourlyChart) return
+ updateCharts() {
+ this.devices.forEach((device) => {
+ this.updateDeviceCharts(device)
+ })
+ },
+ updateDeviceCharts(device) {
+ const deviceId = device.deviceId
+ const deviceHourlyData = device.hourlyData || []
- const option = {
+ const _baseOption = {
tooltip: {
trigger: 'axis',
- axisPointer: {
- type: 'cross',
- label: {
- backgroundColor: '#6a7985',
- },
- },
- },
- legend: {
- data: ['娌圭儫娴撳害', '椋庢満鐢垫祦', '鍑�鍖栧櫒鐢垫祦'],
},
grid: {
- left: '3%',
- right: '4%',
- bottom: '3%',
+ left: '0%',
+ right: '0%',
+ top: '10%',
+ bottom: '0%',
containLabel: true,
},
xAxis: {
type: 'category',
boundaryGap: false,
- data: this.hourlyData.map((item) => item.time),
+ data: deviceHourlyData.map((item) => item.time),
+ axisLabel: {
+ fontSize: 10,
+ },
},
- yAxis: [
- {
- type: 'value',
- name: '娌圭儫娴撳害 (mg/m鲁)',
- position: 'left',
- },
- {
- type: 'value',
- name: '鐢垫祦 (A)',
- position: 'right',
- },
- ],
- series: [
- {
- name: '娌圭儫娴撳害',
- type: 'line',
- data: this.hourlyData.map((item) => parseFloat(item.娌圭儫娴撳害)),
- yAxisIndex: 0,
- },
- {
- name: '椋庢満鐢垫祦',
- type: 'line',
- data: this.hourlyData.map((item) => parseFloat(item.椋庢満鐢垫祦)),
- yAxisIndex: 1,
- },
- {
- name: '鍑�鍖栧櫒鐢垫祦',
- type: 'line',
- data: this.hourlyData.map((item) => parseFloat(item.鍑�鍖栧櫒鐢垫祦)),
- yAxisIndex: 1,
- },
- ],
}
- this.hourlyChart.setOption(option)
+ // 鏇存柊娌圭儫娴撳害鍥捐〃
+ if (this.charts[`${deviceId}_smoke`]) {
+ const smokeOption = {
+ ..._baseOption,
+ yAxis: {
+ type: 'value',
+ name: 'mg/m鲁',
+ // nameLocation: 'middle',
+ // nameGap: 30,
+ axisLabel: {
+ fontSize: 10,
+ },
+ },
+ series: [
+ {
+ name: '娌圭儫娴撳害',
+ type: 'line',
+ data: deviceHourlyData.map((item) => parseFloat(item.smokeDensity)),
+ smooth: true,
+ },
+ ],
+ }
+ this.charts[`${deviceId}_smoke`].setOption(smokeOption)
+ }
+
+ // 鏇存柊椋庢満鐢垫祦鍥捐〃
+ if (this.charts[`${deviceId}_fan`]) {
+ const fanOption = {
+ ..._baseOption,
+ yAxis: {
+ type: 'value',
+ name: 'A',
+ // nameLocation: 'middle',
+ // nameGap: 30,
+ axisLabel: {
+ fontSize: 10,
+ },
+ },
+ series: [
+ {
+ name: '椋庢満鐢垫祦',
+ type: 'line',
+ data: deviceHourlyData.map((item) => parseFloat(item.fanCurrent)),
+ smooth: true,
+ },
+ ],
+ }
+ this.charts[`${deviceId}_fan`].setOption(fanOption)
+ }
+
+ // 鏇存柊鍑�鍖栧櫒鐢垫祦鍥捐〃
+ if (this.charts[`${deviceId}_purifier`]) {
+ const purifierOption = {
+ ..._baseOption,
+ yAxis: {
+ type: 'value',
+ name: 'A',
+ // nameLocation: 'middle',
+ // nameGap: 30,
+ axisLabel: {
+ fontSize: 10,
+ },
+ },
+ series: [
+ {
+ name: '鍑�鍖栧櫒鐢垫祦',
+ type: 'line',
+ data: deviceHourlyData.map((item) => parseFloat(item.purifierCurrent)),
+ smooth: true,
+ },
+ ],
+ }
+ this.charts[`${deviceId}_purifier`].setOption(purifierOption)
+ }
+ },
+ isDeviceAbnormal(device) {
+ return (
+ this.isAbnormal('smokeDensity', device.smokeDensity) ||
+ this.isAbnormal('fanCurrent', device.fanCurrent) ||
+ this.isAbnormal('purifierCurrent', device.purifierCurrent)
+ )
+ },
+ isAbnormal(type, value) {
+ // 杩欓噷鍙互鏍规嵁瀹為檯鎯呭喌瀹氫箟寮傚父鍊煎垽鏂�昏緫
+ const thresholds = {
+ smokeDensity: 10,
+ fanCurrent: 5,
+ purifierCurrent: 3,
+ }
+ return parseFloat(value) > (thresholds[type] || 0)
},
},
}
</script>
-<style scoped>
+<style scoped lang="scss">
.section {
margin-bottom: 20px;
}
@@ -163,8 +323,191 @@
align-items: center;
}
-.chart-container {
- height: 300px;
+.device-card {
+ // width: 100%;
+ margin-bottom: 20px;
+ transition: all 0.3s ease;
+}
+
+.device-card:hover {
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
+}
+
+.abnormal-device {
+ border-bottom: 4px solid #f56c6c;
+}
+
+.device-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.device-id {
+ font-size: 16px;
+ font-weight: bold;
+ color: #303133;
+}
+
+.device-status {
+ display: flex;
+ align-items: center;
+ gap: 5px;
+}
+
+.status-icon {
+ font-size: 16px;
+}
+
+.normal-icon {
+ color: #67c23a;
+}
+
+.abnormal-icon {
+ color: #f56c6c;
+}
+
+.realtime-data {
+ margin-bottom: 20px;
+}
+
+.basic-info {
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 15px;
+ font-size: 12px;
+ color: #909399;
+}
+
+.supplier {
+ font-style: italic;
+}
+
+.monitor-time {
+ font-family: monospace;
+}
+
+.monitor-values {
+ display: flex;
+ justify-content: space-around;
+ gap: 10px;
+}
+
+.value-item {
+ flex: 1;
+ width: 60px;
+ text-align: center;
+ padding: 10px;
+ border-radius: 4px;
+ background-color: #f9f9f9;
+ border: 1px solid transparent;
+}
+
+.value-label {
+ display: block;
+ font-size: 12px;
+ color: #606266;
+ margin-bottom: 5px;
+}
+
+.value {
+ display: block;
+ font-size: 20px;
+ font-weight: bold;
+ color: #303133;
+}
+
+.unit {
+ font-size: 12px;
+ font-weight: normal;
+ color: #909399;
+}
+
+.abnormal-value {
+ background-color: #fef0f0;
+ border: 1px solid #fbc4c4;
+}
+
+.abnormal-value .value {
+ color: #f56c6c;
+}
+
+.hourly-charts {
+ margin-top: 20px;
+}
+
+.chart-header {
+ margin-top: 10px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ padding: 5px 0;
+}
+
+.popover-content {
+ padding: 10px;
+}
+
+.popover-header {
+ margin-bottom: 15px;
+ border-bottom: 1px solid #f0f0f0;
+ padding-bottom: 10px;
+}
+
+.popover-header h3 {
+ margin: 0;
+ font-size: 14px;
+ font-weight: bold;
+ color: #303133;
+}
+
+.date {
+ font-size: 12px;
+ color: #909399;
+ font-family: monospace;
+}
+
+.charts-container {
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+}
+
+.chart-item {
+ background-color: #f9f9f9;
+ border-radius: 4px;
+ padding: 10px;
+}
+
+.chart-title {
+ font-size: 12px;
+ color: #606266;
+ margin-bottom: 5px;
+ text-align: center;
+}
+
+.small-chart {
+ height: 120px;
width: 100%;
}
+
+.no-data {
+ padding: 40px 0;
+ text-align: center;
+}
+
+/* 鍝嶅簲寮忚璁� */
+@media (max-width: 768px) {
+ .monitor-values {
+ flex-direction: column;
+ }
+
+ .value-item {
+ width: 100%;
+ }
+
+ .small-chart {
+ height: 100px;
+ }
+}
</style>
diff --git a/src/components/table/FYTable.vue b/src/components/table/FYTable.vue
index 25023f6..8cd1348 100644
--- a/src/components/table/FYTable.vue
+++ b/src/components/table/FYTable.vue
@@ -1,4 +1,5 @@
<template>
+ <div>
<el-row ref="searchRef">
<FYSearchBar @search="onSearch">
<template #options v-if="$slots.options">
@@ -75,30 +76,30 @@
cellClassName: Function || String,
pagination: {
type: Boolean,
- default: true
+ default: true,
},
// '' | 'small' | 'default' | 'large'
size: {
type: String,
- default: 'default'
+ default: 'default',
},
data: {
type: Array,
- default: () => []
+ default: () => [],
},
totalCount: {
type: Number,
- default: 0
+ default: 0,
},
defaultPageSize: {
type: Number,
- default: 20
+ default: 20,
},
// 棰濆鐨勯珮搴︼紝鐢ㄤ簬璁$畻琛ㄦ牸楂樺害
extraHeight: {
type: Number,
- default: 0
- }
+ default: 0,
+ },
},
data() {
return {
@@ -108,46 +109,46 @@
currentPage: 1,
pageSize: this.defaultPageSize,
loading: false,
- fontSize: 'default'
- };
+ fontSize: 'default',
+ }
},
emits: ['search', 'cellClick', 'tablePaste', 'sortChange'],
watch: {
currentPage(nValue, oValue) {
if (nValue != oValue) {
- this.onSearch();
+ this.onSearch()
}
},
pageSize(nValue, oValue) {
if (nValue != oValue) {
- this.onSearch();
+ this.onSearch()
}
},
size: {
handler(nValue, oValue) {
if (nValue != oValue) {
- this.fontSize = nValue;
+ this.fontSize = nValue
}
},
- immediate: true
+ immediate: true,
},
data(nValue, oValue) {
if (nValue != oValue) {
- this.tableData = nValue;
+ this.tableData = nValue
}
},
totalCount(nValue, oValue) {
if (nValue != oValue) {
- this.total = nValue;
+ this.total = nValue
}
},
extraHeight: {
handler(nValue, oValue) {
if (nValue != oValue) {
- this.tableHeight = this.calcTableHeight();
+ this.tableHeight = this.calcTableHeight()
}
- }
- }
+ },
+ },
},
computed: {},
methods: {
@@ -157,73 +158,71 @@
* 鍥炶皟鍑芥暟鎺ユ敹涓�涓璞★紝鍖呮嫭琛ㄦ牸鏁版嵁鏁扮粍data鍜屾暟鎹�绘暟total
*/
onSearch() {
- this.loading = true;
+ this.loading = true
this.$emit(
'search',
{
currentPage: this.currentPage,
- pageSize: this.pageSize
+ pageSize: this.pageSize,
},
(res) => {
if (res) {
if (res.data) {
- this.tableData = res.data;
+ this.tableData = res.data
}
if (res.total) {
- this.total = res.total;
+ this.total = res.total
}
}
- this.loading = false;
- this.doLayout();
- }
- );
+ this.loading = false
+ this.doLayout()
+ },
+ )
},
calcTableHeight() {
- const h1 = this.$refs.searchRef.$el.offsetHeight;
- const h2 = this.$refs.paginationRef
- ? this.$refs.paginationRef.$el.offsetHeight
- : 0;
- const h3 = this.$refs.expandRef.$el.offsetHeight;
- const h4 = this.$refs.expand2Ref.offsetHeight;
+ const h1 = this.$refs.searchRef.$el.offsetHeight
+ const h2 = this.$refs.paginationRef ? this.$refs.paginationRef.$el.offsetHeight : 0
+ const h3 = this.$refs.expandRef.$el.offsetHeight
+ const h4 = this.$refs.expand2Ref.offsetHeight
- const h = h1 + h2 + h3 + h4 + this.extraHeight;
- return this.contentMaxHeight.value - h + 'px';
+ const h = h1 + h2 + h3 + h4 + this.extraHeight
+ return this.contentMaxHeight - h + 'px'
// return `calc(100vh - ${h}px - 60px - var(--el-main-padding) * 2)`;
},
tableRowClassName({ row }) {
if (this.rowClassName) {
if (typeof this.rowClassName == 'string') {
- return this.rowClassName;
+ return this.rowClassName
} else if (typeof this.rowClassName == 'function') {
- return this.rowClassName({ row });
+ return this.rowClassName({ row })
}
} else {
- return row.extension1 != '0' ? 'online-row' : 'offline-row';
+ return row.extension1 != '0' ? 'online-row' : 'offline-row'
}
},
cellClick(row, column, cell, event) {
- this.$emit('cellClick', row, column, cell, event);
+ this.$emit('cellClick', row, column, cell, event)
},
handlePaste(event) {
- this.$emit('tablePaste', event);
+ this.$emit('tablePaste', event)
},
doLayout() {
- this.$refs.tableRef.doLayout();
+ this.$refs.tableRef.doLayout()
},
handleSortChange({ column, prop, order }) {
- this.$emit('sortChange', { column, prop, order });
+ this.$emit('sortChange', { column, prop, order })
},
clearSort() {
- this.$refs.tableRef.clearSort();
- }
+ this.$refs.tableRef.clearSort()
+ },
},
mounted() {
setTimeout(() => {
- this.tableHeight = this.calcTableHeight();
- }, 100);
- this.onSearch();
- }
-};
+ this.tableHeight = this.calcTableHeight()
+ }, 100)
+ this.onSearch()
+ },
+}
</script>
<style>
diff --git a/src/constants/envCreditCode.js b/src/constants/envCreditCode.js
new file mode 100644
index 0000000..184d7af
--- /dev/null
+++ b/src/constants/envCreditCode.js
@@ -0,0 +1,26 @@
+// 鐜俊鐮佽浆鎹�
+
+function envCreditCode(score) {
+ const s = parseInt(score)
+ if (s <= 59) {
+ return {
+ value: 2,
+ name: '绾㈢爜',
+ color: '#db2828'
+ };
+ } else if (s <= 89) {
+ return {
+ value: 1,
+ name: '榛勭爜',
+ color: '#f7a62c'
+ };
+ } else {
+ return {
+ value: 0,
+ name: '缁跨爜',
+ color: '#21ba45'
+ };
+ }
+}
+
+export { envCreditCode };
diff --git a/src/router/index.js b/src/router/index.js
index 6713a23..4f042be 100644
--- a/src/router/index.js
+++ b/src/router/index.js
@@ -98,7 +98,7 @@
{
name: 'auto-evalution',
path: 'auto-evalution',
- component: () => import('@/views/analysis/evalution/AutoEvalution.vue'),
+ component: () => import('@/views/analysis/evalution/EvalutationRecord.vue'),
},
{
name: 'huanxincode-manage',
diff --git a/src/views/analysis/evalution/EvalutationEdit.vue b/src/views/analysis/evalution/EvalutationEdit.vue
new file mode 100644
index 0000000..f45dabf
--- /dev/null
+++ b/src/views/analysis/evalution/EvalutationEdit.vue
@@ -0,0 +1,279 @@
+<template>
+ <FYPageHeader title="璇勪及缁撴灉璇︽儏"></FYPageHeader>
+ <el-row v-for="item in evaluation" :key="item.id"> </el-row>
+ <div class="btns">
+ <el-button type="primary" @click="submit" :disabled="!isUpdated">鎻愪氦</el-button>
+ </div>
+ <el-table
+ class="table-style"
+ :data="tableData"
+ ref="tableRef"
+ :span-method="objectSpanMethod"
+ table-layout="fixed"
+ :cell-style="cellClassName"
+ border
+ stripe
+ >
+ <el-table-column v-slot="scope" prop="one_title" label="涓�绾ф寚鏍�" width="200">
+ <!-- <el-checkbox v-model="scope.row.one_select" @change="checked => oneSelectChange(checked, scope.row)">{{ scope.row.one_title }}</el-checkbox> -->
+ </el-table-column>
+ <el-table-column prop="one_score" label="鍒嗗��" width="55" />
+ <el-table-column prop="one_maxScore" label="鏈�澶у垎鍊�" width="90" />
+ <el-table-column v-slot="scope" prop="two_title" label="浜岀骇鎸囨爣" width="200">
+ <!-- <el-checkbox v-model="scope.row.two_select" @change="checked => twoSelectChange(checked, scope.row)">{{ scope.row.two_title }}</el-checkbox> -->
+ </el-table-column>
+ <el-table-column prop="two_score" label="鍒嗗��" width="55" />
+ <el-table-column prop="two_maxScore" label="鏈�澶у垎鍊�" width="90" />
+ <el-table-column v-slot="scope" prop="three_title" label="鍏蜂綋闂">
+ <el-checkbox
+ v-model="scope.row.three_select"
+ @change="(checked) => threeSelectChange(checked, scope.row)"
+ >{{ scope.row.three_title }}</el-checkbox
+ >
+ </el-table-column>
+ <el-table-column prop="three_score" label="鍗曢」鎵e垎" width="90" />
+ </el-table>
+</template>
+
+<script>
+import evaluateApi from '@/api/fysp/evaluateApi';
+import { useFetchData } from '@/composables/fetchData';
+import { ElMessage } from 'element-plus';
+export default {
+ setup() {
+ const { loading, fetchData } = useFetchData();
+ return { loading, fetchData };
+ },
+ data() {
+ return {
+ tableData: [],
+ evaluation: [],
+ subTaskId: '',
+ isUpdated: false
+ };
+ },
+ created() {
+ // // watch 璺敱鐨勫弬鏁帮紝浠ヤ究鍐嶆鑾峰彇鏁版嵁
+ // this.$watch(
+ // () => this.$route.params,
+ // () => {
+ // this.getScore();
+ // },
+ // // 缁勪欢鍒涘缓瀹屽悗鑾峰彇鏁版嵁锛�
+ // // 姝ゆ椂 data 宸茬粡琚� observed 浜�
+ // { immediate: true }
+ // );
+ },
+ computed: {
+ // 宸茶鍕鹃�夌殑item
+ checkedUpdatedList() {
+ var list = [];
+ for (let index = 0; index < this.tableData.length; index++) {
+ const element = this.tableData[index];
+ if (element.three_select) {
+ list.push(element.three_id);
+ }
+ }
+ return list;
+ }
+ },
+ mounted() {
+ this.getList();
+ },
+ methods: {
+ // 姣忎竴涓崟鍏冩牸鐨刢lass
+ cellClassName({ row, column, rowIndex, columnIndex }) {
+ if (column.property === 'one_score') {
+ if (row.one_score < 0) {
+ return { color: 'red' };
+ }
+ } else if (column.property === 'two_score') {
+ if (row.two_score < 0) {
+ return { color: 'red' };
+ }
+ } else if (column.property === 'three_score') {
+ if (row.three_score < 0) {
+ return { color: 'red' };
+ }
+ }
+ return { color: 'black' };
+ },
+ /** 鎻愪环 */
+ submit() {
+ evaluateApi
+ .updateScore({
+ subTaskId: this.subTaskId,
+ itemList: this.checkedUpdatedList
+ })
+ .then((res) => {
+ if (res.success) {
+ ElMessage({
+ message: res.message,
+ type: 'success'
+ });
+ }else {
+ ElMessage({
+ message: res.message,
+ type: 'error'
+ });
+ }
+ });
+ setTimeout(() => {
+ this.getList();
+ }, 1000);
+ },
+ /** 閫氳繃绗笁绾х殑id鑾峰彇涓婄骇浠ュ強椤剁骇 */
+ getSuperObjByThreeId(threeId, list, path = []) {
+ for (let index = 0; index < list.length; index++) {
+ const item = list[index];
+ // 灏嗗綋鍓嶉」娣诲姞鍒拌矾寰勪腑
+ const currentPath = path.concat(item);
+ if (item.id === threeId) {
+ // 濡傛灉鎵惧埌鍖归厤鐨� id锛岃繑鍥炶矾寰勬暟缁�
+ return currentPath;
+ }
+ const subList = item.subList;
+ if (subList) {
+ // 閫掑綊鏌ユ壘瀛愬垪琛�
+ const result = this.getSuperObjByThreeId(threeId, subList, currentPath);
+ if (result) {
+ return result; // 濡傛灉鎵惧埌鍖归厤鐨� id锛岃繑鍥炵粨鏋�
+ }
+ }
+ }
+ return null; // 濡傛灉娌℃湁鎵惧埌鍖归厤鐨� id锛岃繑鍥� null
+ },
+ /** 闂閫夋嫨妗� */
+ threeSelectChange(isSelect, row) {
+ this.isUpdated = true;
+ },
+ /** 鍒楀悎骞� */
+ objectSpanMethod({ row, column, rowIndex, columnIndex }) {
+ if (columnIndex === 0 || columnIndex === 1 || columnIndex === 2) {
+ // 瀵� 涓�绾ф寚鏍� 鍒楄繘琛屽悎骞�
+ let rowSpan = 1;
+ for (let i = rowIndex + 1; i < this.tableData.length; i++) {
+ if (this.tableData[i].one_id === row.one_id) {
+ rowSpan++;
+ } else {
+ break;
+ }
+ }
+ if (rowIndex > 0) {
+ if (this.tableData[rowIndex - 1].one_id === row.one_id) {
+ return { rowspan: 0, colspan: 0 };
+ }
+ }
+ return { rowspan: rowSpan, colspan: 1 };
+ } else if (columnIndex === 3 || columnIndex === 4 || columnIndex === 5) {
+ // 瀵� 浜岀骇鎸囨爣 鍒楄繘琛屽悎骞讹紝纭繚 涓�绾ф寚鏍� 涓�鏍�
+ let rowSpan = 1;
+ for (let i = rowIndex + 1; i < this.tableData.length; i++) {
+ if (this.tableData[i].one_id === row.one_id && this.tableData[i].two_id === row.two_id) {
+ rowSpan++;
+ } else {
+ break;
+ }
+ }
+ if (rowIndex > 0) {
+ if (
+ this.tableData[rowIndex - 1].one_id === row.one_id &&
+ this.tableData[rowIndex - 1].two_id === row.two_id
+ ) {
+ return { rowspan: 0, colspan: 0 };
+ }
+ }
+ return { rowspan: rowSpan, colspan: 1 };
+ }
+ },
+ /** 瀵硅薄灞炴�ф嫹璐� */
+ deepCopyWithPrefix(obj, target, prefix) {
+ // 纭繚 target 鏄竴涓璞�
+ if (typeof target !== 'object' || target === null) {
+ target = {};
+ }
+
+ // 閬嶅巻瀵硅薄鐨勬墍鏈夊睘鎬�
+ for (const key in obj) {
+ if (obj.hasOwnProperty(key)) {
+ // 涓哄睘鎬у悕鍔犱笂鍓嶇紑
+ const newKey = prefix + key;
+ // 濡傛灉灞炴�у�兼槸瀵硅薄锛屽垯閫掑綊澶嶅埗
+ if (typeof obj[key] === 'object' && obj[key] !== null) {
+ this.deepCopyWithPrefix(obj[key], (target[newKey] = {}), prefix);
+ } else {
+ // 鍚﹀垯鐩存帴澶嶅埗灞炴��
+ target[newKey] = obj[key];
+ }
+ }
+ }
+
+ return target;
+ },
+ /** @param data 鍒楄〃鏁版嵁 */
+ genTableData(data) {
+ var result = [];
+ if (data) {
+ for (let i = 0; i < data.length; i++) {
+ const firstLevelItem = data[i];
+ var secondLevel = firstLevelItem.subList;
+ if (secondLevel) {
+ for (let j = 0; j < secondLevel.length; j++) {
+ const secondLevelItem = secondLevel[j];
+ var thirdLevel = secondLevelItem.subList;
+ if (thirdLevel) {
+ for (let q = 0; q < thirdLevel.length; q++) {
+ const thirdLevelItem = thirdLevel[q];
+ var item = {};
+ this.deepCopyWithPrefix(firstLevelItem, item, 'one_');
+ this.deepCopyWithPrefix(secondLevelItem, item, 'two_');
+ this.deepCopyWithPrefix(thirdLevelItem, item, 'three_');
+ result.push(item);
+ }
+ }
+ }
+ }
+ }
+ }
+ return result;
+ },
+ getList() {
+ this.subTaskId = this.$route.params.subTaskId;
+ evaluateApi.fetchItemEvaluation(this.subTaskId).then((res) => {
+ this.isUpdated = false;
+ this.tableData = this.genTableData(res.data.details);
+ });
+ },
+ onSearch(page, func) {
+ evaluateApi.fetchItemEvaluation(this.$route.params.subTaskId).then((res) => {
+ if (typeof func === 'function') {
+ // 澶勭悊鏁版嵁
+ var data = this.genTableData(res.data);
+
+ func({ data: data });
+ }
+ this.tableData = this.genTableData(res.data);
+ });
+ }
+ }
+};
+</script>
+<style scoped>
+.table-style {
+ width: 100%;
+ padding-bottom: 30px;
+}
+.btns {
+ padding-bottom: 10px;
+ padding-right: 30px;
+ display: flex;
+ flex-direction: row-reverse;
+}
+/* 鏀瑰彉琛ㄦ牸鍐呭崟鍏冩牸杈规棰滆壊 */
+.el-table {
+ --el-table-border-color: #000000;
+}
+.red-cell {
+ background-color: red;
+}
+</style>
diff --git a/src/views/analysis/evalution/EvalutationRecord.vue b/src/views/analysis/evalution/EvalutationRecord.vue
new file mode 100644
index 0000000..40735b6
--- /dev/null
+++ b/src/views/analysis/evalution/EvalutationRecord.vue
@@ -0,0 +1,451 @@
+<template>
+ <FYTable
+ @search="onSearch"
+ :pagination="false"
+ ref="tableRef"
+ @cell-click="cellClick"
+ :cell-class-name="cellClassName"
+ @table-paste="handlePaste"
+ @sort-change="handleSortChange"
+ >
+ <template #options>
+ <!-- 鍖哄幙 -->
+ <FYOptionLocation
+ :allOption="false"
+ :level="3"
+ :checkStrictly="false"
+ v-model:value="formSearch.locations"
+ ></FYOptionLocation>
+ <!-- 鍦烘櫙绫诲瀷 -->
+ <FYOptionScene
+ :allOption="false"
+ :type="2"
+ v-model:value="formSearch.scenetype"
+ ></FYOptionScene>
+ <!-- 鏃堕棿 -->
+ <FYOptionTime
+ :initValue="false"
+ type="month"
+ v-model:value="formSearch.time"
+ ></FYOptionTime>
+ </template>
+ <template #buttons>
+ <!-- <el-button icon="Download" size="default" type="success" @click="download"
+ >瑙勮寖鎬ц瘎浼颁笌鍒嗘瀽鎶ュ憡</el-button
+ > -->
+ <CompReport
+ :locations="formSearch.locations"
+ :scenetype="formSearch.scenetype"
+ :time="formSearch.time"
+ ></CompReport>
+ </template>
+
+ <template #options-expand>
+ <el-form :inline="true">
+ <CompQuickSet @quick-set="setOptions"></CompQuickSet>
+ </el-form>
+ </template>
+
+ <template #table-column="{ size }">
+ <el-table-column
+ fixed="left"
+ sortable="custom"
+ prop="sceneIndex"
+ label="缂栧彿"
+ width="80"
+ >
+ </el-table-column>
+ <el-table-column
+ prop="sceneName"
+ :show-overflow-tooltip="true"
+ label="鍚嶇О"
+ width="300"
+ >
+ </el-table-column>
+ <el-table-column
+ prop="subTaskTime"
+ label="宸℃煡鏃ユ湡"
+ width="110"
+ sortable="custom"
+ :formatter="timeFormat"
+ />
+ <el-table-column
+ prop="evaluation.resultscorebef"
+ label="寰楀垎"
+ width="90"
+ sortable="custom"
+ />
+ <el-table-column
+ prop="evaluation.resultscorebef"
+ label="鐜俊鐮�"
+ width="100"
+ >
+ <template #default="{ row }">
+ <span :style="`color: ${toCode(row).color};`">{{
+ toCode(row).name
+ }}</span>
+ </template>
+ </el-table-column>
+
+ <el-table-column prop="dname" label="鍖哄幙" width="90" />
+ <el-table-column
+ prop="tname"
+ label="琛楅亾"
+ width="110"
+ :filters="townFilters"
+ :filter-method="filterHandler"
+ />
+ <el-table-column prop="evaluation.scenseaddress" label="鍦板潃" />
+ <!-- <el-table-column prop="biArea" label="闆嗕腑鍖�" width="110" />
+ <el-table-column prop="biManagementCompany" label="鐗╀笟" min-width="110"/> -->
+ <el-table-column
+ v-if="scoreShow"
+ fixed="right"
+ align="right"
+ label="鐩戞祴鏁版嵁瓒呮爣"
+ width="160"
+ >
+ <template #default="{ row }">
+ <el-input :size="size" v-model="row.score1" />
+ </template>
+ </el-table-column>
+ <el-table-column
+ v-if="scoreShow"
+ fixed="right"
+ align="right"
+ label="鐩戞祴鏁版嵁瓒呭尯鏈堝潎鍊�"
+ width="160"
+ >
+ <template #default="{ row }">
+ <el-input :size="size" v-model="row.score2" />
+ </template>
+ </el-table-column>
+ <el-table-column fixed="right" align="right" label="鎿嶄綔" width="160">
+ <template #header>
+ <el-button
+ v-show="!scoreShow"
+ icon="ArrowLeft"
+ size="small"
+ type="success"
+ @click="scoreShow = true"
+ >鐩戞祴鏁版嵁寰楀垎</el-button
+ >
+ <el-button
+ v-show="scoreShow"
+ size="small"
+ type="primary"
+ @click="updateMultipleScore"
+ :loading="updateLoading"
+ >涓婁紶</el-button
+ >
+ <el-button
+ v-show="scoreShow"
+ size="small"
+ type="error"
+ @click="scoreShow = false"
+ >鍙栨秷</el-button
+ >
+ </template>
+ <template #default="{ row }">
+ <el-button type="primary" size="small" @click="editRow(row)"
+ >鏌ョ湅</el-button
+ >
+ </template>
+ </el-table-column>
+ </template>
+ </FYTable>
+</template>
+
+<script>
+import dayjs from 'dayjs';
+import evaluateApi from '@/api/fysp/evaluateApi';
+import { envCreditCode } from '@/constants/index';
+import CompReport from './components/CompReport.vue';
+import { useTablePaste } from '@/composables/tablePaste';
+import { useCloned } from '@vueuse/core';
+import { useMessageBoxTip } from '@/composables/messageBox';
+
+export default {
+ setup() {
+ const {
+ cellClick,
+ cellClassName,
+ handlePaste,
+ setTableData,
+ addRefreshEvent,
+ tableData
+ } = useTablePaste({
+ score1: 8,
+ score2: 9
+ });
+ return {
+ cellClick,
+ cellClassName,
+ handlePaste,
+ setTableData,
+ addRefreshEvent,
+ tableData
+ };
+ },
+ components: { CompReport },
+ data() {
+ return {
+ formSearch: {
+ locations: {},
+ scenetype: {},
+ time: dayjs().add(-1, 'M').date(1).toDate()
+ },
+ townFilters: [],
+ // 鍘熷鏁版嵁锛岀敤浜庢帓搴忓彇娑堝悗
+ orginData: [],
+ evaluationRule: undefined,
+ evaluationSubRule: undefined,
+ //鐩戞祴鏁版嵁瑙勫垯鍚嶇О
+ ruleName: {
+ score1: {
+ id: undefined,
+ name: '鐩戞祴鏁版嵁鍑虹幇鍗曟棩鍙婁互涓婃湁鏁堣秴鏍�'
+ },
+ score2: {
+ id: undefined,
+ name: '鐩戞祴鏁版嵁鏈堝潎鍊艰秴鍖哄煙鏈堝潎鍊�20%浠ヤ笂鎴栨暟鎹槑鏄惧紓甯�'
+ }
+ },
+ scoreShow: false,
+ updateLoading: false
+ };
+ },
+ computed: {
+ area() {
+ const { locations, scenetype, time } = this.formSearch;
+ return {
+ provincecode: locations.pCode,
+ provincename: locations.pName,
+ citycode: locations.cCode,
+ cityname: locations.cName,
+ districtcode: locations.dCode,
+ districtname: locations.dName,
+ starttime: dayjs(time).format('YYYY-MM-DD HH:mm:ss'),
+ scensetypeid: scenetype.value
+ };
+ }
+ },
+ methods: {
+ // _getParam() {
+ // const { locations, scenetype, time } = this.formSearch;
+ // return {
+ // provincecode: locations.pCode,
+ // provincename: locations.pName,
+ // citycode: locations.cCode,
+ // cityname: locations.cName,
+ // districtcode: locations.dCode,
+ // districtname: locations.dName,
+ // starttime: dayjs(time).format('YYYY-MM-DD HH:mm:ss'),
+ // scensetypeid: scenetype.value
+ // };
+ // },
+ editRow(row) {
+ this.$router.push(`evalutationEdit/${row.subTaskId}`);
+ },
+ setOptions(param) {
+ this.formSearch.locations = param.locations;
+ this.formSearch.scenetype = param.scenetype;
+ this.formSearch.sourceType = param.sourceType;
+ this.$refs.tableRef.onSearch();
+ },
+ onSearch(page, func) {
+ this.$refs.tableRef.clearSort();
+ this.fetchEvaluationRule(this.area).then(() => {
+ evaluateApi.fetchAutoEvaluation(this.area).then((res) => {
+ if (res.data) {
+ this.tableData = res.data;
+ this.tableData.forEach((v) => {
+ // 灏嗗師濮嬬殑寰楀垎灞曠ず鍒拌〃鏍间腑
+ if (v.itemEvaluations) {
+ for (const key in this.ruleName) {
+ const value = this.ruleName[key];
+ const itemEva = v.itemEvaluations.find((ie) => {
+ return ie.esrguid == value.id && ie.extension1 == 'true';
+ });
+ if (itemEva) {
+ v[key] = itemEva.value;
+ }
+ }
+ }
+ });
+ this.orginData = useCloned(this.tableData).cloned;
+ this.getFilters(res.data);
+ if (typeof func === 'function') {
+ func({ data: this.tableData });
+ }
+ } else {
+ this.tableData = [];
+ this.orginData = [];
+ if (typeof func === 'function') {
+ func({ data: this.tableData });
+ }
+ }
+ });
+ });
+ },
+ fetchEvaluationRule() {
+ const param = {
+ // 鑷姩璇勪及绫诲瀷
+ taskTypeId: 99,
+ ...this.area
+ };
+ // 鑾峰彇璇勪及鎬昏鍒�
+ return evaluateApi.fetchEvaluationRule(param).then((res) => {
+ if (res.data.length > 0) {
+ this.evaluationRule = res.data[0];
+ // 鑾峰彇鍏蜂綋瀛愯鍒�
+ return evaluateApi
+ .getSubRules(this.evaluationRule.guid)
+ .then((res) => {
+ this.evaluationSubRule = res.data;
+ // 鏌ユ壘鍙鍏ュ緱鍒嗙殑瑙勫垯id
+ for (const key in this.ruleName) {
+ const value = this.ruleName[key];
+ const subrule = this.evaluationSubRule.find((v) => {
+ return v.itemname == value.name;
+ });
+ if (subrule) {
+ value.id = subrule.guid;
+ }
+ }
+ });
+ }
+ });
+ },
+ // 鎵归噺鏇存柊鐩戞祴鏁版嵁寰楀垎
+ updateMultipleScore() {
+ this.updateLoading = true;
+ useMessageBoxTip({
+ confirmMsg: '鏄惁涓婁紶鐩戞祴鏁版嵁寰楀垎',
+ confirmTitle: '涓婁紶鐩戞祴鏁版嵁寰楀垎',
+ onConfirm: async () => {
+ if (this.evaluationRule) {
+ const subTaskEvaList = this.tableData.map((v) => {
+ const subRule = [];
+ for (const key in this.ruleName) {
+ const value = this.ruleName[key];
+ subRule.push({
+ id: value.id,
+ selected: v[key] && (v[key] + '').trim() != ''
+ });
+ }
+ return {
+ subTaskId: v.subTaskId,
+ ruleId: this.evaluationRule.guid,
+ subRule
+ };
+ });
+ const param = {
+ ...this.area,
+ subTaskEvaList
+ };
+
+ return await evaluateApi
+ .updateMultipleScore(param)
+ .finally(() => (this.updateLoading = false));
+ }
+ }
+ });
+ },
+ // 瑙勮寖鎬ц瘎浼颁笌鍒嗘瀽鎶ュ憡鍚庡彴鐢熸垚浠诲姟
+ download() {
+ evaluateApi.downloadAutoEvaluation(this.area).then((res) => {
+ if (res == false) {
+ // 鏈笅杞芥枃妗o紝鑰屾槸寮�鍚簡鏂囨。鐢熸垚鍚庡彴浠诲姟
+ this.$parent;
+ }
+ });
+ },
+ // 瀵煎嚭琛ㄦ牸涓篹xcel鏍煎紡
+ exportExcel() {},
+ getFilters(data) {
+ const townList = [];
+ data.forEach((e) => {
+ if (townList.indexOf(e.tname) == -1) {
+ townList.push(e.tname);
+ }
+ });
+ this.townFilters = townList.map((v) => {
+ return { text: v, value: v };
+ });
+ },
+ toCode(row, column) {
+ if (row.evaluation) {
+ return envCreditCode(row.evaluation.resultscorebef);
+ } else {
+ return '';
+ }
+ },
+ timeFormat(row, column) {
+ const time = row.subTaskTime;
+ if (time) {
+ return dayjs(time).format('MM-DD');
+ } else {
+ return '';
+ }
+ },
+ filterHandler(value, row, column) {
+ const property = column['property'];
+ return row[property] === value;
+ },
+ sortScore(a, b) {
+ const s1 = a.evaluation ? parseInt(a.evaluation.resultscorebef) : 0;
+ const s2 = b.evaluation ? parseInt(b.evaluation.resultscorebef) : 0;
+ return s1 - s2;
+ },
+ handleSortChange({ column, prop, order }) {
+ console.log(column, prop, order);
+ if (order == null) {
+ this.orginData.forEach((e, i) => {
+ this.tableData[i] = e;
+ });
+ } else if (prop == 'evaluation.resultscorebef') {
+ this.tableData.sort((a, b) => {
+ const s1 = a.evaluation ? parseInt(a.evaluation.resultscorebef) : 0;
+ const s2 = b.evaluation ? parseInt(b.evaluation.resultscorebef) : 0;
+ if (order == 'ascending') {
+ return s1 - s2;
+ } else if (order == 'descending') {
+ return s2 - s1;
+ }
+ });
+ } else if (prop == 'sceneIndex') {
+ this.tableData.sort((a, b) => {
+ if (order == 'ascending') {
+ if (a.sceneIndex === b.sceneIndex) {
+ return a.subTaskTime > b.subTaskTime ? 1 : -1;
+ } else {
+ return a.sceneIndex - b.sceneIndex;
+ }
+ } else if (order == 'descending') {
+ if (a.sceneIndex === b.sceneIndex) {
+ return b.subTaskTime > a.subTaskTime ? 1 : -1;
+ } else {
+ return b.sceneIndex - a.sceneIndex;
+ }
+ }
+ });
+ } else if (prop == 'subTaskTime') {
+ this.tableData.sort((a, b) => {
+ if (order == 'ascending') {
+ return a[prop] > b[prop] ? 1 : -1;
+ // return dayjs(a).isAfter(dayjs(b)) ? 1 : -1;
+ } else if (order == 'descending') {
+ return b[prop] > a[prop] ? 1 : -1;
+ // return dayjs(b).isAfter(dayjs(a)) ? 1 : -1;
+ }
+ });
+ }
+ }
+ },
+ mounted() {
+ this.addRefreshEvent(this.$refs.tableRef.doLayout);
+ }
+};
+</script>
+<style scoped></style>
diff --git a/src/views/analysis/evalution/EvalutationTask.vue b/src/views/analysis/evalution/EvalutationTask.vue
new file mode 100644
index 0000000..239df8c
--- /dev/null
+++ b/src/views/analysis/evalution/EvalutationTask.vue
@@ -0,0 +1,34 @@
+<template>
+ <el-row :gutter="16">
+ <el-col :span="16">
+ <CompPreCheck @start-task="refreshTask"></CompPreCheck>
+ </el-col>
+ <el-col :span="8">
+ <CompEvaTask ref="refEvaTask"></CompEvaTask>
+ </el-col>
+ </el-row>
+</template>
+
+<script>
+import CompEvaTask from './components/CompEvaTask.vue';
+import CompPreCheck from './components/precheck/CompPreCheck.vue';
+export default {
+ name: 'EvalutationTask',
+ components: { CompPreCheck, CompEvaTask },
+ data() {
+ return {};
+ },
+ methods:{
+ refreshTask(){
+ this.$refs.refEvaTask.fetchTask()
+ }
+ }
+};
+</script>
+<style scoped>
+.radius {
+ height: 80vh;
+ /* border: 1px solid var(--el-border-color); */
+ /* border-radius: var(--el-border-radius-base); */
+}
+</style>
diff --git a/src/views/analysis/evalution/components/CompDataResultEdit.vue b/src/views/analysis/evalution/components/CompDataResultEdit.vue
new file mode 100644
index 0000000..8cb5a18
--- /dev/null
+++ b/src/views/analysis/evalution/components/CompDataResultEdit.vue
@@ -0,0 +1,556 @@
+<template>
+ <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
+ >
+ </el-row>
+ <el-table
+ ref="tableRef"
+ :data="data"
+ v-loading="tableLoading"
+ table-layout="fixed"
+ 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="鍦烘櫙鍚嶇О"
+ >
+ <template #default="{ row }">
+ <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
+ 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, 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() {
+ monitordataApi.fetchDustDataResult(props.areaInfo).then((res) => {
+ data.value = res.data;
+ });
+}
+
+function handleExceed(files, uploadFiles) {
+ upload.value.clearFiles();
+ const file = files[0];
+ file.uid = genFileId();
+ 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 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() {
+ 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();
+});
+</script>
+<style scoped>
+.upload-file {
+ /* background-color: aliceblue; */
+ width: 300px;
+ min-height: 60px;
+}
+
+: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>
diff --git a/src/views/analysis/evalution/components/CompEvaTask.vue b/src/views/analysis/evalution/components/CompEvaTask.vue
new file mode 100644
index 0000000..dd1dd53
--- /dev/null
+++ b/src/views/analysis/evalution/components/CompEvaTask.vue
@@ -0,0 +1,144 @@
+<template>
+ <el-card shadow="never" :body-style="{ padding: 0 }">
+ <template #header>
+ <el-row justify="space-between">
+ <div>
+ <div><el-text tag="b" size="large">鑷姩璇勪及浠诲姟</el-text></div>
+ <el-text size="small" type="info">鏄剧ず褰撳墠姝e湪杩涜鐨勮嚜鍔ㄨ瘎浼颁换鍔$姸鎬�</el-text>
+ </div>
+ <el-button
+ icon="Refresh"
+ type="primary"
+ size="default"
+ :loading="loading"
+ @click="fetchTask"
+ >鍒锋柊浠诲姟</el-button
+ >
+ </el-row>
+ <!-- <el-row>
+ <el-button type="default" size="default" @click="newTestTask">鏂板娴嬭瘯浠诲姟</el-button>
+ <el-button type="default" size="default" @click="startNewTestTask"
+ >鏂板缓骞惰繍琛屼竴涓祴璇曚换鍔�</el-button
+ >
+ <el-button type="default" size="default" @click="shutDownTask"
+ >寮哄埗鍏抽棴鎵�鏈夋祴璇曚换鍔�</el-button
+ >
+ </el-row> -->
+ </template>
+ <el-scrollbar height="70vh" class="scrollbar">
+ <template v-for="(v, i) in taskList" :key="i">
+ <FYBgTaskItem
+ :model="v"
+ :index="i"
+ @start="startTask"
+ @shutDown="shutDownTask"
+ @remove="removeTask"
+ @gotoResult="gotoResult"
+ ></FYBgTaskItem>
+ </template>
+ </el-scrollbar>
+ </el-card>
+</template>
+<script>
+/**
+ * 鑷姩璇勪及浠诲姟绠$悊
+ */
+import { useFetchData } from '@/composables/fetchData';
+import bgtaskApi from '@/api/fysp/bgtaskApi';
+import { enumBgTask, BG_TASK_TYPE } from '@/enum/bgTask';
+
+export default {
+ setup() {
+ const { loading, fetchData } = useFetchData();
+ return { loading, fetchData };
+ },
+ data() {
+ return {
+ taskList: [],
+ taskIndex: 0
+ };
+ },
+ methods: {
+ addTask(){
+
+ },
+ newTestTask() {
+ this.fetchData((page, pageSize) => {
+ return bgtaskApi.newTestTask(`Test-Task-${++this.taskIndex}`).then((res) => {
+ this.taskList.push(res.data);
+ });
+ });
+ },
+ startNewTestTask() {
+ this.fetchData((page, pageSize) => {
+ return bgtaskApi.startNewTestTask(`Test-Task-${++this.taskIndex}`).then((res) => {
+ this.taskList.push(res.data);
+ });
+ });
+ },
+
+ _getParam(taskStatus) {
+ return {
+ type: taskStatus.type,
+ id: taskStatus.id
+ };
+ },
+ fetchTask() {
+ this.fetchData((page, pageSize) => {
+ return bgtaskApi
+ .fetchTaskStatus({
+ type: BG_TASK_TYPE.AUTO_SCORE.name
+ })
+ .then((res) => {
+ this.taskList = res.data;
+ });
+ });
+ },
+ startTask(index, callback) {
+ this.fetchData((page, pageSize) => {
+ const param = this._getParam(this.taskList[index]);
+ return bgtaskApi.startTask(param).then((res) => {
+ this.taskList[index] = res.data;
+ callback(true);
+ });
+ });
+ },
+ shutDownTask(index, callback) {
+ this.fetchData((page, pageSize) => {
+ const param = this._getParam(this.taskList[index]);
+ return bgtaskApi.shutDownTask(param).then((res) => {
+ if (index && res.data && res.data.length == 1) {
+ this.taskList[index] = res.data[0];
+ } else {
+ res.data.forEach((e) => {
+ let v = this.taskList.find((value) => {
+ return value.id == e.id;
+ });
+ const i = this.taskList.indexOf(v);
+ this.taskList[i] = e;
+ });
+ }
+ callback(true);
+ });
+ });
+ },
+ removeTask(index, callback) {
+ this.fetchData((page, pageSize) => {
+ const param = this._getParam(this.taskList[index]);
+ return bgtaskApi.removeTask(param).then((res) => {
+ if (res.data) {
+ this.taskList.splice(index, 1);
+ callback(true);
+ }
+ });
+ });
+ },
+ gotoResult(index) {}
+ }
+};
+</script>
+<style scoped>
+.scrollbar {
+ padding: 8px;
+}
+</style>
diff --git a/src/views/analysis/evalution/components/CompReport.vue b/src/views/analysis/evalution/components/CompReport.vue
new file mode 100644
index 0000000..7d1a7b0
--- /dev/null
+++ b/src/views/analysis/evalution/components/CompReport.vue
@@ -0,0 +1,101 @@
+<template>
+ <el-button icon="Download" type="success" @click="dialogVisible = true"
+ >瑙勮寖鎬ц瘎浼颁笌鍒嗘瀽鎶ュ憡</el-button
+ >
+ <el-dialog
+ v-model="dialogVisible"
+ title="瑙勮寖鎬ц瘎浼颁笌鍒嗘瀽鎶ュ憡鐢熸垚"
+ width="500"
+ >
+ <el-text tag="b" size="large">鏁版嵁鑼冨洿纭</el-text>
+ <el-text tag="div">鍖哄煙锛歿{ locationText }}</el-text>
+ <el-text tag="div">绫诲瀷锛歿{ scenetype.label }}</el-text>
+ <el-text tag="div">鏃堕棿锛歿{ timeText }}</el-text>
+ <template #footer>
+ <div class="dialog-footer">
+ <el-row align="middle">
+ <el-checkbox v-model="forceUpdate" label="寮哄埗鐢熸垚鏂版姤鍛�" />
+ <el-tooltip placement="bottom-start" effect="light">
+ <template #content>
+ <el-text tag="b" size="small">涓嶅嬀閫夛細</el-text><br />
+ <el-text size="small"
+ >涓嶅嬀閫夋椂锛屽鏋滃凡鐢熸垚杩囩浉鍚屽尯鍩熺殑鎶ュ憡锛屽垯鐩存帴鑾峰彇璇ヤ唤鎶ュ憡璁板綍</el-text
+ ><br />
+ <el-text tag="b" size="small">鍕鹃�夛細</el-text><br />
+ <el-text size="small"
+ >鍕鹃�夋椂锛屾棤璁烘槸鍚︽湁鍘嗗彶璁板綍锛岄兘浼氬惎鍔ㄦ姤鍛婄敓鎴愪换鍔¤鐩栨棫璁板綍锛屽彲鍦ㄥ悗鍙颁换鍔$晫闈㈡煡鐪嬩换鍔¤繘搴�</el-text
+ ><br />
+ </template>
+ <el-icon class="m-l-8 cursor-p" :size="16" color="var(--el-color-warning)"
+ ><QuestionFilled
+ /></el-icon>
+ </el-tooltip>
+ </el-row>
+ <div>
+ <el-button @click="dialogVisible = false">鍙栨秷</el-button>
+ <el-button type="primary" @click="download">纭畾</el-button>
+ </div>
+ </div>
+ </template>
+ </el-dialog>
+</template>
+
+<script>
+import dayjs from 'dayjs';
+import evaluateApi from '@/api/fysp/evaluateApi';
+
+export default {
+ props: ['locations', 'time', 'scenetype'],
+ data() {
+ return {
+ dialogVisible: false,
+ forceUpdate: false
+ };
+ },
+ computed: {
+ locationText() {
+ const loc = this.locations;
+ let text = '';
+ text = loc.pName == loc.cName ? loc.pName : loc.pName + loc.cName;
+ text += loc.dName;
+ return text;
+ },
+ timeText() {
+ return dayjs(this.time).format('YYYY骞碝M鏈�');
+ }
+ },
+ methods: {
+ // 瑙勮寖鎬ц瘎浼颁笌鍒嗘瀽鎶ュ憡鍚庡彴鐢熸垚浠诲姟
+ download() {
+ const locations = this.locations;
+ const time = this.time;
+ const scenetype = this.scenetype;
+ const area = {
+ provincecode: locations.pCode,
+ provincename: locations.pName,
+ citycode: locations.cCode,
+ cityname: locations.cName,
+ districtcode: locations.dCode,
+ districtname: locations.dName,
+ starttime: dayjs(this.time).format('YYYY-MM-DD HH:mm:ss'),
+ scensetypeid: scenetype.value
+ };
+ evaluateApi.downloadAutoEvaluation(area, this.forceUpdate).then((res) => {
+ if (res == false) {
+ // 鏈笅杞芥枃妗o紝鑰屾槸寮�鍚簡鏂囨。鐢熸垚鍚庡彴浠诲姟
+ this.$parent;
+ }
+ this.dialogVisible = false;
+ });
+ }
+ }
+};
+</script>
+<style scoped>
+.dialog-footer {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 2px;
+}
+</style>
diff --git a/src/views/analysis/evalution/components/precheck/CompPreCheck.vue b/src/views/analysis/evalution/components/precheck/CompPreCheck.vue
new file mode 100644
index 0000000..3dba2b8
--- /dev/null
+++ b/src/views/analysis/evalution/components/precheck/CompPreCheck.vue
@@ -0,0 +1,97 @@
+<template>
+ <el-steps :active="stepIndex" finish-status="success" style="" align-center>
+ <el-step title="璇勪及鑼冨洿" />
+ <el-step title="鏁版嵁婧愭鏌�" />
+ <el-step title="鏉$洰璞佸厤" />
+ <el-step title="鑷姩璇勪及" />
+ </el-steps>
+ <CompCheckArea v-show="stepIndex == 0" v-model="stepIndex" @change="onAreaChange"></CompCheckArea>
+ <CompCheckSource
+ v-show="stepIndex == 1"
+ v-model="stepIndex"
+ ref="refSource"
+ @change="onDataSourceChange"
+ ></CompCheckSource>
+ <CompCheckExemption
+ v-show="stepIndex == 2"
+ v-model="stepIndex"
+ @change="onExemptionChange"
+ ></CompCheckExemption>
+ <CompCheckConfirm
+ v-show="stepIndex == 3"
+ v-model="stepIndex"
+ :area-info="area"
+ :data-source="dataSource"
+ :exemption-items="exemptionItems"
+ @start="onNewTask"
+ ></CompCheckConfirm>
+</template>
+
+<script>
+import dayjs from 'dayjs';
+import CompCheckArea from './components/CompCheckArea.vue';
+import CompCheckSource from './components/CompCheckSource.vue';
+import CompCheckExemption from './components/CompCheckExemption.vue';
+import CompCheckConfirm from './components/CompCheckConfirm.vue';
+
+/**
+ * 鑷姩璇勪及鏉′欢鍚堣鎬ф鏌�
+ */
+export default {
+ name: 'CompPreCheck',
+ components: { CompCheckArea, CompCheckSource, CompCheckExemption, CompCheckConfirm },
+ props: {},
+ emits: ['startTask'],
+ data() {
+ return {
+ // 鎿嶄綔姝ラ涓嬫爣
+ stepIndex: 0,
+ area: {
+ _locations: {},
+ _scenetype: {}
+ },
+ dataSource: {},
+ // 璞佸厤鏉$洰
+ exemptionItems: {}
+ };
+ },
+ methods: {
+ /**
+ * 鐩戝惉璇勪及鑼冨洿鍙樻洿
+ */
+ onAreaChange(val) {
+ const v = val.value;
+ this.area = v;
+ const a = {
+ provincecode: v._locations.pCode,
+ provincename: v._locations.pName,
+ citycode: v._locations.cCode,
+ cityname: v._locations.cName,
+ districtcode: v._locations.dCode,
+ districtname: v._locations.dName,
+ towncode: v._locations.tCode,
+ townname: v._locations.tName,
+ starttime: this.$fm.formatYMDHMS(v.time),
+ endtime: this.$fm.formatYMDHMS(v.time),
+ scensetypeid: v._scenetype.value,
+ online: true,
+ sourceType: v.sourceType
+ };
+ this.$refs.refSource.startCheck(a);
+ },
+ onDataSourceChange(val) {
+ this.dataSource = val;
+ },
+ onExemptionChange(val) {
+ this.exemptionItems = val;
+ },
+ /**
+ * 鑷姩璇勪及鍓嶇疆鍚堣鎬ф鏌�
+ * 妫�鏌ユ墍閫夎寖鍥村唴鍚勯」璇勪及鏁版嵁婧愭槸鍚﹀畬鏁�
+ */
+ onNewTask() {
+ this.$emit('startTask');
+ }
+ }
+};
+</script>
diff --git a/src/views/analysis/evalution/components/precheck/components/CompCheckArea.vue b/src/views/analysis/evalution/components/precheck/components/CompCheckArea.vue
new file mode 100644
index 0000000..b2ce350
--- /dev/null
+++ b/src/views/analysis/evalution/components/precheck/components/CompCheckArea.vue
@@ -0,0 +1,138 @@
+<template>
+ <el-card shadow="never">
+ <template #header>
+ <div><el-text tag="b" size="large">閫夋嫨璇勪及鑼冨洿</el-text></div>
+ <el-text size="small" type="info">鍖呮嫭鍖哄幙銆佸満鏅被鍨嬩互鍙婃湀浠�</el-text>
+ </template>
+ <FormCol>
+ <FYForm ref="formRef" :rules="evaConditionRules" :showButtons="false" @submit="nextStep">
+ <template #form-item="{ formObj }">
+ <CompQuickSet @quick-set="setOptions"></CompQuickSet>
+ <el-form-item label="涓绘暟鎹簮" prop="sourceType">
+ <el-radio-group
+ v-model="formObj.sourceType"
+ size="small"
+ @change="sceneOptionSourceInit = true"
+ >
+ <el-radio-button :value="1">瀹堟硶鏈嶅姟璁板綍</el-radio-button>
+ <el-radio-button :value="2">鐜板満宸℃煡璁板綍</el-radio-button>
+ </el-radio-group>
+ <el-tooltip placement="bottom-start" effect="light">
+ <template #content>
+ <el-text tag="i" size="default" type="warning"
+ >璇ラ�夐」鏄敤浜庡喅瀹氳瘎浼颁富浣撳璞$殑鑾峰彇鏂瑰紡</el-text
+ ><br />
+ <el-text tag="b" size="small">瀹堟硶鏈嶅姟璁板綍锛�</el-text><br />
+ <el-text size="small"
+ >琛ㄧず鍦ㄨ瘎浼版椂锛岃瘎浼板璞℃槸浠庡畧娉曟湇鍔″皬绋嬪簭绯荤粺涓幏鍙栫殑褰撳墠鍙敤鐨勭敤鎴凤紱<br />
+ 涓�鑸儏鍐典笅锛屽綋璇勪及瀵硅薄娌℃湁杩涜鐜板満宸℃煡锛屽彧鏈夊畧娉曟湇鍔$浉鍏宠褰曟椂锛岄噰鐢ㄦ閫夐」锛�</el-text
+ ><br />
+ <el-text tag="b" size="small">鐜板満宸℃煡璁板綍锛�</el-text><br />
+ <el-text size="small"
+ >琛ㄧず鍦ㄨ瘎浼版椂锛岃瘎浼板璞℃槸浠庣幇鍦哄贰鏌ョ洃绠$郴缁熶腑鑾峰彇鐨勬�讳换鍔′笅鐨勬墍鏈夌洃绠″満鏅紱<br />
+ 涓�鑸儏鍐典笅锛屽綋璇勪及瀵硅薄鏈夎繘琛岀幇鍦哄贰鏌ワ紝閲囩敤姝ら�夐」锛� </el-text
+ ><br />
+ </template>
+ <el-icon class="m-l-8 cursor-p" :size="16" color="var(--el-color-warning)"
+ ><QuestionFilled
+ /></el-icon>
+ </el-tooltip>
+ </el-form-item>
+ <!-- 鍖哄幙 -->
+ <FYOptionLocation
+ :allOption="false"
+ :level="3"
+ :initValue="false"
+ :checkStrictly="false"
+ v-model:value="formObj._locations"
+ ></FYOptionLocation>
+ <!-- 鍦烘櫙绫诲瀷 -->
+ <FYOptionScene
+ :allOption="false"
+ :initValue="false"
+ :sourceInit="sceneOptionSourceInit"
+ :type="formObj.sourceType"
+ v-model:value="formObj._scenetype"
+ ></FYOptionScene>
+ <!-- 鏃堕棿 -->
+ <FYOptionTime
+ prop="time"
+ :initValue="true"
+ type="month"
+ v-model:value="formObj.time"
+ ></FYOptionTime>
+ </template>
+ </FYForm>
+ </FormCol>
+ <template #footer>
+ <el-row justify="space-around">
+ <el-button type="primary" size="default" :loading="loading" @click="submit"
+ >涓嬩竴姝�</el-button
+ >
+ </el-row>
+ </template>
+ </el-card>
+</template>
+
+<script>
+
+/**
+ * 璇勪及鑼冨洿鍚堣鎬ф鏌�
+ */
+export default {
+ props: {
+ // 姝ラ涓嬫爣
+ modelValue: Number
+ },
+ emits: ['update:modelValue', 'change'],
+ data() {
+ return {
+ loading: false,
+ evaConditionRules: {
+ time: [
+ {
+ required: true,
+ message: '鏃堕棿涓嶈兘涓虹┖',
+ trigger: 'change'
+ }
+ ],
+ sourceType: [
+ {
+ required: true,
+ message: '涓绘暟鎹簮蹇呴』閫夋嫨',
+ trigger: 'change'
+ }
+ ]
+ },
+ // 褰撳満鏅�夐」鍒囨崲鏁版嵁婧愭椂锛屾槸鍚︽竻绌哄綋鍓嶉�夐」鍊�
+ sceneOptionSourceInit: true
+ };
+ },
+ methods: {
+ setOptions(param) {
+ this.sceneOptionSourceInit = false;
+ this.$refs.formRef.formObj._locations = param.locations;
+ this.$refs.formRef.formObj._scenetype = param.scenetype;
+ this.$refs.formRef.formObj.sourceType = param.sourceType;
+ },
+ submit() {
+ this.$refs.formRef.onSubmit(false);
+ },
+ // 璺宠浆涓嬩竴姝�
+ nextStep(formObj, success, fail) {
+ // todo: 妫�鏌ユ槸鍚﹀凡鏈夎瘎浼拌褰曪紝鎻愮ず鐢ㄦ埛鍙洿鎺ヨ烦杞煡鐪嬫垨缁х画涓嬩竴姝�
+
+ this.loading = true;
+ return new Promise((reslove, reject) => {
+ setTimeout(() => {
+ this.$emit('change', formObj);
+ this.$emit('update:modelValue', this.modelValue + 1);
+ this.loading = false;
+ success();
+ reslove();
+ }, 1000);
+ });
+ }
+ }
+};
+</script>
diff --git a/src/views/analysis/evalution/components/precheck/components/CompCheckConfirm.vue b/src/views/analysis/evalution/components/precheck/components/CompCheckConfirm.vue
new file mode 100644
index 0000000..7c6deb2
--- /dev/null
+++ b/src/views/analysis/evalution/components/precheck/components/CompCheckConfirm.vue
@@ -0,0 +1,108 @@
+<template>
+ <el-card shadow="never">
+ <template #header>
+ <div><el-text tag="b" size="large">鑷姩璇勪及纭</el-text></div>
+ <el-text size="small" type="info">鏈�缁堢‘璁よ嚜鍔ㄨ瘎浼板悇閰嶇疆椤癸紝骞跺紑濮嬭嚜鍔ㄨ瘎浼�</el-text>
+ </template>
+ <el-form label-width="160px" label-position="left">
+ <div class="m-b-16"><el-text tag="b" size="large">璇勪及鑼冨洿</el-text></div>
+ <el-form-item label="鍖哄煙">
+ <el-text size="default">{{ areaInfo._locations.pName }}</el-text>
+ <el-text size="default">{{ areaInfo._locations.cName }}</el-text>
+ <el-text size="default">{{ areaInfo._locations.dName }}</el-text>
+ <el-text size="default">{{ areaInfo.starttime }}</el-text>
+ </el-form-item>
+ <el-form-item label="鏃堕棿">
+ <el-text size="default">{{ $fm.formatYM(areaInfo.time) }}</el-text>
+ </el-form-item>
+ <el-form-item label="鍦烘櫙">
+ <el-text size="default">{{ areaInfo._scenetype.label }}</el-text>
+ </el-form-item>
+ <el-divider />
+ <div class="m-b-16"><el-text tag="b" size="large">璇勪及鏁版嵁婧愬畬鏁村害</el-text></div>
+ <el-form-item :label="v.name" v-for="v in dataSource" :key="v.name">
+ <template v-if="v.pass == true">
+ <el-icon color="var(--el-color-success)"><Check /></el-icon>
+ <el-text size="default" type="success">閫氳繃</el-text>
+ </template>
+ <template v-else-if="v.pass == false">
+ <el-icon color="var(--el-color-danger)"><Close /></el-icon>
+ <el-text size="default" type="danger">缂哄け</el-text>
+ </template>
+ <template v-else>
+ <el-icon color="var(--el-color-warning)"><Warning /></el-icon>
+ <el-text size="default" type="warning">鏆傜暐杩�</el-text>
+ </template>
+ </el-form-item>
+ <el-divider />
+ <div class="m-b-16"><el-text tag="b" size="large">璞佸厤鏉$洰</el-text></div>
+ <div class="m-b-16"><el-text size="default">鏃犺眮鍏嶆潯鐩�</el-text></div>
+ </el-form>
+
+ <template #footer>
+ <el-row justify="space-around">
+ <el-button type="primary" size="default" @click="lastStep">涓婁竴姝�</el-button>
+ <el-button type="primary" size="default" @click="startEvaluate">寮�濮嬭瘎浼�</el-button>
+ </el-row>
+ </template>
+ </el-card>
+</template>
+
+<script>
+import evaluateApi from '@/api/fysp/evaluateApi';
+
+/**
+ * 璇勪及浠诲姟鏈�缁堝紑鍚‘璁�
+ */
+export default {
+ props: {
+ // 姝ラ涓嬫爣
+ modelValue: Number,
+ // 鍖哄煙淇℃伅
+ areaInfo: {
+ type: Object,
+ default: () => {
+ return {
+ _locations: {},
+ _scenetype: {}
+ };
+ }
+ },
+ // 鏁版嵁婧愬畬鏁村害鎯呭喌
+ dataSource: Array,
+ // 鏉$洰璞佸厤鎯呭喌
+ exemptionItems: Array
+ },
+ emits: ['update:modelValue', 'start'],
+ data() {
+ return {};
+ },
+ methods: {
+ // 寮�鍚嚜鍔ㄨ瘎浼颁换鍔�
+ startEvaluate() {
+ const v = this.areaInfo
+ const a = {
+ provincecode: v._locations.pCode,
+ provincename: v._locations.pName,
+ citycode: v._locations.cCode,
+ cityname: v._locations.cName,
+ districtcode: v._locations.dCode,
+ districtname: v._locations.dName,
+ towncode: v._locations.tCode,
+ townname: v._locations.tName,
+ starttime: this.$fm.formatYMDHMS(v.time),
+ scensetypeid: v._scenetype.value,
+ online: true,
+ sourceType: v.sourceType
+ };
+ evaluateApi.autoEvaluate(a).then((res) => {
+ this.$emit('start', res.data);
+ });
+ },
+ // 璺宠浆涓婁竴姝�
+ lastStep() {
+ this.$emit('update:modelValue', this.modelValue - 1);
+ }
+ }
+};
+</script>
diff --git a/src/views/analysis/evalution/components/precheck/components/CompCheckExemption.vue b/src/views/analysis/evalution/components/precheck/components/CompCheckExemption.vue
new file mode 100644
index 0000000..5578e54
--- /dev/null
+++ b/src/views/analysis/evalution/components/precheck/components/CompCheckExemption.vue
@@ -0,0 +1,45 @@
+<template>
+ <el-card shadow="never">
+ <template #header>
+ <div><el-text tag="b" size="large">鏉$洰璞佸厤</el-text></div>
+ <el-text size="small" type="info">鑷畾涔夎缃娆¤瘎浼颁笉鍙備笌璁$畻鐨勬潯鐩�</el-text>
+ </template>
+ 璞佸厤鏉$洰鍔熻兘鏆傛湭瀹屾垚锛岃鐩存帴鐐瑰嚮涓嬩竴姝�
+ <template #footer>
+ <el-row justify="space-around">
+ <el-button type="primary" size="default" @click="lastStep">涓婁竴姝�</el-button>
+ <el-button type="primary" size="default" @click="nextStep">涓嬩竴姝�</el-button>
+ </el-row>
+ </template>
+ </el-card>
+</template>
+
+<script>
+/**
+ * 璇勪及鏉$洰璞佸厤璁惧畾
+ */
+export default {
+ props: {
+ // 姝ラ涓嬫爣
+ modelValue: Number
+ },
+ emits: ['update:modelValue', 'change'],
+ data() {
+ return {
+ // 璞佸厤鏉$洰
+ exemptionItems: []
+ };
+ },
+ methods: {
+ // 璺宠浆涓嬩竴姝�
+ nextStep() {
+ this.$emit('change', this.exemptionItems);
+ this.$emit('update:modelValue', this.modelValue + 1);
+ },
+ // 璺宠浆涓嬩竴姝�
+ lastStep() {
+ this.$emit('update:modelValue', this.modelValue - 1);
+ }
+ }
+};
+</script>
diff --git a/src/views/analysis/evalution/components/precheck/components/CompCheckSource.vue b/src/views/analysis/evalution/components/precheck/components/CompCheckSource.vue
new file mode 100644
index 0000000..2103658
--- /dev/null
+++ b/src/views/analysis/evalution/components/precheck/components/CompCheckSource.vue
@@ -0,0 +1,334 @@
+<template>
+ <div>
+ <el-card shadow="never">
+ <template #header>
+ <div><el-text tag="b" size="large">鏁版嵁婧愭鏌�</el-text></div>
+ <el-text size="small" type="info">妫�鏌ヨ瘎浼版墍闇�鏁版嵁婧愭槸鍚﹀畬鏁�</el-text>
+ </template>
+ <FormCol>
+ <template v-for="(v, i) in checkResults" :key="i">
+ <el-row class="h-small" align="middle">
+ <el-col :span="14">
+ <el-row align="middle">
+ <el-text
+ size="default"
+ :class="v.required ? 'required' : 'not-required'"
+ >*</el-text
+ >
+ <el-text size="default" class="m-l-4">{{ v.name }}</el-text>
+ </el-row>
+ </el-col>
+ <el-col :span="5">
+ <el-row align="middle">
+ <el-space>
+ <template v-if="v.loading">
+ <el-icon class="is-loading"><Loading /></el-icon>
+ <el-text size="default" type="default">妫�鏌ヤ腑...</el-text>
+ </template>
+ <template v-else-if="v.pass == true">
+ <el-icon color="var(--el-color-success)"><Check /></el-icon>
+ <el-text size="default" type="success">閫氳繃</el-text>
+ </template>
+ <template v-else-if="v.pass == false">
+ <el-icon color="var(--el-color-danger)"><Close /></el-icon>
+ <el-text size="default" type="danger">缂哄け</el-text>
+ </template>
+ <template v-else>
+ <el-icon color="var(--el-color-warning)"
+ ><Warning
+ /></el-icon>
+ <el-text size="default" type="warning">鏆傜暐杩�</el-text>
+ </template>
+ </el-space>
+ </el-row>
+ </el-col>
+ <el-col :span="5">
+ <el-button
+ v-show="!v.loading"
+ :type="v.pass ? '' : 'danger'"
+ size="small"
+ @click="goto(v.path)"
+ :disabled="v.path == ''"
+ >
+ {{ v.pass ? '鍘讳慨鏀�' : '鍘诲畬鍠�' }}
+ <el-icon class="m-l-4"><Right /></el-icon>
+ </el-button>
+ </el-col>
+ </el-row>
+ <el-row align="middle" class="m-b-16">
+ <el-text size="small" class="not-required">*</el-text>
+ <el-text size="small" class="m-l-4 color-i">{{ v.des }}</el-text>
+ </el-row>
+ </template>
+ </FormCol>
+ <template #footer>
+ <el-row justify="space-around">
+ <el-button type="primary" size="default" @click="lastStep"
+ >涓婁竴姝�</el-button
+ >
+ <el-button
+ :disabled="!checkPass"
+ type="primary"
+ size="default"
+ @click="nextStep"
+ >涓嬩竴姝�</el-button
+ >
+ </el-row>
+ </template>
+ </el-card>
+ <el-dialog
+ title="鎵皹鐩戞祴鏁版嵁鏈堝害缁熻绠$悊"
+ v-model="dialog1"
+ destroy-on-close
+ width="90%"
+ >
+ <CompDataResultEdit :areaInfo="areaInfo"></CompDataResultEdit>
+ <template #footer> </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script>
+import evaluateApi from '@/api/fysp/evaluateApi';
+import taskApi from '@/api/fysp/taskApi';
+import userMapApi from '@/api/fysp/userMapApi';
+import problemApi from '@/api/fysp/problemApi';
+import monitordataApi from '@/api/fysp/monitordataApi';
+import complaintApi from '@/api/fytz/complaintApi';
+import CompDataResultEdit from '../../CompDataResultEdit.vue';
+
+/**
+ * 鐢熸垚涓�椤规暟鎹簮妫�鏌ユ潯鐩�
+ * @param {*} _name 鏉$洰鍚嶇О
+ * @param {*} _path 璺宠浆椤甸潰URL
+ * @param {*} _fetch 鏉$洰鐨勭綉缁滆姹傚嚱鏁�
+ * @param {*} _required 鏄惁蹇呴��
+ */
+function baseCheckItem(_name, _path, _fetch, _required) {
+ return {
+ required: _required,
+ name: _name,
+ loading: true,
+ pass: false,
+ path: _path,
+ des: '',
+ async fetch() {
+ this.loading = true;
+ setTimeout(async () => {
+ if (typeof _fetch === 'function') {
+ _fetch()
+ .then((res) => {
+ this.pass = res ? res.pass : undefined;
+ this.des = res ? res.des : undefined;
+ })
+ .catch(() => {
+ this.pass = false;
+ this.des = '缃戠粶閾炬帴閿欒';
+ })
+ .finally(() => {
+ this.loading = false;
+ });
+ } else {
+ this.pass = undefined;
+ this.des = undefined;
+ this.loading = false;
+ }
+ }, 1000);
+ }
+ };
+}
+
+/**
+ * 璇勪及鏁版嵁婧愬畬鏁存�ф鏌�
+ */
+export default {
+ components: {
+ CompDataResultEdit
+ },
+ props: {
+ // 姝ラ涓嬫爣
+ modelValue: Number
+ },
+ emits: ['update:modelValue', 'change'],
+ data() {
+ return {
+ areaInfo: {},
+ // 鏁版嵁婧愭鏌ヨ褰�
+ checkResults: [
+ // 鍖哄煙鑼冨洿鍐呯殑鑷姩璇勪及瑙勫垯琛ㄦ槸鍚﹀瓨鍦�
+ baseCheckItem(
+ '鑷姩璇勪及瑙勫垯琛�',
+ '',
+ () => {
+ const param = {
+ taskTypeId: 99,
+ ...this.areaInfo
+ };
+ return evaluateApi.fetchEvaluationRule(param).then((res) => {
+ const pass = res.data.length > 0;
+ let des = '';
+ if (pass) {
+ res.data.forEach((e) => {
+ if (des != '') {
+ des += '銆�';
+ }
+ des += `銆�${e.rulename}銆媊;
+ });
+ } else {
+ des = '鏈壘鍒扮浉鍏宠瘎浼拌鍒欒〃';
+ }
+ return { pass, des };
+ });
+ },
+ true
+ ),
+ // 鍖哄煙鑼冨洿鍐呯殑鐩戠浠诲姟鏄惁瀛樺湪
+ baseCheckItem('鐜板満鐩戠宸℃煡鎬讳换鍔�', '', () => {
+ return taskApi.fetchTopTasks(this.areaInfo).then((res) => {
+ const pass = res.data.length > 0;
+ let des = '';
+ if (pass) {
+ res.data.forEach((e) => {
+ if (des != '') {
+ des += '銆�';
+ }
+ des += e.name;
+ });
+ } else {
+ des = '鏈壘鍒扮浉鍏冲贰鏌ユ�讳换鍔�';
+ }
+ return { pass, des };
+ });
+ }),
+ // 鍖哄煙鑼冨洿鍐呯殑鐩戞祴鏁版嵁鏄惁瀛樺湪銆佹暟鎹椂闂磋法搴︽槸鍚﹀畬鏁淬�佹暟鎹殑鍒濇鍒嗘瀽鏄惁瀹屾垚
+ baseCheckItem(
+ '鐜板満鐩戞祴鏁版嵁',
+ () => {
+ this.dialog1 = true;
+ },
+ () => {
+ return monitordataApi
+ .fetchDustDataResult(this.areaInfo)
+ .then((res) => {
+ const pass = res.data.length > 0;
+ let des = '';
+ if (pass) {
+ des = `鎵惧埌鏈堝害缁熻鍏�${res.data.length}鏉;
+ } else {
+ des = '鏈壘鍒扮浉鍏宠褰�';
+ }
+ return { pass, des };
+ });
+ }
+ ),
+ // 鍖哄煙鑼冨洿鍐呯殑姣忎釜鐩戠鐐逛綅涓庣洃娴嬩华鍣ㄧ殑鍖归厤璁板綍鏄惁瀛樺湪锛岀己澶辨儏鍐电瓑
+ baseCheckItem('鐩戠鐐逛綅涓庣洃娴嬬偣鍖归厤', '', () => {
+ return userMapApi.fetchDeviceMap(this.areaInfo).then((res) => {
+ const pass = res.data.length > 0;
+ let des = '';
+ if (pass) {
+ des = `鎵惧埌鍖归厤璁板綍鍏�${res.data.length}鏉;
+ } else {
+ des = '鏈壘鍒扮浉鍏冲尮閰嶈褰�';
+ }
+ return { pass, des };
+ });
+ }),
+ // 鍖哄煙鑼冨洿鍐呯殑鐩戠闂閰嶇疆琛ㄦ槸鍚﹀瓨鍦�
+ baseCheckItem('鐜板満鐩戠闂绫诲瀷', '', () => {
+ const param = {
+ cityCode: this.areaInfo.citycode,
+ districtCode: this.areaInfo.districtcode,
+ sceneTypeId: this.areaInfo.scensetypeid
+ };
+ return problemApi.fetchProblemType(param).then((res) => {
+ const pass = res.length > 0;
+ let des = '';
+ if (pass) {
+ des = `鎵惧埌闂绫诲瀷鍏�${res.length}鏉;
+ } else {
+ des = '鏈壘鍒扮浉鍏抽棶棰樼被鍨�';
+ }
+ return { pass, des };
+ });
+ }),
+ // complaintApi.fetchComplaints();
+ // 鍖哄煙鑼冨洿鍐呯殑淇¤鎶曡瘔璁板綍鏄惁瀛樺湪锛屽彲闅忔椂琛ュ厖
+ baseCheckItem('淇¤鎶曡瘔', ''),
+ // complaintApi.fetchPunishment();
+ // 鍖哄煙鑼冨洿鍐呯殑琛屾斂澶勭綒璁板綍鏄惁瀛樺湪锛屽彲闅忔椂琛ュ厖
+ baseCheckItem('琛屾斂澶勭綒', '')
+ ],
+ dialog1: false
+ };
+ },
+ computed: {
+ /**
+ * 鍒ゆ柇鏁版嵁婧愭鏌ユ槸鍚﹂�氳繃
+ * 鍏ㄩ儴鍔犺浇瀹屾垚鍚庯紝蹇呰椤瑰繀椤婚�氳繃锛屽彲閫夐」闈炲繀椤婚�氳繃
+ */
+ checkPass() {
+ let res = true;
+ this.checkResults.forEach((e) => {
+ if (e.loading) {
+ res = res && false;
+ } else if (e.required) {
+ res = res && e.pass;
+ }
+ });
+ return res;
+ }
+ },
+ methods: {
+ // 璺宠浆涓嬩竴姝�
+ nextStep() {
+ this.$emit('change', this.checkResults);
+ this.$emit('update:modelValue', this.modelValue + 1);
+ },
+ // 璺宠浆涓婁竴姝�
+ lastStep() {
+ this.$emit('update:modelValue', this.modelValue - 1);
+ },
+ // 璺宠浆妫�鏌ラ」鐨勯摼鎺�
+ goto(path) {
+ if (typeof path === 'string' && path != '') {
+ this.$router.push(path);
+ } else if (typeof path === 'function') {
+ path();
+ }
+ },
+ // 寮�濮嬫鏌ヤ换鍔�
+ startCheck(value) {
+ // const v = value.value;
+ // this.areaInfo = {
+ // provincecode: v._locations.pCode,
+ // provincename: v._locations.pName,
+ // citycode: v._locations.cCode,
+ // cityname: v._locations.cName,
+ // districtcode: v._locations.dCode,
+ // districtname: v._locations.dName,
+ // towncode: v._locations.tCode,
+ // townname: v._locations.tName,
+ // starttime: this.$fm.formatYMDHMS(v.time),
+ // scensetypeid: v._scenetype.value,
+ // online: true,
+ // sourceType: v.sourceType
+ // };
+ this.areaInfo = value;
+
+ this.checkResults.forEach((e) => {
+ e.fetch();
+ });
+ }
+ }
+};
+</script>
+<style scoped>
+.required {
+ color: var(--el-color-danger);
+}
+
+.not-required {
+ color: transparent;
+}
+</style>
diff --git a/src/views/monitor/DataDashboard.vue b/src/views/monitor/DataDashboard.vue
index 4e266ec..3292858 100644
--- a/src/views/monitor/DataDashboard.vue
+++ b/src/views/monitor/DataDashboard.vue
@@ -1,27 +1,31 @@
-<!-- e:\VSprojects\fume-supervision-vue\src\views\monitor\DataDashboard.vue -->
<template>
<el-container class="data-dashboard">
<el-main>
- <!-- 璁惧鍦ㄧ嚎鎯呭喌鍖哄煙 -->
- <DeviceStatus
- :online-count="onlineCount"
- :offline-count="offlineCount"
- :normal-count="normalCount"
- :fault-count="faultCount"
- />
-
- <!-- 璁惧瀹炴椂鏁版嵁鍖哄煙 -->
- <RealTimeData :current-device="currentDevice" :hourly-data="hourlyData" />
-
- <!-- 鍒嗗尯鏁版嵁鎺掑悕鍖哄煙 -->
- <DistrictRanking
- :selected-month="selectedMonth"
- :ranking-type="rankingType"
- :ranking-data="rankingData"
- :sorted-ranking-data="sortedRankingData"
- @month-change="handleMonthChange"
- @type-change="handleTypeChange"
- />
+ <div class="grid-container">
+ <div class="left-section">
+ <!-- 璁惧鍦ㄧ嚎鎯呭喌鍖哄煙 -->
+ <DeviceStatus
+ :online-count="onlineCount"
+ :offline-count="offlineCount"
+ :normal-count="normalCount"
+ :fault-count="faultCount"
+ />
+ <!-- 鍒嗗尯鏁版嵁鎺掑悕鍖哄煙 -->
+ <DistrictRanking
+ style="flex: 1"
+ :selected-month="selectedMonth"
+ :ranking-type="rankingType"
+ :ranking-data="rankingData"
+ :sorted-ranking-data="sortedRankingData"
+ @month-change="handleMonthChange"
+ @type-change="handleTypeChange"
+ />
+ </div>
+ <div class="right-section">
+ <!-- 璁惧瀹炴椂鏁版嵁鍖哄煙 -->
+ <RealTimeData style="flex: 1" :devices="devices" />
+ </div>
+ </div>
<!-- 鍦ㄧ嚎璁惧鍜屽簵閾烘竻鍗曞尯鍩� -->
<ShopList
@@ -58,8 +62,7 @@
faultCount: 0,
// 璁惧瀹炴椂鏁版嵁
- currentDevice: null,
- hourlyData: [],
+ devices: [],
// 鍒嗗尯鏁版嵁鎺掑悕
selectedMonth: '2023-12',
@@ -147,45 +150,80 @@
updateRealTimeData() {
// 妯℃嫙鏁版嵁 - 瀹為檯搴斾粠API鑾峰彇
- const devices = [
+ this.devices = [
{
deviceId: 'DEV-001',
supplier: '渚涘簲鍟咥',
- 娌圭儫娴撳害: (Math.random() * 2).toFixed(2),
- 椋庢満鐢垫祦: (Math.random() * 5 + 1).toFixed(2),
- 鍑�鍖栧櫒鐢垫祦: (Math.random() * 3 + 0.5).toFixed(2),
+ status: '姝e父',
+ monitorTime: new Date().toLocaleString(),
+ smokeDensity: (Math.random() * 2).toFixed(2),
+ fanCurrent: (Math.random() * 5 + 1).toFixed(2),
+ purifierCurrent: (Math.random() * 3 + 0.5).toFixed(2),
+ hourlyData: this.generateHourlyData(),
+ },
+ {
+ deviceId: 'DEV-002',
+ supplier: '渚涘簲鍟咮',
+ status: '姝e父',
+ monitorTime: new Date().toLocaleString(),
+ smokeDensity: (Math.random() * 2).toFixed(2),
+ fanCurrent: (Math.random() * 5 + 1).toFixed(2),
+ purifierCurrent: (Math.random() * 3 + 0.5).toFixed(2),
+ hourlyData: this.generateHourlyData(),
+ },
+ {
+ deviceId: 'DEV-003',
+ supplier: '渚涘簲鍟咰',
+ status: '寮傚父',
+ monitorTime: new Date().toLocaleString(),
+ smokeDensity: (Math.random() * 15 + 5).toFixed(2),
+ fanCurrent: (Math.random() * 3 + 4).toFixed(2),
+ purifierCurrent: (Math.random() * 2 + 2).toFixed(2),
+ hourlyData: this.generateHourlyData(),
+ },
+ {
+ deviceId: 'DEV-004',
+ supplier: '渚涘簲鍟咲',
+ status: '寮傚父',
+ monitorTime: new Date().toLocaleString(),
+ smokeDensity: (Math.random() * 15 + 5).toFixed(2),
+ fanCurrent: (Math.random() * 3 + 4).toFixed(2),
+ purifierCurrent: (Math.random() * 2 + 2).toFixed(2),
+ hourlyData: this.generateHourlyData(),
},
]
+ },
- this.currentDevice = devices[0]
-
+ generateHourlyData() {
// 鐢熸垚妯℃嫙鐨勮繎涓�灏忔椂鏁版嵁
- this.hourlyData = []
+ const hourlyData = []
for (let i = 59; i >= 0; i--) {
const time = new Date()
time.setMinutes(time.getMinutes() - i)
- this.hourlyData.push({
+ hourlyData.push({
time: time.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' }),
- 娌圭儫娴撳害: (Math.random() * 2).toFixed(2),
- 椋庢満鐢垫祦: (Math.random() * 5 + 1).toFixed(2),
- 鍑�鍖栧櫒鐢垫祦: (Math.random() * 3 + 0.5).toFixed(2),
+ smokeDensity: (Math.random() * 2).toFixed(2),
+ fanCurrent: (Math.random() * 5 + 1).toFixed(2),
+ purifierCurrent: (Math.random() * 3 + 0.5).toFixed(2),
})
}
+ return hourlyData
},
updateRankingData() {
// 妯℃嫙鏁版嵁 - 瀹為檯搴斾粠API鑾峰彇
this.rankingData = [
- { name: '涓滃煄鍖�', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 0 },
- { name: '瑗垮煄鍖�', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: -1 },
- { name: '鏈濋槼鍖�', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 1 },
- { name: '娴锋穩鍖�', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 0 },
- { name: '涓板彴鍖�', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: -2 },
- { name: '鐭虫櫙灞卞尯', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 2 },
- { name: '閫氬窞鍖�', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 0 },
- { name: '椤轰箟鍖�', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 1 },
- { name: '鏄屽钩鍖�', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: -1 },
- { name: '澶у叴鍖�', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 0 },
+ { name: '鐜勬鍖�', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 0 },
+ { name: '绉︽樊鍖�', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: -1 },
+ { name: '寤洪偤鍖�', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 1 },
+ { name: '榧撴ゼ鍖�', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 0 },
+ { name: '娴﹀彛鍖�', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: -2 },
+ { name: '鏍栭湠鍖�', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 2 },
+ { name: '闆ㄨ姳鍙板尯', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 0 },
+ { name: '姹熷畞鍖�', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 1 },
+ { name: '鍏悎鍖�', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: -1 },
+ { name: '婧ф按鍖�', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 0 },
+ { name: '楂樻烦鍖�', value: (Math.random() * 1.5 + 0.5).toFixed(2), rankChange: 1 },
]
// 鎺掑簭
@@ -240,14 +278,35 @@
padding: 20px;
}
+.grid-container {
+ display: flex;
+ /* display: grid;
+ grid-template-columns: 1fr 1fr;
+ grid-template-rows: min-content; */
+ gap: 20px;
+}
+
+.left-section {
+ flex: 2;
+ display: flex;
+ flex-direction: column;
+ gap: 20px;
+}
+
+.right-section {
+ width: 670px;
+ display: flex;
+ flex-direction: column;
+}
+
/* 鍝嶅簲寮忚璁� */
@media (max-width: 768px) {
- .el-row {
- flex-direction: column;
+ .grid-container {
+ grid-template-columns: 1fr;
}
- .el-col {
- width: 100% !important;
+ .left-section,
+ .right-section {
margin-bottom: 10px;
}
}
--
Gitblit v1.9.3