修改测试问题

This commit is contained in:
guanj
2026-06-16 08:34:45 +08:00
parent 1c01fe5ae1
commit d9dfd804c5
63 changed files with 5289 additions and 3842 deletions

View File

@@ -455,7 +455,8 @@ const handleTolerableEventClick = async (row: any) => {
persistTime: row.value[0], //持续时间 persistTime: row.value[0], //持续时间
featureAmplitude: (row.value[1] / 100), //残余电压 featureAmplitude: (row.value[1] / 100), //残余电压
startTime: row.value[2], //时间 startTime: row.value[2], //时间
lineName: row.value[4] //监测点名称 lineName: row.value[4], //监测点名称
engineeringName: row.value[5],
} }
boxoList.value.systemType = 'YPT' boxoList.value.systemType = 'YPT'
wp.value = res.data wp.value = res.data

View File

@@ -387,7 +387,8 @@ const handleTolerableEventClick = async (row: any) => {
persistTime: row.value[0], //持续时间 persistTime: row.value[0], //持续时间
featureAmplitude: (row.value[1] / 100), //残余电压 featureAmplitude: (row.value[1] / 100), //残余电压
startTime: row.value[2], //时间 startTime: row.value[2], //时间
lineName: row.value[4] //监测点名称 lineName: row.value[4], //监测点名称
engineeringName: row.value[5],
} }
boxoList.value.systemType = 'YPT' boxoList.value.systemType = 'YPT'
wp.value = res.data wp.value = res.data

View File

@@ -82,15 +82,50 @@ const tableStore: any = new TableStore({
title: '指标名称', title: '指标名称',
field: 'name', field: 'name',
minWidth: 120 minWidth: 120
}, {
title: '越限时间',
field: 'time',
minWidth: 100,
formatter: (row: any) => {
return row.cellValue || '/'
}
}, },
{ {
title: '越限最高监测点', title: '越限最高监测点名称',
field: 'lineName', field: 'lineName',
minWidth: 120, minWidth: 140,
formatter: (row: any) => { formatter: (row: any) => {
return row.cellValue || '/' return row.cellValue || '/'
} }
}, },
{
title: '越限程度(%)',
field: 'extent',
minWidth: 100,
formatter: (row: any) => {
return row.cellValue ? Math.floor(row.cellValue * 100) / 100 : '/'
}
},
{
title: '越限最大值',
field: 'maxValue',
minWidth: 100,
render: 'customTemplate',
customTemplate: (row: any) => {
const extentValue =
row.maxValue !== null && row.maxValue !== undefined && row.maxValue !== ''
? Math.floor(row.maxValue * 100) / 100
: '/'
return extentValue == '/' ? '/' : `<span style='cursor: pointer;text-decoration: underline;'>${extentValue}</span>`
}
},
{
title: '国标限值',
field: 'internationalValue',
minWidth: 100, formatter: (row: any) => {
return row.cellValue || '/'
}
},
{ {
title: '设备名称', field: 'devName', minWidth: 130, align: 'center', formatter: (row: any) => { title: '设备名称', field: 'devName', minWidth: 130, align: 'center', formatter: (row: any) => {
return row.cellValue || '/' return row.cellValue || '/'
@@ -106,42 +141,9 @@ const tableStore: any = new TableStore({
return row.cellValue || '/' return row.cellValue || '/'
} }
}, },
{
title: '越限最大值',
field: 'maxValue',
minWidth: 100,
render: 'customTemplate',
customTemplate: (row: any) => {
const extentValue =
row.maxValue !== null && row.maxValue !== undefined && row.maxValue !== ''
? Math.floor(row.maxValue * 100) / 100
: '/'
return extentValue=='/' ? '/' : `<span style='cursor: pointer;text-decoration: underline;'>${extentValue}</span>`
}
},
{
title: '国标限值',
field: 'internationalValue',
minWidth: 100, formatter: (row: any) => {
return row.cellValue || '/'
}
},
{
title: '越限程度(%)',
field: 'extent',
minWidth: 100,
formatter: (row: any) => {
return row.cellValue? Math.floor(row.cellValue * 100) / 100 : '/'
}
},
{
title: '越限时间',
field: 'time',
minWidth: 100,
formatter: (row: any) => {
return row.cellValue || '/'
}
},
], ],
beforeSearchFun: () => { beforeSearchFun: () => {

View File

@@ -46,6 +46,7 @@ import { ref, onMounted, onUnmounted, provide, reactive, watch, h, computed, nex
import TableStore from '@/utils/tableStore' import TableStore from '@/utils/tableStore'
import { exportExcel } from '@/views/govern/reportForms/export.js' import { exportExcel } from '@/views/govern/reportForms/export.js'
import { destroyLuckysheet, renderLuckysheetReport } from '@/utils/luckysheetHelper' import { destroyLuckysheet, renderLuckysheetReport } from '@/utils/luckysheetHelper'
import { buildExportBaseName } from '@/utils/echartMethod'
import TableHeader from '@/components/table/header/index.vue' import TableHeader from '@/components/table/header/index.vue'
import { querySysExcel } from '@/api/harmonic-boot/luckyexcel' import { querySysExcel } from '@/api/harmonic-boot/luckyexcel'
import { getListByIds } from '@/api/harmonic-boot/cockpit/cockpit' import { getListByIds } from '@/api/harmonic-boot/cockpit/cockpit'
@@ -72,6 +73,8 @@ const templateList = ref([])
const idList = ref() const idList = ref()
const exportSubjectName = ref('')
const handleNodeClick = async (data: any) => { const handleNodeClick = async (data: any) => {
if (templateList.value.length == 0) { if (templateList.value.length == 0) {
await querySysExcel({}).then(res => { await querySysExcel({}).then(res => {
@@ -83,6 +86,8 @@ const handleNodeClick = async (data: any) => {
} }
if (data?.level == 3 || data?.level == 2) { if (data?.level == 3 || data?.level == 2) {
exportSubjectName.value = data.name || ''
tableStore.exportName = { subject: exportSubjectName.value, feature: '治理效果报表' }
tableStore.table.params.sensitiveUserId = data.id tableStore.table.params.sensitiveUserId = data.id
await tableStore.index() await tableStore.index()
} else { } else {
@@ -104,7 +109,14 @@ const templateListData = () => {
} }
// 下载表格 // 下载表格
const downloadExcel = () => { const downloadExcel = () => {
exportExcel(luckysheet.getAllSheets(), '治理效果报表') exportExcel(
luckysheet.getAllSheets(),
buildExportBaseName({
subject: exportSubjectName.value,
feature: '治理效果报表',
date: tableStore.table.params.searchEndTime || tableStore.table.params.searchBeginTime
})
)
} }
onMounted(() => { onMounted(() => {

View File

@@ -343,6 +343,11 @@ const setEchart = () => {
} }
echartsData.value = { echartsData.value = {
exportFileName: {
subject: trendRequestData.value?.lineName,
feature: '趋势图',
date: datePickerRef.value?.timeValue?.[1] || datePickerRef.value?.timeValue?.[0]
},
legend: { legend: {
itemWidth: 20, itemWidth: 20,
itemHeight: 20, itemHeight: 20,
@@ -411,10 +416,7 @@ const setEchart = () => {
title: '下载csv', title: '下载csv',
icon: 'path://M642 673.1H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9s-8 17.9-17.9 17.9zM642 511.8H301.6c-9.9 0-17.9-8-17.9-17.9 0-9.9 8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9 0 9.9-8 17.9-17.9 17.9zM480.7 350.6H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9h179.2c9.9 0 17.9 8 17.9 17.9s-8.1 17.9-18 17.9zM874.9 350.6H695.7c-49.4 0-89.6-40.2-89.6-89.6V81.9c0-9.9 8-17.9 17.9-17.9 9.9 0 17.9 8 17.9 17.9V261c0 29.6 24.1 53.7 53.7 53.7h179.2c9.9 0 17.9 8 17.9 17.9s-7.9 18-17.8 18zM794.3 959.7H221c-49.4 0-89.6-40.2-89.6-89.6V153.5c0-49.4 40.2-89.6 89.6-89.6h403.1c4.8 0 9.3 1.9 12.7 5.2L887.6 320c3.4 3.4 5.2 7.9 5.2 12.7v537.5c0 52.7-51.9 89.5-98.5 89.5zM221 99.8c-29.6 0-53.7 24.1-53.7 53.7v716.6c0 29.6 24.1 53.7 53.7 53.7h573.3c29 0 62.7-23.5 62.7-53.7v-530L616.7 99.8H221z', icon: 'path://M642 673.1H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9s-8 17.9-17.9 17.9zM642 511.8H301.6c-9.9 0-17.9-8-17.9-17.9 0-9.9 8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9 0 9.9-8 17.9-17.9 17.9zM480.7 350.6H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9h179.2c9.9 0 17.9 8 17.9 17.9s-8.1 17.9-18 17.9zM874.9 350.6H695.7c-49.4 0-89.6-40.2-89.6-89.6V81.9c0-9.9 8-17.9 17.9-17.9 9.9 0 17.9 8 17.9 17.9V261c0 29.6 24.1 53.7 53.7 53.7h179.2c9.9 0 17.9 8 17.9 17.9s-7.9 18-17.8 18zM794.3 959.7H221c-49.4 0-89.6-40.2-89.6-89.6V153.5c0-49.4 40.2-89.6 89.6-89.6h403.1c4.8 0 9.3 1.9 12.7 5.2L887.6 320c3.4 3.4 5.2 7.9 5.2 12.7v537.5c0 52.7-51.9 89.5-98.5 89.5zM221 99.8c-29.6 0-53.7 24.1-53.7 53.7v716.6c0 29.6 24.1 53.7 53.7 53.7h573.3c29 0 62.7-23.5 62.7-53.7v-530L616.7 99.8H221z',
onclick: () => { onclick: () => {
exportSeriesCSV( exportSeriesCSV(echartsData.value.options.series, echartsData.value.exportFileName)
echartsData.value.options.series,
`${dialogTitle.value || '监测点指标趋势'}.csv`
)
} }
}, },
myTool2: { myTool2: {

View File

@@ -342,6 +342,11 @@ const setEchart = () => {
} }
echartsData.value = { echartsData.value = {
exportFileName: {
subject: trendRequestData.value?.lineName,
feature: '趋势图',
date: datePickerRef.value?.timeValue?.[1] || datePickerRef.value?.timeValue?.[0]
},
legend: { legend: {
itemWidth: 20, itemWidth: 20,
itemHeight: 20, itemHeight: 20,
@@ -410,10 +415,7 @@ const setEchart = () => {
title: '下载csv', title: '下载csv',
icon: 'path://M642 673.1H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9s-8 17.9-17.9 17.9zM642 511.8H301.6c-9.9 0-17.9-8-17.9-17.9 0-9.9 8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9 0 9.9-8 17.9-17.9 17.9zM480.7 350.6H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9h179.2c9.9 0 17.9 8 17.9 17.9s-8.1 17.9-18 17.9zM874.9 350.6H695.7c-49.4 0-89.6-40.2-89.6-89.6V81.9c0-9.9 8-17.9 17.9-17.9 9.9 0 17.9 8 17.9 17.9V261c0 29.6 24.1 53.7 53.7 53.7h179.2c9.9 0 17.9 8 17.9 17.9s-7.9 18-17.8 18zM794.3 959.7H221c-49.4 0-89.6-40.2-89.6-89.6V153.5c0-49.4 40.2-89.6 89.6-89.6h403.1c4.8 0 9.3 1.9 12.7 5.2L887.6 320c3.4 3.4 5.2 7.9 5.2 12.7v537.5c0 52.7-51.9 89.5-98.5 89.5zM221 99.8c-29.6 0-53.7 24.1-53.7 53.7v716.6c0 29.6 24.1 53.7 53.7 53.7h573.3c29 0 62.7-23.5 62.7-53.7v-530L616.7 99.8H221z', icon: 'path://M642 673.1H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9s-8 17.9-17.9 17.9zM642 511.8H301.6c-9.9 0-17.9-8-17.9-17.9 0-9.9 8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9 0 9.9-8 17.9-17.9 17.9zM480.7 350.6H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9h179.2c9.9 0 17.9 8 17.9 17.9s-8.1 17.9-18 17.9zM874.9 350.6H695.7c-49.4 0-89.6-40.2-89.6-89.6V81.9c0-9.9 8-17.9 17.9-17.9 9.9 0 17.9 8 17.9 17.9V261c0 29.6 24.1 53.7 53.7 53.7h179.2c9.9 0 17.9 8 17.9 17.9s-7.9 18-17.8 18zM794.3 959.7H221c-49.4 0-89.6-40.2-89.6-89.6V153.5c0-49.4 40.2-89.6 89.6-89.6h403.1c4.8 0 9.3 1.9 12.7 5.2L887.6 320c3.4 3.4 5.2 7.9 5.2 12.7v537.5c0 52.7-51.9 89.5-98.5 89.5zM221 99.8c-29.6 0-53.7 24.1-53.7 53.7v716.6c0 29.6 24.1 53.7 53.7 53.7h573.3c29 0 62.7-23.5 62.7-53.7v-530L616.7 99.8H221z',
onclick: () => { onclick: () => {
exportSeriesCSV( exportSeriesCSV(echartsData.value.options.series, echartsData.value.exportFileName)
echartsData.value.options.series,
`${dialogTitle.value || '历史趋势'}.csv`
)
} }
}, },
myTool2: { myTool2: {

View File

@@ -1,8 +1,8 @@
<template> <template>
<div> <div>
<!--主要监测点列表 --> <!--主要监测点列表 -->
<TableHeader :showReset="false" :timeKeyList="prop.timeKey" @selectChange="selectChange" v-if="fullscreen" <TableHeader :showReset="false" showExport :timeKeyList="prop.timeKey" @selectChange="selectChange"
ref="TableHeaderRef"> v-if="fullscreen" ref="TableHeaderRef">
<template v-slot:select> <template v-slot:select>
<el-form-item label="关键字筛选"> <el-form-item label="关键字筛选">
<el-input maxlength="32" show-word-limit v-model="tableStore.table.params.keywords" clearable <el-input maxlength="32" show-word-limit v-model="tableStore.table.params.keywords" clearable
@@ -17,7 +17,7 @@
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, provide, reactive, watch, nextTick } from 'vue' import { ref, onMounted, provide, watch, computed } from 'vue'
import TableStore from '@/utils/tableStore' import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue' import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue' import TableHeader from '@/components/table/header/index.vue'

View File

@@ -75,8 +75,6 @@ import { getTime } from '@/utils/formatTime'
import { exportSeriesCSV } from '@/utils/echartMethod' import { exportSeriesCSV } from '@/utils/echartMethod'
import PointTree from '@/components/tree/govern/pointTree.vue' import PointTree from '@/components/tree/govern/pointTree.vue'
const CSV_DOWNLOAD_ICON =
'path://M896 346.8c-0.1 0 0 0 0 0 0-0.9-0.1-1.7-0.2-2.5 0-0.1 0-0.3-0.1-0.4-0.2-1.7-0.5-3.3-1-4.9-0.5-1.7-1-3.3-1.7-4.9v-0.1c-0.3-0.8-0.7-1.5-1.1-2.3v-0.1c-0.4-0.7-0.8-1.5-1.2-2.2-0.1-0.1-0.1-0.2-0.2-0.3-0.4-0.6-0.8-1.2-1.3-1.9-0.1-0.1-0.1-0.2-0.2-0.2-0.5-0.6-1-1.3-1.5-1.9-0.1-0.1-0.2-0.3-0.4-0.4-0.5-0.6-1-1.2-1.6-1.7l-0.1-0.1L637.3 74.5c-0.6-0.6-1.2-1.1-1.8-1.6-0.1-0.1-0.3-0.2-0.4-0.4-0.6-0.5-1.2-1-1.9-1.5-0.1 0-0.1-0.1-0.2-0.1-0.6-0.5-1.3-0.9-1.9-1.3-0.1-0.1-0.2-0.1-0.3-0.2-0.7-0.4-1.4-0.9-2.2-1.3-0.8-0.4-1.5-0.8-2.3-1.1h-0.1c-1.6-0.7-3.2-1.3-4.9-1.7-1.6-0.4-3.2-0.8-4.9-1-0.1 0-0.3 0-0.4-0.1-1.4-0.2-2.8-0.3-4.3-0.3H164c-19.9 0-36 16.1-36 36v823.3c0 19.9 16.1 36 36 36h696c19.9 0 36-16.1 36-36V348.6v-1.8zM647.8 186.9l125.4 125.6H647.8V186.9zM200 887.2V135.9h375.8v212.7c0 19.9 16.1 36 36 36H824v502.7H200zM363.5 661.5c-7.2 6.3-15.8 9.5-25.8 9.5-13.5 0-24.5-5-33-15S292 629.3 292 605.7c0-22.2 4.3-38.2 12.9-48.1 8.6-9.9 19.8-14.9 33.6-14.9 10 0 18.5 2.8 25.5 8.4s11.6 13.2 13.8 22.9l37.2-8.9c-4.2-14.9-10.6-26.3-19-34.3-14.2-13.5-32.7-20.2-55.5-20.2-26.1 0-47.1 8.6-63.1 25.7s-24 41.2-24 72.2c0 29.3 8 52.4 23.9 69.3 15.9 16.9 36.2 25.3 60.9 25.3 20 0 36.5-4.9 49.4-14.8 13-9.9 22.3-24.9 27.9-45.3L379 631.6c-3.1 13.6-8.3 23.6-15.5 29.9zM561.5 597.2c-8.8-4.6-22.3-9.1-40.6-13.4s-29.8-8.5-34.5-12.4c-3.7-3.1-5.6-6.9-5.6-11.3 0-4.8 2-8.7 6-11.6 6.2-4.5 14.7-6.7 25.6-6.7 10.6 0 18.5 2.1 23.8 6.3 5.3 4.2 8.7 11.1 10.3 20.6l37.6-1.7c-0.6-17.1-6.8-30.8-18.6-41s-29.4-15.4-52.7-15.4c-14.3 0-26.5 2.2-36.6 6.5-10.1 4.3-17.9 10.6-23.2 18.9-5.4 8.3-8.1 17.1-8.1 26.6 0 14.7 5.7 27.2 17.1 37.5 8.1 7.3 22.3 13.4 42.4 18.4 15.7 3.9 25.7 6.6 30.1 8.1 6.4 2.3 10.9 5 13.5 8.1 2.6 3.1 3.9 6.8 3.9 11.2 0 6.9-3.1 12.8-9.2 18-6.1 5.1-15.3 7.7-27.4 7.7-11.4 0-20.5-2.9-27.2-8.6-6.7-5.8-11.2-14.8-13.4-27l-36.6 3.6c2.5 20.8 10 36.7 22.6 47.5 12.6 10.9 30.7 16.3 54.2 16.3 16.2 0 29.7-2.3 40.5-6.8s19.2-11.4 25.1-20.8c5.9-9.3 8.9-19.3 8.9-30 0-11.8-2.5-21.6-7.4-29.6s-11.7-14.3-20.5-19zM689.9 651.6l-47.1-137.7h-40.7L668.6 700h40.1l66.7-186.1h-39.9z'
const prop = defineProps({ const prop = defineProps({
w: { type: [String, Number] }, w: { type: [String, Number] },
@@ -138,11 +136,14 @@ const indicatorList = ref()
// initCode() // initCode()
// }) // })
// } // }
const exportSubjectName = ref('')
const nodeClick = (e: any) => { const nodeClick = (e: any) => {
if (e == undefined) { if (e == undefined) {
} }
if (e.level == 3) { if (e.level == 3) {
exportSubjectName.value = e.name || ''
tableStore.table.params.lineId = e.id tableStore.table.params.lineId = e.id
tableStore.exportName = { subject: exportSubjectName.value, feature: '主要监测点列表' }
initCode() initCode()
} }
} }
@@ -182,6 +183,12 @@ const getSeriesForCsvExport = () => {
})) }))
} }
const getChartExportFileName = () => ({
subject: exportSubjectName.value,
feature: '负荷曲线拟合图',
date: tableStore.table.params.searchEndTime || tableStore.table.params.searchBeginTime
})
const setEchart = () => { const setEchart = () => {
// 获取当前选择的功率和指标名称 // 获取当前选择的功率和指标名称
const powerName = powerList.value?.find((item: any) => item.id === tableStore.table.params.power)?.name || '功率' const powerName = powerList.value?.find((item: any) => item.id === tableStore.table.params.power)?.name || '功率'
@@ -191,6 +198,7 @@ const setEchart = () => {
const chartTitle = `${indicatorName}${powerName}负荷曲线拟合图` const chartTitle = `${indicatorName}${powerName}负荷曲线拟合图`
echartList.value = { echartList.value = {
exportFileName: getChartExportFileName(),
title: { title: {
text: chartTitle text: chartTitle
}, },
@@ -199,12 +207,9 @@ const setEchart = () => {
myTool1: { myTool1: {
show: true, show: true,
title: '下载csv', title: '下载csv',
icon: CSV_DOWNLOAD_ICON, icon: 'path://M642 673.1H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9s-8 17.9-17.9 17.9zM642 511.8H301.6c-9.9 0-17.9-8-17.9-17.9 0-9.9 8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9 0 9.9-8 17.9-17.9 17.9zM480.7 350.6H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9h179.2c9.9 0 17.9 8 17.9 17.9s-8.1 17.9-18 17.9zM874.9 350.6H695.7c-49.4 0-89.6-40.2-89.6-89.6V81.9c0-9.9 8-17.9 17.9-17.9 9.9 0 17.9 8 17.9 17.9V261c0 29.6 24.1 53.7 53.7 53.7h179.2c9.9 0 17.9 8 17.9 17.9s-7.9 18-17.8 18zM794.3 959.7H221c-49.4 0-89.6-40.2-89.6-89.6V153.5c0-49.4 40.2-89.6 89.6-89.6h403.1c4.8 0 9.3 1.9 12.7 5.2L887.6 320c3.4 3.4 5.2 7.9 5.2 12.7v537.5c0 52.7-51.9 89.5-98.5 89.5zM221 99.8c-29.6 0-53.7 24.1-53.7 53.7v716.6c0 29.6 24.1 53.7 53.7 53.7h573.3c29 0 62.7-23.5 62.7-53.7v-530L616.7 99.8H221z',
onclick: () => { onclick: () => {
exportSeriesCSV( exportSeriesCSV(getSeriesForCsvExport(), echartList.value.exportFileName)
getSeriesForCsvExport(),
`${echartList.value.title?.text || '负荷曲线拟合图'}.csv`
)
} }
} }
} }

View File

@@ -2,7 +2,7 @@
<div> <div>
<!-- 监测点列表 --> <!-- 监测点列表 -->
<TableHeader ref="TableHeaderRef" :showReset="false" @selectChange="selectChange" v-if="fullscreen" <TableHeader ref="TableHeaderRef" :showReset="false" showExport @selectChange="selectChange" v-if="fullscreen"
:timeKeyList="prop.timeKey"> :timeKeyList="prop.timeKey">
<template #select> <template #select>
<el-form-item label="关键字筛选"> <el-form-item label="关键字筛选">
@@ -37,7 +37,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, provide, reactive, watch, h } from 'vue' import { ref, onMounted, provide, watch, computed } from 'vue'
import TableStore from '@/utils/tableStore' import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue' import Table from '@/components/table/index.vue'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
@@ -159,7 +159,7 @@ const tableStore: any = new TableStore({
{ {
title: '电压等级(kV)', title: '电压等级(kV)',
field: 'volGrade', field: 'volGrade',
minWidth: '80', minWidth: '100',
formatter: (row: any) => { formatter: (row: any) => {
return row.cellValue == 0 ? '/' : row.cellValue || '/' return row.cellValue == 0 ? '/' : row.cellValue || '/'
} }

View File

@@ -377,6 +377,11 @@ const setEchart = () => {
} }
echartsData.value = { echartsData.value = {
exportFileName: {
subject: trendRequestData.value?.lineName,
feature: '趋势图',
date: datePickerRef.value?.timeValue?.[1] || datePickerRef.value?.timeValue?.[0]
},
legend: { legend: {
itemWidth: 20, itemWidth: 20,
itemHeight: 20, itemHeight: 20,
@@ -446,10 +451,7 @@ const setEchart = () => {
title: '下载csv', title: '下载csv',
icon: 'path://M642 673.1H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9s-8 17.9-17.9 17.9zM642 511.8H301.6c-9.9 0-17.9-8-17.9-17.9 0-9.9 8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9 0 9.9-8 17.9-17.9 17.9zM480.7 350.6H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9h179.2c9.9 0 17.9 8 17.9 17.9s-8.1 17.9-18 17.9zM874.9 350.6H695.7c-49.4 0-89.6-40.2-89.6-89.6V81.9c0-9.9 8-17.9 17.9-17.9 9.9 0 17.9 8 17.9 17.9V261c0 29.6 24.1 53.7 53.7 53.7h179.2c9.9 0 17.9 8 17.9 17.9s-7.9 18-17.8 18zM794.3 959.7H221c-49.4 0-89.6-40.2-89.6-89.6V153.5c0-49.4 40.2-89.6 89.6-89.6h403.1c4.8 0 9.3 1.9 12.7 5.2L887.6 320c3.4 3.4 5.2 7.9 5.2 12.7v537.5c0 52.7-51.9 89.5-98.5 89.5zM221 99.8c-29.6 0-53.7 24.1-53.7 53.7v716.6c0 29.6 24.1 53.7 53.7 53.7h573.3c29 0 62.7-23.5 62.7-53.7v-530L616.7 99.8H221z', icon: 'path://M642 673.1H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9s-8 17.9-17.9 17.9zM642 511.8H301.6c-9.9 0-17.9-8-17.9-17.9 0-9.9 8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9 0 9.9-8 17.9-17.9 17.9zM480.7 350.6H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9h179.2c9.9 0 17.9 8 17.9 17.9s-8.1 17.9-18 17.9zM874.9 350.6H695.7c-49.4 0-89.6-40.2-89.6-89.6V81.9c0-9.9 8-17.9 17.9-17.9 9.9 0 17.9 8 17.9 17.9V261c0 29.6 24.1 53.7 53.7 53.7h179.2c9.9 0 17.9 8 17.9 17.9s-7.9 18-17.8 18zM794.3 959.7H221c-49.4 0-89.6-40.2-89.6-89.6V153.5c0-49.4 40.2-89.6 89.6-89.6h403.1c4.8 0 9.3 1.9 12.7 5.2L887.6 320c3.4 3.4 5.2 7.9 5.2 12.7v537.5c0 52.7-51.9 89.5-98.5 89.5zM221 99.8c-29.6 0-53.7 24.1-53.7 53.7v716.6c0 29.6 24.1 53.7 53.7 53.7h573.3c29 0 62.7-23.5 62.7-53.7v-530L616.7 99.8H221z',
onclick: () => { onclick: () => {
exportSeriesCSV( exportSeriesCSV(echartsData.value.options.series, echartsData.value.exportFileName)
echartsData.value.options.series,
`${titles.value || '监测点指标趋势'}.csv`
)
} }
}, },
myTool2: { myTool2: {

View File

@@ -6,7 +6,7 @@
<template #select> <template #select>
<el-form-item label="关键字筛选"> <el-form-item label="关键字筛选">
<el-input maxlength="32" show-word-limit style="width: 240px" <el-input maxlength="32" show-word-limit style="width: 240px"
v-model.trim="tableStore.table.params.searchValue" clearable placeholder="请输入敏感用户名称" /> v-model.trim="tableStore.table.params.searchValue" clearable placeholder="请输入用户名称" />
</el-form-item> </el-form-item>
</template> </template>
</TableHeader> </TableHeader>
@@ -77,7 +77,7 @@ const tableStore: any = new TableStore({
} }
}, },
{ {
title: '敏感用户名称', title: '用户名称',
field: 'name', field: 'name',
minWidth: '90' minWidth: '90'
}, },

View File

@@ -32,6 +32,7 @@ import MultiCondition from '@/views/govern/alarm/multiCondition.vue'
import waveFormAnalysis from '@/views/govern/device/control/tabs/components/waveFormAnalysis.vue' import waveFormAnalysis from '@/views/govern/device/control/tabs/components/waveFormAnalysis.vue'
import { analyseWave } from '@/api/common' import { analyseWave } from '@/api/common'
import { getFileZip } from '@/api/cs-harmonic-boot/datatrend' import { getFileZip } from '@/api/cs-harmonic-boot/datatrend'
import { buildWaveExportFileName, getExportSubjectFromRow } from '@/utils/echartMethod'
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
const dialogVisible = ref(false) const dialogVisible = ref(false)
@@ -85,14 +86,14 @@ const tableStore: any = new TableStore({
field: 'advanceReason', field: 'advanceReason',
minWidth: 100, minWidth: 100,
align: 'center', align: 'center',
formatter: (row: any) => ReasonList.find((item: any) => item.id == row.cellValue)?.name || '未知' formatter: (row: any) => ReasonList.find((item: any) => item.id == row.cellValue)?.name || '其他'
}, },
{ {
title: '暂降类型', title: '暂降类型',
field: 'advanceType', field: 'advanceType',
minWidth: 100, minWidth: 100,
align: 'center', align: 'center',
formatter: (row: any) => EventTypeList.find((item: any) => item.id == row.cellValue)?.name || '未知' formatter: (row: any) => EventTypeList.find((item: any) => item.id == row.cellValue)?.name || '其他'
}, },
{ title: '监测点名称', field: 'lineName', minWidth: 130, align: 'center' }, { title: '监测点名称', field: 'lineName', minWidth: 130, align: 'center' },
{ title: '电压等级(kV)', field: 'lineVoltage', minWidth: 120, align: 'center', sortable: true }, { title: '电压等级(kV)', field: 'lineVoltage', minWidth: 120, align: 'center', sortable: true },
@@ -183,7 +184,7 @@ const tableStore: any = new TableStore({
const url = window.URL.createObjectURL(blob) const url = window.URL.createObjectURL(blob)
const link = document.createElement('a') const link = document.createElement('a')
link.href = url link.href = url
link.download = row.wavePath.split('/')[2] || '波形文件' link.download = buildWaveExportFileName(getExportSubjectFromRow(row))
document.body.appendChild(link) document.body.appendChild(link)
link.click() link.click()
document.body.removeChild(link) document.body.removeChild(link)

View File

@@ -32,9 +32,9 @@
<template #content> <template #content>
<!-- <span v-html="list?.filter(item => item.time == data.day)[0]?.type || ''"></span> --> <!-- <span v-html="list?.filter(item => item.time == data.day)[0]?.type || ''"></span> -->
<div v-for="item in list?.filter((item:any) => item.name == data.day)"> <div v-for="item in list?.filter((item:any) => item.name == data.day)">
<div>电压暂降{{ item.eventDown || 0 }}</div> <div>暂降: {{ item.eventDown || 0 }}</div>
<div>电压中断{{ item.eventOff || 0 }}</div> <div>中断: {{ item.eventOff || 0 }}</div>
<div>电压暂升{{ item.eventUp || 0 }}</div> <div>暂升: {{ item.eventUp || 0 }}</div>
</div> </div>
</template> </template>
<div <div
@@ -43,13 +43,13 @@
v-for="item in list?.filter((item:any) => item.name == data.day)" v-for="item in list?.filter((item:any) => item.name == data.day)"
@click="descentClick(item)" @click="descentClick(item)"
> >
<!-- <div>电压暂降:{{ item.eventDown || 0 }}</div> <!-- <div>暂降:{{ item.eventDown || 0 }}</div>
<div>电压中断:{{ item.eventOff || 0 }}</div> <div>中断:{{ item.eventOff || 0 }}</div>
<div>电压暂升:{{ item.eventUp || 0 }}</div> --> <div>暂升:{{ item.eventUp || 0 }}</div> -->
<template v-if="fullscreen"> <template v-if="fullscreen">
<div>电压暂降:{{ item.eventDown || 0 }}</div> <div>暂降: {{ item.eventDown || 0 }}</div>
<div>电压中断:{{ item.eventOff || 0 }}</div> <div>中断: {{ item.eventOff || 0 }}</div>
<div>电压暂升:{{ item.eventUp || 0 }}</div> <div>暂升: {{ item.eventUp || 0 }}</div>
</template> </template>
<template v-else>暂态事件</template> <template v-else>暂态事件</template>
</div> </div>

View File

@@ -37,6 +37,7 @@ import MultiCondition from '@/views/govern/alarm/multiCondition.vue'
import waveFormAnalysis from '@/views/govern/device/control/tabs/components/waveFormAnalysis.vue' import waveFormAnalysis from '@/views/govern/device/control/tabs/components/waveFormAnalysis.vue'
import { analyseWave } from '@/api/common' import { analyseWave } from '@/api/common'
import { getFileZip } from '@/api/cs-harmonic-boot/datatrend' import { getFileZip } from '@/api/cs-harmonic-boot/datatrend'
import { buildWaveExportFileName, getExportSubjectFromRow } from '@/utils/echartMethod'
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
const dialogVisible = ref(false) const dialogVisible = ref(false)
@@ -115,14 +116,14 @@ const tableStore: any = new TableStore({
field: 'advanceReason', field: 'advanceReason',
minWidth: 100, minWidth: 100,
align: 'center', align: 'center',
formatter: (row: any) => ReasonList.find((item: any) => item.id == row.cellValue)?.name || '未知' formatter: (row: any) => ReasonList.find((item: any) => item.id == row.cellValue)?.name || '其他'
}, },
{ {
title: '暂降类型', title: '暂降类型',
field: 'advanceType', field: 'advanceType',
minWidth: 100, minWidth: 100,
align: 'center', align: 'center',
formatter: (row: any) => EventTypeList.find((item: any) => item.id == row.cellValue)?.name || '未知' formatter: (row: any) => EventTypeList.find((item: any) => item.id == row.cellValue)?.name || '其他'
}, },
{ title: '电压等级(kV)', field: 'lineVoltage', minWidth: 120, align: 'center', sortable: true }, { title: '电压等级(kV)', field: 'lineVoltage', minWidth: 120, align: 'center', sortable: true },
{ {
@@ -206,7 +207,7 @@ const tableStore: any = new TableStore({
const url = window.URL.createObjectURL(blob) const url = window.URL.createObjectURL(blob)
const link = document.createElement('a') const link = document.createElement('a')
link.href = url link.href = url
link.download = row.wavePath.split('/')[2] || '波形文件' link.download = buildWaveExportFileName(getExportSubjectFromRow(row))
document.body.appendChild(link) document.body.appendChild(link)
link.click() link.click()
document.body.removeChild(link) document.body.removeChild(link)

File diff suppressed because it is too large Load Diff

View File

@@ -13,6 +13,7 @@ import 'echarts-liquidfill'
import 'echarts/lib/component/dataZoom' import 'echarts/lib/component/dataZoom'
import { color, gradeColor3 } from './color' import { color, gradeColor3 } from './color'
import { useConfig } from '@/stores/config' import { useConfig } from '@/stores/config'
import { buildExportBaseName, formatExportDateTime } from '@/utils/echartMethod'
// import { nextTick } from 'process' // import { nextTick } from 'process'
const emit = defineEmits(['chartClick']) const emit = defineEmits(['chartClick'])
@@ -71,7 +72,9 @@ const initChart = () => {
feature: { feature: {
saveAsImage: { saveAsImage: {
title: '下载图片', title: '下载图片',
name: props.options?.title?.text || '图表' name: props.options?.exportFileName
? buildExportBaseName(props.options.exportFileName)
: ((props.options?.title?.text || '图表') + '_' + formatExportDateTime())
}, },
...(props.options?.toolbox?.featureProps || null) ...(props.options?.toolbox?.featureProps || null)
}, },
@@ -93,7 +96,7 @@ const initChart = () => {
...(props.options?.legend || null) ...(props.options?.legend || null)
}, },
grid: { grid: {
top: props.options?.title?.text ? '50px' : '25px', top: props.options?.title?.text ? '50px' : '25px',
left: '30px', left: '30px',
right: '70px', right: '70px',
bottom: props.options?.options?.dataZoom === null ? '10px' : '40px', bottom: props.options?.options?.dataZoom === null ? '10px' : '40px',

View File

@@ -1,4 +1,18 @@
export let color = [ '#07CCCA','#00BFF5', '#FFBF00', '#77DA63', '#Ff6600', '#FF9100', '#5B6E96', '#66FFCC', '#B3B3B3'] export let color = ['#07CCCA', '#00BFF5', '#FFBF00', '#77DA63', '#Ff6600', '#FF9100', '#5B6E96', '#66FFEC', '#B3B3B3', '#9B59B6', '#3498DB', '#2ECC71']
export const gradeColor3 = ['#339966', '#FFCC33', '#A52a2a'] export let color1 = [
export const gradeColor5 = ['#00CC00', '#99CC99', '#FF9900','#996600','#A52a2a'] '#00A8B5', // 青
'#3B7DD8', // 蓝
'#5B5FC7', // 靛
'#8B5CF6', // 紫
'#B07CC6', // 淡紫
'#C060A8', // 玫红
'#D4A017', // 金
'#6AAF50', // 草绿
'#00A878', // 翠绿
'#7C9EB2', // 烟蓝
'#6B7B8C', // 板岩灰
'#A8A8A8' // 灰
]
export const gradeColor3 = ['#339966', '#FFCC33', '#A52a2a']
export const gradeColor5 = ['#00CC00', '#99CC99', '#FF9900','#996600','#A52a2a']

View File

@@ -19,7 +19,7 @@ import url from '@/assets/img/point.png'
import url2 from '@/assets/img/dw.png' import url2 from '@/assets/img/dw.png'
import { buildWaveCacheKey, getWaveCache, setWaveCache } from '@/utils/waveCache' import { buildWaveCacheKey, getWaveCache, setWaveCache } from '@/utils/waveCache'
import { getRmsWorker, buildWorkerPayload } from '@/utils/waveWorkerPool' import { getRmsWorker, buildWorkerPayload } from '@/utils/waveWorkerPool'
import { buildExportBaseName, formatExportDateTime } from '@/utils/echartMethod'
let waveRequestId = 0 let waveRequestId = 0
const pendingCacheKeys = new Map<number, string>() const pendingCacheKeys = new Map<number, string>()
let rmsWorker: Worker | null = null let rmsWorker: Worker | null = null
@@ -202,7 +202,7 @@ const download = () => {
scale: 2 scale: 2
}).then(function (canvas) { }).then(function (canvas) {
const creatIMg = document.createElement('a') const creatIMg = document.createElement('a')
creatIMg.download = 'rms波形.png' creatIMg.download = (props.boxoList.lineName || props.boxoList.measurementPointName || props.boxoList.equipmentName) + '_RMS波形_' + formatExportDateTime() + '.png'
creatIMg.href = canvas.toDataURL() creatIMg.href = canvas.toDataURL()
creatIMg.click() creatIMg.click()
creatIMg.remove() creatIMg.remove()
@@ -810,7 +810,7 @@ const initWave = (
start: 0, start: 0,
bottom: '20px', bottom: '20px',
end: 100, end: 100,
filterMode: 'filter' filterMode: 'filter'
}, },
{ {
start: 0, start: 0,

View File

@@ -18,6 +18,7 @@ import { calcShuYAxisRange, formatAxisLabel } from '@/utils/chartAxisHelper'
import url from '@/assets/img/point.png' import url from '@/assets/img/point.png'
import { buildWaveCacheKey, getWaveCache, setWaveCache } from '@/utils/waveCache' import { buildWaveCacheKey, getWaveCache, setWaveCache } from '@/utils/waveCache'
import { getShuWorker, buildWorkerPayload } from '@/utils/waveWorkerPool' import { getShuWorker, buildWorkerPayload } from '@/utils/waveWorkerPool'
import { buildExportBaseName, formatExportDateTime } from '@/utils/echartMethod'
let waveRequestId = 0 let waveRequestId = 0
const pendingCacheKeys = new Map<number, string>() const pendingCacheKeys = new Map<number, string>()
@@ -207,7 +208,7 @@ const download = () => {
scale: 2 scale: 2
}).then(function (canvas) { }).then(function (canvas) {
const creatIMg = document.createElement('a') const creatIMg = document.createElement('a')
creatIMg.download = '瞬间波形.png' creatIMg.download = (props.boxoList.lineName || props.boxoList.measurementPointName || props.boxoList.equipmentName) + '_瞬间波形_' + formatExportDateTime() + '.png'
creatIMg.href = canvas.toDataURL() creatIMg.href = canvas.toDataURL()
creatIMg.click() creatIMg.click()
creatIMg.remove() creatIMg.remove()
@@ -566,7 +567,7 @@ const initWave = (
start: 0, start: 0,
bottom: '20px', bottom: '20px',
end: 100, end: 100,
filterMode: 'filter' filterMode: 'filter'
}, },
{ {
start: 0, start: 0,

View File

@@ -74,6 +74,7 @@ import { useConfig } from '@/stores/config'
import type TableStoreClass from '@/utils/tableStore' import type TableStoreClass from '@/utils/tableStore'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { defaultAttribute } from '@/components/table/defaultAttribute' import { defaultAttribute } from '@/components/table/defaultAttribute'
import { buildExportBaseName } from '@/utils/echartMethod'
const config = useConfig() const config = useConfig()
const tableRef = ref<VxeTableInstance>() const tableRef = ref<VxeTableInstance>()
@@ -150,6 +151,16 @@ const selectChangeEvent: VxeTableEvents.CheckboxChange<any> = ({ checked }) => {
const getRef = () => { const getRef = () => {
return tableRef.value return tableRef.value
} }
const getTableExportFilename = () => {
const exportName = tableStore.exportName
if (exportName && typeof exportName === 'object') {
return buildExportBaseName(exportName)
}
const feature =
exportName || (document.querySelectorAll('.ba-nav-tab.active')[0] as HTMLElement | undefined)?.textContent || '导出'
return buildExportBaseName({ feature })
}
watch( watch(
() => tableStore.table.allFlag, () => tableStore.table.allFlag,
newVal => { newVal => {
@@ -157,7 +168,7 @@ watch(
console.log('🚀 ~ tableStore.table.allData:', tableStore.table.allData) console.log('🚀 ~ tableStore.table.allData:', tableStore.table.allData)
tableRef.value?.exportData({ tableRef.value?.exportData({
filename: tableStore.exportName || document.querySelectorAll('.ba-nav-tab.active')[0].textContent || '', // 文件名字 filename: getTableExportFilename(), // 文件名字
sheetName: 'Sheet1', sheetName: 'Sheet1',
type: 'xlsx', //导出文件类型 xlsx 和 csv type: 'xlsx', //导出文件类型 xlsx 和 csv
useStyle: true, useStyle: true,

View File

@@ -1,6 +1,7 @@
<template> <template>
<Tree <Tree
ref="treRef" ref="treRef"
:width="width" :width="width"
:showPush="props.showPush" :showPush="props.showPush"
:expand-on-click-node="false" :expand-on-click-node="false"

View File

@@ -79,7 +79,7 @@ async function selectInitialNode(type: string | undefined, leaves: LineTreeLeave
} }
const loadTree = (type?: string) => { const loadTree = (type?: string) => {
console.log("🚀 ~ loadTree ~ type:", type) // console.log("🚀 ~ loadTree ~ type:", type)
tree.value = [] tree.value = []
getLineTree({ type: type === '2' ? 'engineering' : '' }).then(res => { getLineTree({ type: type === '2' ? 'engineering' : '' }).then(res => {
const leaves = decorateLineTree(res.data, type, decorators, { disableParents: false }) const leaves = decorateLineTree(res.data, type, decorators, { disableParents: false })

View File

@@ -93,7 +93,7 @@ interface Props {
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
width: '280px', width: '270px',
canExpand: true, canExpand: true,
showPush: false, showPush: false,
baseOffset: 190, baseOffset: 190,
@@ -138,10 +138,12 @@ defineExpose({ treeRef })
<style lang="scss" scoped> <style lang="scss" scoped>
.cn-tree-root { .cn-tree-root {
// width: 280px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow: hidden; overflow: hidden;
height: 100%; height: 100%;
width: 270px;
transition: width 0.3s; transition: width 0.3s;
box-sizing: border-box; box-sizing: border-box;

View File

@@ -135,6 +135,56 @@ export const yMethod = (arr: any) => {
return [min, max] return [min, max]
} }
export interface ExportFileNameOptions {
subject?: string
feature: string
date?: string | Date | string[] | null
ext?: string
}
/** 导出文件名中的日期,固定为当前年月日 yyyy-mm-dd */
export const formatExportDate = (): string => {
const pad = (n: number) => String(n).padStart(2, '0')
const now = new Date()
return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`
}
/** 波形下载文件名中的时间,固定为当前时间 yyyy-mm-dd-HH-mm-ss */
export const formatExportDateTime = (): string => {
const pad = (n: number) => String(n).padStart(2, '0')
const now = new Date()
return `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`
}
/** 监测点 / 设备 / 项目可选_ 功能 _ yyyy-mm-dd当前日期 */
export const buildExportBaseName = (options: Pick<ExportFileNameOptions, 'subject' | 'feature' | 'date'>): string => {
const { subject, feature } = options
const dateStr = formatExportDate()
return [subject?.trim(), feature?.trim(), dateStr].filter(part => part).join('_')
}
/** 波形 zip 下载监测点_波形_yyyy-mm-dd-HH-mm-ss.zip当前时间 */
export const buildWaveExportFileName = (subject?: string): string => {
const base = [subject?.trim(), '波形', formatExportDateTime()].filter(part => part).join('_')
return `${base}.zip`
}
export const buildExportFileName = (options: ExportFileNameOptions): string => {
const ext = (options.ext || 'csv').replace(/^\./, '')
return `${buildExportBaseName(options)}.${ext}`
}
export const resolveExportFileName = (filenameOrOptions: string | ExportFileNameOptions): string => {
if (typeof filenameOrOptions === 'string') {
return filenameOrOptions
}
return buildExportFileName(filenameOrOptions)
}
/** 从行数据中取监测点 / 设备 / 项目名称 */
export const getExportSubjectFromRow = (row: any): string =>
row?.lineName || row?.equipmentName || row?.projectName || row?.engineeringName || row?.name || ''
/** /**
* title['A相','B相',] * title['A相','B相',]
* data[[1,2],[3,4]] * data[[1,2],[3,4]]
@@ -150,7 +200,8 @@ const convertToCSV = (title: object, data: any) => {
}) })
return csv return csv
} }
export const exportCSV = (title: object, data: any, filename: string) => { export const exportCSV = (title: object, data: any, filenameOrOptions: string | ExportFileNameOptions) => {
const filename = resolveExportFileName(filenameOrOptions)
const csv = convertToCSV(title, data) const csv = convertToCSV(title, data)
const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' }) const blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' })
const link = document.createElement('a') const link = document.createElement('a')
@@ -190,10 +241,13 @@ export const buildSeriesCsvData = (seriesList: Array<{ name: string; data?: any[
return { titles, rows } return { titles, rows }
} }
export const exportSeriesCSV = (seriesList: Array<{ name: string; data?: any[] }>, filename: string) => { export const exportSeriesCSV = (
seriesList: Array<{ name: string; data?: any[] }>,
filenameOrOptions: string | ExportFileNameOptions
) => {
const { titles, rows } = buildSeriesCsvData(seriesList) const { titles, rows } = buildSeriesCsvData(seriesList)
if (!rows.length) return if (!rows.length) return
exportCSV(titles, rows, filename) exportCSV(titles, rows, filenameOrOptions)
} }
/** /**

View File

@@ -1,3 +1,4 @@
import { buildExportBaseName, type ExportFileNameOptions } from '@/utils/echartMethod'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { nextTick } from 'vue' import { nextTick } from 'vue'
import { exportExcel } from '@/views/system/reportForms/export.js' import { exportExcel } from '@/views/system/reportForms/export.js'
@@ -12,6 +13,10 @@ export function parseLuckysheetSheets(sheets: any[]) {
/* ignore invalid json */ /* ignore invalid json */
} }
} }
if (!item.config) item.config = {}
if (item.row == null) item.row = 36
if (item.column == null) item.column = 18
if (!item.data) item.data = []
item.celldata?.forEach((cell: any) => { item.celldata?.forEach((cell: any) => {
if (item.data?.[cell.r]?.[cell.c]?.v != null) { if (item.data?.[cell.r]?.[cell.c]?.v != null) {
item.data[cell.r][cell.c] = cell.v item.data[cell.r][cell.c] = cell.v
@@ -47,10 +52,15 @@ export function renderLuckysheetReport(
sheets: any[], sheets: any[],
options: Record<string, any> = {} options: Record<string, any> = {}
) { ) {
if (!Array.isArray(sheets) || sheets.length === 0) {
destroyLuckysheet()
return
}
parseLuckysheetSheets(sheets) parseLuckysheetSheets(sheets)
destroyLuckysheet() destroyLuckysheet()
nextTick(() => { nextTick(() => {
requestAnimationFrame(() => { requestAnimationFrame(() => {
if (!document.getElementById(container)) return
luckysheet.create({ luckysheet.create({
container, container,
...DEFAULT_REPORT_OPTIONS, ...DEFAULT_REPORT_OPTIONS,
@@ -62,7 +72,7 @@ export function renderLuckysheetReport(
} }
/** 安全导出 Luckysheet无数据时提示并返回 false */ /** 安全导出 Luckysheet无数据时提示并返回 false */
export function exportLuckysheetFile(filename: string, hasData = true): boolean { export function exportLuckysheetFile(filenameOrOptions: string | ExportFileNameOptions, hasData = true): boolean {
if (!hasData) { if (!hasData) {
ElMessage.warning('暂无数据') ElMessage.warning('暂无数据')
return false return false
@@ -77,6 +87,8 @@ export function exportLuckysheetFile(filename: string, hasData = true): boolean
ElMessage.warning('暂无数据') ElMessage.warning('暂无数据')
return false return false
} }
const filename =
typeof filenameOrOptions === 'string' ? filenameOrOptions : buildExportBaseName(filenameOrOptions)
exportExcel(sheets, filename) exportExcel(sheets, filename)
ElMessage.success('生成成功') ElMessage.success('生成成功')
return true return true

View File

@@ -14,17 +14,13 @@
></el-cascader> ></el-cascader>
</el-form-item> --> </el-form-item> -->
<el-form-item label="关键字筛选"> <el-form-item label="关键字筛选">
<el-input maxlength="32" show-word-limit style="width: 240px" <el-input maxlength="32" show-word-limit style="width: 240px"
v-model.trim="tableStore.table.params.searchValue" clearable placeholder="请输入监测点名称" /> v-model.trim="tableStore.table.params.searchValue" clearable placeholder="请输入设备名称" />
</el-form-item> </el-form-item>
<el-form-item label="级别"> <el-form-item label="级别">
<el-select v-model.trim="tableStore.table.params.level" placeholder="请选择级别" clearable> <el-select v-model.trim="tableStore.table.params.level" placeholder="请选择级别" clearable>
<el-option <el-option v-for="item in rankOptions" :key="item.value" :label="item.label"
v-for="item in rankOptions" :value="item.value"></el-option>
:key="item.value"
:label="item.label"
:value="item.value"
></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
</template> </template>
@@ -103,12 +99,17 @@ const tableStore = new TableStore({
} }
}, },
{ title: '发生时刻', field: 'startTime', align: 'center', minWidth: 180, sortable: true }, { title: '发生时刻', field: 'startTime', align: 'center', minWidth: 180, sortable: true },
{ title: '设备名称', field: 'equipmentName', align: 'center', minWidth: 120 }, {
{ title: '项目名称', field: 'projectName', align: 'center', minWidth: 120 }, title: '监测点名称', field: 'lineName', minWidth: 130, align: 'center', formatter: (row: any) => {
{ title: '工程名称', field: 'engineeringName', align: 'center', minWidth: 120 }, return row.cellValue ? row.cellValue : '/'
}
},
{ title: '设备名称', field: 'equipmentName', align: 'center', minWidth: 130 },
{ title: '项目名称', field: 'projectName', align: 'center', minWidth: 130 },
{ title: '工程名称', field: 'engineeringName', align: 'center', minWidth: 130 },
// { title: '监测点名称', field: 'lineName', align: 'center', minWidth: 120 }, // { title: '监测点名称', field: 'lineName', align: 'center', minWidth: 120 },
{ {
title: '事件描述', title: '事件描述',
minWidth: 300, minWidth: 300,
@@ -123,7 +124,7 @@ const tableStore = new TableStore({
return row.cellValue ? row.cellValue : '/' return row.cellValue ? row.cellValue : '/'
} }
}, },
{ {
title: '告警代码', title: '告警代码',
field: 'code', field: 'code',
@@ -168,23 +169,23 @@ const tableStore = new TableStore({
// } // }
// } // }
], ],
beforeSearchFun: () => {}, beforeSearchFun: () => { },
exportProcessingData: () => { exportProcessingData: () => {
tableStore.table.allData = tableStore.table.allData.filter(item => { tableStore.table.allData = tableStore.table.allData.filter(item => {
item.level = item.level =
item.level == 1 item.level == 1
? '1级' ? '1级'
: item.level == 2 : item.level == 2
? '2级' ? '2级'
: item.level == 3 : item.level == 3
? '3级' ? '3级'
: item.level == 4 : item.level == 4
? 'DEBUG' ? 'DEBUG'
: item.level == 5 : item.level == 5
? 'NORMAL' ? 'NORMAL'
: item.level == 6 : item.level == 6
? 'WARN' ? 'WARN'
: 'ERROR' : 'ERROR'
return item return item
}) })
} }
@@ -241,6 +242,6 @@ onMounted(() => {
setTimeout(() => { setTimeout(() => {
// tableStore.table.height = mainHeight(200).height as any // tableStore.table.height = mainHeight(200).height as any
}, 0) }, 0)
const addMenu = () => {} const addMenu = () => { }
</script> </script>
<style></style> <style></style>

View File

@@ -18,6 +18,7 @@
</template> </template>
<template v-slot:operation> <template v-slot:operation>
<el-button type="primary" icon="el-icon-Operation" @click="openFilterDialog">事件筛选</el-button> <el-button type="primary" icon="el-icon-Operation" @click="openFilterDialog">事件筛选</el-button>
<el-button type="primary" icon="el-icon-Histogram" @click="statistics">暂降原因分析</el-button>
</template> </template>
</TableHeader> </TableHeader>
@@ -43,10 +44,12 @@ import { analyseWave, getFileByEventId } from '@/api/common'
import { mainHeight } from '@/utils/layout' import { mainHeight } from '@/utils/layout'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { getFileZip } from '@/api/cs-harmonic-boot/datatrend' import { getFileZip } from '@/api/cs-harmonic-boot/datatrend'
import { buildWaveExportFileName, getExportSubjectFromRow } from '@/utils/echartMethod'
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
import { queryByCode, queryByid, queryCsDictTree } from '@/api/system-boot/dictTree' import { queryByCode, queryByid, queryCsDictTree } from '@/api/system-boot/dictTree'
import analysisList from '@/views/govern/device/control/analysisList/index.vue' import analysisList from '@/views/govern/device/control/analysisList/index.vue'
const props = defineProps(['deviceTree']) const props = defineProps(['deviceTree'])
const emit = defineEmits(['statistics'])
const refheader = ref() const refheader = ref()
const waveFormAnalysisRef = ref() const waveFormAnalysisRef = ref()
@@ -91,12 +94,12 @@ const tableStore = new TableStore({
{ title: '触发类型', field: 'showName', minWidth: 100, align: 'center' }, { title: '触发类型', field: 'showName', minWidth: 100, align: 'center' },
{ {
title: '暂降原因', field: 'advanceReason', minWidth: 100, align: 'center', formatter: (row: any) => { title: '暂降原因', field: 'advanceReason', minWidth: 100, align: 'center', formatter: (row: any) => {
return ReasonList.find((item: any) => item.id == row.cellValue)?.name || '未知' return ReasonList.find((item: any) => item.id == row.cellValue)?.name || '其他'
} }
}, },
{ {
title: '暂降类型', field: 'advanceType', minWidth: 100, align: 'center', formatter: (row: any) => { title: '暂降类型', field: 'advanceType', minWidth: 100, align: 'center', formatter: (row: any) => {
return EventTypeList.find((item: any) => item.id == row.cellValue)?.name || '未知' return EventTypeList.find((item: any) => item.id == row.cellValue)?.name || '其他'
} }
}, },
{ title: '监测点名称', field: 'lineName', minWidth: 130, align: 'center' }, { title: '监测点名称', field: 'lineName', minWidth: 130, align: 'center' },
@@ -158,7 +161,7 @@ const tableStore = new TableStore({
waveFormAnalysisRef.value.getWpData(wp.value, boxoList.value, true) waveFormAnalysisRef.value.getWpData(wp.value, boxoList.value, true)
// waveFormAnalysisRef.value && waveFormAnalysisRef.value.setHeight(200, 190) // waveFormAnalysisRef.value && waveFormAnalysisRef.value.setHeight(200, 190)
}) })
} }
}, },
{ {
@@ -179,7 +182,7 @@ const tableStore = new TableStore({
const url = window.URL.createObjectURL(blob) const url = window.URL.createObjectURL(blob)
const link = document.createElement('a') // 创建a标签 const link = document.createElement('a') // 创建a标签
link.href = url link.href = url
link.download = row.wavePath.split('/')[2] || '波形文件' // 设置下载的文件名 link.download = buildWaveExportFileName(getExportSubjectFromRow(row))
document.body.appendChild(link) document.body.appendChild(link)
link.click() //执行下载 link.click() //执行下载
document.body.removeChild(link) //释放标签 document.body.removeChild(link) //释放标签
@@ -224,7 +227,7 @@ const tableStore = new TableStore({
deviceId: row.deviceId deviceId: row.deviceId
}) })
} else if (code == 'DEV_CLD') { } else if (code == 'DEV_CLD') {
row.loading2 = true row.loading2 = true
// 监测设备 // 监测设备
getFileByEventId(row.id).then(res => { getFileByEventId(row.id).then(res => {
@@ -361,6 +364,10 @@ onMounted(() => {
}) })
tableStore.index() tableStore.index()
}) })
const statistics = () => {
emit('statistics')
}
const bxecharts = mainHeight(175).height as any const bxecharts = mainHeight(175).height as any
setTimeout(() => { setTimeout(() => {
tableStore.table.height = mainHeight(200).height as any tableStore.table.height = mainHeight(200).height as any

View File

@@ -0,0 +1,39 @@
<template>
<div>
<el-tabs type="border-card" v-model.trim="activeName" tab-position="left">
<el-tab-pane label="暂降分布统计" name="1">
<Distribution v-if="activeName == '1'" />
</el-tab-pane>
<el-tab-pane label="ITIC曲线" name="2">
<ITIC v-if="activeName == '2'" />
</el-tab-pane>
<el-tab-pane label="F47曲线" name="3">
<F47 v-if="activeName == '3'" />
</el-tab-pane>
</el-tabs>
</div>
</template>
<script setup lang="ts">
import { ref, provide } from 'vue'
import Distribution from './eventStatistics/distribution.vue'
import ITIC from './eventStatistics/ITIC.vue'
import F47 from './eventStatistics/F47.vue'
import { mainHeight } from '@/utils/layout'
const emit = defineEmits(['back'])
const activeName = ref('1')
const layout = mainHeight(80)
provide('eventStatisticsBack', () => emit('back'))
</script>
<style lang="scss" scoped>
:deep(.el-tabs--border-card>.el-tabs__content) {
padding: 10px 10px 10px 0;
}
:deep(.el-tabs--left.el-tabs--border-card .el-tabs__header.is-left) {
height: calc(100vh - 193px);
}
</style>

View File

@@ -0,0 +1,346 @@
<template>
<div v-show="!isWaveCharts" class="event-statistics-curve" :style="pageHeight">
<TableHeader ref="TableHeaderRef" :showReset="false" :timeKeyList="timeKeyList" datePicker
@selectChange="selectChange"> <template v-slot:operation>
<el-button icon="el-icon-Back" @click="handleBack">返回</el-button>
</template>
</TableHeader>
<el-descriptions class="mt2" direction="vertical" :column="4" border>
<el-descriptions-item align="center" label="名称">{{ data.name }}</el-descriptions-item>
<el-descriptions-item align="center" label="事件总数">{{ data.gs }}</el-descriptions-item>
<el-descriptions-item align="center" label="可容忍">{{ data.krr }}</el-descriptions-item>
<el-descriptions-item align="center" label="不可容忍">{{ data.bkrr }}</el-descriptions-item>
</el-descriptions>
<my-echart v-loading="tableStore.table.loading" ref="chartRef" class="tall" :options="echartList"
:style="chartStyle" @chart-click="handleChartClick" />
</div>
<waveFormAnalysis v-loading="loading" v-if="isWaveCharts" ref="waveFormAnalysisRef"
@handleHideCharts="isWaveCharts = false" :wp="wp" />
</template>
<script setup lang="ts">
import { ref, onMounted, provide, reactive, computed, nextTick, inject } from 'vue'
import TableStore from '@/utils/tableStore'
import MyEchart from '@/components/echarts/MyEchart.vue'
import waveFormAnalysis from '@/views/govern/device/control/tabs/components/waveFormAnalysis.vue'
import TableHeader from '@/components/table/header/index.vue'
import { analyseWave } from '@/api/common'
import { getTime } from '@/utils/formatTime'
import { mainHeight } from '@/utils/layout'
import { ElMessage } from 'element-plus'
const pageHeight = mainHeight(105)
const eventStatisticsBack = inject<() => void>('eventStatisticsBack', () => {})
const handleBack = () => eventStatisticsBack()
const timeKeyList = ['1', '2', '3', '4', '5']
const defaultInterval = 3
const TableHeaderRef = ref()
const headerHeight = ref(57)
const echartList = ref()
const chartRef = ref()
const isWaveCharts = ref(false)
const loading = ref(false)
const wp = ref({})
const boxoList: any = ref({})
const waveFormAnalysisRef: any = ref(null)
const chartStyle = computed(() => ({
width: '100%',
height: `calc(${pageHeight.height} - 80px - ${headerHeight.value}px)`
}))
const data = reactive({
name: '事件个数',
gs: 0,
krr: 0,
bkrr: 0
})
const tableStore: any = new TableStore({
url: '/cs-harmonic-boot/csevent/f47Curve',
method: 'POST',
showPage: false,
column: [],
beforeSearchFun: () => {
setTime()
},
loadCallback: () => {
const gongData = gongfunction(tableStore.table.data)
data.gs = tableStore.table.data.length
data.krr = gongData.pointF.length
data.bkrr = gongData.pointFun.length
echartList.value = {
title: {
text: 'F47曲线'
},
legend: {
data: ['分割线', '可容忍事件', '不可容忍事件'],
itemGap: 15
},
tooltip: {
trigger: 'item',
show: true,
axisPointer: {
type: 'shadow',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.55)',
borderWidth: 0,
formatter: function (a: any) {
let relVal = `<strong>${a.seriesName}</strong><br/>`
relVal += "<font style='color:" + "'>发生时间:" + a.value[2] + '</font><br/>'
relVal += "<font style='color:" + "'>特征幅值:" + Math.floor(a.value[1] * 100) / 100 + '%</font><br/>'
relVal += "<font style='color:" + "'>持续时间:" + a.value[0] + 's</font><br/>'
relVal += "<font style='color:" + "'>监测点名称:" + (a.value[4] || '/') + '</font><br/>'
relVal += "<font style='color:" + "'>设备名称:" + (a.value[5] || '/') + '</font><br/>'
relVal += "<font style='color:" + "'>项目名称:" + (a.value[6] || '/') + '</font><br/>'
relVal += "<font style='color:" + "'>工程名称:" + (a.value[7] || '/') + '</font>'
return relVal
}
},
xAxis: [
{
type: 'log',
min: 0.001,
max: 1000,
splitLine: {
show: false
},
name: 's'
}
],
yAxis: [
{
type: 'value',
name: '%'
}
],
color: ['#DAA520', 'green', 'red'],
options: {
dataZoom: null,
series: [
{
name: '分割线',
type: 'line',
data: [
[0.05, 0],
[0.05, 50],
[0.2, 50],
[0.2, 70],
[0.5, 70],
[0.5, 80],
[10, 80],
[1000, 80]
],
showSymbol: false,
tooltips: {
show: false
}
},
{
name: '可容忍事件',
type: 'scatter',
symbol: 'circle',
symbolSize: 8,
data: gongData.pointF,
legendSymbol: 'circle'
},
{
name: '不可容忍事件',
type: 'scatter',
symbol: 'circle',
symbolSize: 8,
data: gongData.pointFun,
legendSymbol: 'rect'
}
]
}
}
}
})
const tableRef = ref()
provide('tableRef', tableRef)
provide('tableStore', tableStore)
const selectChange = (_showSelect: any, height: any, datePickerValue?: any) => {
headerHeight.value = height
if (datePickerValue && datePickerValue.timeValue) {
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
}
}
const setTime = () => {
const time = getTime(
(TableHeaderRef.value?.datePickerRef.interval || defaultInterval) ?? 0,
timeKeyList,
[tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
)
if (Array.isArray(time)) {
tableStore.table.params.searchBeginTime = time[0]
tableStore.table.params.searchEndTime = time[1]
TableHeaderRef.value?.setInterval(time[2] - 0)
TableHeaderRef.value?.setTimeInterval([time[0], time[1]])
} else {
console.warn('获取时间失败time 不是一个有效数组')
}
}
function gongfunction(arr: any) {
let standI = 0
let unstandI = 0
let standF = 0
let unstandF = 0
let pointIun: any[] = []
let pointI: any[] = []
let pointF: any[] = []
let pointFun: any[] = []
const total = arr.length
if (total > 0) {
for (let i = 0; i < arr.length; i++) {
const xx = arr[i].persistTime
const yy = arr[i].eventValue
const time = arr[i].time
const eventId = arr[i].eventId
const lineName = arr[i].lineName
const equipmentName = arr[i].equipmentName
const projectName = arr[i].projectName
const engineeringName = arr[i].engineeringName
const point = [xx, yy, time, eventId, lineName, equipmentName, projectName, engineeringName]
if (xx <= 0.003) {
const line = 250 - 30000 * xx
if (yy > line) {
unstandI++
pointIun.push({ value: point, itemStyle: { normal: { color: 'red' } } })
} else {
standI++
pointI.push({ value: point, itemStyle: { normal: { color: 'green' } } })
}
} else if (xx <= 0.02) {
if (yy > 120) {
unstandI++
pointIun.push({ value: point, itemStyle: { normal: { color: 'red' } } })
} else {
standI++
pointI.push({ value: point, itemStyle: { normal: { color: 'green' } } })
}
} else if (xx <= 0.5) {
if (yy > 120 || yy < 70) {
unstandI++
pointIun.push({ value: point, itemStyle: { normal: { color: 'red' } } })
} else {
standI++
pointI.push({ value: point, itemStyle: { normal: { color: 'green' } } })
}
} else if (xx <= 10) {
if (yy > 110 || yy < 80) {
unstandI++
pointIun.push({ value: point, itemStyle: { normal: { color: 'red' } } })
} else {
standI++
pointI.push({ value: point, itemStyle: { normal: { color: 'green' } } })
}
} else {
if (yy > 110 || yy < 90) {
unstandI++
pointIun.push({ value: point, itemStyle: { normal: { color: 'red' } } })
} else {
standI++
pointI.push({ value: point, itemStyle: { normal: { color: 'green' } } })
}
}
if (xx < 0.05) {
standF++
pointF.push({ value: point, itemStyle: { normal: { color: 'green' } } })
} else if (xx < 0.2) {
if (yy > 50) {
standF++
pointF.push({ value: point, itemStyle: { normal: { color: 'green' } } })
} else {
unstandF++
pointFun.push({ value: point, itemStyle: { normal: { color: 'red' } } })
}
} else if (xx < 0.5) {
if (yy > 70) {
standF++
pointF.push({ value: point, itemStyle: { normal: { color: 'green' } } })
} else {
unstandF++
pointFun.push({ value: point, itemStyle: { normal: { color: 'red' } } })
}
} else {
if (yy > 80) {
standF++
pointF.push({ value: point, itemStyle: { normal: { color: 'green' } } })
} else {
unstandF++
pointFun.push({ value: point, itemStyle: { normal: { color: 'red' } } })
}
}
}
}
return { standI, unstandI, pointI, pointIun, standF, unstandF, pointF, pointFun }
}
onMounted(() => {
setTimeout(() => {
tableStore.index()
}, 100)
})
const handleChartClick = (params: any) => {
if (params.seriesName === '可容忍事件' || params.seriesName === '不可容忍事件') {
handleTolerableEventClick(params)
}
}
const handleTolerableEventClick = async (row: any) => {
loading.value = true
ElMessage.info(`正在加载,请稍等...`)
await analyseWave(row.value[3])
.then(res => {
if (res != undefined) {
loading.value = true
isWaveCharts.value = true
boxoList.value = {
persistTime: row.value[0],
featureAmplitude: row.value[1] / 100,
startTime: row.value[2],
lineName: row.value[4],
engineeringName: row.value[5],
systemType: 'YPT'
}
wp.value = res.data
}
loading.value = false
})
.catch(() => {
loading.value = false
})
nextTick(() => {
waveFormAnalysisRef.value?.getWpData(wp.value, boxoList.value, true)
})
}
</script>
<style scoped>
.event-statistics-curve {
width: 100%;
}
</style>

View File

@@ -0,0 +1,332 @@
<template>
<div v-show="!isWaveCharts" class="event-statistics-curve" :style="pageHeight">
<TableHeader ref="TableHeaderRef" :showReset="false" :timeKeyList="timeKeyList" datePicker
@selectChange="selectChange"> <template v-slot:operation>
<el-button icon="el-icon-Back" @click="handleBack">返回</el-button>
</template>
</TableHeader>
<el-descriptions class="mt2" direction="vertical" :column="4" border>
<el-descriptions-item align="center" label="名称">{{ data.name }}</el-descriptions-item>
<el-descriptions-item align="center" label="事件总数">{{ data.gs }}</el-descriptions-item>
<el-descriptions-item align="center" label="可容忍">{{ data.krr }}</el-descriptions-item>
<el-descriptions-item align="center" label="不可容忍">{{ data.bkrr }}</el-descriptions-item>
</el-descriptions>
<my-echart v-loading="tableStore.table.loading" ref="chartRef" class="tall" :options="echartList"
:style="chartStyle" @chart-click="handleChartClick" />
</div>
<waveFormAnalysis v-loading="loading" v-if="isWaveCharts" ref="waveFormAnalysisRef"
@handleHideCharts="isWaveCharts = false" :wp="wp" />
</template>
<script setup lang="ts">
import { ref, onMounted, provide, reactive, computed, nextTick, inject } from 'vue'
import TableStore from '@/utils/tableStore'
import MyEchart from '@/components/echarts/MyEchart.vue'
import waveFormAnalysis from '@/views/govern/device/control/tabs/components/waveFormAnalysis.vue'
import TableHeader from '@/components/table/header/index.vue'
import { analyseWave } from '@/api/common'
import { getTime } from '@/utils/formatTime'
import { mainHeight } from '@/utils/layout'
import { ElMessage } from 'element-plus'
const pageHeight = mainHeight(105)
const eventStatisticsBack = inject<() => void>('eventStatisticsBack', () => {})
const handleBack = () => eventStatisticsBack()
const timeKeyList = ['1', '2', '3', '4', '5']
const defaultInterval = 3
const TableHeaderRef = ref()
const headerHeight = ref(57)
const echartList = ref()
const chartRef = ref()
const isWaveCharts = ref(false)
const loading = ref(false)
const wp = ref({})
const boxoList: any = ref({})
const waveFormAnalysisRef: any = ref(null)
const chartStyle = computed(() => ({
width: '100%',
height: `calc(${pageHeight.height} - 80px - ${headerHeight.value}px)`
}))
const data = reactive({
name: '事件个数',
gs: 0,
krr: 0,
bkrr: 0
})
const tableStore: any = new TableStore({
url: '/cs-harmonic-boot/csevent/f47Curve',
method: 'POST',
showPage: false,
column: [],
beforeSearchFun: () => {
setTime()
},
loadCallback: () => {
const gongData = gongfunction(tableStore.table.data)
data.gs = tableStore.table.data.length
data.krr = gongData.pointI.length
data.bkrr = gongData.pointIun.length
echartList.value = {
title: {
text: 'ITIC曲线'
},
legend: {
data: ['上限', '下限', '可容忍事件', '不可容忍事件'],
itemGap: 15
},
tooltip: {
trigger: 'item',
show: true,
axisPointer: {
type: 'shadow',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.55)',
borderWidth: 0,
formatter: function (a: any) {
let relVal = `<strong>${a.seriesName}</strong><br/>`
relVal += "<font style='color:" + "'>发生时间:" + a.value[2] + '</font><br/>'
relVal += "<font style='color:" + "'>特征幅值:" + Math.floor(a.value[1] * 100) / 100 + '%</font><br/>'
relVal += "<font style='color:" + "'>持续时间:" + a.value[0] + 's</font><br/>'
relVal += "<font style='color:" + "'>监测点名称:" + (a.value[4] || '/') + '</font><br/>'
relVal += "<font style='color:" + "'>设备名称:" + (a.value[5] || '/') + '</font><br/>'
relVal += "<font style='color:" + "'>项目名称:" + (a.value[6] || '/') + '</font><br/>'
relVal += "<font style='color:" + "'>工程名称:" + (a.value[7] || '/') + '</font>'
return relVal
}
},
xAxis: [
{
type: 'log',
min: 0.001,
max: 1000,
splitLine: {
show: false
},
name: 's'
}
],
yAxis: [
{
type: 'value',
splitNumber: 10,
minInterval: 3,
name: '%'
}
],
color: ['#FF8C00', '#00BFFF', 'green', 'red'],
options: {
dataZoom: null,
series: [
{
name: '上限',
type: 'line',
data: [
[0.001, 200],
[0.003, 140],
[0.003, 120],
[0.5, 120],
[0.5, 110],
[10, 110],
[1000, 110]
],
showSymbol: false,
tooltips: {
show: false
}
},
{
name: '下限',
type: 'line',
data: [
[0.02, 0],
[0.02, 70],
[0.5, 70],
[0.5, 80],
[10, 80],
[10, 90],
[1000, 90]
],
showSymbol: false,
tooltips: {
show: false
}
},
{
name: '可容忍事件',
type: 'scatter',
symbol: 'circle',
symbolSize: 8,
data: gongData.pointI,
legendSymbol: 'circle'
},
{
name: '不可容忍事件',
type: 'scatter',
symbol: 'circle',
symbolSize: 8,
data: gongData.pointIun,
legendSymbol: 'rect'
}
]
}
}
}
})
const tableRef = ref()
provide('tableRef', tableRef)
provide('tableStore', tableStore)
const selectChange = (_showSelect: any, height: any, datePickerValue?: any) => {
headerHeight.value = height
if (datePickerValue && datePickerValue.timeValue) {
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
}
}
const setTime = () => {
const time = getTime(
(TableHeaderRef.value?.datePickerRef.interval || defaultInterval) ?? 0,
timeKeyList,
[tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
)
if (Array.isArray(time)) {
tableStore.table.params.searchBeginTime = time[0]
tableStore.table.params.searchEndTime = time[1]
TableHeaderRef.value?.setInterval(time[2] - 0)
TableHeaderRef.value?.setTimeInterval([time[0], time[1]])
} else {
console.warn('获取时间失败time 不是一个有效数组')
}
}
function gongfunction(arr: any) {
let standI = 0
let unstandI = 0
let pointIun: any[] = []
let pointI: any[] = []
const total = arr.length
if (total > 0) {
for (let i = 0; i < arr.length; i++) {
const xx = arr[i].persistTime
const yy = arr[i].eventValue
const time = arr[i].time
const eventId = arr[i].eventId
const lineName = arr[i].lineName
const equipmentName = arr[i].equipmentName
const projectName = arr[i].projectName
const engineeringName = arr[i].engineeringName
const point = [xx, yy, time, eventId, lineName, equipmentName, projectName, engineeringName]
if (xx <= 0.003) {
const line = 230 - 30000 * xx
if (yy > line) {
unstandI++
pointIun.push({ value: point, itemStyle: { normal: { color: 'red' } } })
} else {
standI++
pointI.push({ value: point, itemStyle: { normal: { color: 'green' } } })
}
} else if (xx <= 0.02) {
if (yy > 120) {
unstandI++
pointIun.push({ value: point, itemStyle: { normal: { color: 'red' } } })
} else {
standI++
pointI.push({ value: point, itemStyle: { normal: { color: 'green' } } })
}
} else if (xx <= 0.5) {
if (yy > 120 || yy < 70) {
unstandI++
pointIun.push({ value: point, itemStyle: { normal: { color: 'red' } } })
} else {
standI++
pointI.push({ value: point, itemStyle: { normal: { color: 'green' } } })
}
} else if (xx <= 10) {
if (yy > 110 || yy < 80) {
unstandI++
pointIun.push({ value: point, itemStyle: { normal: { color: 'red' } } })
} else {
standI++
pointI.push({ value: point, itemStyle: { normal: { color: 'green' } } })
}
} else {
if (yy > 110 || yy < 90) {
unstandI++
pointIun.push({ value: point, itemStyle: { normal: { color: 'red' } } })
} else {
standI++
pointI.push({ value: point, itemStyle: { normal: { color: 'green' } } })
}
}
}
}
return { standI, unstandI, pointI, pointIun }
}
onMounted(() => {
setTimeout(() => {
tableStore.index()
}, 100)
})
const handleChartClick = (params: any) => {
if (params.seriesName === '可容忍事件' || params.seriesName === '不可容忍事件') {
handleTolerableEventClick(params)
}
}
const handleTolerableEventClick = async (row: any) => {
loading.value = true
ElMessage.info(`正在加载,请稍等...`)
await analyseWave(row.value[3])
.then(res => {
if (res != undefined) {
loading.value = true
isWaveCharts.value = true
boxoList.value = {
persistTime: row.value[0],
featureAmplitude: row.value[1] / 100,
startTime: row.value[2],
lineName: row.value[4],
engineeringName: row.value[5],
systemType: 'YPT'
}
wp.value = res.data
}
loading.value = false
})
.catch(() => {
loading.value = false
})
nextTick(() => {
waveFormAnalysisRef.value?.getWpData(wp.value, boxoList.value, true)
})
}
</script>
<style scoped>
.event-statistics-curve {
width: 100%;
}
</style>

View File

@@ -0,0 +1,248 @@
<template>
<div class="distribution-page" :style="pageHeight" v-loading="tableStore.table.loading">
<TableHeader ref="TableHeaderRef" :showReset="false" :timeKeyList="timeKeyList" datePicker
@selectChange="selectChange">
<template v-slot:operation>
<el-button icon="el-icon-Back" @click="handleBack">返回</el-button>
</template>
</TableHeader>
<p class="note">暂降类型仅统计暂降原因为短路故障事件</p>
<div class="statistics-main" v-if="renderFlag">
<div class="chart-cell">
<my-echart :options="reasonChart" class="chart-box" />
</div>
<div class="table-cell">
<vxe-table height="auto" auto-resize :data="reasonData" v-bind="defaultAttribute">
<vxe-column field="name" title="暂降原因" />
<vxe-column field="value" title="暂降次数" sortable />
</vxe-table>
</div>
<div class="chart-cell">
<my-echart :options="typeChart" class="chart-box" />
</div>
<div class="table-cell">
<vxe-table height="auto" auto-resize :data="typeData" v-bind="defaultAttribute">
<vxe-column field="name" title="暂降类型" />
<vxe-column field="value" title="暂降次数" sortable />
</vxe-table>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, provide, inject } from 'vue'
import TableStore from '@/utils/tableStore'
import MyEchart from '@/components/echarts/MyEchart.vue'
import TableHeader from '@/components/table/header/index.vue'
import { defaultAttribute } from '@/components/table/defaultAttribute'
import { getTime } from '@/utils/formatTime'
import { useDictData } from '@/stores/dictData'
import { mainHeight } from '@/utils/layout'
import { color1 } from '@/components/echarts/color'
const dictData = useDictData()
const ReasonList: any = dictData.getBasicData('Event_Reason')
const EventTypeList: any = dictData.getBasicData('Event_Type')
const pageHeight = mainHeight(106)
const eventStatisticsBack = inject<() => void>('eventStatisticsBack', () => {})
const handleBack = () => eventStatisticsBack()
const timeKeyList = ['1', '2', '3', '4', '5']
const defaultInterval = 3
const TableHeaderRef = ref()
const renderFlag = ref(true)
const reasonChart = ref({})
const typeChart = ref({})
const reasonData = ref<any[]>([])
const typeData = ref<any[]>([])
const sortDistributionList = (list: any[]) => {
const totalRow = list.find((item: any) => item.name === '总计')
const total = totalRow?.value ?? list.reduce((sum, item) => sum + (item.value ?? 0), 0)
const sorted = list
.filter((item: any) => item.name !== '总计')
.sort((a, b) => (b.value ?? 0) - (a.value ?? 0))
return [{ name: '总计', value: total }, ...sorted]
}
const transformReasonData = (eventReason: any[] = []) => {
const list = ReasonList.map((item: any) => {
const matched = eventReason.find((row: any) => row.eventReasonId === item.id)
return {
name: item.name,
value: matched?.eventReasonCount ?? 0
}
})
return sortDistributionList(list)
}
const transformTypeData = (eventType: any[] = []) => {
const list = EventTypeList.map((item: any) => {
const matched = eventType.find((row: any) => row.eventTypeId === item.id)
return {
name: item.name,
value: matched?.eventTypeCount ?? 0
}
})
return sortDistributionList(list)
}
const parseDistributionData = (raw: any) => {
if (raw?.eventReason || raw?.eventType) {
return {
reason: transformReasonData(raw.eventReason || []),
type: transformTypeData(raw.eventType || [])
}
}
if (raw?.reason?.length || raw?.type?.length) {
return {
reason: sortDistributionList(raw.reason || []),
type: sortDistributionList(raw.type || [])
}
}
return {
reason: transformReasonData([]),
type: transformTypeData([])
}
}
const buildPieOptions = (title: string, seriesName: string, data: any[], exportFileName: string) => ({
title: { text: title },
exportFileName,
legend: {
type: 'scroll',
orient: 'vertical',
left: 10,
top: '5%',
tooltip: { show: true }
},
color: color1,
xAxis: { show: false },
yAxis: { show: false },
dataZoom: { show: false },
tooltip: {
trigger: 'item',
formatter: '{a} <br/>{b} : {c} (次)',
confine: true
},
options: {
series: [
{
name: seriesName,
type: 'pie',
center: ['50%', '50%'],
selectedOffset: 30,
clockwise: true,
label: { show: false, position: 'outside' },
data: data.filter((item: any) => item.name !== '总计')
}
]
}
})
const updateCharts = (res: any) => {
renderFlag.value = false
reasonData.value = res?.reason || []
typeData.value = res?.type || []
reasonChart.value = buildPieOptions('暂降原因', '暂降原因', reasonData.value, '暂降原因')
typeChart.value = buildPieOptions('暂降类型', '暂降类型', typeData.value, '暂降类型')
renderFlag.value = true
}
const tableStore: any = new TableStore({
url: '/cs-harmonic-boot/event/eventReasonAndTypeStatistics',
method: 'POST',
showPage: false,
column: [],
beforeSearchFun: () => {
setTime()
},
loadCallback: () => {
updateCharts(parseDistributionData(tableStore.table.data))
}
})
const tableRef = ref()
provide('tableRef', tableRef)
provide('tableStore', tableStore)
const selectChange = (_showSelect: any, _height: any, datePickerValue?: any) => {
if (datePickerValue?.timeValue) {
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
}
}
const setTime = () => {
const time = getTime(
(TableHeaderRef.value?.datePickerRef.interval || defaultInterval) ?? 0,
timeKeyList,
[tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
)
if (Array.isArray(time)) {
tableStore.table.params.searchBeginTime = time[0]
tableStore.table.params.searchEndTime = time[1]
TableHeaderRef.value?.setInterval(time[2] - 0)
TableHeaderRef.value?.setTimeInterval([time[0], time[1]])
} else {
console.warn('获取时间失败time 不是一个有效数组')
}
}
onMounted(() => {
updateCharts(parseDistributionData(null))
setTimeout(() => {
tableStore.index()
}, 100)
})
</script>
<style scoped>
.distribution-page {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
min-height: 0;
box-sizing: border-box;
}
.note {
margin: 8px 0 0;
flex-shrink: 0;
color: #f56c6c;
font-size: 12px;
}
.statistics-main {
flex: 1;
min-height: 0;
display: grid;
grid-template-columns: 1fr 420px;
grid-template-rows: 1fr 1fr;
gap: 20px;
margin-top: 8px;
}
.chart-cell,
.table-cell {
min-height: 0;
overflow: hidden;
}
.chart-cell {
display: flex;
}
.chart-box {
flex: 1;
min-height: 0;
width: 100%;
}
.chart-box :deep(.chart),
.chart-box :deep(.my-chart) {
height: 100%;
}
</style>

View File

@@ -2,8 +2,17 @@
<div class="default-main"> <div class="default-main">
<el-tabs v-model.trim="activeName" type="border-card" class="demo-tabs"> <el-tabs v-model.trim="activeName" type="border-card" class="demo-tabs">
<el-tab-pane label="暂态事件" name="4"> <el-tab-pane label="暂态事件" name="4">
<Transient v-if="activeName == '4'" :deviceTree="deviceTree" :key="key" /> <Transient
v-if="!showEventStatistics"
:deviceTree="deviceTree"
:key="key"
@statistics="showEventStatistics = true"
/>
<eventStatistics v-else @back="showEventStatistics = false" />
</el-tab-pane> </el-tab-pane>
<!-- <el-tab-pane label="事件统计" name="5">
</el-tab-pane> -->
<el-tab-pane label="稳态越限告警" name="3"> <el-tab-pane label="稳态越限告警" name="3">
<Steady v-if="activeName == '3'" :deviceTree="deviceTree" :key="key" /> <Steady v-if="activeName == '3'" :deviceTree="deviceTree" :key="key" />
</el-tab-pane> </el-tab-pane>
@@ -15,16 +24,17 @@
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted, provide } from 'vue' import { ref, onMounted, watch } from 'vue'
import Steady from './Steady.vue' import Steady from './Steady.vue'
import Transient from './Transient.vue' import Transient from './Transient.vue'
import Device from './Device.vue' import Device from './Device.vue'
import Front from './Front.vue' import Front from './Front.vue'
import eventStatistics from './eventStatistics.vue'
import { getDeviceTree } from '@/api/cs-device-boot/csLedger' import { getDeviceTree } from '@/api/cs-device-boot/csLedger'
defineOptions({ defineOptions({
name: 'govern/alarm/index' name: 'govern/alarm/index'
@@ -32,25 +42,32 @@ defineOptions({
const deviceTree = ref([]) const deviceTree = ref([])
const activeName = ref('4') const activeName = ref('4')
const showEventStatistics = ref(false)
const key = ref(0) const key = ref(0)
getDeviceTree().then(res => {
// res.data.forEach((item: any) => { watch(activeName, val => {
// item.value = item.id if (val !== '4') {
// item.label = item.name showEventStatistics.value = false
// item.children.forEach((child: any) => { }
// child.value = child.id
// child.label = child.name
// child.children.forEach((grand: any) => {
// grand.value = grand.id
// grand.label = grand.name
// delete grand.children
// })
// })
// })
deviceTree.value = res.data
key.value += 1
activeName.value = '4'
}) })
// getDeviceTree().then(res => {
// res.data.forEach((item: any) => {
// item.value = item.id
// item.label = item.name
// item.children.forEach((child: any) => {
// child.value = child.id
// child.label = child.name
// child.children.forEach((grand: any) => {
// grand.value = grand.id
// grand.label = grand.name
// delete grand.children
// })
// })
// })
// deviceTree.value = res.data
// key.value += 1
// activeName.value = '4'
// })
onMounted(() => { }) onMounted(() => { })
const addMenu = () => { } const addMenu = () => { }

View File

@@ -120,12 +120,14 @@ const init = () => {
}) })
}) })
} }
const exportSubjectName = ref('')
const deviceTypeChange = (val: any, obj: any) => { const deviceTypeChange = (val: any, obj: any) => {
flag.value = true flag.value = true
nodeClick(obj) nodeClick(obj)
} }
const nodeClick = async (e: anyObj) => { const nodeClick = async (e: anyObj) => {
if ((e.level == 2 || e.level == 3)) { if ((e.level == 2 || e.level == 3)) {
exportSubjectName.value = e.name || ''
formInline.devId = e.id formInline.devId = e.id
loading.value = true loading.value = true
if (zblist.value.length === 0) { if (zblist.value.length === 0) {
@@ -259,6 +261,11 @@ const setEchart = () => {
} }
echartsData.value = { echartsData.value = {
exportFileName: {
subject: exportSubjectName.value,
feature: zblist.value.filter(item => item.id == formInline.statisticalId)[0]?.name || 'APF数据',
date: formInline.endTime || formInline.startTime
},
title: { title: {
text: zblist.value.filter(item => item.id == formInline.statisticalId)[0].name text: zblist.value.filter(item => item.id == formInline.statisticalId)[0].name
}, },
@@ -319,9 +326,7 @@ const setEchart = () => {
title: '下载csv', title: '下载csv',
icon: 'path://M642 673.1H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9s-8 17.9-17.9 17.9zM642 511.8H301.6c-9.9 0-17.9-8-17.9-17.9 0-9.9 8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9 0 9.9-8 17.9-17.9 17.9zM480.7 350.6H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9h179.2c9.9 0 17.9 8 17.9 17.9s-8.1 17.9-18 17.9zM874.9 350.6H695.7c-49.4 0-89.6-40.2-89.6-89.6V81.9c0-9.9 8-17.9 17.9-17.9 9.9 0 17.9 8 17.9 17.9V261c0 29.6 24.1 53.7 53.7 53.7h179.2c9.9 0 17.9 8 17.9 17.9s-7.9 18-17.8 18zM794.3 959.7H221c-49.4 0-89.6-40.2-89.6-89.6V153.5c0-49.4 40.2-89.6 89.6-89.6h403.1c4.8 0 9.3 1.9 12.7 5.2L887.6 320c3.4 3.4 5.2 7.9 5.2 12.7v537.5c0 52.7-51.9 89.5-98.5 89.5zM221 99.8c-29.6 0-53.7 24.1-53.7 53.7v716.6c0 29.6 24.1 53.7 53.7 53.7h573.3c29 0 62.7-23.5 62.7-53.7v-530L616.7 99.8H221z', icon: 'path://M642 673.1H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9s-8 17.9-17.9 17.9zM642 511.8H301.6c-9.9 0-17.9-8-17.9-17.9 0-9.9 8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9 0 9.9-8 17.9-17.9 17.9zM480.7 350.6H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9h179.2c9.9 0 17.9 8 17.9 17.9s-8.1 17.9-18 17.9zM874.9 350.6H695.7c-49.4 0-89.6-40.2-89.6-89.6V81.9c0-9.9 8-17.9 17.9-17.9 9.9 0 17.9 8 17.9 17.9V261c0 29.6 24.1 53.7 53.7 53.7h179.2c9.9 0 17.9 8 17.9 17.9s-7.9 18-17.8 18zM794.3 959.7H221c-49.4 0-89.6-40.2-89.6-89.6V153.5c0-49.4 40.2-89.6 89.6-89.6h403.1c4.8 0 9.3 1.9 12.7 5.2L887.6 320c3.4 3.4 5.2 7.9 5.2 12.7v537.5c0 52.7-51.9 89.5-98.5 89.5zM221 99.8c-29.6 0-53.7 24.1-53.7 53.7v716.6c0 29.6 24.1 53.7 53.7 53.7h573.3c29 0 62.7-23.5 62.7-53.7v-530L616.7 99.8H221z',
onclick: () => { onclick: () => {
const chartTitle = exportSeriesCSV(echartsData.value.options.series, echartsData.value.exportFileName)
zblist.value.filter(item => item.id == formInline.statisticalId)[0]?.name || 'APF数据'
exportSeriesCSV(echartsData.value.options.series, `${chartTitle}.csv`)
} }
}, },
myTool2: { myTool2: {

View File

@@ -1,10 +1,10 @@
<template> <template>
<div class="default-main apf"> <div class="default-main apf">
<el-tabs type="border-card" v-model="activeName"> <el-tabs type="border-card" v-model="activeName">
<el-tab-pane label="APF" name="1"> <el-tab-pane label="稳态" name="1">
<APF v-if="activeName == '1'" /> <APF v-if="activeName == '1'" />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="DVR" name="2"> <el-tab-pane label="暂态" name="2">
<DVR v-if="activeName == '2'" /> <DVR v-if="activeName == '2'" />
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>

View File

@@ -58,6 +58,7 @@ import { analyseWave } from '@/api/common'
import TableHeader from '@/components/table/header/index.vue' import TableHeader from '@/components/table/header/index.vue'
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
import { getFileZip } from '@/api/cs-harmonic-boot/datatrend' import { getFileZip } from '@/api/cs-harmonic-boot/datatrend'
import { buildWaveExportFileName, getExportSubjectFromRow } from '@/utils/echartMethod'
import MultiCondition from '@/views/govern/alarm/multiCondition.vue' import MultiCondition from '@/views/govern/alarm/multiCondition.vue'
import { queryByCode, queryByid, queryCsDictTree } from '@/api/system-boot/dictTree' import { queryByCode, queryByid, queryCsDictTree } from '@/api/system-boot/dictTree'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
@@ -104,12 +105,12 @@ const tableStore = new TableStore({
{ title: '触发类型', field: 'showName', minWidth: 100, align: 'center' }, { title: '触发类型', field: 'showName', minWidth: 100, align: 'center' },
{ {
title: '暂降原因', field: 'advanceReason', minWidth: 100, align: 'center', formatter: (row: any) => { title: '暂降原因', field: 'advanceReason', minWidth: 100, align: 'center', formatter: (row: any) => {
return ReasonList.find((item: any) => item.id == row.cellValue)?.name || '未知' return ReasonList.find((item: any) => item.id == row.cellValue)?.name || '其他'
} }
}, },
{ {
title: '暂降类型', field: 'advanceType', minWidth: 100, align: 'center', formatter: (row: any) => { title: '暂降类型', field: 'advanceType', minWidth: 100, align: 'center', formatter: (row: any) => {
return EventTypeList.find((item: any) => item.id == row.cellValue)?.name || '未知' return EventTypeList.find((item: any) => item.id == row.cellValue)?.name || '其他'
} }
}, },
@@ -196,7 +197,7 @@ const tableStore = new TableStore({
const url = window.URL.createObjectURL(blob) const url = window.URL.createObjectURL(blob)
const link = document.createElement('a') // 创建a标签 const link = document.createElement('a') // 创建a标签
link.href = url link.href = url
link.download = row.wavePath.split('/')[2] || '波形文件' // 设置下载的文件名 link.download = buildWaveExportFileName(getExportSubjectFromRow(row))
document.body.appendChild(link) document.body.appendChild(link)
link.click() //执行下载 link.click() //执行下载
document.body.removeChild(link) //释放标签 document.body.removeChild(link) //释放标签

View File

@@ -271,6 +271,11 @@ const setEchart = () => {
} }
echartsData.value = { echartsData.value = {
exportFileName: {
subject: defaultCheckedKeys.value.map(item => item.name).filter(Boolean).join(''),
feature: zblist.value.filter(item => item.id == formInline.statisticalId)[0]?.name || '稳态数据',
date: formInline.endTime || formInline.startTime
},
title: { title: {
text: zblist.value.filter(item => item.id == formInline.statisticalId)[0]?.name text: zblist.value.filter(item => item.id == formInline.statisticalId)[0]?.name
}, },
@@ -321,9 +326,7 @@ const setEchart = () => {
title: '下载csv', title: '下载csv',
icon: 'path://M642 673.1H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9s-8 17.9-17.9 17.9zM642 511.8H301.6c-9.9 0-17.9-8-17.9-17.9 0-9.9 8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9 0 9.9-8 17.9-17.9 17.9zM480.7 350.6H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9h179.2c9.9 0 17.9 8 17.9 17.9s-8.1 17.9-18 17.9zM874.9 350.6H695.7c-49.4 0-89.6-40.2-89.6-89.6V81.9c0-9.9 8-17.9 17.9-17.9 9.9 0 17.9 8 17.9 17.9V261c0 29.6 24.1 53.7 53.7 53.7h179.2c9.9 0 17.9 8 17.9 17.9s-7.9 18-17.8 18zM794.3 959.7H221c-49.4 0-89.6-40.2-89.6-89.6V153.5c0-49.4 40.2-89.6 89.6-89.6h403.1c4.8 0 9.3 1.9 12.7 5.2L887.6 320c3.4 3.4 5.2 7.9 5.2 12.7v537.5c0 52.7-51.9 89.5-98.5 89.5zM221 99.8c-29.6 0-53.7 24.1-53.7 53.7v716.6c0 29.6 24.1 53.7 53.7 53.7h573.3c29 0 62.7-23.5 62.7-53.7v-530L616.7 99.8H221z', icon: 'path://M642 673.1H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9s-8 17.9-17.9 17.9zM642 511.8H301.6c-9.9 0-17.9-8-17.9-17.9 0-9.9 8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9 0 9.9-8 17.9-17.9 17.9zM480.7 350.6H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9h179.2c9.9 0 17.9 8 17.9 17.9s-8.1 17.9-18 17.9zM874.9 350.6H695.7c-49.4 0-89.6-40.2-89.6-89.6V81.9c0-9.9 8-17.9 17.9-17.9 9.9 0 17.9 8 17.9 17.9V261c0 29.6 24.1 53.7 53.7 53.7h179.2c9.9 0 17.9 8 17.9 17.9s-7.9 18-17.8 18zM794.3 959.7H221c-49.4 0-89.6-40.2-89.6-89.6V153.5c0-49.4 40.2-89.6 89.6-89.6h403.1c4.8 0 9.3 1.9 12.7 5.2L887.6 320c3.4 3.4 5.2 7.9 5.2 12.7v537.5c0 52.7-51.9 89.5-98.5 89.5zM221 99.8c-29.6 0-53.7 24.1-53.7 53.7v716.6c0 29.6 24.1 53.7 53.7 53.7h573.3c29 0 62.7-23.5 62.7-53.7v-530L616.7 99.8H221z',
onclick: () => { onclick: () => {
const chartTitle = exportSeriesCSV(echartsData.value.options.series, echartsData.value.exportFileName)
zblist.value.filter(item => item.id == formInline.statisticalId)[0]?.name || '稳态数据'
exportSeriesCSV(echartsData.value.options.series, `${chartTitle}.csv`)
} }
}, },
myTool2: { myTool2: {

View File

@@ -148,13 +148,14 @@ const handleNodeClick = (data: any, node: any) => {
const exportEvent = () => { const exportEvent = () => {
const now = new Date() const now = new Date()
const year = now.getFullYear() // 4位年份 exportLuckysheetFile(
const month = now.getMonth() + 1 // 月份0-11需+1 {
const day = now.getDate() // 日期1-31 subject: name.value,
feature: '统计报表',
// 格式化YYYY - MM - DD补零 date: datePickerRef.value?.timeValue?.[1] || now
const formattedDate = `${year}${String(month).padStart(2, '0')}${String(day).padStart(2, '0')}` },
exportLuckysheetFile(name.value + formattedDate, tableStore.table.data.length > 0) tableStore.table.data.length > 0
)
} }
</script> </script>
<style lang="scss"> <style lang="scss">

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -118,6 +118,11 @@ const init = () => {
}) })
let [min, max] = yMethod(arr.map((item: any) => item.statisticalData.toFixed(2))) let [min, max] = yMethod(arr.map((item: any) => item.statisticalData.toFixed(2)))
echartsData.value = { echartsData.value = {
exportFileName: {
subject: props.detail.name?.split('(')[0],
feature: '历史趋势',
date: datePickerRef.value?.timeValue?.[1] || datePickerRef.value?.timeValue?.[0]
},
options: { options: {
legend: { legend: {
@@ -261,7 +266,11 @@ const init = () => {
return [item[0], item[1], value1, value2, value3]; return [item[0], item[1], value1, value2, value3];
}); });
exportCSV(echartsData.value.options.series.map(item => item.name), dataList, echartsData.value.title.text + '.csv') exportCSV(
echartsData.value.options.series.map(item => item.name),
dataList,
echartsData.value.exportFileName
)
} }
} }

View File

@@ -377,6 +377,7 @@ import {
getRawData getRawData
} from '@/api/cs-device-boot/EquipmentDelivery' } from '@/api/cs-device-boot/EquipmentDelivery'
import { deviceHisData, deviceRtData, realTimeData, getTestData } from '@/api/cs-device-boot/csGroup' import { deviceHisData, deviceRtData, realTimeData, getTestData } from '@/api/cs-device-boot/csGroup'
import { buildExportFileName } from '@/utils/echartMethod'
import { ref, reactive, onMounted, onUnmounted, inject, nextTick, onBeforeUnmount } from 'vue' import { ref, reactive, onMounted, onUnmounted, inject, nextTick, onBeforeUnmount } from 'vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import DatePicker from '@/components/form/datePicker/index.vue' import DatePicker from '@/components/form/datePicker/index.vue'
@@ -1372,7 +1373,11 @@ const downloadTxt = () => {
// 创建 <a> 标签并触发下载 // 创建 <a> 标签并触发下载
const link = document.createElement('a') const link = document.createElement('a')
link.href = url link.href = url
link.download = '实时数据.txt' // 文件名 link.download = buildExportFileName({
subject: (TrendList.value as any)?.name,
feature: '实时数据',
ext: 'txt'
})
link.click() link.click()
// 释放 URL 对象 // 释放 URL 对象

View File

@@ -210,15 +210,12 @@ const buildTMetric = (name: string, items: RawMetricItem[]): DisplayMetric => {
return { return {
name, name,
otherName: name, otherName: name,
unit: sharedUnit, unit: getSharedUnit(items),
type: 't-multi', type: 't-multi',
subItems: items.map(item => { subItems: items.map(item => ({
const keyword = extractSubTitle(item.otherName || item.name || '') subTitle: extractSubTitle(item.otherName || item.name || ''),
return { value: item.data,
subTitle: unitsDiffer ? buildTitle(keyword, item.unit) : keyword, })),
value: item.data,
}
}),
} }
} }

View File

@@ -222,6 +222,11 @@ const setEchart = () => {
} }
echartsData.value = { echartsData.value = {
exportFileName: {
subject: (props.TrendList as any)?.name || trendRequestData.value?.name,
feature: '电度数据',
date: datePickerRef.value?.timeValue?.[1] || datePickerRef.value?.timeValue?.[0]
},
legend: { legend: {
itemWidth: 20, itemWidth: 20,
itemHeight: 20, itemHeight: 20,
@@ -290,7 +295,7 @@ const setEchart = () => {
title: '下载csv', title: '下载csv',
icon: 'path://M642 673.1H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9s-8 17.9-17.9 17.9zM642 511.8H301.6c-9.9 0-17.9-8-17.9-17.9 0-9.9 8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9 0 9.9-8 17.9-17.9 17.9zM480.7 350.6H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9h179.2c9.9 0 17.9 8 17.9 17.9s-8.1 17.9-18 17.9zM874.9 350.6H695.7c-49.4 0-89.6-40.2-89.6-89.6V81.9c0-9.9 8-17.9 17.9-17.9 9.9 0 17.9 8 17.9 17.9V261c0 29.6 24.1 53.7 53.7 53.7h179.2c9.9 0 17.9 8 17.9 17.9s-7.9 18-17.8 18zM794.3 959.7H221c-49.4 0-89.6-40.2-89.6-89.6V153.5c0-49.4 40.2-89.6 89.6-89.6h403.1c4.8 0 9.3 1.9 12.7 5.2L887.6 320c3.4 3.4 5.2 7.9 5.2 12.7v537.5c0 52.7-51.9 89.5-98.5 89.5zM221 99.8c-29.6 0-53.7 24.1-53.7 53.7v716.6c0 29.6 24.1 53.7 53.7 53.7h573.3c29 0 62.7-23.5 62.7-53.7v-530L616.7 99.8H221z', icon: 'path://M642 673.1H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9s-8 17.9-17.9 17.9zM642 511.8H301.6c-9.9 0-17.9-8-17.9-17.9 0-9.9 8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9 0 9.9-8 17.9-17.9 17.9zM480.7 350.6H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9h179.2c9.9 0 17.9 8 17.9 17.9s-8.1 17.9-18 17.9zM874.9 350.6H695.7c-49.4 0-89.6-40.2-89.6-89.6V81.9c0-9.9 8-17.9 17.9-17.9 9.9 0 17.9 8 17.9 17.9V261c0 29.6 24.1 53.7 53.7 53.7h179.2c9.9 0 17.9 8 17.9 17.9s-7.9 18-17.8 18zM794.3 959.7H221c-49.4 0-89.6-40.2-89.6-89.6V153.5c0-49.4 40.2-89.6 89.6-89.6h403.1c4.8 0 9.3 1.9 12.7 5.2L887.6 320c3.4 3.4 5.2 7.9 5.2 12.7v537.5c0 52.7-51.9 89.5-98.5 89.5zM221 99.8c-29.6 0-53.7 24.1-53.7 53.7v716.6c0 29.6 24.1 53.7 53.7 53.7h573.3c29 0 62.7-23.5 62.7-53.7v-530L616.7 99.8H221z',
onclick: () => { onclick: () => {
exportSeriesCSV(echartsData.value.options.series, '电度数据.csv') exportSeriesCSV(echartsData.value.options.series, echartsData.value.exportFileName)
} }
}, },
myTool2: { myTool2: {

View File

@@ -26,6 +26,7 @@ import { ArrowLeft, Message } from '@element-plus/icons-vue'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { analyseWave, getFileByEventId } from '@/api/common' import { analyseWave, getFileByEventId } from '@/api/common'
import { getFileZip } from '@/api/cs-harmonic-boot/datatrend' import { getFileZip } from '@/api/cs-harmonic-boot/datatrend'
import { buildWaveExportFileName, getExportSubjectFromRow } from '@/utils/echartMethod'
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
const emit=defineEmits(['fileRecall']) const emit=defineEmits(['fileRecall'])
const tableParams: any = ref({}) const tableParams: any = ref({})
@@ -108,12 +109,12 @@ const tableStore: any = new TableStore({
{ field: 'showName', title: '触发类型', minWidth: 100 }, { field: 'showName', title: '触发类型', minWidth: 100 },
{ {
title: '暂降原因', field: 'advanceReason', minWidth: 100, align: 'center', formatter: (row: any) => { title: '暂降原因', field: 'advanceReason', minWidth: 100, align: 'center', formatter: (row: any) => {
return ReasonList.find((item: any) => item.id == row.cellValue)?.name || '未知' return ReasonList.find((item: any) => item.id == row.cellValue)?.name || '其他'
} }
}, },
{ {
title: '暂降类型', field: 'advanceType', minWidth: 100, align: 'center', formatter: (row: any) => { title: '暂降类型', field: 'advanceType', minWidth: 100, align: 'center', formatter: (row: any) => {
return EventTypeList.find((item: any) => item.id == row.cellValue)?.name || '未知' return EventTypeList.find((item: any) => item.id == row.cellValue)?.name || '其他'
} }
}, },
{ title: '电压等级(kV)', field: 'lineVoltage', minWidth: 120, align: 'center', sortable: true, }, { title: '电压等级(kV)', field: 'lineVoltage', minWidth: 120, align: 'center', sortable: true, },
@@ -206,7 +207,7 @@ const tableStore: any = new TableStore({
const url = window.URL.createObjectURL(blob) const url = window.URL.createObjectURL(blob)
const link = document.createElement('a') // 创建a标签 const link = document.createElement('a') // 创建a标签
link.href = url link.href = url
link.download = row.wavePath.split('/')[2] || '波形文件' // 设置下载的文件名 link.download = buildWaveExportFileName(getExportSubjectFromRow(row))
document.body.appendChild(link) document.body.appendChild(link)
link.click() //执行下载 link.click() //执行下载
document.body.removeChild(link) //释放标签 document.body.removeChild(link) //释放标签

View File

@@ -62,7 +62,7 @@ import { ref, onMounted, watch } from 'vue'
import MyEchart from '@/components/echarts/MyEchart.vue' import MyEchart from '@/components/echarts/MyEchart.vue'
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
import { queryStatistical } from '@/api/system-boot/csstatisticalset' import { queryStatistical } from '@/api/system-boot/csstatisticalset'
import { yMethod, exportSeriesCSV, completeTimeSeries } from '@/utils/echartMethod' import { yMethod, exportSeriesCSV, completeTimeSeries, buildExportFileName } from '@/utils/echartMethod'
import TableHeader from '@/components/table/header/index.vue' import TableHeader from '@/components/table/header/index.vue'
import { getTabsDataByType } from '@/api/cs-device-boot/EquipmentDelivery' import { getTabsDataByType } from '@/api/cs-device-boot/EquipmentDelivery'
import DatePicker from '@/components/form/datePicker/index.vue' import DatePicker from '@/components/form/datePicker/index.vue'
@@ -283,6 +283,15 @@ const init = async () => {
} }
} }
} }
const getChartExportFileName = () => {
const obj = deviceData.value.records?.find((item: any) => item.id == activeName.value)
return {
subject: (props.TrendList as any)?.name,
feature: obj?.itemName || '历史趋势',
date: datePickerRef.value?.timeValue?.[1] || datePickerRef.value?.timeValue?.[0]
}
}
const setEchart = () => { const setEchart = () => {
loading.value = true loading.value = true
echartsData.value = {} echartsData.value = {}
@@ -315,6 +324,7 @@ const setEchart = () => {
} }
echartsData.value = { echartsData.value = {
exportFileName: getChartExportFileName(),
legend: { legend: {
itemWidth: 20, itemWidth: 20,
itemHeight: 20, itemHeight: 20,
@@ -383,7 +393,7 @@ const setEchart = () => {
title: '下载csv', title: '下载csv',
icon: 'path://M642 673.1H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9s-8 17.9-17.9 17.9zM642 511.8H301.6c-9.9 0-17.9-8-17.9-17.9 0-9.9 8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9 0 9.9-8 17.9-17.9 17.9zM480.7 350.6H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9h179.2c9.9 0 17.9 8 17.9 17.9s-8.1 17.9-18 17.9zM874.9 350.6H695.7c-49.4 0-89.6-40.2-89.6-89.6V81.9c0-9.9 8-17.9 17.9-17.9 9.9 0 17.9 8 17.9 17.9V261c0 29.6 24.1 53.7 53.7 53.7h179.2c9.9 0 17.9 8 17.9 17.9s-7.9 18-17.8 18zM794.3 959.7H221c-49.4 0-89.6-40.2-89.6-89.6V153.5c0-49.4 40.2-89.6 89.6-89.6h403.1c4.8 0 9.3 1.9 12.7 5.2L887.6 320c3.4 3.4 5.2 7.9 5.2 12.7v537.5c0 52.7-51.9 89.5-98.5 89.5zM221 99.8c-29.6 0-53.7 24.1-53.7 53.7v716.6c0 29.6 24.1 53.7 53.7 53.7h573.3c29 0 62.7-23.5 62.7-53.7v-530L616.7 99.8H221z', icon: 'path://M642 673.1H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9s-8 17.9-17.9 17.9zM642 511.8H301.6c-9.9 0-17.9-8-17.9-17.9 0-9.9 8-17.9 17.9-17.9H642c9.9 0 17.9 8 17.9 17.9 0 9.9-8 17.9-17.9 17.9zM480.7 350.6H301.6c-9.9 0-17.9-8-17.9-17.9s8-17.9 17.9-17.9h179.2c9.9 0 17.9 8 17.9 17.9s-8.1 17.9-18 17.9zM874.9 350.6H695.7c-49.4 0-89.6-40.2-89.6-89.6V81.9c0-9.9 8-17.9 17.9-17.9 9.9 0 17.9 8 17.9 17.9V261c0 29.6 24.1 53.7 53.7 53.7h179.2c9.9 0 17.9 8 17.9 17.9s-7.9 18-17.8 18zM794.3 959.7H221c-49.4 0-89.6-40.2-89.6-89.6V153.5c0-49.4 40.2-89.6 89.6-89.6h403.1c4.8 0 9.3 1.9 12.7 5.2L887.6 320c3.4 3.4 5.2 7.9 5.2 12.7v537.5c0 52.7-51.9 89.5-98.5 89.5zM221 99.8c-29.6 0-53.7 24.1-53.7 53.7v716.6c0 29.6 24.1 53.7 53.7 53.7h573.3c29 0 62.7-23.5 62.7-53.7v-530L616.7 99.8H221z',
onclick: () => { onclick: () => {
exportSeriesCSV(echartsData.value.options.series, '历史趋势.csv') exportSeriesCSV(echartsData.value.options.series, echartsData.value.exportFileName)
} }
}, },
myTool2: { myTool2: {
@@ -651,11 +661,7 @@ const handleExport = async () => {
const blob = new Blob([csvs], { type: 'text/csv;charset=utf-8;' }) const blob = new Blob([csvs], { type: 'text/csv;charset=utf-8;' })
const link = document.createElement('a') const link = document.createElement('a')
link.href = URL.createObjectURL(blob) link.href = URL.createObjectURL(blob)
let obj = deviceData.value.records.find((item: any) => { link.download = buildExportFileName(echartsData.value?.exportFileName || getChartExportFileName())
return item.id == activeName.value
})
const date = window.XEUtils.toDateString(new Date(), 'yyyyMMdd HHmmss').replace(' ', '_')
link.download = `${deviceData.value.itemName}_${obj?.itemName}_${date}.csv`
link.click() link.click()
return return
} }

View File

@@ -104,6 +104,7 @@ import DeviceTree from '@/components/tree/govern/deviceTree.vue'
import { mainHeight } from '@/utils/layout' import { mainHeight } from '@/utils/layout'
import { queryByCode, queryByid, queryCsDictTree } from '@/api/system-boot/dictTree' import { queryByCode, queryByid, queryCsDictTree } from '@/api/system-boot/dictTree'
import { getDeviceData } from '@/api/cs-device-boot/EquipmentDelivery' import { getDeviceData } from '@/api/cs-device-boot/EquipmentDelivery'
import { buildExportBaseName } from '@/utils/echartMethod'
import { getTargetById } from '@/api/cs-device-boot/csDataArray' import { getTargetById } from '@/api/cs-device-boot/csDataArray'
import { getGroup } from '@/api/cs-device-boot/csGroup' import { getGroup } from '@/api/cs-device-boot/csGroup'
import { ref } from 'vue' import { ref } from 'vue'
@@ -135,6 +136,7 @@ const deviceTypeChange = (val: any, obj: any) => {
deviceType.value = val deviceType.value = val
nodeClick(obj) nodeClick(obj)
} }
const exportSubjectName = ref('')
// 树节点点击 // 树节点点击
const nodeClick = (e: anyObj) => { const nodeClick = (e: anyObj) => {
if (!e) { if (!e) {
@@ -142,6 +144,7 @@ const nodeClick = (e: anyObj) => {
return return
} }
if (e.level == 2 || e.level == 3) { if (e.level == 2 || e.level == 3) {
exportSubjectName.value = e.name || ''
pName.value = e.pName pName.value = e.pName
nDid.value = e.ndid nDid.value = e.ndid
loading.value = true loading.value = true
@@ -288,8 +291,12 @@ const handleRestartDevice = () => {
}) })
} }
const exportData = () => { const exportData = () => {
const dataSetName = deviceData.value.dataSetList.filter((item: any) => item.id == dataSet.value)[0]?.name
xTableRef.value.exportData({ xTableRef.value.exportData({
filename: deviceData.value.dataSetList.filter((item: any) => item.id == dataSet.value)[0]?.name, // 文件名字 filename: buildExportBaseName({
subject: exportSubjectName.value || deviceData.value?.name,
feature: dataSetName || '数据集'
}), // 文件名字
sheetName: 'Sheet1', sheetName: 'Sheet1',
type: 'xlsx', //导出文件类型 xlsx 和 csv type: 'xlsx', //导出文件类型 xlsx 和 csv
useStyle: true, useStyle: true,

View File

@@ -34,6 +34,7 @@ import waveFormAnalysis from '@/views/govern/device/control/tabs/components/wave
import { analyseWave, getFileByEventId } from '@/api/common' import { analyseWave, getFileByEventId } from '@/api/common'
import { mainHeight } from '@/utils/layout' import { mainHeight } from '@/utils/layout'
import { getFileZip } from '@/api/cs-harmonic-boot/datatrend' import { getFileZip } from '@/api/cs-harmonic-boot/datatrend'
import { buildWaveExportFileName, getExportSubjectFromRow } from '@/utils/echartMethod'
import { queryByCode, queryByid, queryCsDictTree } from '@/api/system-boot/dictTree' import { queryByCode, queryByid, queryCsDictTree } from '@/api/system-boot/dictTree'
import analysisList from '@/views/govern/device/control/analysisList/index.vue' import analysisList from '@/views/govern/device/control/analysisList/index.vue'
@@ -109,12 +110,12 @@ const tableStore = new TableStore({
{ field: 'showName', title: '触发类型', minWidth: 100 }, { field: 'showName', title: '触发类型', minWidth: 100 },
{ {
title: '暂降原因', field: 'advanceReason', minWidth: 100, align: 'center', formatter: (row: any) => { title: '暂降原因', field: 'advanceReason', minWidth: 100, align: 'center', formatter: (row: any) => {
return ReasonList.find((item: any) => item.id == row.cellValue)?.name || '未知' return ReasonList.find((item: any) => item.id == row.cellValue)?.name || '其他'
} }
}, },
{ {
title: '暂降类型', field: 'advanceType', minWidth: 100, align: 'center', formatter: (row: any) => { title: '暂降类型', field: 'advanceType', minWidth: 100, align: 'center', formatter: (row: any) => {
return EventTypeList.find((item: any) => item.id == row.cellValue)?.name || '未知' return EventTypeList.find((item: any) => item.id == row.cellValue)?.name || '其他'
} }
}, },
{ title: '监测点名称', field: 'lineName', minWidth: 120, align: 'center' }, { title: '监测点名称', field: 'lineName', minWidth: 120, align: 'center' },
@@ -204,7 +205,7 @@ const tableStore = new TableStore({
const url = window.URL.createObjectURL(blob) const url = window.URL.createObjectURL(blob)
const link = document.createElement('a') // 创建a标签 const link = document.createElement('a') // 创建a标签
link.href = url link.href = url
link.download = row.wavePath.split('/')[2] || '波形文件' // 设置下载的文件名 link.download = buildWaveExportFileName(getExportSubjectFromRow(row))
document.body.appendChild(link) document.body.appendChild(link)
link.click() //执行下载 link.click() //执行下载
document.body.removeChild(link) //释放标签 document.body.removeChild(link) //释放标签

View File

@@ -26,9 +26,9 @@
:name="item.id" :key="index"> :name="item.id" :key="index">
<template #label> <template #label>
<span class="custom-tabs-label"> <span class="custom-tabs-label">
<el-icon> <!-- <el-icon>
<TrendCharts /> <TrendCharts />
</el-icon> </el-icon> -->
<span>{{ item.itemName }}</span> <span>{{ item.itemName }}</span>
</span> </span>
</template> </template>
@@ -203,7 +203,7 @@ import { getTestRecordInfo, getHistoryTrend } from '@/api/cs-device-boot/planDat
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
import { queryStatistical } from '@/api/system-boot/csstatisticalset' import { queryStatistical } from '@/api/system-boot/csstatisticalset'
import { TrendCharts, Plus, Platform } from '@element-plus/icons-vue' import { TrendCharts, Plus, Platform } from '@element-plus/icons-vue'
import { yMethod, completeTimeSeries } from '@/utils/echartMethod' import { yMethod, completeTimeSeries, buildExportFileName } from '@/utils/echartMethod'
import { color, gradeColor3 } from '@/components/echarts/color' import { color, gradeColor3 } from '@/components/echarts/color'
import TableHeader from '@/components/table/header/index.vue' import TableHeader from '@/components/table/header/index.vue'
import { useConfig } from '@/stores/config' import { useConfig } from '@/stores/config'
@@ -341,10 +341,12 @@ const handleClickTabs = async () => {
transientRef.value && transientRef.value.init() transientRef.value && transientRef.value.init()
}, 100) }, 100)
} }
const exportSubjectName = ref('')
const nodeClick = async (e: anyObj) => { const nodeClick = async (e: anyObj) => {
if (e == undefined) { if (e == undefined) {
return return
} }
exportSubjectName.value = e.name || ''
// onIndexChange([]) // onIndexChange([])
deviceData.value = [] deviceData.value = []
historyDevId.value = e?.children && e?.children.length != 0 ? e?.children[0].id : e?.id historyDevId.value = e?.children && e?.children.length != 0 ? e?.children[0].id : e?.id
@@ -567,6 +569,15 @@ const init = (flag: boolean) => {
} }
} }
const getChartExportFileName = () => {
const obj = deviceData.value.records?.find((item: any) => item.id == activeName.value)
return {
subject: exportSubjectName.value,
feature: obj?.itemName || '预案数据',
date: obj?.endTime || obj?.startTime
}
}
const setEchart = () => { const setEchart = () => {
loading.value = true loading.value = true
echartsData.value = {} echartsData.value = {}
@@ -597,6 +608,7 @@ const setEchart = () => {
} }
echartsData.value = { echartsData.value = {
exportFileName: getChartExportFileName(),
// title: { // title: {
// text: chartTitle.value, // text: chartTitle.value,
// left: '0', // left: '0',
@@ -919,11 +931,7 @@ const handleExport = async () => {
const blob = new Blob([csvs], { type: 'text/csv;charset=utf-8;' }) const blob = new Blob([csvs], { type: 'text/csv;charset=utf-8;' })
const link = document.createElement('a') const link = document.createElement('a')
link.href = URL.createObjectURL(blob) link.href = URL.createObjectURL(blob)
let obj = deviceData.value.records.find((item: any) => { link.download = buildExportFileName(echartsData.value?.exportFileName || getChartExportFileName())
return item.id == activeName.value
})
const date = window.XEUtils.toDateString(new Date(), 'yyyyMMdd HHmmss').replace(' ', '_')
link.download = `${deviceData.value.itemName}_${obj?.itemName}_${date}.csv`
link.click() link.click()
return return
} }

View File

@@ -2,13 +2,15 @@
<div> <div>
<TableHeader datePicker showExport> <TableHeader datePicker showExport>
<template v-slot:select> <template v-slot:select>
<el-form-item label="设备名称"> <el-form-item label="关键字筛选">
<el-input maxlength="32" show-word-limit <el-input maxlength="32" show-word-limit v-model.trim="tableStore.table.params.searchValue"
placeholder="请输入设备、监测点名称" />
</el-form-item>
v-model.trim="tableStore.table.params.searchValue" <el-form-item label="级别">
placeholder="请输入设备名称" <el-select v-model="levelFilter" multiple clearable collapse-tags placeholder="请选择级别">
/> <el-option v-for="item in rankOptions" :key="item.value" :label="item.label"
:value="item.value"></el-option>
</el-select>
</el-form-item> </el-form-item>
</template> </template>
</TableHeader> </TableHeader>
@@ -25,8 +27,44 @@ import TableHeader from '@/components/table/header/index.vue'
defineOptions({ defineOptions({
name: 'govern/log/debug' name: 'govern/log/debug'
}) })
const rankOptions = ref([
// {
// value: '1',
// label: '1级'
// },
// {
// value: '2',
// label: '2级'
// },
// {
// value: '3',
// label: '3级'
// },
// {
// value: '3',
// label: '3级'
// },
{
value: '4',
label: 'DEBUG'
},
{
value: '5',
label: 'NORMAL'
},
{
value: '6',
label: 'WARN'
},
{
value: '7',
label: 'ERROR'
}
])
const levelFilter = ref<string[]>([])
const tableStore = new TableStore({ const tableStore = new TableStore({
url: '/cs-device-boot/process/queryPage', url: '/cs-harmonic-boot/event/getFrontDebugLogs',
method: 'POST', method: 'POST',
publicHeight: 65, publicHeight: 65,
column: [ column: [
@@ -38,36 +76,65 @@ const tableStore = new TableStore({
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1 return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
} }
}, },
{ title: '设备名称', field: 'devName', align: 'center' }, { title: '调试时间', field: 'startTime', align: 'center', sortable: true, width: 180 },
{ title: '操作用户', field: 'operatorName', align: 'center' }, { title: '设备名称', field: 'deviceName', align: 'center', width: 180 },
{ {
title: '操作内容', title: '监测点名称', field: 'lineName', align: 'center', width: 180, formatter: (row: any) => {
field: 'process', return row.cellValue ? row.cellValue : '/'
align: 'center',
formatter: (row: any) => {
return row.cellValue == 1
? '设备登记'
: row.cellValue == 2
? '功能调试'
: row.cellValue == 3
? '出厂调试'
: row.cellValue == 4
? '设备投运'
: ''
} }
}, },
{ title: '开始时间', field: 'startTime', align: 'center', sortable: true },
// { title: '操作用户', field: 'operatorName', align: 'center' },
{ {
title: '结束时间', title: '调试内容',
field: 'endTime', field: 'event',
align: 'center', align: 'center',
sortable: true, minWidth: 250,
formatter: (row: any) => {
return row.cellValue || '/' },
{
title: '级别',
field: 'level',
width: 110,
render: 'tag',
custom: {
// 1:Ⅰ级 2:Ⅱ级 3:Ⅲ级 4:DEBUG 5:NORMAL 6:WARN 7:ERROR
// 1: 'danger',
// 2: 'warning',
// 3: 'success',
4: 'success',
5: 'success',
6: 'warning',
7: 'danger'
},
replaceValue: {
// 1: '1级',
// 2: '2级',
// 3: '3级',
4: 'DEBUG',
5: 'NORMAL',
6: 'WARN',
7: 'ERROR'
} }
} }
// {
// title: '结束时间',
// field: 'endTime',
// align: 'center',
// sortable: true,
// formatter: (row: any) => {
// return row.cellValue || '/'
// }
// }
], ],
beforeSearchFun: () => {
tableStore.table.params.level = levelFilter.value.length ? levelFilter.value.join(',') : ''
},
resetCallback: () => {
levelFilter.value = []
},
loadCallback: () => { loadCallback: () => {
tableStore.table.data.forEach((item: any) => { tableStore.table.data.forEach((item: any) => {
item.result = item.result === 1 ? '成功' : '失败' item.result = item.result === 1 ? '成功' : '失败'
@@ -88,6 +155,6 @@ tableStore.table.params.searchValue = ''
onMounted(() => { onMounted(() => {
tableStore.index() tableStore.index()
}) })
tableStore.table.params.level = ''
const addMenu = () => {} const addMenu = () => { }
</script> </script>

View File

@@ -1,10 +1,10 @@
<template> <template>
<div class="default-main apf"> <div class="default-main apf">
<el-tabs type="border-card" v-model="activeName"> <el-tabs type="border-card" v-model="activeName">
<el-tab-pane label="治理交互日志" name="1"> <el-tab-pane label="治理设备" name="1">
<governance v-if="activeName == '1'" /> <governance v-if="activeName == '1'" />
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="前置交互日志" name="2"> <el-tab-pane label="前置" name="2">
<front v-if="activeName == '2'" /> <front v-if="activeName == '2'" />
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>

View File

@@ -15,7 +15,7 @@ defineOptions({
name: 'govern/log/operation' name: 'govern/log/operation'
}) })
const tableStore = new TableStore({ const tableStore = new TableStore({
url: '/cs-device-boot/cslog/queryLog', url: '/cs-system-boot/cslog/queryLog',
method: 'POST', method: 'POST',
column: [ column: [
{ {
@@ -26,10 +26,27 @@ const tableStore = new TableStore({
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1 return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
} }
}, },
{ title: '操作日期', field: 'createTime', align: 'center', sortable: true, minWidth: '150' }, { title: '操作日期', field: 'createTime', align: 'center', sortable: true, width: '180' },
{ title: '用户名称', field: 'userName', align: 'center', width: '180' },
{ title: '操作描述', field: 'operate', align: 'center', minWidth: '300' }, { title: '操作描述', field: 'operate', align: 'center', minWidth: '300' },
{ title: '用户名称', field: 'userName', align: 'center', minWidth: '130' },
{ title: '更新时间', field: 'updateTime', align: 'center', sortable: true, minWidth: '150' }, {
title: '状态',
field: 'result',
align: 'center',
width: '100',
render: 'tag',
custom: {
0: 'danger',
1: 'success',
null:'info'
},
replaceValue: {
0: '失败',
1: '成功',
null: '/'
}
},
{ {
title: '失败原因', title: '失败原因',
field: 'failReason', field: 'failReason',
@@ -39,24 +56,15 @@ const tableStore = new TableStore({
return row.cellValue || '/' return row.cellValue || '/'
} }
}, },
{ // {
title: '状态', // title: '登录名称',
field: 'result', // field: 'loginName',
align: 'center', // align: 'center',
minWidth: '100', // minWidth: '120',
formatter: (row: any) => { // formatter: (row: any) => {
return row.cellValue == 1 ? '成功' : '失败' // return row.cellValue || '/'
} // }
}, // }
{
title: '登录名',
field: 'loginName',
align: 'center',
minWidth: '120',
formatter: (row: any) => {
return row.cellValue || '/'
}
}
], ],
loadCallback: () => { loadCallback: () => {
@@ -76,5 +84,5 @@ onMounted(() => {
tableStore.index() tableStore.index()
}) })
const addMenu = () => {} const addMenu = () => { }
</script> </script>

View File

@@ -22,13 +22,13 @@
:value="item.value"></el-option> :value="item.value"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="治理类型" class="top"> <el-form-item label="治理类型" class="top">
<el-select v-model.trim="form.governType" filterable placeholder="请选择治理类型" clearable> <el-select v-model.trim="form.governType" filterable placeholder="请选择治理类型" clearable>
<el-option label="暂态" value="event"></el-option> <el-option label="暂态" value="event"></el-option>
<el-option label="稳态" value="harmonic"></el-option> <el-option label="稳态" value="harmonic"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="敏感用户"class="top"> <el-form-item label="敏感用户" class="top">
<div style="display: flex;"> <div style="display: flex;">
<el-select v-model.trim="form.monitorUser" style="width: 230px;" filterable placeholder="请选择敏感用户" <el-select v-model.trim="form.monitorUser" style="width: 230px;" filterable placeholder="请选择敏感用户"
clearable> clearable>
@@ -38,7 +38,7 @@
<el-button type="primary" icon="el-icon-Plus" class="ml10" @click="addMonitorUser" /> <el-button type="primary" icon="el-icon-Plus" class="ml10" @click="addMonitorUser" />
</div> </div>
</el-form-item> </el-form-item>
<el-form-item label="治理方法" class="top"> <el-form-item label="治理方法" class="top">
<el-input maxlength="32" show-word-limit v-model="form.governMethod" autocomplete="off" clearable <el-input maxlength="32" show-word-limit v-model="form.governMethod" autocomplete="off" clearable
placeholder="例: 250A APF 或 100kVar SVG"></el-input> placeholder="例: 250A APF 或 100kVar SVG"></el-input>
</el-form-item> </el-form-item>
@@ -48,9 +48,12 @@
<el-option label="CLD" value="CLD"></el-option> <el-option label="CLD" value="CLD"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="关联项目" class="top"> <el-form-item label="关联项目" class="top" prop="association" :required="isMonitorDeviceType">
<el-cascader v-model.trim="form.association" filterable :options="engineeringList" <div style="display: flex;">
:props="cascaderProps" clearable placeholder="请选择关联项目" /> <el-cascader v-model.trim="form.association" filterable :options="engineeringList"
:props="cascaderProps" clearable placeholder="请选择关联项目" />
<el-button type="primary" icon="el-icon-Plus" class="ml10" @click="addProject" />
</div>
</el-form-item> </el-form-item>
<el-form-item label="排序" class="top" prop="sort"> <el-form-item label="排序" class="top" prop="sort">
<el-input-number v-model.trim="form.sort" style="width: 100%;" :min="0" /> <el-input-number v-model.trim="form.sort" style="width: 100%;" :min="0" />
@@ -105,9 +108,40 @@ const rules = reactive({
devModel: [{ required: true, message: '请选择设备型号', trigger: 'change' }], devModel: [{ required: true, message: '请选择设备型号', trigger: 'change' }],
devAccessMethod: [{ required: true, message: '请输入接入方式', trigger: 'blur' }], devAccessMethod: [{ required: true, message: '请输入接入方式', trigger: 'blur' }],
cntractNo: [{ required: true, message: '请输入合同号', trigger: 'blur' }], cntractNo: [{ required: true, message: '请输入合同号', trigger: 'blur' }],
sort: [{ required: true, message: '请输入排序', trigger: 'blur' }] sort: [{ required: true, message: '请输入排序', trigger: 'blur' }],
association: [{
validator: (_rule: any, value: any, callback: (error?: Error) => void) => {
if (isMonitorDevType(form.devType)) {
if (!Array.isArray(value) || value.length < 2 || !value[0] || !value[1]) {
callback(new Error('请选择关联项目'))
return
}
}
callback()
},
trigger: 'change'
}]
}) })
const getDevTypeOptions = () => {
if (form.devAccessMethod === 'CLD') {
return Array.isArray(props.devTypeOptions2)
? props.devTypeOptions2
: props.devTypeOptions2
? [props.devTypeOptions2]
: []
}
return props.devTypeOptions
}
const isMonitorDevType = (devType: unknown) => {
if (!devType) return false
const selected = getDevTypeOptions().find((item: any) => (item.value || item.id) == devType)
return selected?.name === '监测设备' || selected?.label === '监测设备' || selected?.code === 'DEV_CLD'
}
const isMonitorDeviceType = computed(() => isMonitorDevType(form.devType))
function getDefaultForm() { function getDefaultForm() {
return { return {
cntractNo: '', cntractNo: '',
@@ -170,6 +204,12 @@ const formDevTypeOptions = computed(() => {
const formDevTypeChange = (e: any) => { const formDevTypeChange = (e: any) => {
if (!e) return if (!e) return
form.devModel = '' form.devModel = ''
nextTick(() => {
ruleFormRef.value?.clearValidate('association')
if (isMonitorDevType(e)) {
ruleFormRef.value?.validateField('association')
}
})
} }
const openAdd = () => { const openAdd = () => {
@@ -219,6 +259,12 @@ const addMonitorUser = () => {
name: 'govern/sensitiveLoadMange/index', name: 'govern/sensitiveLoadMange/index',
}) })
} }
const addProject = () => {
sessionStorage.setItem('factoryNeedRefreshEngineeringList', '1')
router.push({
name: 'govern/manage/engineering',
})
}
const onSubmit = () => { const onSubmit = () => {
ruleFormRef.value.validate((valid: boolean) => { ruleFormRef.value.validate((valid: boolean) => {
if (!valid) return if (!valid) return

View File

@@ -1,5 +1,5 @@
<template> <template>
<div class="default-main" v-loading="loading"> <div v-loading="loading">
<TableHeader> <TableHeader>
<template v-slot:select> <template v-slot:select>
<el-form-item label="关键字筛选"> <el-form-item label="关键字筛选">
@@ -214,6 +214,7 @@ const tableStore = new TableStore({
url: '/cs-device-boot/EquipmentDelivery/list', url: '/cs-device-boot/EquipmentDelivery/list',
method: 'POST', method: 'POST',
isWebPaging: true, isWebPaging: true,
publicHeight: 60,
column: [ column: [
{ {
width: '60', width: '60',
@@ -837,20 +838,8 @@ const getUserList = () => {
}) })
} }
// 页面被 keep-alive 缓存后,从敏感用户页返回时刷新下拉列表 const getEngineeringList = () => {
onActivated(() => { return engineeringProject().then(res => {
if (sessionStorage.getItem('factoryNeedRefreshUserList')) {
sessionStorage.removeItem('factoryNeedRefreshUserList')
getUserList()
}
})
provide('tableStore', tableStore)
onMounted(() => {
getUserList()
queryTheDictionary()
engineeringProject().then(res => {
engineeringList.value = res.data.filter(item => { engineeringList.value = res.data.filter(item => {
item.projectName = item.engineeringName item.projectName = item.engineeringName
item.projectId = item.engineeringId item.projectId = item.engineeringId
@@ -858,6 +847,27 @@ onMounted(() => {
return item return item
}) })
}) })
}
// 页面被 keep-alive 缓存后,从敏感用户/工程页返回时刷新下拉列表
onActivated(() => {
// if (sessionStorage.getItem('factoryNeedRefreshUserList')) {
// sessionStorage.removeItem('factoryNeedRefreshUserList')
getUserList()
// }
// if (sessionStorage.getItem('factoryNeedRefreshEngineeringList')) {
// sessionStorage.removeItem('factoryNeedRefreshEngineeringList')
getEngineeringList()
// }
})
provide('tableStore', tableStore)
onMounted(() => {
queryTheDictionary()
// getUserList()
// getEngineeringList()
setTimeout(() => { }, 100) setTimeout(() => { }, 100)
}) })

View File

@@ -30,6 +30,7 @@ import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue' import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue' import TableHeader from '@/components/table/header/index.vue'
import { queryByCode, queryByid, queryCsDictTree } from '@/api/system-boot/dictTree' import { queryByCode, queryByid, queryCsDictTree } from '@/api/system-boot/dictTree'
import { buildExportBaseName } from '@/utils/echartMethod'
defineOptions({ defineOptions({
name: 'manage/monthly' name: 'manage/monthly'
}) })
@@ -180,7 +181,7 @@ tableStore.table.params.name = ''
const tableRef = ref() const tableRef = ref()
const exportTab = () => { const exportTab = () => {
tableRef.value.getRef()?.exportData({ tableRef.value.getRef()?.exportData({
filename: '半月报功能', // 文件名字 filename: buildExportBaseName({ feature: '半月报功能' }), // 文件名字
sheetName: 'Sheet1', sheetName: 'Sheet1',
type: 'xlsx', //导出文件类型 xlsx 和 csv type: 'xlsx', //导出文件类型 xlsx 和 csv
useStyle: true, useStyle: true,

View File

@@ -140,6 +140,7 @@ import { genFileId, ElMessage, ElNotification } from 'element-plus'
import type { UploadProps, UploadUserFile } from 'element-plus' import type { UploadProps, UploadUserFile } from 'element-plus'
import pointTree from '@/components/tree/govern/pointTree.vue' import pointTree from '@/components/tree/govern/pointTree.vue'
import { getLineExport } from '@/api/harmonic-boot/cockpit/cockpit' import { getLineExport } from '@/api/harmonic-boot/cockpit/cockpit'
import { buildExportFileName } from '@/utils/echartMethod'
import { isReportMonitorPoint } from '@/components/tree/govern/lineTreeUtils' import { isReportMonitorPoint } from '@/components/tree/govern/lineTreeUtils'
defineOptions({ defineOptions({
name: 'TransientReport/monitoringpointReport' name: 'TransientReport/monitoringpointReport'
@@ -216,12 +217,6 @@ const exportEvent = () => {
ElMessage('生成报告中,请稍等!') ElMessage('生成报告中,请稍等!')
const now = new Date() const now = new Date()
const year = now.getFullYear() // 4位年份
const month = now.getMonth() + 1 // 月份0-11需+1
const day = now.getDate() // 日期1-31
// 格式化YYYY - MM - DD补零
const formattedDate = `${year}${String(month).padStart(2, '0')}${String(day).padStart(2, '0')}`
getLineExport(formd.value) getLineExport(formd.value)
.then(async (res: any) => { .then(async (res: any) => {
if (res == undefined) { if (res == undefined) {
@@ -236,7 +231,12 @@ const exportEvent = () => {
const url = window.URL.createObjectURL(blob) const url = window.URL.createObjectURL(blob)
const link = document.createElement('a') // 创建a标签 const link = document.createElement('a') // 创建a标签
link.href = url link.href = url
link.download = dotList.value.name + formattedDate // 设置下载的文件名 link.download = buildExportFileName({
subject: dotList.value.name,
feature: '报告',
date: formd.value.searchEndTime || now,
ext: 'docx'
})
document.body.appendChild(link) document.body.appendChild(link)
link.click() //执行下载 link.click() //执行下载
document.body.removeChild(link) document.body.removeChild(link)

View File

@@ -113,7 +113,14 @@ const handleNodeClick = (data: any, node: any) => {
} }
const exportEvent = () => { const exportEvent = () => {
exportLuckysheetFile('统计报表下载', tableStore.table.data.length > 0) exportLuckysheetFile(
{
subject: dotList.value?.name,
feature: '统计报表',
date: TableHeaderRef.value?.datePickerRef?.timeValue?.[1]
},
tableStore.table.data.length > 0
)
} }
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@@ -61,6 +61,7 @@ import TableStore from '@/utils/tableStore'
import TableHeader from '@/components/table/header/index.vue' import TableHeader from '@/components/table/header/index.vue'
import { ElMessage, ElNotification } from 'element-plus' import { ElMessage, ElNotification } from 'element-plus'
import { exportModel } from '@/api/cs-harmonic-boot/datatrend' import { exportModel } from '@/api/cs-harmonic-boot/datatrend'
import { buildExportFileName } from '@/utils/echartMethod'
import { isReportMonitorPoint } from '@/components/tree/govern/lineTreeUtils' import { isReportMonitorPoint } from '@/components/tree/govern/lineTreeUtils'
defineOptions({ defineOptions({
@@ -153,7 +154,6 @@ const exportEvent = () => {
ElMessage('生成报告中...') ElMessage('生成报告中...')
const now = new Date() const now = new Date()
const formattedDate = `${now.getFullYear()}${String(now.getMonth() + 1).padStart(2, '0')}${String(now.getDate()).padStart(2, '0')}`
exportModel(form) exportModel(form)
.then((res: any) => { .then((res: any) => {
@@ -164,7 +164,12 @@ const exportEvent = () => {
const url = window.URL.createObjectURL(blob) const url = window.URL.createObjectURL(blob)
const link = document.createElement('a') const link = document.createElement('a')
link.href = url link.href = url
link.download = props.dotList.name + formattedDate link.download = buildExportFileName({
subject: props.dotList.name,
feature: '报告',
date: tableHeaderRef.value?.datePickerRef?.timeValue?.[1] || now,
ext: 'docx'
})
document.body.appendChild(link) document.body.appendChild(link)
link.click() link.click()
document.body.removeChild(link) document.body.removeChild(link)

View File

@@ -110,11 +110,14 @@ const exportEvent = () => {
return ElMessage.warning('治理监测点暂不支持出报表!') return ElMessage.warning('治理监测点暂不支持出报表!')
} }
const now = new Date() const now = new Date()
const year = now.getFullYear() exportLuckysheetFile(
const month = now.getMonth() + 1 {
const day = now.getDate() subject: exportName.value,
const formattedDate = `${year}${String(month).padStart(2, '0')}${String(day).padStart(2, '0')}` feature: '统计报表',
exportLuckysheetFile(exportName.value + formattedDate, tableStore.table.data.length > 0) date: tableHeaderRef.value?.datePickerRef?.timeValue?.[1] || now
},
tableStore.table.data.length > 0
)
} }
watch( watch(

View File

@@ -122,14 +122,15 @@ const handleNodeClick = (data: any, node: any) => {
} }
const exportEvent = () => { const exportEvent = () => {
const now = new Date() const now = new Date()
const year = now.getFullYear() // 4位年份 exportLuckysheetFile(
const month = now.getMonth() + 1 // 月份0-11需+1 {
const day = now.getDate() // 日期1-31 subject: name.value,
feature: '统计报表',
// 格式化YYYY - MM - DD补零 date: datePickerRef.value?.timeValue?.[1] || now
const formattedDate = `${year}${String(month).padStart(2, '0')}${String(day).padStart(2, '0')}` },
exportLuckysheetFile(name.value + formattedDate, tableStore.table.data.length > 0) tableStore.table.data.length > 0
)
} }
onUnmounted(() => { onUnmounted(() => {
destroyLuckysheet() destroyLuckysheet()

View File

@@ -1,13 +1,7 @@
<template> <template>
<div class="statistics-wx-zl default-main" :style="height"> <div class="statistics-wx-zl default-main" :style="height">
<aside> <aside>
<!-- <CloudDeviceEntryTree <APFTree @node-click="handleNodeClick" template @init="handleNodeClick" @Policy="stencil"></APFTree>
ref="TerminalRef"
template
@Policy="stencil"
@init="handleNodeClick"
/> -->
<APFTree @node-click="handleNodeClick" template @init="handleNodeClick" @Policy="stencil"></APFTree>
</aside> </aside>
<main class="statistics-wx-zl__main "> <main class="statistics-wx-zl__main ">
<TableHeader datePicker ref="TableHeaderRef" :showReset="false"> <TableHeader datePicker ref="TableHeaderRef" :showReset="false">
@@ -33,25 +27,26 @@
</template> </template>
</TableHeader> </TableHeader>
<div class="statistics-wx-zl__sheet-box pl0" v-loading="tableStore.table.loading"> <div class="statistics-wx-zl__sheet-box pl0" v-loading="tableStore.table.loading">
<div <div class="statistics-wx-zl__sheet-wrap">
v-if="tableStore.table.data.length > 0" <div id="luckysheet" class="statistics-wx-zl__sheet"></div>
id="luckysheet" <el-empty
class="statistics-wx-zl__sheet" v-show="!tableStore.table.loading && tableStore.table.data.length === 0"
/> class="statistics-wx-zl__empty"
<el-empty v-else class="statistics-wx-zl__empty" description="暂无数据" /> description="暂无数据"
/>
</div>
</div> </div>
</main> </main>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, ref, provide, nextTick } from 'vue' import { onMounted, onUnmounted, ref, provide, nextTick } from 'vue'
import TableStore from '@/utils/tableStore' import TableStore from '@/utils/tableStore'
import TableHeader from '@/components/table/header/index.vue' import TableHeader from '@/components/table/header/index.vue'
import APFTree from '@/components/tree/govern/APFTree.vue' import APFTree from '@/components/tree/govern/APFTree.vue'
import { mainHeight } from '@/utils/layout' import { mainHeight } from '@/utils/layout'
import { exportExcel } from '@/views/system/reportForms/export.js' import { destroyLuckysheet, exportLuckysheetFile, renderLuckysheetReport } from '@/utils/luckysheetHelper'
import CloudDeviceEntryTree from '@/components/tree/govern/cloudDeviceEntryTreeZL.vue'
import { getListByIds } from '@/api/harmonic-boot/cockpit/cockpit' import { getListByIds } from '@/api/harmonic-boot/cockpit/cockpit'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
@@ -72,31 +67,30 @@ const tableStore = new TableStore({
url: '/cs-harmonic-boot/customReport/getSensitiveUserReport', url: '/cs-harmonic-boot/customReport/getSensitiveUserReport',
method: 'POST', method: 'POST',
column: [], column: [],
showPage: false,
beforeSearchFun: () => { beforeSearchFun: () => {
tableStore.table.params.tempId = Template.value.id tableStore.table.params.tempId = Template.value.id
tableStore.table.params.lineId = dotList.value.id tableStore.table.params.lineId = dotList.value.id
tableStore.table.params.sensitiveUserId = dotList.value.id tableStore.table.params.sensitiveUserId = dotList.value.id
if (!tableStore.table.params.tempId) { if (!tableStore.table.params.tempId) {
return ElMessage.warning('请选择模板') ElMessage.warning('请选择模板')
return false
} }
delete tableStore.table.params.searchBeginTime const datePicker = TableHeaderRef.value?.datePickerRef
delete tableStore.table.params.searchEndTime if (datePicker?.timeValue?.[0] && datePicker?.timeValue?.[1]) {
tableStore.table.params.searchBeginTime = datePicker.timeValue[0]
tableStore.table.params.searchEndTime = datePicker.timeValue[1]
}
destroyLuckysheet()
delete tableStore.table.params.timeFlag delete tableStore.table.params.timeFlag
}, },
loadCallback: () => { loadCallback: () => {
name.value = dotList.value.name name.value = dotList.value.name
setTimeout(() => { if (tableStore.table.data.length > 0) {
luckysheet.create({ renderLuckysheetReport('luckysheet', tableStore.table.data, { allowEdit: false })
container: 'luckysheet', } else {
title: '', destroyLuckysheet()
lang: 'zh', }
showtoolbar: false,
showinfobar: false,
showsheetbar: true,
allowEdit: false,
data: tableStore.table.data
})
}, 10)
} }
}) })
@@ -108,6 +102,10 @@ onMounted(() => {
initListByIds() initListByIds()
}) })
onUnmounted(() => {
destroyLuckysheet()
})
function initListByIds() { function initListByIds() {
getListByIds({}).then((res: any) => { getListByIds({}).then((res: any) => {
if (res.data?.length > 0) { if (res.data?.length > 0) {
@@ -130,7 +128,7 @@ const changetype = (val: any) => {
} }
const handleNodeClick = (data: any) => { const handleNodeClick = (data: any) => {
if (data?.level == 3||data?.level == 2) { if (data?.level == 3 || data?.level == 2) {
dotList.value = data dotList.value = data
nextTick(() => tableStore.index()) nextTick(() => tableStore.index())
} else { } else {
@@ -139,13 +137,13 @@ const handleNodeClick = (data: any) => {
} }
const exportEvent = () => { const exportEvent = () => {
const now = new Date() exportLuckysheetFile(
const formattedDate = [ {
now.getFullYear(), subject: dotList.value?.name || name.value,
String(now.getMonth() + 1).padStart(2, '0'), feature: '统计报表'
String(now.getDate()).padStart(2, '0') },
].join('') tableStore.table.data.length > 0
exportExcel(luckysheet.getAllSheets(), name.value + formattedDate) )
} }
</script> </script>
@@ -196,6 +194,13 @@ const exportEvent = () => {
box-sizing: border-box; box-sizing: border-box;
} }
&__sheet-wrap {
flex: 1;
min-height: 0;
position: relative;
height: 100%;
}
&__sheet, &__sheet,
&__empty { &__empty {
height: 100%; height: 100%;
@@ -207,6 +212,8 @@ const exportEvent = () => {
} }
&__empty { &__empty {
position: absolute;
inset: 0;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;

View File

@@ -4,8 +4,8 @@
<el-form-item label="所属厂站名称" prop="substationName"> <el-form-item label="所属厂站名称" prop="substationName">
<el-input maxlength="32" show-word-limit v-model.trim="form.substationName" placeholder="请输入所属厂站名称"></el-input> <el-input maxlength="32" show-word-limit v-model.trim="form.substationName" placeholder="请输入所属厂站名称"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="敏感用户名称" prop="name"> <el-form-item label="用户名称" prop="name">
<el-input maxlength="32" show-word-limit v-model.trim="form.name" placeholder="请输入敏感用户名称"></el-input> <el-input maxlength="32" show-word-limit v-model.trim="form.name" placeholder="请输入用户名称"></el-input>
</el-form-item> </el-form-item>
<el-form-item label="敏感负荷类型" prop="loadType"> <el-form-item label="敏感负荷类型" prop="loadType">
<el-select v-model.trim="form.loadType" filterable clearable placeholder="请选择敏感负荷类型"> <el-select v-model.trim="form.loadType" filterable clearable placeholder="请选择敏感负荷类型">
@@ -64,7 +64,7 @@ const form = reactive<any>({
}) })
const rules = { const rules = {
substationName: [{ required: true, message: '请输入所属厂站名称', trigger: 'blur' }], substationName: [{ required: true, message: '请输入所属厂站名称', trigger: 'blur' }],
name: [{ required: true, message: '请输入敏感用户名称', trigger: 'blur' }], name: [{ required: true, message: '请输入用户名称', trigger: 'blur' }],
loadType: [{ required: true, message: '请输入请选择敏感负荷类型', trigger: 'blur' }], loadType: [{ required: true, message: '请输入请选择敏感负荷类型', trigger: 'blur' }],
installedCapacity: [{ required: true, message: '请输入用户协议容量', trigger: 'blur' }], installedCapacity: [{ required: true, message: '请输入用户协议容量', trigger: 'blur' }],
userAgreementCapacity: [{ required: true, message: '请输入装机容量', trigger: 'blur' }], userAgreementCapacity: [{ required: true, message: '请输入装机容量', trigger: 'blur' }],

View File

@@ -9,7 +9,7 @@
style="width: 240px" style="width: 240px"
v-model.trim="tableStore.table.params.searchValue" v-model.trim="tableStore.table.params.searchValue"
clearable clearable
placeholder="请输入敏感用户名称" placeholder="请输入用户名称"
/> />
</el-form-item> </el-form-item>
</template> </template>
@@ -51,7 +51,7 @@ const tableStore: any = new TableStore({
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1 return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
} }
}, },
{ title: '敏感用户名称', field: 'name', minWidth: 180 }, { title: '用户名称', field: 'name', minWidth: 180 },
{ {
title: '敏感用户类型', title: '敏感用户类型',
field: 'loadType', field: 'loadType',

File diff suppressed because one or more lines are too long