Files
admin-sjzx/src/views/pqs/harmonicMonitoring/area/getIntegrityData/index.vue
2025-12-24 11:19:41 +08:00

541 lines
19 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="default-main online">
<div class="online_header">
<TableHeader date-picker ref="tableHeaderRef">
<template #select>
<el-form-item label="统计类型:">
<el-select v-model="formData.statisticalType" placeholder="请选择统计类型" value-key="id"
style="width: 100%">
<el-option v-for="item in classificationData" :key="item.id" :label="item.name"
:value="item"></el-option>
</el-select>
</el-form-item>
<el-form-item label="区域选择:">
<!-- <el-select ref="select1" v-model="deptName" placeholder="请选择所属部门区域" style="width: 100%">
<el-option :value="formData.deptIndex" style="height: auto"> -->
<!-- {{ formData.deptIndex }} -->
<el-cascader v-model="formData.deptIndex" :props="defaultProps" :options="treeData" filterable
collapse-tags placeholder="请选择区域" />
<!-- <el-tree
ref="tree"
v-model="formData.deptName"
:data="treeData"
node-key="id"
accordion
:default-expanded-keys="idArr"
:props="defaultProps"
@node-click="handleNodeClick"
>
<template #default="{ node, data }">
<span :title="data.name">{{ data?.name }}</span>
</template>
</el-tree> -->
<!-- </el-option>
</el-select> -->
</el-form-item>
<el-form-item label="电压等级:">
<el-select v-model="formData.scale" multiple collapse-tags clearable placeholder="请选择电压等级"
style="width: 100%" value-key="id">
<el-option v-for="item in voltageleveloption" :key="item.id" :label="item.name"
:value="item"></el-option>
</el-select>
</el-form-item>
<el-form-item label="终端厂家:">
<el-select v-model="formData.manufacturer" multiple collapse-tags clearable
placeholder="请选择终端厂家" style="width: 100%" value-key="id">
<el-option v-for="(item, index) in terminaloption" :key="index" :label="item.name"
:value="item"></el-option>
</el-select>
</el-form-item>
<el-form-item label="干扰源类型:">
<el-select v-model="formData.loadType" multiple collapse-tags clearable placeholder="请选择干扰源类型"
style="width: 100%" value-key="id">
<el-option v-for="(item, index) in interfereoption" :key="index" :label="item.name"
:value="item"></el-option>
</el-select>
</el-form-item>
</template>
<template #operation>
<el-button type="primary" icon="el-icon-Tickets" @click="makeUp" v-if="!VITE_FLAG">补招</el-button>
</template>
</TableHeader>
</div>
<div class="online_main">
<el-tabs v-model="activeName" type="border-card" @tab-click="handleClick">
<el-tab-pane :name="0" :lazy="true" label="数据完整性列表">
<Table ref="tableRef" :tree-config="{ transform: true, parentField: 'uPid', rowField: 'uId' }"
:checkbox-config="{ labelField: 'name', checkMethod: ({ row }) => true }"
:scroll-y="{ enabled: true }" v-if="activeName == 0" />
</el-tab-pane>
<el-tab-pane :name="1" :lazy="true" label="数据完整性图表">
<charts v-if="activeName == 1" ref="chartsRef" />
</el-tab-pane>
</el-tabs>
</div>
<el-dialog v-model="timePopUp" draggable title="补招" width="500">
补招时间:
<el-date-picker v-model="timeData" type="datetimerange" format="YYYY-MM-DD HH:mm:00"
value-format="YYYY-MM-DD HH:mm:00" range-separator="" date-format="YYYY-MM-DD" time-format="HH:mm:00"
start-placeholder="开始日期" end-placeholder="结束日期" style="width: 400px" :disabledDate="disabledDate" />
<template #footer>
<div class="dialog-footer">
<el-button @click="timePopUp = false">取消</el-button>
<el-button type="primary" @click="makeUpSubmit">确认</el-button>
</div>
</template>
</el-dialog>
<el-dialog v-model="logPopUp" draggable title="补招日志" width="800" @close="close">
<div class="logList" ref="logRef">
<p v-for="item in logList" :style="{
color: item.type === 'error' ? '#F56C6C' : ''
}">
<div style="width: 150px;"> {{ item.time }}</div>
<div style="flex: 1;">{{ item.name }}</div>
</p>
</div>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, watch, nextTick } from 'vue'
import { useDictData } from '@/stores/dictData'
import DatePicker from '@/components/form/datePicker/index.vue'
import { getAreaDept, FullRecall } from '@/api/harmonic-boot/area'
import TableHeader from '@/components/table/header/index.vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import charts from './components/charts.vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import socketClient from '@/utils/webSocketClient'
import { formatDate } from '@/utils/formatTime'
import { useAdminInfo } from '@/stores/adminInfo'
const adminInfo = useAdminInfo()
defineOptions({
name: 'harmonic-boot/harmonic/getIntegrityData'
})
const VITE_FLAG = import.meta.env.VITE_NAME == 'hainan'
const logRef = ref()
const tableRef = ref()
const chartsRef = ref()
const dictData = useDictData()
const timePopUp = ref(false)
const logPopUp = ref(false)
//开始创建webSocket客户端
const dataSocket = reactive({
socketServe: socketClient.Instance
})
//字典获取电压等级
const voltageleveloption = dictData.getBasicData('Dev_Voltage_Stand')
//字典获取终端厂家
const terminaloption = dictData.getBasicData('Dev_Manufacturers')
//字典获取干扰源类型
const interfereoption = dictData.getBasicData('Interference_Source')
//字典获取统计类型
const classificationData = dictData.getBasicData('Statistical_Type', ['Report_Type'])
//调用区域接口获取区域
const treeData = ref([])
const idArr = ref([])
const timeData = ref([])
const logList: any = ref([])
const activeName = ref(0)
const getTreeData = async () => {
await getAreaDept().then(res => {
var data = res.data
data.forEach(element => {
idArr.value.push(element.id)
})
treeData.value = JSON.parse(JSON.stringify(res.data))
})
}
getTreeData()
const formData = ref({
statisticalType: classificationData[0], //统计类型
deptIndex: treeData.value[0]?.id, //区域选择
scale: voltageleveloption, //电压等级
manufacturer: terminaloption, //终端厂家
loadType: interfereoption //干扰源类型
// searchBeginTime: '',
// searchEndTime: ''
})
formData.value.deptIndex = treeData.value[0]?.id
const defaultProps = ref({
label: 'name',
value: 'id',
checkStrictly: true,
emitPath: false,
expandTrigger: 'click' as const
})
const handleClick = (tab: any, e: any) => {
// if(activeName.value===1){
tableStore.index()
// }
}
const tableHeaderRef = ref()
const tableStore = new TableStore({
publicHeight: 60,
showPage: false,
url: '/device-boot/LineIntegrityData/getLineIntegrityData',
method: 'POST',
column: [
{
title: formData.value.statisticalType.name,
field: 'name',
align: 'left',
type: 'checkbox',
treeNode: true,
width: 350,
formatter: function (row) {
return row.cellValue ? row.cellValue : '/'
}
},
{
title: '网络参数',
field: 'ip',
align: 'center',width:'120px',
formatter: function (row) {
return row.cellValue ? row.cellValue : '/'
}
},
{
title: '厂家',
field: 'manufacturer',
align: 'center',
formatter: function (row) {
return row.cellValue ? row.cellValue : '/'
}
},
{
title: '终端名称',
field: 'deviceName',
align: 'center',
formatter: function (row) {
return row.cellValue ? row.cellValue : '/'
}
},
{
title: '通讯状态',
field: 'comFlag',
align: 'center',
render: 'tag',
custom: {
null: 'primary',
0: 'danger',
1: 'success'
},
replaceValue: {
null: '/',
0: '中断',
1: '正常'
}
},
{
title: '最新数据时间',
field: 'updateTime',
align: 'center',
formatter: function (row) {
return row.cellValue ? row.cellValue : '/'
}
},
{
title: '完整性(%)',
field: 'integrityData',
align: 'center',
formatter: function (row) {
return row.cellValue == 3.14159 ? '暂无数据' : row.cellValue.toFixed(2)
}
},
{
title: '评估',
field: 'valueOver',
align: 'center',
render: 'tag',
custom: {
null: 'danger',
0: 'danger',
1: 'success',
2: 'primary',
3: 'danger'
},
replaceValue: {
null: '暂无评估',
0: '暂无评估',
1: '优秀',
2: '合格',
3: '不合格'
}
}
],
beforeSearchFun: () => {
tableStore.table.params.deptIndex = formData.value.deptIndex
tableStore.table.params.statisticalType = formData.value.statisticalType
tableStore.table.params.scale = formData.value.scale
tableStore.table.params.manufacturer = formData.value.manufacturer
tableStore.table.params.loadType = formData.value.loadType
tableStore.table.params.serverName = 'harmonicBoot'
delete tableStore.table.params.timeFlag
delete tableStore.table.params.startTime
delete tableStore.table.params.endTime
delete tableStore.table.params.pageNum
delete tableStore.table.params.pageSize
// tableStore.table.params.searchBeginTime = tableHeaderRef.value.datePickerRef.timeValue[0]
// tableStore.table.params.searchEndTime = tableHeaderRef.value.datePickerRef.timeValue[1]
},
loadCallback: () => {
tableStore.table.data = tree2List(tableStore.table.data, Math.random() * 1000)
tableStore.table.column[0].title = formData.value.statisticalType.name
chartsRef.value && chartsRef.value.getTableStoreParams(tableStore.table.params)
setTimeout(() => {
activeName.value == 0 && tableRef.value && tableRef.value.getRef().setAllTreeExpand(true)
}, 0)
},
resetCallback: () => {
// 重置表单数据到默认值
formData.value.statisticalType = classificationData[0]
formData.value.deptIndex = treeData.value[0]?.id
formData.value.scale = voltageleveloption
formData.value.manufacturer = terminaloption
formData.value.loadType = interfereoption
}
})
tableStore.table.params.deptIndex = ''
tableStore.table.params.filterName = ''
tableStore.table.params.statisticalType = []
tableStore.table.params.scale = []
tableStore.table.params.manufacturer = []
tableStore.table.params.loadType = []
provide('tableStore', tableStore)
const tree2List = (list: any, id?: string) => {
//存储结果的数组
let arr: any = []
// 遍历 tree 数组
list.forEach((item: any) => {
item.uPid = id
item.uId = Math.random() * 1000
item.valueOver =
item.integrityData == 3.14159
? 0
: item.integrityData >= 90
? 1
: item.integrityData >= 60 && item.integrityData < 90
? 2
: 3
// 判断item是否存在children
if (!item.children) return arr.push(item)
// 函数递归对children数组进行tree2List的转换
const children = tree2List(item.children, item.uId)
// 删除item的children属性
delete item.children
// 把item和children数组添加至结果数组
//..children: 意思是把children数组展开
arr.push(item, ...children)
})
// 返回结果数组
return arr
}
// 禁用超过当前日期的选择
const disabledDate = (date: Date) => {
return date > new Date() // 如果日期大于当前日期,则禁用
}
onMounted(() => { })
// 补招
const makeUp = () => {
// tableRef.value && tableRef.value.getRef().getCheckboxRecords()
let list =
tableRef.value
.getRef()
.getCheckboxRecords()
.find((item: any) => item.level == '6') || []
if (list.length == 0) {
return ElMessage({
message: '请选择监测点',
type: 'warning'
})
}
timeData.value = []
timePopUp.value = true
}
// 补招提交
const makeUpSubmit = () => {
if (timeData.value.length == 0) {
return ElMessage({
message: '请选择补招时间',
type: 'warning'
})
}
let form = {
monitorId: tableRef.value
.getRef()
.getCheckboxRecords()
.filter(item => item.level == 6)
.map(item => item.id),
reCallEndTime: timeData.value[1],
reCallStartTime: timeData.value[0]
}
socket(form)
timePopUp.value = false
logPopUp.value = true
}
const socket = async (form: any) => {
const url = (localStorage.getItem('WebSocketUrl2') || 'ws://192.168.1.67:10405/api/recell/')
logList.value = []
await dataSocket.socketServe.connect(`${url}${adminInfo.id}`)
await dataSocket.socketServe.send(form)
logList.value.push({
type: '',
time: formatDate(new Date(), 'YYYY-MM-DD hh:mm:ss'),
name: '开始补召,请稍等...',
})
await dataSocket.socketServe.registerCallBack('message', (res: any) => {
logList.value.push({
type: res.code == 500 ? 'error' : '',
time: formatDate(new Date(), 'YYYY-MM-DD hh:mm:ss'),
name: res.message
})
setTimeout(() => {
logRef.value && (logRef.value.scrollTop = (logRef.value.scrollHeight + 30))
}, 10)
})
}
const close = () => {
dataSocket.socketServe?.closeWs()
}
watch(
() => treeData.value,
(val, oldVal) => {
if (val && val.length != 0) {
formData.value.deptIndex = val[0].id
tableStore.index()
}
},
{
immediate: true,
deep: true
}
)
</script>
<style lang="scss" scoped>
// .online {
// width: 100%;
// height: 100%;
// .online_header {
// width: 100%;
// max-height: 140px;
// padding: 10px;
// box-sizing: border-box;
// }
// .online_main {
// padding: 0 10px;
// }
// }
// 修复VXE表格树表checkbox的样式问题
:deep(.vxe-table--main-wrapper) {
.vxe-table--body-wrapper {
.vxe-body--row {
.vxe-cell--checkbox {
.vxe-checkbox--icon {
color: var(--el-color-primary-light-3);
}
}
}
}
}
// 确保空数据状态下没有灰色遮罩层
:deep(.vxe-table--empty-block) {
background: transparent;
.vxe-table--empty-content {
color: #909399;
}
}
// 修复树表header的样式
:deep(.vxe-table--header-wrapper) {
.vxe-header--row {
.vxe-cell--checkbox {
.vxe-checkbox--icon {
color: var(--el-color-primary-light-3);
}
}
}
}
// 精确修复checkbox的disabled状态样式
:deep(.vxe-checkbox.is--disabled) {
.vxe-checkbox--icon {
color: var(--el-color-primary-light-3) !important;
}
}
// 确保树表节点没有灰色背景,但保留边框
:deep(.vxe-tree-cell) {
background: transparent;
}
// 精确修复空数据状态下的灰色背景
:deep(.vxe-table--empty-block) {
background: transparent;
}
// 修复checkbox在空数据状态下的样式
:deep(.vxe-table--body-wrapper:empty) {
.vxe-cell--checkbox {
background: transparent;
.vxe-checkbox--icon {
color: var(--el-color-primary-light-3);
}
}
}
// 专门修复checkbox和treeNode组合的样式问题
:deep(.vxe-cell--checkbox) {
background: transparent !important;
.vxe-checkbox--icon {
color: var(--el-color-primary-light-3) !important;
}
}
// 修复树表checkbox的特殊样式
:deep(.vxe-tree-cell .vxe-cell--checkbox) {
background: transparent !important;
.vxe-checkbox--icon {
color: var(--el-color-primary-light-3) !important;
}
}
// 确保checkbox在树表中的正确显示
:deep(.vxe-body--row .vxe-cell--checkbox) {
background: transparent !important;
.vxe-checkbox--icon {
color: var(--el-color-primary-light-3) !important;
}
}
.logList {
height: 300px;
overflow-y: auto;
p {
margin-bottom: 10px;
display: flex;
}
}
</style>