8 Commits

Author SHA1 Message Date
guanj
3ffb11defa 调整台账 2026-04-03 14:47:36 +08:00
guanj
0b9aafc1b5 联调文件管理页面 2026-04-02 09:08:57 +08:00
guanj
762965b1e4 联调设备文件 2026-03-30 09:03:53 +08:00
guanj
a30379ab01 绘制 运维版本管理页面 2026-03-19 11:29:26 +08:00
dk
9f1fbf93cd 新增实时运维页面 2026-03-18 21:06:48 +08:00
dk
b5fc946ce2 测试修改提交 2026-03-17 14:32:14 +08:00
guanj
1171d37a86 添加工程树 2026-03-06 09:36:42 +08:00
guanj
3fdb41c468 修改测试bug 2026-02-04 09:35:24 +08:00
72 changed files with 5070 additions and 3061 deletions

2
.gitignore vendored
View File

@@ -23,3 +23,5 @@ dist-ssr
*.sln *.sln
*.sw? *.sw?
pnpm-lock.yaml pnpm-lock.yaml
#test

View File

@@ -1,144 +1,152 @@
import createAxios from '@/utils/request' import createAxios from '@/utils/request'
// 装置基础数据和模板数据 // 设备基础数据和模板数据
export function getDeviceData(deviceId: string, type: string, lineId: string) { export function getDeviceData(deviceId: string, type: string, lineId: string) {
let form = new FormData() let form = new FormData()
form.append('deviceId', deviceId) form.append('deviceId', deviceId)
form.append('lineId', lineId) form.append('lineId', lineId)
form.append('type', type) form.append('type', type)
return createAxios({ return createAxios({
url: '/cs-device-boot/EquipmentDelivery/deviceData', url: '/cs-device-boot/EquipmentDelivery/deviceData',
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/x-www-form-urlencoded' 'Content-Type': 'application/x-www-form-urlencoded'
}, },
data: form data: form
}) })
} }
//获取趋势数据、暂态数据、实时数据 //获取趋势数据、暂态数据、实时数据
export function getTabsDataByType(data: any) { export function getTabsDataByType(data: any) {
return createAxios({ return createAxios({
url: '/cs-device-boot/csGroup/deviceDataByType', url: '/cs-device-boot/csGroup/deviceDataByType',
method: 'POST', method: 'POST',
data data
}) })
} }
/**** 获取基础实施数据 ****/ /**** 获取基础实施数据 ****/
export function getBasicRealData(id: any) { export function getBasicRealData(id: any) {
return createAxios({ return createAxios({
url: `/cs-harmonic-boot/realData/getBaseRealData?lineId=${id}`, url: `/cs-harmonic-boot/realData/getBaseRealData?lineId=${id}`,
method: 'POST' method: 'POST'
}) })
} }
/**** 获取谐波实时数据 ****/ /**** 获取谐波实时数据 ****/
export function getHarmRealData(id: any, target: any) { export function getHarmRealData(id: any, target: any) {
return createAxios({ return createAxios({
url: `/cs-harmonic-boot/realData/getHarmRealData?lineId=${id}&target=${target}`, url: `/cs-harmonic-boot/realData/getHarmRealData?lineId=${id}&target=${target}`,
method: 'POST' method: 'POST'
}) })
} }
/**** 获取国标限值 ****/ /**** 获取国标限值 ****/
export function getOverLimitData(id: any) { export function getOverLimitData(id: any) {
return createAxios({ return createAxios({
url: `/cs-device-boot/csline/getOverLimitData?id=${id}`, url: `/cs-device-boot/csline/getOverLimitData?id=${id}`,
method: 'POST' method: 'POST'
}) })
} }
//获取实时数据列表数据 //获取实时数据列表数据
export function getRealTimeTableList() { export function getRealTimeTableList() {
return createAxios({ return createAxios({
url: '/cs-device-boot/csGroup/getGroupPortableStatistical', url: '/cs-device-boot/csGroup/getGroupPortableStatistical',
method: 'GET' method: 'GET'
}) })
} }
//离线数据导入 //离线数据导入
export function uploadOffLineDataFile(data: any) { export function uploadOffLineDataFile(data: any) {
return createAxios({ return createAxios({
headers: { headers: {
'Content-Type': 'multipart/form-data' 'Content-Type': 'multipart/form-data'
}, },
url: '/cs-device-boot/portableOfflLog/importEquipment', url: '/cs-device-boot/portableOfflLog/importEquipment',
method: 'POST', method: 'POST',
data data
}) })
} }
//查询实时数据中实时趋势中指标分组 //查询实时数据中实时趋势中指标分组
export function getDeviceTrendDataGroup() { export function getDeviceTrendDataGroup() {
return createAxios({ return createAxios({
url: '/cs-device-boot/csGroup/getDeviceTrendDataGroup', url: '/cs-device-boot/csGroup/getDeviceTrendDataGroup',
method: 'GET' method: 'GET'
}) })
} }
//根据指标分组查询实时数据中实时趋势 //根据指标分组查询实时数据中实时趋势
export function getDeviceTrendData(query: any) { export function getDeviceTrendData(query: any) {
return createAxios({ return createAxios({
url: '/cs-device-boot/csGroup/getDeviceTrendData', url: '/cs-device-boot/csGroup/getDeviceTrendData',
method: 'GET', method: 'GET',
params: query params: query
}) })
} }
//查询实时数据-谐波频谱-稳态指标 //查询实时数据-谐波频谱-稳态指标
export function getGroupPortableStatistical() { export function getGroupPortableStatistical() {
return createAxios({ return createAxios({
url: '/cs-device-boot/csGroup/getGroupPortableStatistical', url: '/cs-device-boot/csGroup/getGroupPortableStatistical',
method: 'GET' method: 'GET'
}) })
} }
//查询实时数据-谐波频谱 //查询实时数据-谐波频谱
export function getDeviceHarmonicSpectrumData(data: any) { export function getDeviceHarmonicSpectrumData(data: any) {
return createAxios({ return createAxios({
url: '/cs-device-boot/csGroup/getDeviceHarmonicSpectrumData', url: '/cs-device-boot/csGroup/getDeviceHarmonicSpectrumData',
method: 'POST', method: 'POST',
data: data data: data
}) })
} }
//获取指标类型-谐波频谱 //获取指标类型-谐波频谱
export function queryDictType(data?: any) { export function queryDictType(data?: any) {
return createAxios({ return createAxios({
url: '/system-boot/dictTree/queryDictType', url: '/system-boot/dictTree/queryDictType',
method: 'GET', method: 'GET',
params: data params: data
}) })
} }
//根据监测点id获取监测点详情 //根据监测点id获取监测点详情
export function getById(data?: any) { export function getById(data?: any) {
return createAxios({ return createAxios({
url: '/cs-device-boot/csline/getById', url: '/cs-device-boot/csline/getById',
method: 'POST', method: 'POST',
params: data params: data
}) })
} }
//测试项日志修改 //测试项日志修改
export function updateRecordData(data?: any) { export function updateRecordData(data?: any) {
return createAxios({ return createAxios({
url: '/cs-device-boot/wlRecord/updateRecordData', url: '/cs-device-boot/wlRecord/updateRecordData',
method: 'POST', method: 'POST',
data data
}) })
} }
//模块数据 //模块数据
export function allModelData(data?: any) { export function allModelData(data?: any) {
return createAxios({ return createAxios({
url: '/cs-harmonic-boot/data/allModelData', url: '/cs-harmonic-boot/data/allModelData',
method: 'POST', method: 'POST',
data data
}) })
} }
//刷新状态 //刷新状态
export function getModuleState(data?: any) { export function getModuleState(data?: any) {
return createAxios({ return createAxios({
url: '/cs-harmonic-boot/data/getModuleState', url: '/cs-harmonic-boot/data/getModuleState',
method: 'POST', method: 'POST',
params: data params: data
}) })
} }
//获取运行取数
export function getRawData(data?: any) {
return createAxios({
url: '/cs-device-boot/pqsCommunicate/getRawData',
method: 'POST',
data
})
}

View File

@@ -1,4 +1,4 @@
import createAxios from "@/utils/request"; import createAxios from '@/utils/request'
//根据Id获取台账信息 //根据Id获取台账信息
export function getInfoById(id: any) { export function getInfoById(id: any) {
@@ -11,7 +11,6 @@ export function getInfoById(id: any) {
}) })
} }
//工程查询通过id获取 //工程查询通过id获取
export function getEngineerById(id: any) { export function getEngineerById(id: any) {
let form = new FormData() let form = new FormData()
@@ -23,7 +22,6 @@ export function getEngineerById(id: any) {
}) })
} }
//项目查询通过id获取 //项目查询通过id获取
export function getProjectById(id: any) { export function getProjectById(id: any) {
let form = new FormData() let form = new FormData()
@@ -53,7 +51,7 @@ export function getById(id: any) {
return createAxios({ return createAxios({
url: '/cs-device-boot/csline/getById', url: '/cs-device-boot/csline/getById',
method: 'POST', method: 'POST',
data: form data: form
}) })
} }
@@ -75,13 +73,15 @@ export function addLedger(data: any) {
} }
//修改-删除项目 //修改-删除项目
export function deleteProject(id: any,name:any,area:any,description:any,status:any) { export function deleteProject(id: any, name: any, area: any, description: any, status: any, sort: any, topoIds: any) {
let form = new FormData() let form = new FormData()
form.append('id', id) form.append('id', id)
form.append('name', name) form.append('name', name)
form.append('area', area) form.append('area', area)
form.append('description', description) form.append('description', description)
form.append('status', status) form.append('status', status)
form.append('sort', sort)
form.append('topoIds', topoIds)
return createAxios({ return createAxios({
url: '/cs-device-boot/project/auditAppProject', url: '/cs-device-boot/project/auditAppProject',
method: 'post', method: 'post',
@@ -105,7 +105,7 @@ export const deleteLine = (id: any) => {
let form = new FormData() let form = new FormData()
form.append('id', id) form.append('id', id)
return createAxios({ return createAxios({
url: '/cs-device-boot/csline/delCldLine', url: '/cs-device-boot/csline/delCldLine',
method: 'POST', method: 'POST',
data: form data: form
}) })
@@ -120,7 +120,6 @@ export function updateEquipment(data: any) {
}) })
} }
//修改监测点 //修改监测点
export function updateLine(data: any) { export function updateLine(data: any) {
return createAxios({ return createAxios({
@@ -134,8 +133,7 @@ export function updateLine(data: any) {
export function pushLog() { export function pushLog() {
return createAxios({ return createAxios({
url: '/cs-device-boot/csTerminalLogs/pushCldInfo', url: '/cs-device-boot/csTerminalLogs/pushCldInfo',
method: 'post', method: 'post'
}) })
} }
@@ -143,7 +141,6 @@ export function pushLog() {
export function queryPushResult() { export function queryPushResult() {
return createAxios({ return createAxios({
url: '/cs-device-boot/csTerminalReply/queryData', url: '/cs-device-boot/csTerminalReply/queryData',
method: 'post', method: 'post'
}) })
} }

View File

@@ -1,86 +1,86 @@
import createAxios from '@/utils/request' import createAxios from '@/utils/request'
// 查询分组 // 查询分组
export function getGroup(dataSet: string) { export function getGroup(dataSet: string) {
let form = new FormData() let form = new FormData()
form.append('dataSet', dataSet) form.append('dataSet', dataSet)
return createAxios({ return createAxios({
url: '/cs-device-boot/csGroup/getGroup', url: '/cs-device-boot/csGroup/getGroup',
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/x-www-form-urlencoded' 'Content-Type': 'application/x-www-form-urlencoded'
}, },
data: form data: form
}) })
} }
// 装置分组实时数据 // 设备分组实时数据
export function deviceHisData(data: any) { export function deviceHisData(data: any) {
return createAxios({ return createAxios({
url: '/cs-device-boot/csGroup/deviceHistoryData', url: '/cs-device-boot/csGroup/deviceHistoryData',
method: 'POST', method: 'POST',
data: Object.assign( data: Object.assign(
{ {
endTime: '', endTime: '',
id: '', id: '',
lineId: '', lineId: '',
pageNum: 1, pageNum: 1,
pageSize: 20, pageSize: 20,
startTime: '' startTime: ''
}, },
data data
) )
}) })
} }
// 装置分组历史数据 // 设备分组历史数据
export function deviceRtData(data: any) { export function deviceRtData(data: any) {
let form = new FormData() let form = new FormData()
form.append('id', data.id) form.append('id', data.id)
form.append('lineId', data.lineId) form.append('lineId', data.lineId)
form.append('pageNum', data.pageNum) form.append('pageNum', data.pageNum)
form.append('pageSize', data.pageSize) form.append('pageSize', data.pageSize)
form.append('searchValue', data.searchValue) form.append('searchValue', data.searchValue)
form.append('dataLevel', data.dataLevel) form.append('dataLevel', data.dataLevel)
return createAxios({ return createAxios({
url: '/cs-device-boot/csGroup/deviceRtData', url: '/cs-device-boot/csGroup/deviceRtData',
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/x-www-form-urlencoded' 'Content-Type': 'application/x-www-form-urlencoded'
}, },
data: form data: form
}) })
} }
// 装置分组历史数据 // 设备分组历史数据
export function realTimeData(data: any) { export function realTimeData(data: any) {
let form = new FormData() let form = new FormData()
form.append('id', data.id) form.append('id', data.id)
form.append('lineId', data.lineId) form.append('lineId', data.lineId)
form.append('pageNum', data.pageNum) form.append('pageNum', data.pageNum)
form.append('pageSize', data.pageSize) form.append('pageSize', data.pageSize)
form.append('searchValue', data.searchValue) form.append('searchValue', data.searchValue)
form.append('targetType', data.targetType) form.append('targetType', data.targetType)
form.append('dataLevel', data.dataLevel) form.append('dataLevel', data.dataLevel)
return createAxios({ return createAxios({
url: '/cs-harmonic-boot/data/realTimeData', url: '/cs-harmonic-boot/data/realTimeData',
method: 'POST', method: 'POST',
data data
}) })
} }
// 设备监控-》测试项数据 // 设备监控-》测试项数据
export function getTestData(data: any) { export function getTestData(data: any) {
return createAxios({ return createAxios({
url: '/cs-harmonic-boot/data/getTestData', url: '/cs-harmonic-boot/data/getTestData',
method: 'POST', method: 'POST',
data data
}) })
} }
// 设备监控-删除装置测试项 // 设备监控-删除设备测试项
export function deleteItem(data: any) { export function deleteItem(data: any) {
return createAxios({ return createAxios({
url: '/cs-device-boot/wlRecord/deleteItem', url: '/cs-device-boot/wlRecord/deleteItem',
method: 'POST', method: 'POST',
params: data params: data
}) })
} }

View File

@@ -1,18 +1,20 @@
import createAxios from '@/utils/request' import createAxios from '@/utils/request'
// 设备列表 // 设备列表
export function getDeviceTree() { export function getDeviceTree(params?: any) {
return createAxios({ return createAxios({
url: '/cs-device-boot/csLedger/deviceTree', url: '/cs-device-boot/csLedger/deviceTree',
method: 'POST' method: 'POST',
params
}) })
} }
// 监测点列表 // 监测点列表
export function getLineTree() { export function getLineTree(params?: any) {
return createAxios({ return createAxios({
url: '/cs-device-boot/csLedger/lineTree', url: '/cs-device-boot/csLedger/lineTree',
method: 'POST' method: 'POST',
params
}) })
} }
// 监测点列表治理 // 监测点列表治理

View File

@@ -79,4 +79,12 @@ export const addProject = (data: any) => {
data: data data: data
}) })
} }
// 修改项目
export const updateProjects = (data: any) => {
return request({
url: '/cs-device-boot/engineeringProjectRelation/updateProject',
method: 'post',
data: data
})
}

View File

@@ -1,93 +1,140 @@
import createAxios from '@/utils/request' import createAxios from '@/utils/request'
// 设备文件根目录查询 // 设备文件根目录查询
export function getDeviceRootPath(nDid) { export function getDeviceRootPath(nDid) {
return createAxios({ return createAxios({
url: '/cs-device-boot/deviceFile/askDeviceRootPath?nDid=' + nDid, url: '/cs-device-boot/deviceFile/askDeviceRootPath?nDid=' + nDid,
method: 'POST' method: 'POST'
}) })
} }
// 设备文件-目录信息询问 // 设备文件-目录信息询问
export function getFileServiceFileOrDir(data) { export function getFileServiceFileOrDir(data) {
return createAxios({ return createAxios({
url: `cs-device-boot/deviceFile/askDeviceFileOrDir?nDid=${data.nDid}&name=${data.name}&type=${data.type}`, url: `cs-device-boot/deviceFile/askDeviceFileOrDir?nDid=${data.nDid}&name=${data.name}&type=${data.type}`,
method: 'POST' method: 'POST'
}) })
} }
// 监测设备-目录信息询问
//设备文件下载 export function listDir(data) {
export function downLoadDeviceFile(data) { return createAxios({
return createAxios({ url: `/zl-event-boot/file/listDir`,
url: `/cs-device-boot/deviceFile/downloadFile?nDid=${data.nDid}&name=${data.name}&fileCheck=${data.fileCheck}&size=${data.size}`, method: 'POST',
method: 'POST' data: data
}) })
} }
// 下载文件
//获取下载文件的文件路径地址 export function downloadFileFromFrontr(data: any) {
export function downLoadDeviceFilePath(obj) { return createAxios({
let form = new FormData() url: `/zl-event-boot/file/downloadFileFromFront`,
form.append('name', obj.name) method: 'POST',
form.append('nDid', obj.nDid) data: data,
return createAxios({ responseType: 'blob'
url: `/cs-device-boot/deviceFile/getDownloadFilePath`, })
method: 'POST', }
headers: { // 删除文件
'Content-Type': 'application/x-www-form-urlencoded' export function deleteCld(data: any) {
}, return createAxios({
data: form url: `/zl-event-boot/file/delete`,
}) method: 'POST',
} data: data
//装置重启 })
export function reStartDevice(data) { }
return createAxios({ // 新建文件
url: `/cs-device-boot/EquipmentDelivery/rebootDevice?nDid=${data.nDid}`, export function mkdir(data: any) {
method: 'POST' return createAxios({
}) url: `/zl-event-boot/file/mkdir`,
} method: 'POST',
data: data
//上传文件至装置 })
export function uploadDeviceFile(data) { }
let form = new FormData() // 上传文件
form.append('file', data.file) export function uploadFileToFront(obj: any) {
form.append('filePath', data.filePath) let form = new FormData()
form.append('id', data.id) form.append('file', obj.file)
return createAxios({ form.append('devId', obj.devId)
url: `/access-boot/analyzeModel/uploadDevFile`, form.append('dirPath', obj.dirPath)
method: 'POST', return createAxios({
headers: { url: `/zl-event-boot/file/uploadFileToFront`,
'Content-Type': 'application/x-www-form-urlencoded' method: 'POST',
}, headers: {
data: form 'Content-Type': 'application/x-www-form-urlencoded'
}) },
} data: form
})
//新建文件夹目录 }
export function addDeviceDir(data) { //设备文件下载
let form = new FormData() export function downLoadDeviceFile(data) {
form.append('nDid', data.nDid) return createAxios({
form.append('path', data.path) url: `/cs-device-boot/deviceFile/downloadFile?nDid=${data.nDid}&name=${data.name}&fileCheck=${data.fileCheck}&size=${data.size}`,
return createAxios({ method: 'POST'
url: `/access-boot/askDeviceData/createFolder`, })
method: 'POST', }
headers: {
'Content-Type': 'application/x-www-form-urlencoded' //获取下载文件的文件路径地址
}, export function downLoadDeviceFilePath(obj) {
data: form let form = new FormData()
}) form.append('name', obj.name)
} form.append('nDid', obj.nDid)
return createAxios({
//删除文件/文件夹 url: `/cs-device-boot/deviceFile/getDownloadFilePath`,
export function delDeviceDir(data) { method: 'POST',
let form = new FormData() headers: {
form.append('nDid', data.nDid) 'Content-Type': 'application/x-www-form-urlencoded'
form.append('path', data.path) },
return createAxios({ data: form
url: `/access-boot/askDeviceData/deleteFolder`, })
method: 'POST', }
headers: { //设备重启
'Content-Type': 'application/x-www-form-urlencoded' export function reStartDevice(data) {
}, return createAxios({
data: form url: `/cs-device-boot/EquipmentDelivery/rebootDevice?nDid=${data.nDid}`,
}) method: 'POST'
} })
}
//上传文件至设备
export function uploadDeviceFile(data) {
let form = new FormData()
form.append('file', data.file)
form.append('filePath', data.filePath)
form.append('id', data.id)
return createAxios({
url: `/access-boot/analyzeModel/uploadDevFile`,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: form
})
}
//新建文件夹目录
export function addDeviceDir(data) {
let form = new FormData()
form.append('nDid', data.nDid)
form.append('path', data.path)
return createAxios({
url: `/access-boot/askDeviceData/createFolder`,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: form
})
}
//删除文件/文件夹
export function delDeviceDir(data) {
let form = new FormData()
form.append('nDid', data.nDid)
form.append('path', data.path)
return createAxios({
url: `/access-boot/askDeviceData/deleteFolder`,
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
},
data: form
})
}

View File

@@ -8,7 +8,7 @@ export function getMakeUpData(data: any) {
}) })
} }
//查询装置目录-文件 //查询设备目录-文件
export function getAskDirOrFile(data: any) { export function getAskDirOrFile(data: any) {
return createAxios({ return createAxios({
url: `/cs-harmonic-boot/offlineDataUpload/askDirOrFile?fileType=${data.fileType}&nDid=${data.nDid}&path=${data.path}&prjName=${data.prjName}`, url: `/cs-harmonic-boot/offlineDataUpload/askDirOrFile?fileType=${data.fileType}&nDid=${data.nDid}&path=${data.path}&prjName=${data.prjName}`,

View File

@@ -1,98 +1,105 @@
import createAxios from '@/utils/request' import createAxios from '@/utils/request'
// 新增出厂设备 // 新增出厂设备
export const addEquipmentDelivery = (data: any) => { export const addEquipmentDelivery = (data: any) => {
return createAxios({ return createAxios({
url: '/cs-device-boot/EquipmentDelivery/addEquipmentDelivery', url: '/cs-device-boot/EquipmentDelivery/addEquipmentDelivery',
method: 'POST', method: 'POST',
data: data data: data
}) })
} }
// 删除出厂设备 // 删除出厂设备
export const deleteEquipmentDelivery = (id: any) => { export const deleteEquipmentDelivery = (id: any) => {
let form = new FormData() let form = new FormData()
form.append('id', id) form.append('id', id)
return createAxios({ return createAxios({
url: '/cs-device-boot/EquipmentDelivery/AuditEquipmentDelivery', url: '/cs-device-boot/EquipmentDelivery/AuditEquipmentDelivery',
method: 'POST', method: 'POST',
data: form data: form
}) })
} }
// 恢复出厂设置 // 恢复出厂设置
export const resetEquipmentDelivery = (id: any) => { export const resetEquipmentDelivery = (id: any) => {
let form = new FormData() let form = new FormData()
form.append('nDid', id) form.append('nDid', id)
return createAxios({ return createAxios({
url: '/access-boot/device/resetFactory', url: '/access-boot/device/resetFactory',
method: 'POST', method: 'POST',
data: form data: form
}) })
} }
// 编辑出厂设备 // 编辑出厂设备
export const editEquipmentDelivery = (data: any) => { export const editEquipmentDelivery = (data: any) => {
return createAxios({ return createAxios({
url: '/cs-device-boot/EquipmentDelivery/updateEquipmentDelivery', url: '/cs-device-boot/EquipmentDelivery/updateEquipmentDelivery',
method: 'POST', method: 'POST',
data: data data: data
}) })
} }
// 上传拓扑图 // 上传拓扑图
export const uploadTopo = (file: any) => { export const uploadTopo = (file: any) => {
let form = new FormData() let form = new FormData()
form.append('file', file) form.append('file', file)
return createAxios({ return createAxios({
url: '/cs-device-boot/topologyTemplate/uploadImage', url: '/cs-device-boot/topologyTemplate/uploadImage',
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'multipart/form-data' 'Content-Type': 'multipart/form-data'
}, },
data: form data: form
}) })
} }
// 批量导入设备 // 批量导入设备
export const batchImportDevice = (file: any) => { export const batchImportDevice = (file: any) => {
let form = new FormData() let form = new FormData()
form.append('file', file) form.append('file', file)
return createAxios({ return createAxios({
url: '/cs-device-boot/EquipmentDelivery/importEquipment', url: '/cs-device-boot/EquipmentDelivery/importEquipment',
method: 'POST', method: 'POST',
responseType: 'blob', responseType: 'blob',
data: form data: form
}) })
} }
// 直连设备注册接入 // 直连设备注册接入
export const governDeviceRegister = (data: any) => { export const governDeviceRegister = (data: any) => {
return createAxios({ return createAxios({
url: `/access-boot/device/register?nDid=${data.nDid}&type=${data.type}`, url: `/access-boot/device/register?nDid=${data.nDid}&type=${data.type}`,
method: 'POST' method: 'POST'
}) })
} }
// 便携式设备注册 // 便携式设备注册
export const portableDeviceRegister = (params: any) => { export const portableDeviceRegister = (params: any) => {
return createAxios({ return createAxios({
url: `/access-boot/device/wlRegister`, url: `/access-boot/device/wlRegister`,
method: 'POST', method: 'POST',
params params
}) })
} }
// 便携式设备接入 // 便携式设备接入
export const portableDeviceAccess = (data: any) => { export const portableDeviceAccess = (data: any) => {
return createAxios({ return createAxios({
url: `/access-boot/device/wlAccess?nDid=${data.nDid}`, url: `/access-boot/device/wlAccess?nDid=${data.nDid}`,
method: 'POST', method: 'POST'
}) })
} }
// 下载模版 // 下载模版
export function getExcelTemplate() { export function getExcelTemplate() {
return createAxios({ return createAxios({
url: '/cs-device-boot/EquipmentDelivery/getExcelTemplate', url: '/cs-device-boot/EquipmentDelivery/getExcelTemplate',
method: 'get', method: 'get',
responseType: 'blob' responseType: 'blob'
}) })
} }
// 查询工程信息列表
export function engineeringProject() {
return createAxios({
url: '/cs-device-boot/engineeringProjectRelation/list',
method: 'post'
})
}

View File

@@ -147,8 +147,9 @@ const tableStore: any = new TableStore({
backgroundColor: 'rgba(0,0,0,0.55)', backgroundColor: 'rgba(0,0,0,0.55)',
borderWidth: 0, borderWidth: 0,
formatter: function (a: any) { formatter: function (a: any) {
var relVal = '' var relVal = `<strong>${a.seriesName}</strong><br/>`
relVal = "<font style='color:" + "'>发生时间:" + a.value[2] + '</font><br/>'
relVal += "<font style='color:" + "'>发生时间:" + a.value[2] + '</font><br/>'
relVal += "<font style='color:" + "'>持续时间:" + a.value[0] + 's</font><br/>' relVal += "<font style='color:" + "'>持续时间:" + a.value[0] + 's</font><br/>'
relVal += "<font style='color:" + "'>特征幅值:" + a.value[1].toFixed(2) + '%</font>' relVal += "<font style='color:" + "'>特征幅值:" + a.value[1].toFixed(2) + '%</font>'
return relVal return relVal
@@ -214,18 +215,18 @@ const tableStore: any = new TableStore({
// [0.2, 10, '2023-01-01 10:00:00'], // [0.2, 10, '2023-01-01 10:00:00'],
// [0.4, 50, '2023-01-01 11:00:00'] // [0.4, 50, '2023-01-01 11:00:00']
// ], // ],
legendSymbol: 'circle', legendSymbol: 'circle'
tooltip: { // tooltip: {
show: true, // show: true,
trigger: 'item', // trigger: 'item',
formatter: function (params: any) { // formatter: function (params: any) {
return `<strong>可容忍事件</strong><br/> // return `<strong>可容忍事件</strong><br/>
持续时间: ${params.value[0]}s<br/> // 持续时间: ${params.value[0]}s<br/>
特征幅值: ${params.value[1].toFixed(2)}%<br/> // 特征幅值: ${params.value[1].toFixed(2)}%<br/>
发生时间: ${params.value[2] || 'N/A'}` // 发生时间: ${params.value[2] || 'N/A'}`
} // }
} // }
}, },
{ {
name: '不可容忍事件', name: '不可容忍事件',

View File

@@ -47,7 +47,6 @@ const init = () => {
tooltip: { tooltip: {
trigger: 'axis', trigger: 'axis',
formatter: (params: any) => { formatter: (params: any) => {
console.log('🚀 ~ init ~ params:', params)
if (!params || params.length === 0) return '' if (!params || params.length === 0) return ''
// 使用第一个项目的轴标签作为时间标题 // 使用第一个项目的轴标签作为时间标题
@@ -90,8 +89,6 @@ const initData = async (row: any) => {
let [min, max] = yMethod(res.data.map((item: any) => item.value.split(',')).flat()) let [min, max] = yMethod(res.data.map((item: any) => item.value.split(',')).flat())
// 从第一条数据中提取时间作为x轴数据 // 从第一条数据中提取时间作为x轴数据
const firstItem = res.data[0]
const xAxisData = firstItem.time.split(',')
// 定义相位颜色映射 // 定义相位颜色映射
const phaseColors: any = { const phaseColors: any = {
@@ -107,6 +104,7 @@ const initData = async (row: any) => {
return a.phasic.localeCompare(b.phasic) return a.phasic.localeCompare(b.phasic)
}) })
.map((item: any) => { .map((item: any) => {
const xAxisData = item.time.split(',')
const values = xAxisData.map((time: string, index: number) => { const values = xAxisData.map((time: string, index: number) => {
// 将传入的日期与时间拼接成完整的时间字符串 // 将传入的日期与时间拼接成完整的时间字符串
const fullTime = `${row.time} ${time}` const fullTime = `${row.time} ${time}`

View File

@@ -21,7 +21,8 @@
isGroup isGroup
></Table> ></Table>
<!-- 指标日趋势图 --> <!-- 指标日趋势图 -->
<DailyTrendChart v-if="dialogTrendChart" ref="dailyTrendChartRef" @close="dialogTrendChart = false" /> <HarmonicRatio ref="harmonicRatioRef" v-if="dialogFlag" @close="onHarmonicRatioClose" :showIndex="false" />
<!-- <DailyTrendChart v-if="dialogTrendChart" ref="dailyTrendChartRef" @close="dialogTrendChart = false" /> -->
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@@ -31,9 +32,10 @@ import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue' import TableHeader from '@/components/table/header/index.vue'
import MyEchart from '@/components/echarts/MyEchart.vue' import MyEchart from '@/components/echarts/MyEchart.vue'
import { getTimeOfTheMonth } from '@/utils/formatTime' import { getTimeOfTheMonth } from '@/utils/formatTime'
import { ElMessage, ElMessageBox } from 'element-plus'
import DailyTrendChart from '@/components/cockpit/exceedanceLevel/components/dailyTrendChart.vue' import DailyTrendChart from '@/components/cockpit/exceedanceLevel/components/dailyTrendChart.vue'
import { getTime } from '@/utils/formatTime' import { getTime } from '@/utils/formatTime'
import HarmonicRatio from '@/components/cockpit/overLimitStatistics/components/harmonicRatio.vue'
const prop = defineProps({ const prop = defineProps({
w: { type: [String, Number] }, w: { type: [String, Number] },
h: { type: [String, Number] }, h: { type: [String, Number] },
@@ -47,7 +49,7 @@ const prop = defineProps({
const TableHeaderRef = ref() const TableHeaderRef = ref()
const headerHeight = ref(57) const headerHeight = ref(57)
const harmonicRatioRef: any = ref(null)
const dialogTrendChart = ref(false) const dialogTrendChart = ref(false)
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => { const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
@@ -118,7 +120,7 @@ const tableStore: any = new TableStore({
field: 'extent', field: 'extent',
minWidth: '70', minWidth: '70',
formatter: (row: any) => { formatter: (row: any) => {
return Math.floor(row.cellValue * 100) / 100 return Math.floor(row.cellValue * 100) / 100
} }
}, },
{ {
@@ -143,23 +145,14 @@ const tableStore: any = new TableStore({
}, },
loadCallback: () => { loadCallback: () => {
// 定义 x 轴标签顺序 // 定义 x 轴标签顺序
const xAxisLabels = ['长时闪变', '谐波电压', '谐波电流', '电压偏差', '三相不平衡']
// 根据指标名称顺序提取对应的 extent 数据
const chartData = xAxisLabels.map(label => {
// 在表格数据中查找对应指标名称的数据项
const item = tableStore.table.data.find((row: any) => row.name === label)
// 如果找到对应项,则返回 extent 值,否则返回 0并保留两位小数
const extentValue = item ? item.extent || 0 : 0
return Math.round(extentValue * 100) / 100
})
echartList.value = { echartList.value = {
title: { title: {
text: '指标越限严重度' text: '指标越限严重度'
}, },
xAxis: { xAxis: {
data: xAxisLabels data: tableStore.table.data.map((item: any) => item.name)
}, },
yAxis: { yAxis: {
@@ -175,7 +168,7 @@ const tableStore: any = new TableStore({
{ {
type: 'bar', type: 'bar',
name: '越限占比', name: '越限占比',
data: chartData, data: tableStore.table.data.map((item: any) => Math.floor(item.extent * 100) / 100),
barMaxWidth: 30 barMaxWidth: 30
} }
] ]
@@ -188,15 +181,32 @@ const tableRef = ref()
provide('tableRef', tableRef) provide('tableRef', tableRef)
provide('tableStore', tableStore) provide('tableStore', tableStore)
const codeMap = [
{ key: '闪变', code: 'flickerOvertime' },
{ key: '电压偏差', code: 'voltageDevOvertime' },
{ key: '三相', code: 'ubalanceOvertime' },
{ key: '谐波电压', code: 'uharm' },
{ key: '谐波电流', code: 'iharm' },
];
// 点击行 // 点击行
const cellClickEvent = ({ row, column }: any) => { const cellClickEvent = ({ row, column }: any) => {
dialogTrendChart.value = true dialogTrendChart.value = true
if (column.field == 'maxValue' && row.lineId) { if (column.field == 'maxValue' ) {
nextTick(() => { if(row.lineId==null){
dailyTrendChartRef.value.open(row) ElMessage.info('暂无越限监测点!')
}else{
nextTick(() => {
// dailyTrendChartRef.value.open(row)
dialogFlag.value = true
nextTick(() => {
const code = codeMap.find(item => row.name.includes(item.key))?.code || '';
harmonicRatioRef.value.openDialog(row,code,column.title.replace(/次/g, ""))
})
}) })
}
} }
} }
@@ -218,6 +228,14 @@ const setTime = () => {
console.warn('获取时间失败time 不是一个有效数组') console.warn('获取时间失败time 不是一个有效数组')
} }
} }
const dialogFlag=ref(false)
// 谐波弹窗关闭时的回调
const onHarmonicRatioClose = () => {
dialogFlag.value = false
// 重新打开指标越限详情弹窗
}
onMounted(() => { onMounted(() => {
tableStore.index() tableStore.index()

View File

@@ -93,15 +93,7 @@ const tableStore: any = new TableStore({
return `<span style='cursor: pointer;text-decoration: underline;'>${row.flickerOvertime}</span>` return `<span style='cursor: pointer;text-decoration: underline;'>${row.flickerOvertime}</span>`
} }
}, },
{ {
title: '谐波电压越限(%)',
children: loop50('uharm')
},
{
title: '谐波电流越限(%)',
children: loop50('iharm')
},
{
title: '电压偏差越限(%)', title: '电压偏差越限(%)',
field: 'voltageDevOvertime', field: 'voltageDevOvertime',
width: '100', width: '100',
@@ -119,6 +111,15 @@ const tableStore: any = new TableStore({
return `<span style='cursor: pointer;text-decoration: underline;'>${row.ubalanceOvertime}</span>` return `<span style='cursor: pointer;text-decoration: underline;'>${row.ubalanceOvertime}</span>`
} }
}, },
{
title: '谐波电压越限(%)',
children: loop50('uharm')
},
{
title: '谐波电流越限(%)',
children: loop50('iharm')
},
// { // {
// title: '频率偏差越限(%)', // title: '频率偏差越限(%)',

View File

@@ -186,7 +186,7 @@ const initProbabilityData = () => {
var tips = '' var tips = ''
tips += '指标类型: ' + yAxisData[yIndex] + '</br>' tips += '指标类型: ' + yAxisData[yIndex] + '</br>'
tips += '越限程度: ' + params.seriesName + '</br>' tips += '越限程度: ' + params.seriesName + '</br>'
tips += '越限数: ' + params.value[2] + '</br>' tips += '越限数: ' + params.value[2] + '</br>'
return tips return tips
} }
}, },
@@ -228,7 +228,7 @@ const initProbabilityData = () => {
}, },
zAxis3D: { zAxis3D: {
type: 'value', type: 'value',
name: '越限数', name: '越限数',
nameLocation: 'middle', nameLocation: 'middle',
nameGap: 30, nameGap: 30,
minInterval: 10 minInterval: 10

View File

@@ -185,7 +185,7 @@ const initProbabilityData = () => {
var tips = '' var tips = ''
tips += '指标类型: ' + yAxisData[yIndex] + '</br>' tips += '指标类型: ' + yAxisData[yIndex] + '</br>'
tips += '越限程度: ' + params.seriesName + '</br>' tips += '越限程度: ' + params.seriesName + '</br>'
tips += '越限数: ' + params.value[2] + '</br>' tips += '越限数: ' + params.value[2] + '</br>'
return tips return tips
} }
}, },
@@ -227,7 +227,7 @@ const initProbabilityData = () => {
}, },
zAxis3D: { zAxis3D: {
type: 'value', type: 'value',
name: '越限数', name: '越限数',
nameLocation: 'middle', nameLocation: 'middle',
nameGap: 30, nameGap: 30,
minInterval: 10 minInterval: 10

View File

@@ -93,15 +93,7 @@ const tableStore: any = new TableStore({
customTemplate: (row: any) => { customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.flickerOvertime}</span>` return `<span style='cursor: pointer;text-decoration: underline;'>${row.flickerOvertime}</span>`
} }
}, }, {
{
title: '谐波电压越限(分钟)',
children: loop50('uharm')
},
{
title: '谐波电流越限(分钟)',
children: loop50('iharm')
}, {
title: '电压偏差越限(分钟)', title: '电压偏差越限(分钟)',
field: 'uaberranceOvertime', field: 'uaberranceOvertime',
width: '100', width: '100',
@@ -119,6 +111,14 @@ const tableStore: any = new TableStore({
return `<span style='cursor: pointer;text-decoration: underline;'>${row.ubalanceOvertime}</span>` return `<span style='cursor: pointer;text-decoration: underline;'>${row.ubalanceOvertime}</span>`
} }
}, },
{
title: '谐波电压越限(分钟)',
children: loop50('uharm')
},
{
title: '谐波电流越限(分钟)',
children: loop50('iharm')
},
// { // {
// title: '频率偏差越限(分钟)', // title: '频率偏差越限(分钟)',

View File

@@ -73,15 +73,7 @@ const tableStore: any = new TableStore({
field: 'flicker', field: 'flicker',
width: '80' width: '80'
}, },
{ {
title: '谐波电压越限(分钟)',
children: loop50('voltage')
},
{
title: '谐波电流越限(分钟)',
children: loop50('harmonicCurrent')
},
{
title: '三相不平衡度越限(分钟)', title: '三相不平衡度越限(分钟)',
field: 'flicker', field: 'flicker',
width: '100' width: '100'
@@ -95,7 +87,16 @@ const tableStore: any = new TableStore({
title: '频率偏差越限(分钟)', title: '频率偏差越限(分钟)',
field: 'flicker', field: 'flicker',
width: '100' width: '100'
} },
{
title: '谐波电压越限(分钟)',
children: loop50('voltage')
},
{
title: '谐波电流越限(分钟)',
children: loop50('harmonicCurrent')
},
], ],
beforeSearchFun: () => {}, beforeSearchFun: () => {},
loadCallback: () => { loadCallback: () => {

View File

@@ -92,15 +92,7 @@ const tableStore: any = new TableStore({
return `<span style='cursor: pointer;text-decoration: underline;'>${row.flicker}</span>` return `<span style='cursor: pointer;text-decoration: underline;'>${row.flicker}</span>`
} }
}, },
{ {
title: '谐波电压越限(分钟)',
children: loop50('voltage')
},
{
title: '谐波电流越限(分钟)',
children: loop50('harmonicCurrent')
},
{
title: '三相不平衡度越限(分钟)', title: '三相不平衡度越限(分钟)',
field: 'flicker', field: 'flicker',
width: '100' width: '100'
@@ -114,7 +106,16 @@ const tableStore: any = new TableStore({
title: '频率偏差越限(分钟)', title: '频率偏差越限(分钟)',
field: 'flicker', field: 'flicker',
width: '100' width: '100'
} },
{
title: '谐波电压越限(分钟)',
children: loop50('voltage')
},
{
title: '谐波电流越限(分钟)',
children: loop50('harmonicCurrent')
},
], ],
beforeSearchFun: () => {}, beforeSearchFun: () => {},
loadCallback: () => { loadCallback: () => {

View File

@@ -93,15 +93,7 @@ const tableStore: any = new TableStore({
return `<span style='cursor: pointer;text-decoration: underline;'>${row.flickerOvertime}</span>` return `<span style='cursor: pointer;text-decoration: underline;'>${row.flickerOvertime}</span>`
} }
}, },
{ {
title: '谐波电压越限(%)',
children: loop50('uharm')
},
{
title: '谐波电流越限(%)',
children: loop50('iharm')
},
{
title: '电压偏差越限(%)', title: '电压偏差越限(%)',
field: 'voltageDevOvertime', field: 'voltageDevOvertime',
width: '100', width: '100',
@@ -119,6 +111,15 @@ const tableStore: any = new TableStore({
return `<span style='cursor: pointer;text-decoration: underline;'>${row.ubalanceOvertime}</span>` return `<span style='cursor: pointer;text-decoration: underline;'>${row.ubalanceOvertime}</span>`
} }
}, },
{
title: '谐波电压越限(%)',
children: loop50('uharm')
},
{
title: '谐波电流越限(%)',
children: loop50('iharm')
},
// { // {
// title: '频率偏差越限(%)', // title: '频率偏差越限(%)',

View File

@@ -5,10 +5,22 @@
ref="TableHeaderRef" ref="TableHeaderRef"
:showReset="false" :showReset="false"
@selectChange="selectChange" @selectChange="selectChange"
v-if="fullscreen" v-if="fullscreen"
:timeKeyList="prop.timeKey" :timeKeyList="prop.timeKey"
></TableHeader> >
<template #select>
<el-form-item label="关键字筛选">
<el-input
maxlength="32"
show-word-limit
style="width: 240px"
v-model.trim="tableStore.table.params.searchValue"
clearable
placeholder="请输入监测点名称"
/>
</el-form-item>
</template>
</TableHeader>
<Table <Table
ref="tableRef" ref="tableRef"
@cell-click="cellClickEvent" @cell-click="cellClickEvent"
@@ -189,7 +201,7 @@ const tableStore: any = new TableStore({
field: 'volGrade', field: 'volGrade',
minWidth: '80', minWidth: '80',
formatter: (row: any) => { formatter: (row: any) => {
return row.cellValue==0?'/': row.cellValue+'kV' || '/' return row.cellValue == 0 ? '/' : row.cellValue + 'kV' || '/'
} }
}, },
{ {
@@ -236,7 +248,8 @@ const tableStore: any = new TableStore({
} }
}, },
{ {
title: '操作', fixed: 'right', title: '操作',
fixed: 'right',
width: 150, width: 150,
render: 'buttons', render: 'buttons',
buttons: [ buttons: [
@@ -294,6 +307,7 @@ const tableStore: any = new TableStore({
const tableRef = ref() const tableRef = ref()
provide('tableRef', tableRef) provide('tableRef', tableRef)
tableStore.table.params.keywords = '' tableStore.table.params.keywords = ''
tableStore.table.params.searchValue = ''
provide('tableStore', tableStore) provide('tableStore', tableStore)
const setTime = () => { const setTime = () => {
@@ -304,7 +318,6 @@ const setTime = () => {
// ? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime] // ? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
// : prop.timeValue // : prop.timeValue
// ) // )
// if (Array.isArray(time)) { // if (Array.isArray(time)) {
// tableStore.table.params.searchBeginTime = time[0] // tableStore.table.params.searchBeginTime = time[0]
// tableStore.table.params.searchEndTime = time[1] // tableStore.table.params.searchEndTime = time[1]

View File

@@ -1,5 +1,5 @@
<template> <template>
<el-dialog draggable title="趋势图" v-model="dialogVisible" append-to-body width="70%"> <el-dialog draggable :title="titles" v-model="dialogVisible" append-to-body width="70%">
<!-- 总体指标占比详情谐波含有率 --> <!-- 总体指标占比详情谐波含有率 -->
<div> <div>
<TableHeader ref="tableHeaderRef" :showSearch="false" @selectChange="selectChange"> <TableHeader ref="tableHeaderRef" :showSearch="false" @selectChange="selectChange">
@@ -7,7 +7,7 @@
<el-form-item> <el-form-item>
<DatePicker ref="datePickerRef"></DatePicker> <DatePicker ref="datePickerRef"></DatePicker>
</el-form-item> </el-form-item>
<el-form-item label="统计指标" label-width="80px"> <el-form-item label="统计指标" label-width="80px" v-if="props.showIndex">
<el-select <el-select
multiple multiple
:multiple-limit="2" :multiple-limit="2"
@@ -107,9 +107,14 @@ defineOptions({
const props = defineProps({ const props = defineProps({
TrendList: { TrendList: {
type: Array type: Array
},
showIndex:{
type: Boolean,
default: true
} }
}) })
const titles = ref('趋势图')
const dialogVisible: any = ref(false) const dialogVisible: any = ref(false)
// console.log("🚀 ~ props:", props.TrendList) // console.log("🚀 ~ props:", props.TrendList)
const showEchart = ref(true) const showEchart = ref(true)
@@ -268,6 +273,7 @@ const lineStyle = [{ type: 'solid' }, { type: 'dashed' }, { type: 'dotted' }]
const init = async () => { const init = async () => {
loading.value = true loading.value = true
// 选择指标的时候切换legend内容和data数据 // 选择指标的时候切换legend内容和data数据
echartsData.value = {}
let list: any = [] let list: any = []
legendDictList.value?.selectedList?.map((item: any) => { legendDictList.value?.selectedList?.map((item: any) => {
searchForm.value.index.map((vv: any) => { searchForm.value.index.map((vv: any) => {
@@ -407,6 +413,7 @@ const setEchart = () => {
formatter(params: any) { formatter(params: any) {
const xname = params[0].value[0] const xname = params[0].value[0]
let str = `${xname}<br>` let str = `${xname}<br>`
params.forEach((el: any, index: any) => { params.forEach((el: any, index: any) => {
let marker = '' let marker = ''
@@ -651,6 +658,7 @@ watch(
) )
const openDialog = async (row: any, field: any, title: any) => { const openDialog = async (row: any, field: any, title: any) => {
titles.value = `${row?.lineName ? `${row.lineName}_` : ''}趋势图`
dialogVisible.value = true dialogVisible.value = true
trendRequestData.value = row trendRequestData.value = row

View File

@@ -92,14 +92,6 @@ const tableStore: any = new TableStore({
customTemplate: (row: any) => { customTemplate: (row: any) => {
return `<span style='cursor: pointer;text-decoration: underline;'>${row.flickerOvertime}</span>` return `<span style='cursor: pointer;text-decoration: underline;'>${row.flickerOvertime}</span>`
} }
},
{
title: '谐波电压越限(%)',
children: loop50('uharm')
},
{
title: '谐波电流越限(%)',
children: loop50('iharm')
}, },
{ {
title: '电压偏差越限(%)', title: '电压偏差越限(%)',
@@ -119,7 +111,16 @@ const tableStore: any = new TableStore({
return `<span style='cursor: pointer;text-decoration: underline;'>${row.ubalanceOvertime}</span>` return `<span style='cursor: pointer;text-decoration: underline;'>${row.ubalanceOvertime}</span>`
} }
}, },
{
title: '谐波电压越限(%)',
children: loop50('uharm')
},
{
title: '谐波电流越限(%)',
children: loop50('iharm')
},
// { // {
// title: '频率偏差越限(%)', // title: '频率偏差越限(%)',
// field: 'freqDevOvertime', // field: 'freqDevOvertime',

View File

@@ -5,10 +5,22 @@
ref="TableHeaderRef" ref="TableHeaderRef"
:showReset="false" :showReset="false"
@selectChange="selectChange" @selectChange="selectChange"
v-if="fullscreen" v-if="fullscreen"
:timeKeyList="prop.timeKey" :timeKeyList="prop.timeKey"
></TableHeader> >
<template #select>
<el-form-item label="关键字筛选">
<el-input
maxlength="32"
show-word-limit
style="width: 240px"
v-model.trim="tableStore.table.params.searchValue"
clearable
placeholder="请输入敏感负荷名称"
/>
</el-form-item>
</template>
</TableHeader>
<Table <Table
ref="tableRef" ref="tableRef"
@cell-click="cellClickEvent" @cell-click="cellClickEvent"
@@ -66,7 +78,7 @@ const fullscreen = computed(() => {
const OverLimitDetailsRef = ref() const OverLimitDetailsRef = ref()
const tableStore: any = new TableStore({ const tableStore: any = new TableStore({
url: '/cs-harmonic-boot/pqSensitiveUser/getList', url: '/cs-harmonic-boot/pqSensitiveUser/getListByUser',
method: 'POST', method: 'POST',
showPage: fullscreen.value ? true : false, showPage: fullscreen.value ? true : false,
column: [ column: [
@@ -115,7 +127,7 @@ const tableStore: any = new TableStore({
loadCallback: () => {} loadCallback: () => {}
}) })
tableStore.table.params.searchValue = ''
const tableRef = ref() const tableRef = ref()
provide('tableRef', tableRef) provide('tableRef', tableRef)
@@ -137,7 +149,6 @@ const setTime = () => {
// ? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime] // ? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
// : prop.timeValue // : prop.timeValue
// ) // )
// if (Array.isArray(time)) { // if (Array.isArray(time)) {
// tableStore.table.params.searchBeginTime = time[0] // tableStore.table.params.searchBeginTime = time[0]
// tableStore.table.params.searchEndTime = time[1] // tableStore.table.params.searchEndTime = time[1]

View File

@@ -4,8 +4,8 @@
<el-dialog draggable title="暂态事件详情 " v-model="dialogVisible" append-to-body width="70%"> <el-dialog draggable title="暂态事件详情 " v-model="dialogVisible" append-to-body width="70%">
<TableHeader datePicker showExport :showReset="false" ref="tableHeaderRef" @selectChange="selectChange"> <TableHeader datePicker showExport :showReset="false" ref="tableHeaderRef" @selectChange="selectChange">
<template v-slot:select> <template v-slot:select>
<el-form-item label="监测点"> <el-form-item label="监测点" v-if="props.showLine">
<el-select v-model="tableStore.table.params.lineId" placeholder="请选择监测点名称"> <el-select v-model="tableStore.table.params.lineId" filterable placeholder="请选择监测点名称">
<el-option <el-option
v-for="item in options" v-for="item in options"
:key="item.value" :key="item.value"
@@ -14,6 +14,21 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="暂态类型">
<el-select
v-model="tableStore.table.params.eventType"
style="min-width: 150px"
clearable
placeholder="请选择暂态类型"
>
<el-option
v-for="item in eventList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</template> </template>
</TableHeader> </TableHeader>
<Table ref="tableRef" isGroup :height="heightRef"></Table> <Table ref="tableRef" isGroup :height="heightRef"></Table>
@@ -46,6 +61,13 @@ import { mainHeight } from '@/utils/layout'
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 { getSimpleLine } from '@/api/harmonic-boot/cockpit/cockpit' import { getSimpleLine } from '@/api/harmonic-boot/cockpit/cockpit'
interface Props {
showLine?: boolean
}
const props = withDefaults(defineProps<Props>(), {
showLine: true
})
const dialogVisible: any = ref(false) const dialogVisible: any = ref(false)
const waveFormAnalysisRef: any = ref(null) const waveFormAnalysisRef: any = ref(null)
@@ -62,7 +84,11 @@ const heightRef = ref(mainHeight(168, 2.1).height)
const selectChange = (flag: boolean, h: any) => { const selectChange = (flag: boolean, h: any) => {
heightRef.value = mainHeight(h, 2.1).height heightRef.value = mainHeight(h, 2.1).height
} }
const eventList = [
{ label: '电压暂降', value: '1' },
{ label: '电压中断', value: '2' },
{ label: '电压暂升', value: '3' }
]
const getSimpleLineList = async () => { const getSimpleLineList = async () => {
const res = await getSimpleLine() const res = await getSimpleLine()
options.value = res.data options.value = res.data
@@ -200,9 +226,10 @@ const tableStore: any = new TableStore({
beforeSearchFun: () => {}, beforeSearchFun: () => {},
loadCallback: () => {} loadCallback: () => {}
}) })
tableStore.table.params.eventType = ''
provide('tableStore', tableStore) provide('tableStore', tableStore)
const open = async (time: any) => { const open = async (time: any) => {
tableStore.table.params.eventType = ''
dialogVisible.value = true dialogVisible.value = true
getSimpleLineList() getSimpleLineList()
tableStore.table.params.lineId = '' tableStore.table.params.lineId = ''

View File

@@ -7,7 +7,7 @@
@selectChange="selectChange" @selectChange="selectChange"
datePicker datePicker
v-if="fullscreen" v-if="fullscreen"
:timeKeyList="prop.timeKey" :timeKeyList="prop.timeKey"
></TableHeader> ></TableHeader>
<el-calendar <el-calendar
v-model="value" v-model="value"
@@ -58,7 +58,7 @@
</template> </template>
</el-calendar> </el-calendar>
<!-- 暂态事件列表 --> <!-- 暂态事件列表 -->
<TransientList ref="transientListRef" /> <TransientList ref="transientListRef" :showLine="false" />
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@@ -74,7 +74,7 @@ const prop = defineProps({
h: { type: [String, Number] }, h: { type: [String, Number] },
width: { type: [String, Number] }, width: { type: [String, Number] },
height: { type: [String, Number] }, height: { type: [String, Number] },
timeKey: { type: Array as () => string[] }, timeKey: { type: Array as () => string[] },
timeValue: { type: Object }, timeValue: { type: Object },
interval: { type: Number } interval: { type: Number }
}) })

View File

@@ -14,6 +14,21 @@
/> />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="暂态类型">
<el-select
v-model="tableStore.table.params.eventType"
style="min-width: 150px"
clearable
placeholder="请选择暂态类型"
>
<el-option
v-for="item in eventList"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
</template> </template>
</TableHeader> </TableHeader>
<Table ref="tableRef" isGroup :height="heightRef"></Table> <Table ref="tableRef" isGroup :height="heightRef"></Table>
@@ -62,7 +77,11 @@ const heightRef = ref(mainHeight(168, 2.2).height)
const selectChange = (flag: boolean, h: any) => { const selectChange = (flag: boolean, h: any) => {
heightRef.value = mainHeight(h, 2.2).height heightRef.value = mainHeight(h, 2.2).height
} }
const eventList = [
{ label: '电压暂降', value: '1' },
{ label: '电压中断', value: '2' },
{ label: '电压暂升', value: '3' }
]
const getSimpleLineList = async () => { const getSimpleLineList = async () => {
const res = await getSimpleLine() const res = await getSimpleLine()
options.value = res.data options.value = res.data
@@ -201,9 +220,10 @@ const tableStore: any = new TableStore({
beforeSearchFun: () => {}, beforeSearchFun: () => {},
loadCallback: () => {} loadCallback: () => {}
}) })
tableStore.table.params.eventType = ''
provide('tableStore', tableStore) provide('tableStore', tableStore)
const open = async (row: any, searchBeginTime: any, searchEndTime: any) => { const open = async (row: any, searchBeginTime: any, searchEndTime: any) => {
tableStore.table.params.eventType = ''
dialogVisible.value = true dialogVisible.value = true
getSimpleLineList() getSimpleLineList()
tableStore.table.params.lineId = row.id tableStore.table.params.lineId = row.id

View File

@@ -106,13 +106,15 @@ const initChart = () => {
start: 0, start: 0,
bottom: '20px', bottom: '20px',
end: 100 end: 100,
filterMode: 'none'
}, },
{ {
start: 0, start: 0,
height: 13, height: 13,
bottom: '20px', bottom: '20px',
end: 100 end: 100,
filterMode: 'none'
} }
// { // {
// show: true, // show: true,

View File

@@ -748,8 +748,10 @@ const initWave = (
rotation: 0, rotation: 0,
y: -10 y: -10
}, },
max: rmscm[0]?.[1] * 1.06 || 0, // max: rmscm[0]?.[1] * 1.06 || 0,
min: rmscu[0]?.[1] - rmscu[0]?.[1] * 0.2 || 0, // min: rmscu[0]?.[1] - rmscu[0]?.[1] * 0.2 || 0,
max: Math.floor((rmscm[0]?.[1] * 1.06 || 0) * 1.1 * 10) / 10,
min: Math.floor((rmscu[0]?.[1] - rmscu[0]?.[1] * 0.2 || 0) * 10) / 10,
boundaryGap: [0, '100%'], boundaryGap: [0, '100%'],
showLastLabel: true, showLastLabel: true,
opposite: false, opposite: false,
@@ -780,11 +782,11 @@ const initWave = (
} }
}, },
grid: { grid: {
left: '1%', left: '60px',
right: '45px', right: '45px',
bottom: '40px', bottom: '40px',
top: '60px', top: '60px'
containLabel: true // containLabel: true
}, },
dataZoom: [ dataZoom: [
{ {
@@ -1077,6 +1079,8 @@ const drawPics = (
boundaryGap: [0, '100%'], boundaryGap: [0, '100%'],
showLastLabel: true, showLastLabel: true,
opposite: false, opposite: false,
// max: Math.floor((rmscm[0]?.[1] * 1.06 || 0) * 1.1 * 10) / 10,
// min: Math.floor((rmscu[0]?.[1] - rmscu[0]?.[1] * 0.2 || 0) * 10) / 10,
nameTextStyle: { nameTextStyle: {
fontSize: '12px', fontSize: '12px',
color: props.DColor ? '#000' : echartsColor.WordColor color: props.DColor ? '#000' : echartsColor.WordColor
@@ -1105,11 +1109,11 @@ const drawPics = (
} }
}, },
grid: { grid: {
left: '1%', left: '60px',
right: '45px', right: '45px',
bottom: '40px', bottom: '40px',
top: '60px', top: '60px'
containLabel: true // containLabel: true
}, },
dataZoom: [ dataZoom: [
{ {

View File

@@ -481,8 +481,10 @@ const initWave = (
}, },
boundaryGap: [0, '100%'], boundaryGap: [0, '100%'],
showLastLabel: true, showLastLabel: true,
max: max.toFixed(2) * 1.1, // max: max.toFixed(2) * 1.1,
min: min.toFixed(2) > 0 ? min.toFixed(2) - min.toFixed(2) * 0.1 : min.toFixed(2) * 1.1, // min: min.toFixed(2) > 0 ? min.toFixed(2) - min.toFixed(2) * 0.1 : min.toFixed(2) * 1.1,
max: Math.floor(max.toFixed(2) * 1.1 * 10) / 10,
min: Math.floor(min.toFixed(2) > 0 ? min.toFixed(2) - min.toFixed(2) * 0.1 : min.toFixed(2) * 1.1 * 10) / 10 ,
opposite: false, opposite: false,
nameTextStyle: { nameTextStyle: {
fontSize: '12px', fontSize: '12px',
@@ -512,11 +514,11 @@ const initWave = (
} }
}, },
grid: { grid: {
left: '1%', left: '60px',
right: '45px', right: '45px',
bottom: '40px', bottom: '40px',
top: '60px', top: '60px'
containLabel: true // containLabel: true
}, },
dataZoom: [ dataZoom: [
{ {
@@ -789,8 +791,8 @@ const drawPics = (
}, },
boundaryGap: [0, '100%'], boundaryGap: [0, '100%'],
showLastLabel: true, showLastLabel: true,
max: max.toFixed(2) * 1.1, max: Math.floor(max.toFixed(2) * 1.1 * 10) / 10,
min: min.toFixed(2) > 0 ? min.toFixed(2) - min.toFixed(2) * 0.1 : min.toFixed(2) * 1.1, min: Math.floor(min.toFixed(2) > 0 ? min.toFixed(2) - min.toFixed(2) * 0.1 : min.toFixed(2) * 1.1 * 10) / 10 ,
opposite: false, opposite: false,
nameTextStyle: { nameTextStyle: {
fontSize: '12px', fontSize: '12px',
@@ -820,11 +822,11 @@ const drawPics = (
} }
}, },
grid: { grid: {
left: '1%', left: '60px',
right: '45px', right: '45px',
bottom: '40px', bottom: '40px',
top: '60px', top: '60px'
containLabel: true // containLabel: true
}, },
dataZoom: [ dataZoom: [
{ {

View File

@@ -1,35 +1,36 @@
<template> <template>
<div class="mac-address-input" :class="{ disabled: disabled }"> <div class="mac-address-input" :class="{ disabled: disabled }">
<el-input <el-input
ref="inputRef" ref="inputRef"
v-model="macValue" placeholder="请输入设备mac地址"
type="text" v-model="macValue"
maxlength="17" type="text"
:disabled="disabled" maxlength="17"
@input="handleInput" :disabled="disabled"
@keydown="handleKeydown" @input="handleInput"
@focus="handleFocus" @keydown="handleKeydown"
@blur="handleBlur" @focus="handleFocus"
@paste="handlePaste" @blur="handleBlur"
/> @paste="handlePaste"
</div> />
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref, watch } from 'vue' import { ref, watch } from 'vue'
interface Props { interface Props {
modelValue?: string modelValue?: string
disabled?: boolean disabled?: boolean
} }
interface Emits { interface Emits {
(e: 'update:modelValue', value: string): void (e: 'update:modelValue', value: string): void
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
modelValue: '', modelValue: '',
disabled: false disabled: false
}) })
const emit = defineEmits<Emits>() const emit = defineEmits<Emits>()
@@ -42,35 +43,35 @@ const macValue = ref<string>('')
// 解析传入的MAC地址 // 解析传入的MAC地址
const parseMacAddress = (mac: string): string => { const parseMacAddress = (mac: string): string => {
if (!mac) return '' if (!mac) return ''
// 移除非十六进制字符并转为大写 // 移除非十六进制字符并转为大写
const cleanMac = mac.replace(/[^0-9a-fA-F]/g, '').toUpperCase() const cleanMac = mac.replace(/[^0-9a-fA-F]/g, '').toUpperCase()
// 按每2个字符分割并用冒号连接 // 按每2个字符分割并用冒号连接
let result = '' let result = ''
for (let i = 0; i < cleanMac.length; i += 2) { for (let i = 0; i < cleanMac.length; i += 2) {
if (i > 0) result += ':' if (i > 0) result += ':'
result += cleanMac.substr(i, 2) result += cleanMac.substr(i, 2)
} }
return result.substring(0, 17) // 最多17个字符 (12个数字+5个冒号) return result.substring(0, 17) // 最多17个字符 (12个数字+5个冒号)
} }
// 格式化MAC地址 - 改进版 // 格式化MAC地址 - 改进版
const formatMac = (value: string): string => { const formatMac = (value: string): string => {
// 移除所有冒号 // 移除所有冒号
const cleanValue = value.replace(/:/g, '') const cleanValue = value.replace(/:/g, '')
// 只保留十六进制字符并转为大写 // 只保留十六进制字符并转为大写
const hexOnly = cleanValue.replace(/[^0-9a-fA-F]/g, '').toUpperCase() const hexOnly = cleanValue.replace(/[^0-9a-fA-F]/g, '').toUpperCase()
// 按每两个字符添加冒号最多6段 // 按每两个字符添加冒号最多6段
let formatted = '' let formatted = ''
for (let i = 0; i < Math.min(hexOnly.length, 12); i += 2) { for (let i = 0; i < Math.min(hexOnly.length, 12); i += 2) {
if (i > 0) formatted += ':' if (i > 0) formatted += ':'
formatted += hexOnly.substr(i, 2) formatted += hexOnly.substr(i, 2)
} }
return formatted return formatted
} }
// 当前聚焦的输入框索引 // 当前聚焦的输入框索引
@@ -78,88 +79,86 @@ const focusedIndex = ref<number | null>(null)
// 处理输入事件 // 处理输入事件
const handleInput = (value: string) => { const handleInput = (value: string) => {
const formatted = formatMac(value) const formatted = formatMac(value)
macValue.value = formatted macValue.value = formatted
// 发出不带冒号的纯净值 // 发出不带冒号的纯净值
emit('update:modelValue', formatted.replace(/:/g, '')) emit('update:modelValue', formatted.replace(/:/g, ''))
} }
// 处理键盘事件 // 处理键盘事件
const handleKeydown = (event: KeyboardEvent) => { const handleKeydown = (event: KeyboardEvent) => {
const target = event.target as HTMLInputElement const target = event.target as HTMLInputElement
// 处理退格键 // 处理退格键
if (event.key === 'Backspace') { if (event.key === 'Backspace') {
// 处理在冒号前删除的情况 // 处理在冒号前删除的情况
const cursorPos = target.selectionStart || 0 const cursorPos = target.selectionStart || 0
if (cursorPos > 0 && macValue.value[cursorPos - 1] === ':' && if (cursorPos > 0 && macValue.value[cursorPos - 1] === ':' && target.selectionStart === target.selectionEnd) {
target.selectionStart === target.selectionEnd) { event.preventDefault()
event.preventDefault() // 删除冒号前的两个字符
// 删除冒号前的两个字符 const newValue = macValue.value.substring(0, cursorPos - 3) + macValue.value.substring(cursorPos)
const newValue = macValue.value.substring(0, cursorPos - 3) + macValue.value = newValue
macValue.value.substring(cursorPos) // 设置光标位置
macValue.value = newValue setTimeout(() => {
// 设置光标位置 if (target.setSelectionRange) {
setTimeout(() => { target.setSelectionRange(cursorPos - 3, cursorPos - 3)
if (target.setSelectionRange) { }
target.setSelectionRange(cursorPos - 3, cursorPos - 3) }, 0)
emit('update:modelValue', newValue.replace(/:/g, ''))
} }
}, 0)
emit('update:modelValue', newValue.replace(/:/g, ''))
} }
}
} }
// 处理焦点事件 // 处理焦点事件
const handleFocus = () => { const handleFocus = () => {
focusedIndex.value = 0 focusedIndex.value = 0
} }
// 处理失焦事件 // 处理失焦事件
const handleBlur = () => { const handleBlur = () => {
focusedIndex.value = null focusedIndex.value = null
} }
// 处理粘贴事件 // 处理粘贴事件
const handlePaste = (event: ClipboardEvent) => { const handlePaste = (event: ClipboardEvent) => {
event.preventDefault() event.preventDefault()
const pastedText = event.clipboardData?.getData('text') || '' const pastedText = event.clipboardData?.getData('text') || ''
// 清理粘贴的文本 // 清理粘贴的文本
const cleanPastedText = pastedText.replace(/[^0-9a-fA-F]/g, '').toUpperCase() const cleanPastedText = pastedText.replace(/[^0-9a-fA-F]/g, '').toUpperCase()
const formatted = formatMac(cleanPastedText) const formatted = formatMac(cleanPastedText)
macValue.value = formatted macValue.value = formatted
emit('update:modelValue', formatted.replace(/:/g, '')) emit('update:modelValue', formatted.replace(/:/g, ''))
} }
// 监听modelValue变化 // 监听modelValue变化
watch( watch(
() => props.modelValue, () => props.modelValue,
(newVal) => { newVal => {
const cleanNewVal = (newVal || '').replace(/[^0-9a-fA-F]/g, '').toUpperCase() const cleanNewVal = (newVal || '').replace(/[^0-9a-fA-F]/g, '').toUpperCase()
const currentCleanValue = macValue.value.replace(/:/g, '') const currentCleanValue = macValue.value.replace(/:/g, '')
if (cleanNewVal !== currentCleanValue) { if (cleanNewVal !== currentCleanValue) {
macValue.value = parseMacAddress(cleanNewVal) macValue.value = parseMacAddress(cleanNewVal)
} }
}, },
{ immediate: true } { immediate: true }
) )
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.mac-address-input { .mac-address-input {
width: 100%; width: 100%;
&.disabled { &.disabled {
opacity: 0.7; opacity: 0.7;
} }
:deep(.el-input__wrapper) { :deep(.el-input__wrapper) {
input { input {
text-transform: uppercase; text-transform: uppercase;
font-family: inherit; // 使用继承的字体而不是等宽字体 font-family: inherit; // 使用继承的字体而不是等宽字体
}
} }
}
} }
</style> </style>

View File

@@ -14,7 +14,7 @@
/> />
<div class="cn-tree" :style="{ opacity: menuCollapse ? 0 : 1 }"> <div class="cn-tree" :style="{ opacity: menuCollapse ? 0 : 1 }">
<div style="display: flex; align-items: center" class="mb10"> <div style="display: flex; align-items: center" class="mb10">
<el-input maxlength="32" show-word-limit v-model.trim="filterText" placeholder="请输入内容" clearable> <el-input maxlength="32" v-model.trim="filterText" placeholder="请输入内容" clearable>
<template #prefix> <template #prefix>
<Icon name="el-icon-Search" style="font-size: 16px" /> <Icon name="el-icon-Search" style="font-size: 16px" />
</template> </template>

View File

@@ -5,7 +5,7 @@
style='cursor: pointer' /> style='cursor: pointer' />
<div class='cn-tree' :style='{ opacity: menuCollapse ? 0 : 1 }'> <div class='cn-tree' :style='{ opacity: menuCollapse ? 0 : 1 }'>
<div style='display: flex; align-items: center' class='mb10'> <div style='display: flex; align-items: center' class='mb10'>
<el-input maxlength="32" show-word-limit v-model.trim='filterText' placeholder='请输入内容' clearable> <el-input maxlength="32" v-model.trim='filterText' placeholder='请输入内容' clearable>
<template #prefix> <template #prefix>
<Icon name='el-icon-Search' style='font-size: 16px' /> <Icon name='el-icon-Search' style='font-size: 16px' />
</template> </template>

View File

@@ -13,18 +13,29 @@
<div class="cn-tree" :style="{ opacity: menuCollapse ? 0 : 1 }"> <div class="cn-tree" :style="{ opacity: menuCollapse ? 0 : 1 }">
<div style="display: flex; align-items: center" class="mb10"> <div style="display: flex; align-items: center" class="mb10">
<!-- <el-form-item> --> <!-- <el-form-item> -->
<el-input <el-input
maxlength="32" maxlength="32"
show-word-limit
v-model.trim="filterText" v-model.trim="filterText"
autocomplete="off" autocomplete="off"
placeholder="请输入内容" placeholder="请输入内容"
clearable clearable
> >
<template #prepend>
<el-select v-model="treeType" @change="changeTreeType" style="min-width: 75px">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</template>
<template #prefix> <template #prefix>
<Icon name="el-icon-Search" style="font-size: 16px" /> <Icon name="el-icon-Search" style="font-size: 16px" />
</template> </template>
</el-input> </el-input>
<!-- </el-form-item> --> <!-- </el-form-item> -->
<Icon <Icon
@click="onMenuCollapse" @click="onMenuCollapse"
@@ -42,6 +53,8 @@
v-model.trim="activeName" v-model.trim="activeName"
style="flex: 1; height: 100%" style="flex: 1; height: 100%"
@change="changeDevice" @change="changeDevice"
v-if="treeType == '1'"
v-loading="loading"
> >
<el-collapse-item title="治理设备" name="0" v-if="zlDeviceData.length != 0"> <el-collapse-item title="治理设备" name="0" v-if="zlDeviceData.length != 0">
<el-select v-model.trim="process" clearable placeholder="请选择状态" class="mb10"> <el-select v-model.trim="process" clearable placeholder="请选择状态" class="mb10">
@@ -52,7 +65,7 @@
<el-tree <el-tree
:style="{ :style="{
height: height:
bxsDeviceData.length != 0 treeType.length != 0
? `calc(100vh - 380px - ${props.height}px)` ? `calc(100vh - 380px - ${props.height}px)`
: 'calc(100vh - 278px)' : 'calc(100vh - 278px)'
}" }"
@@ -142,6 +155,32 @@
</el-tree> </el-tree>
</el-collapse-item> </el-collapse-item>
</el-collapse> </el-collapse>
<div v-if="treeType == '2'" v-loading="loading">
<el-tree
:style="{ height: `calc(100vh - 188px - ${props.height}px )` }"
ref="treeRef4"
:props="defaultProps"
highlight-current
:filter-node-method="filterNode"
node-key="id"
v-bind="$attrs"
:data="data"
style="overflow: auto"
:default-expand-all="false"
>
<template #default="{ node, data }">
<span class="custom-tree-node">
<Icon
:name="data.icon"
style="font-size: 16px"
:style="{ color: data.color }"
v-if="data.icon"
/>
<span style="margin-left: 4px">{{ node.label }}</span>
</span>
</template>
</el-tree>
</div>
</div> </div>
</div> </div>
</template> </template>
@@ -154,13 +193,14 @@ import { ref, watch, defineEmits, onMounted, nextTick } from 'vue'
defineOptions({ defineOptions({
name: 'govern/tree' name: 'govern/tree'
}) })
const emit = defineEmits(['changeDeviceType']) const emit = defineEmits(['changeDeviceType', 'changeTreeType'])
interface Props { interface Props {
width?: string width?: string
canExpand?: boolean canExpand?: boolean
type?: string type?: string
data?: any data?: any
height?: number height?: number
engineering: boolean
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
@@ -168,8 +208,20 @@ const props = withDefaults(defineProps<Props>(), {
canExpand: true, canExpand: true,
type: '', type: '',
data: [], data: [],
height: 0 height: 0,
engineering: false
}) })
const treeType = ref('1')
const options = [
{
label: '设备',
value: '1'
},
{
label: '工程',
value: '2'
}
]
const { proxy } = useCurrentInstance() const { proxy } = useCurrentInstance()
const menuCollapse = ref(false) const menuCollapse = ref(false)
const activeName = ref('0') const activeName = ref('0')
@@ -219,7 +271,9 @@ watch(
) )
watch(filterText, val => { watch(filterText, val => {
if (activeName.value == '0') { if (treeType.value == '2') {
treeRef4.value!.filter(val)
} else if (activeName.value == '0') {
treeRef1.value!.filter(val) treeRef1.value!.filter(val)
} else if (activeName.value == '1') { } else if (activeName.value == '1') {
treeRef2.value!.filter(val) treeRef2.value!.filter(val)
@@ -362,27 +416,44 @@ const treeRef1 = ref<InstanceType<typeof ElTree>>()
const treeRef2 = ref<InstanceType<typeof ElTree>>() const treeRef2 = ref<InstanceType<typeof ElTree>>()
//前置 //前置
const treeRef3 = ref<InstanceType<typeof ElTree>>() const treeRef3 = ref<InstanceType<typeof ElTree>>()
defineExpose({ treeRef1, treeRef2, treeRef3 }) const treeRef4 = ref<InstanceType<typeof ElTree>>()
defineExpose({ treeRef1, treeRef2, treeRef3, treeRef4 })
onMounted(() => { onMounted(() => {
treeType.value = props.engineering ? '2' : '1'
setTimeout(() => { setTimeout(() => {
if (zlDeviceData.value.length != 0) { setActiveName()
zlDevList.value = filterProcess(JSON.parse(JSON.stringify(zlDeviceData.value)))
activeName.value = '0'
}
if (zlDeviceData.value.length === 0 && bxsDeviceData.value.length != 0) {
activeName.value = '1'
}
if (zlDeviceData.value.length === 0 && bxsDeviceData.value.length === 0) {
activeName.value = '2'
}
if (!zlDeviceData.value && !bxsDeviceData.value) {
activeName.value = ''
}
nextTick(() => {
changeDevice(activeName.value)
})
}, 500) }, 500)
}) })
const setActiveName = () => {
if (zlDeviceData.value.length != 0) {
zlDevList.value = filterProcess(JSON.parse(JSON.stringify(zlDeviceData.value)))
activeName.value = '0'
}
if (zlDeviceData.value.length === 0 && bxsDeviceData.value.length != 0) {
activeName.value = '1'
}
if (zlDeviceData.value.length === 0 && bxsDeviceData.value.length === 0) {
activeName.value = '2'
}
if (!zlDeviceData.value && !bxsDeviceData.value) {
activeName.value = ''
}
nextTick(() => {
changeDevice(activeName.value)
})
}
const loading = ref(false)
const changeTreeType = (val: string) => {
loading.value = true
emit('changeTreeType', val)
if (val == '1') {
setActiveName()
}
setTimeout(() => {
loading.value = false
}, 1000)
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@@ -412,4 +483,7 @@ onMounted(() => {
display: flex; display: flex;
align-items: center; align-items: center;
} }
:deep(.el-input-group__prepend) {
background-color: var(--el-fill-color-blank);
}
</style> </style>

View File

@@ -1,11 +1,19 @@
<template> <template>
<Tree ref="treRef" :width="width" :showPush="props.showPush" :data="tree" default-expand-all @changePointType="changePointType" @onAdd="onAdd"/> <Tree
ref="treRef"
:width="width"
:showPush="props.showPush"
:expand-on-click-node="false"
:data="tree"
@changePointType="changePointType"
@onAdd="onAdd"
/>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, nextTick, onMounted, defineProps } from 'vue' import { ref, nextTick, onMounted, defineProps } from 'vue'
import Tree from '../index.vue' import Tree from '../index.vue'
import { getLineTree,getCldTree } from '@/api/cs-device-boot/csLedger' import { getLineTree, getCldTree } from '@/api/cs-device-boot/csLedger'
import { useConfig } from '@/stores/config' import { useConfig } from '@/stores/config'
import { querySysExcel } from '@/api/harmonic-boot/luckyexcel' import { querySysExcel } from '@/api/harmonic-boot/luckyexcel'
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
@@ -22,136 +30,61 @@ defineOptions({
name: 'govern/deviceTree' name: 'govern/deviceTree'
}) })
const emit = defineEmits(['init', 'checkChange', 'pointTypeChange', 'Policy','onAdd']) const emit = defineEmits(['init', 'checkChange', 'pointTypeChange', 'Policy', 'onAdd'])
const config = useConfig() const config = useConfig()
const tree = ref() const tree = ref()
const dictData = useDictData() const dictData = useDictData()
const treRef = ref() const treRef = ref()
const width = ref('') const width = ref('')
const info = (selectedNodeId?: string) => { const info = (selectedNodeId?: string) => {
tree.value = [] tree.value = []
let arr1: any[] = [] let arr1: any[] = []
getCldTree().then(res => { getCldTree().then(res => {
try { res.data.icon = 'el-icon-Menu'
// 检查响应数据结构 res.data.color = config.getColorVal('elementUiPrimary')
let rootData = null; res.data?.children.map((item: any) => {
if (Array.isArray(res.data)) { item.icon = 'el-icon-HomeFilled'
// 旧的数据结构 - 数组 item.color = config.getColorVal('elementUiPrimary')
rootData = res.data.find((item: any) => item.name == '监测设备'); item.children.forEach((item: any) => {
} else if (res.data && res.data.name == '监测设备') { item.icon = 'el-icon-List'
// 新的数据结构 - 单个对象 item.color = config.getColorVal('elementUiPrimary')
rootData = res.data; item.children.forEach((item2: any) => {
} // item2.icon = 'el-icon-List'
// item2.color = config.getColorVal('elementUiPrimary')
// 治理设备 item2.icon = 'el-icon-Platform'
if (rootData) { item2.level = 2
rootData.icon = 'el-icon-Menu' item2.color = item2.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
rootData.level = 0 item2.children.forEach((item3: any) => {
rootData.color = config.getColorVal('elementUiPrimary') item3.icon = 'el-icon-Platform'
// 确保根节点的 children 是数组 item3.color =
if (!Array.isArray(rootData.children)) { item3.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
rootData.children = [] arr1.push(item3)
}
rootData.children.forEach((item: any) => {
item.icon = 'el-icon-HomeFilled'
item.level = 1
item.color = config.getColorVal('elementUiPrimary')
// 确保 children 是数组
if (!Array.isArray(item.children)) {
item.children = []
}
item.children.forEach((item2: any) => {
item2.icon = 'el-icon-List'
item2.level = 2
item2.color = config.getColorVal('elementUiPrimary')
// 确保 children 是数组
if (!Array.isArray(item2.children)) {
item2.children = []
}
item2.children.forEach((item3: any) => {
item3.icon = 'el-icon-Platform'
item3.level = 3
item3.color =
item3.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
// 确保 children 是数组
if (!Array.isArray(item3.children)) {
item3.children = []
}
item3.children.forEach((item4: any) => {
item4.icon = 'el-icon-Platform'
item4.level = 4
item4.color =
item4.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
arr1.push(item4)
})
})
}) })
}) })
tree.value = [rootData] // 确保 tree.value 是数组
} else {
tree.value = []
}
nextTick(() => {
if (arr1.length) {
// 安全检查 treRef 和 treeRef 是否存在
console.log("🚀 ~ info ~ treRef.value && treRef.value.treeRef && treRef.value.treeRef.setCurrentKey:", treRef.value && treRef.value.treeRef1 && treRef.value.treeRef1.setCurrentKey)
if (treRef.value && treRef.value.treeRef && treRef.value.treeRef.setCurrentKey) {
// 如果传入了要选中的节点ID则选中该节点否则选中第一个节点
console.log('selectedNodeId:', selectedNodeId);
if (selectedNodeId) {
treRef.value.treeRef.setCurrentKey(selectedNodeId);
// 查找对应的节点数据并触发事件
let selectedNode = null;
const findNode = (nodes: any[]) => {
for (const node of nodes) {
if (node.id === selectedNodeId) {
selectedNode = node;
return true;
}
if (node.children && findNode(node.children)) {
return true;
}
}
return false;
};
findNode(tree.value);
if (selectedNode) {
emit('init', {
level: selectedNode.level,
...selectedNode
});
}
} else {
// 初始化选中第一个节点
treRef.value.treeRef.setCurrentKey(arr1[0].id);
emit('init', {
level: 2,
...arr1[0]
});
}
}
} else {
}
}) })
} catch (error) { })
console.error('Error in processing getCldTree response:', error) tree.value = [res.data]
}
nextTick(() => {
setTimeout(() => {
//初始化选中
treRef.value?.treeRef.setCurrentKey(arr1[0].id)
// 注册父组件事件
emit('init', {
level: 3,
...arr1[0]
})
changePointType('4', arr1[0])
return
}, 500)
})
}) })
} }
const changePointType = (val: any, obj: any) => { const changePointType = (val: any, obj: any) => {
emit('pointTypeChange', val, obj) // emit('pointTypeChange', val, obj)
} }
const onAdd = () => { const onAdd = () => {

View File

@@ -1,11 +1,19 @@
<template> <template>
<Tree ref="treRef" :width="width" :showPush="props.showPush" :data="tree" default-expand-all @changePointType="changePointType" @onAdd="onAdd"/> <Tree
ref="treRef"
:width="width"
:showPush="props.showPush"
:data="tree"
default-expand-all
@changePointType="changePointType"
@onAdd="onAdd"
/>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, nextTick, onMounted, defineProps } from 'vue' import { ref, nextTick, onMounted, defineProps } from 'vue'
import Tree from '../index.vue' import Tree from '../index.vue'
import { getLineTree,lineTree } from '@/api/cs-device-boot/csLedger' import { getLineTree, lineTree } from '@/api/cs-device-boot/csLedger'
import { useConfig } from '@/stores/config' import { useConfig } from '@/stores/config'
import { querySysExcel } from '@/api/harmonic-boot/luckyexcel' import { querySysExcel } from '@/api/harmonic-boot/luckyexcel'
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
@@ -22,27 +30,26 @@ defineOptions({
name: 'govern/deviceTree' name: 'govern/deviceTree'
}) })
const emit = defineEmits(['init', 'checkChange', 'pointTypeChange', 'Policy','onAdd']) const emit = defineEmits(['init', 'checkChange', 'pointTypeChange', 'Policy', 'onAdd'])
const config = useConfig() const config = useConfig()
const tree = ref() const tree = ref()
const dictData = useDictData() const dictData = useDictData()
const treRef = ref() const treRef = ref()
const width = ref('') const width = ref('')
const info = (selectedNodeId?: string) => { const info = (selectedNodeId?: string) => {
tree.value = [] tree.value = []
let arr1: any[] = [] let arr1: any[] = []
lineTree().then(res => { lineTree().then(res => {
try { try {
// 检查响应数据结构 // 检查响应数据结构
let rootData = null; let rootData = null
if (Array.isArray(res.data)) { if (Array.isArray(res.data)) {
// 旧的数据结构 - 数组 // 旧的数据结构 - 数组
rootData = res.data.find((item: any) => item.name == '监测设备'); rootData = res.data.find((item: any) => item.name == '监测设备')
} else if (res.data && res.data.name == '监测设备') { } else if (res.data && res.data.name == '监测设备') {
// 新的数据结构 - 单个对象 // 新的数据结构 - 单个对象
rootData = res.data; rootData = res.data
} }
// 治理设备 // 治理设备
@@ -66,7 +73,7 @@ const info = (selectedNodeId?: string) => {
item2.icon = 'el-icon-List' item2.icon = 'el-icon-List'
item2.level = 2 item2.level = 2
item2.color = config.getColorVal('elementUiPrimary') item2.color = config.getColorVal('elementUiPrimary')
// 确保 children 是数组 // 确保 children 是数组
if (!Array.isArray(item2.children)) { if (!Array.isArray(item2.children)) {
item2.children = [] item2.children = []
@@ -76,12 +83,12 @@ const info = (selectedNodeId?: string) => {
item3.level = 3 item3.level = 3
item3.color = item3.color =
item3.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important' item3.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
// 确保 children 是数组 // 确保 children 是数组
if (!Array.isArray(item3.children)) { if (!Array.isArray(item3.children)) {
item3.children = [] item3.children = []
} }
item3.children.forEach((item4: any) => { item3.children.forEach((item4: any) => {
item4.icon = 'el-icon-Platform' item4.icon = 'el-icon-Platform'
item4.level = 4 item4.level = 4
@@ -97,50 +104,51 @@ const info = (selectedNodeId?: string) => {
tree.value = [] tree.value = []
} }
nextTick(() => { nextTick(() => {
if (arr1.length) { if (arr1.length) {
// 安全检查 treRef 和 treeRef 是否存在 // 安全检查 treRef 和 treeRef 是否存在
console.log("🚀 ~ info ~ treRef.value && treRef.value.treeRef && treRef.value.treeRef.setCurrentKey:", treRef.value && treRef.value.treeRef1 && treRef.value.treeRef1.setCurrentKey) console.log(
'🚀 ~ info ~ treRef.value && treRef.value.treeRef && treRef.value.treeRef.setCurrentKey:',
treRef.value && treRef.value.treeRef1 && treRef.value.treeRef1.setCurrentKey
)
if (treRef.value && treRef.value.treeRef && treRef.value.treeRef.setCurrentKey) { if (treRef.value && treRef.value.treeRef && treRef.value.treeRef.setCurrentKey) {
// 如果传入了要选中的节点ID则选中该节点否则选中第一个节点 // 如果传入了要选中的节点ID则选中该节点否则选中第一个节点
console.log('selectedNodeId:', selectedNodeId); console.log('selectedNodeId:', selectedNodeId)
if (selectedNodeId) { if (selectedNodeId) {
treRef.value.treeRef.setCurrentKey(selectedNodeId); treRef.value.treeRef.setCurrentKey(selectedNodeId)
// 查找对应的节点数据并触发事件 // 查找对应的节点数据并触发事件
let selectedNode = null; let selectedNode = null
const findNode = (nodes: any[]) => { const findNode = (nodes: any[]) => {
for (const node of nodes) { for (const node of nodes) {
if (node.id === selectedNodeId) { if (node.id === selectedNodeId) {
selectedNode = node; selectedNode = node
return true; return true
} }
if (node.children && findNode(node.children)) { if (node.children && findNode(node.children)) {
return true; return true
} }
} }
return false; return false
}; }
findNode(tree.value); findNode(tree.value)
if (selectedNode) { if (selectedNode) {
emit('init', { emit('init', {
level: selectedNode.level, level: selectedNode.level,
...selectedNode ...selectedNode
}); })
} }
} else { } else {
// 初始化选中第一个节点 // 初始化选中第一个节点
treRef.value.treeRef.setCurrentKey(arr1[0].id); treRef.value.treeRef.setCurrentKey(arr1[0].id)
emit('init', { emit('init', {
level: 2, level: 2,
...arr1[0] ...arr1[0]
}); })
} }
} }
} else { } else {
} }
}) })
} catch (error) { } catch (error) {
@@ -149,7 +157,6 @@ const info = (selectedNodeId?: string) => {
}) })
} }
const changePointType = (val: any, obj: any) => { const changePointType = (val: any, obj: any) => {
emit('pointTypeChange', val, obj) emit('pointTypeChange', val, obj)
} }
@@ -158,7 +165,8 @@ const onAdd = () => {
emit('onAdd') emit('onAdd')
} }
if (props.template) { if (props.template) {
querySysExcel({ id: dictData.state.area[0]?.id }) // id: dictData.state.area[0]?.id
querySysExcel({})
.then((res: any) => { .then((res: any) => {
emit('Policy', res.data) emit('Policy', res.data)
info() info()

View File

@@ -7,6 +7,8 @@
:data="tree" :data="tree"
:height="props.height" :height="props.height"
@changeDeviceType="changeDeviceType" @changeDeviceType="changeDeviceType"
@changeTreeType="info"
:engineering="props.engineering"
/> />
</template> </template>
@@ -16,6 +18,7 @@ import Tree from '../device.vue'
import { getDeviceTree } from '@/api/cs-device-boot/csLedger' import { getDeviceTree } from '@/api/cs-device-boot/csLedger'
import { useConfig } from '@/stores/config' import { useConfig } from '@/stores/config'
import { throttle } from 'lodash' import { throttle } from 'lodash'
defineOptions({ defineOptions({
name: 'govern/deviceTree' name: 'govern/deviceTree'
}) })
@@ -24,11 +27,13 @@ const props = withDefaults(
showCheckbox?: boolean showCheckbox?: boolean
defaultCheckedKeys?: any defaultCheckedKeys?: any
height?: number height?: number
engineering?: boolean
}>(), }>(),
{ {
showCheckbox: false, showCheckbox: false,
defaultCheckedKeys: [], defaultCheckedKeys: [],
height: 0 height: 0,
engineering: false
} }
) )
const emit = defineEmits(['init', 'checkChange', 'deviceTypeChange']) const emit = defineEmits(['init', 'checkChange', 'deviceTypeChange'])
@@ -38,112 +43,149 @@ const treRef = ref()
const changeDeviceType = (val: any, obj: any) => { const changeDeviceType = (val: any, obj: any) => {
emit('deviceTypeChange', val, obj) emit('deviceTypeChange', val, obj)
} }
getDeviceTree().then(res => {
let arr: any[] = [] const info = (type?: string) => {
let arr2: any[] = [] getDeviceTree({ type: type == '2' ? 'engineering' : '' }).then(res => {
let arr3: any[] = [] let arr: any[] = []
//治理设备 let arr2: any[] = []
res.data.map((item: any) => { let arr3: any[] = []
if (item.name == '治理设备') { let arr4: any[] = []
item.children.forEach((item: any) => { //治理设备
res.data.map((item: any) => {
if (type == '2') {
item.icon = 'el-icon-HomeFilled' item.icon = 'el-icon-HomeFilled'
item.color = config.getColorVal('elementUiPrimary') item.color = config.getColorVal('elementUiPrimary')
item.children.forEach((item2: any) => { item.children.forEach((item: any) => {
item2.icon = 'el-icon-List' item.icon = 'el-icon-List'
item2.color = config.getColorVal('elementUiPrimary') item.color = config.getColorVal('elementUiPrimary')
item2.children.forEach((item3: any) => { item.children.forEach((item2: any) => {
item3.pName = '治理设备' item2.icon = 'el-icon-Platform'
item3.icon = 'el-icon-Platform' item2.color = config.getColorVal('elementUiPrimary')
item3.level = 2 item2.color =
item3.color = config.getColorVal('elementUiPrimary') item2.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
if (item3.comFlag === 1) { arr4.push(item2)
item3.color = '#e26257 !important'
}
arr.push(item3)
}) })
}) })
})
} else if (item.name == '便携式设备') {
item.children.forEach((item: any) => {
item.icon = 'el-icon-Platform'
item.color = config.getColorVal('elementUiPrimary')
item.color = '#e26257 !important'
item.color = item.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
// item.disabled =true
item.pName = '便携式设备'
if (item.type == 'device') {
arr2.push(item)
}
item.children.forEach((item2: any) => {
item2.icon = 'el-icon-Platform'
item2.color = item2.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
item2.pName = '便携式设备'
// item2.children.forEach((item3: any) => {
// item3.icon = 'el-icon-Platform'
// item3.color = config.getColorVal('elementUiPrimary')
// if (item3.comFlag === 1) {
// item3.color = '#e26257 !important'
// }
// arr.push(item3)
// })
})
})
} else if (item.name == '监测设备') {
item.children.forEach((item: any) => {
item.icon = 'el-icon-HomeFilled'
item.color = config.getColorVal('elementUiPrimary')
item.children.forEach((item2: any) => {
item2.icon = 'el-icon-List'
item2.color = config.getColorVal('elementUiPrimary')
item2.children.forEach((item3: any) => {
item3.pName = '监测设备'
item3.icon = 'el-icon-Platform'
item3.color = config.getColorVal('elementUiPrimary')
if (item3.comFlag === 1) {
item3.color = '#e26257 !important'
}
arr3.push(item3)
})
})
})
}
})
tree.value = res.data
nextTick(() => {
setTimeout(() => {
if (arr.length > 0) {
treRef.value.treeRef1.setCurrentKey(arr[0].id)
// 注册父组件事件
emit('init', {
level: 2,
...arr[0]
})
return
} else if (arr2.length > 0) {
treRef.value.treeRef2.setCurrentKey(arr2[0].id)
// 注册父组件事件
emit('init', {
level: 2,
...arr2[0]
})
return
} else if (arr3.length > 0) {
console.log('🚀 ~ arr3:', arr3)
treRef.value.treeRef3.setCurrentKey(arr3[0].id)
// 注册父组件事件
emit('init', {
level: 2,
...arr3[0]
})
return
} else { } else {
emit('init') if (item.name == '治理设备') {
return item.children.forEach((item: any) => {
item.icon = 'el-icon-HomeFilled'
item.color = config.getColorVal('elementUiPrimary')
item.children.forEach((item2: any) => {
item2.icon = 'el-icon-List'
item2.color = config.getColorVal('elementUiPrimary')
item2.children.forEach((item3: any) => {
item3.pName = '治理设备'
item3.icon = 'el-icon-Platform'
item3.level = 2
item3.color = config.getColorVal('elementUiPrimary')
if (item3.comFlag === 1) {
item3.color = '#e26257 !important'
}
arr.push(item3)
})
})
})
} else if (item.name == '便携式设备') {
item.children.forEach((item: any) => {
item.icon = 'el-icon-Platform'
item.color = config.getColorVal('elementUiPrimary')
item.color = '#e26257 !important'
item.color = item.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
// item.disabled =true
item.pName = '便携式设备'
if (item.type == 'device') {
arr2.push(item)
}
item.children.forEach((item2: any) => {
item2.icon = 'el-icon-Platform'
item2.color =
item2.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
item2.pName = '便携式设备'
// item2.children.forEach((item3: any) => {
// item3.icon = 'el-icon-Platform'
// item3.color = config.getColorVal('elementUiPrimary')
// if (item3.comFlag === 1) {
// item3.color = '#e26257 !important'
// }
// arr.push(item3)
// })
})
})
} else if (item.name == '监测设备') {
item.children.forEach((item: any) => {
item.icon = 'el-icon-HomeFilled'
item.color = config.getColorVal('elementUiPrimary')
item.children.forEach((item2: any) => {
item2.icon = 'el-icon-List'
item2.color = config.getColorVal('elementUiPrimary')
item2.children.forEach((item3: any) => {
item3.pName = '监测设备'
item3.icon = 'el-icon-Platform'
item3.color = config.getColorVal('elementUiPrimary')
if (item3.comFlag === 1) {
item3.color = '#e26257 !important'
}
arr3.push(item3)
})
})
})
}
} }
}, 500) })
tree.value = res.data
nextTick(() => {
setTimeout(() => {
if (type == '2') {
//初始化选中
treRef.value?.treeRef4.setCurrentKey(arr4[0].id)
// 注册父组件事件
emit('init', {
level: 2,
...arr4[0]
})
// changePointType('4', arr4[0])
return
}
if (arr.length > 0) {
treRef.value.treeRef1.setCurrentKey(arr[0].id)
// 注册父组件事件
emit('init', {
level: 2,
...arr[0]
})
return
} else if (arr2.length > 0) {
treRef.value.treeRef2.setCurrentKey(arr2[0].id)
// 注册父组件事件
emit('init', {
level: 2,
...arr2[0]
})
return
} else if (arr3.length > 0) {
console.log('🚀 ~ arr3:', arr3)
treRef.value.treeRef3.setCurrentKey(arr3[0].id)
// 注册父组件事件
emit('init', {
level: 2,
...arr3[0]
})
return
} else {
emit('init')
return
}
}, 500)
})
}) })
}
onMounted(() => {
info(props.engineering ? '2' : '1')
}) })
throttle( throttle(

View File

@@ -1,5 +1,12 @@
<template> <template>
<Tree ref="treRef" :width="width" :data="tree" default-expand-all @changePointType="changePointType" /> <Tree
ref="treRef"
:width="width"
:data="tree"
default-expand-all
@changePointType="changePointType"
@changeTreeType="info"
/>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
@@ -27,80 +34,128 @@ const dictData = useDictData()
const treRef = ref() const treRef = ref()
const width = ref('') const width = ref('')
const info = () => { const info = (type?: string) => {
tree.value = [] tree.value = []
let arr1: any[] = [] let arr1: any[] = []
let arr2: any[] = [] let arr2: any[] = []
let arr3: any[] = [] let arr3: any[] = []
getLineTree().then(res => { let arr4: any[] = []
getLineTree({ type: type == '2' ? 'engineering' : '' }).then(res => {
//治理设备 //治理设备
res.data.map((item: any) => { res.data.map((item: any) => {
if (item.name == '治理设备') { if (type == '2') {
item.icon = 'el-icon-HomeFilled'
item.color = config.getColorVal('elementUiPrimary')
item.children.forEach((item: any) => { item.children.forEach((item: any) => {
item.icon = 'el-icon-HomeFilled' item.icon = 'el-icon-List'
item.level = 1
item.color = config.getColorVal('elementUiPrimary') item.color = config.getColorVal('elementUiPrimary')
item.children.forEach((item2: any) => { item.children.forEach((item2: any) => {
item2.icon = 'el-icon-List' // item2.icon = 'el-icon-List'
item2.level = 1 // item2.color = config.getColorVal('elementUiPrimary')
item2.color = config.getColorVal('elementUiPrimary')
item2.children.forEach((item3: any) => {
item3.icon = 'el-icon-Platform'
item3.level = 2
item3.color =
item3.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
item3.children.forEach((item4: any) => {
item4.icon = 'el-icon-Platform'
item4.color =
item4.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
// item4.color = '#e26257 !important'
arr1.push(item4)
})
})
})
})
} else if (item.name == '便携式设备') {
item.children.forEach((item: any) => {
item.icon = 'el-icon-Platform'
item.color = config.getColorVal('elementUiPrimary')
item.color = item.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
item.children.forEach((item2: any) => {
item2.icon = 'el-icon-Platform' item2.icon = 'el-icon-Platform'
item2.level = 2
item2.color = item2.color =
item2.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important' item2.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
arr2.push(item2)
})
})
} else if (item.name == '监测设备') {
item.children.forEach((item: any) => {
item.icon = 'el-icon-HomeFilled'
item.level = 1
item.color = config.getColorVal('elementUiPrimary')
item.children.forEach((item2: any) => {
item2.icon = 'el-icon-List'
item2.level = 1
item2.color = config.getColorVal('elementUiPrimary')
item2.children.forEach((item3: any) => { item2.children.forEach((item3: any) => {
item3.icon = 'el-icon-Platform' item3.icon = 'el-icon-Platform'
item3.level = 1
item3.color = item3.color =
item3.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important' item3.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
item3.children.forEach((item4: any) => { arr4.push(item3)
item4.icon = 'el-icon-Platform' // item3.children.forEach((item4: any) => {
item4.color = // item4.icon = 'el-icon-Platform'
item4.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important' // item4.color =
// item4.color = '#e26257 !important' // item4.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
arr3.push(item4)
}) // })
}) })
}) })
}) })
} else {
if (item.name == '治理设备') {
item.children.forEach((item: any) => {
item.icon = 'el-icon-HomeFilled'
item.level = 1
item.color = config.getColorVal('elementUiPrimary')
item.children.forEach((item2: any) => {
item2.icon = 'el-icon-List'
item2.level = 1
item2.color = config.getColorVal('elementUiPrimary')
item2.children.forEach((item3: any) => {
item3.icon = 'el-icon-Platform'
item3.level = 2
item3.color =
item3.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
item3.children.forEach((item4: any) => {
item4.icon = 'el-icon-Platform'
item4.color =
item4.comFlag === 2
? config.getColorVal('elementUiPrimary')
: '#e26257 !important'
// item4.color = '#e26257 !important'
arr1.push(item4)
})
})
})
})
} else if (item.name == '便携式设备') {
item.children.forEach((item: any) => {
item.icon = 'el-icon-Platform'
item.color = config.getColorVal('elementUiPrimary')
item.color = item.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
item.children.forEach((item2: any) => {
item2.icon = 'el-icon-Platform'
item2.color =
item2.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
arr2.push(item2)
})
})
} else if (item.name == '监测设备') {
item.children.forEach((item: any) => {
item.icon = 'el-icon-HomeFilled'
item.level = 1
item.color = config.getColorVal('elementUiPrimary')
item.children.forEach((item2: any) => {
item2.icon = 'el-icon-List'
item2.level = 1
item2.color = config.getColorVal('elementUiPrimary')
item2.children.forEach((item3: any) => {
item3.icon = 'el-icon-Platform'
item3.level = 1
item3.color =
item3.comFlag === 2 ? config.getColorVal('elementUiPrimary') : '#e26257 !important'
item3.children.forEach((item4: any) => {
item4.icon = 'el-icon-Platform'
item4.color =
item4.comFlag === 2
? config.getColorVal('elementUiPrimary')
: '#e26257 !important'
// item4.color = '#e26257 !important'
arr3.push(item4)
})
})
})
})
}
} }
}) })
tree.value = res.data tree.value = res.data
nextTick(() => { nextTick(() => {
setTimeout(() => { setTimeout(() => {
if (arr1.length > 0) { if (type == '2') {
//初始化选中
treRef.value?.treeRef4.setCurrentKey(arr4[0].id)
// 注册父组件事件
emit('init', {
level: 3,
...arr4[0]
})
changePointType('4', arr4[0])
return
} else if (arr1.length > 0) {
//初始化选中 //初始化选中
treRef.value?.treeRef1.setCurrentKey(arr1[0].id) treRef.value?.treeRef1.setCurrentKey(arr1[0].id)
// 注册父组件事件 // 注册父组件事件
@@ -119,7 +174,6 @@ const info = () => {
}) })
return return
} else if (arr3.length > 0) { } else if (arr3.length > 0) {
treRef.value?.treeRef3?.setCurrentKey(arr3[0].id) treRef.value?.treeRef3?.setCurrentKey(arr3[0].id)
emit('init', { emit('init', {
level: 2, level: 2,
@@ -138,7 +192,8 @@ const changePointType = (val: any, obj: any) => {
emit('pointTypeChange', val, obj) emit('pointTypeChange', val, obj)
} }
if (props.template) { if (props.template) {
querySysExcel({ id: dictData.state.area[0]?.id }) // id: dictData.state.area[0]?.id
querySysExcel({})
.then((res: any) => { .then((res: any) => {
emit('Policy', res.data) emit('Policy', res.data)
info() info()

View File

@@ -3,13 +3,7 @@
<div style="transition: all 0.3s; overflow: hidden; height: 100%"> <div style="transition: all 0.3s; overflow: hidden; height: 100%">
<div class="cn-tree"> <div class="cn-tree">
<div style="display: flex; align-items: center" class="mb10"> <div style="display: flex; align-items: center" class="mb10">
<el-input <el-input maxlength="32" v-model.trim="filterText" placeholder="请输入内容" clearable>
maxlength="32"
show-word-limit
v-model.trim="filterText"
placeholder="请输入内容"
clearable
>
<template #prefix> <template #prefix>
<Icon name="el-icon-Search" style="font-size: 16px" /> <Icon name="el-icon-Search" style="font-size: 16px" />
</template> </template>
@@ -37,7 +31,7 @@
:style="{ color: data.color }" :style="{ color: data.color }"
v-if="data.icon" v-if="data.icon"
/> />
<span style="margin-left: 5px;">{{ node.label }}</span> <span style="margin-left: 5px">{{ node.label }}</span>
</div> </div>
</span> </span>
</template> </template>
@@ -157,7 +151,8 @@ const clickNode = (e: anyObj) => {
} }
if (props.template) { if (props.template) {
querySysExcel({ id: dictData.state.area[0]?.id }) // id: dictData.state.area[0]?.id
querySysExcel({})
.then((res: any) => { .then((res: any) => {
emit('Policy', res.data) emit('Policy', res.data)
getTreeList() getTreeList()

View File

@@ -1,41 +1,61 @@
<template> <template>
<div :style="{ width: menuCollapse ? '40px' : props.width }" style='transition: all 0.3s; overflow: hidden;'> <div :style="{ width: menuCollapse ? '40px' : props.width }" style="transition: all 0.3s; overflow: hidden">
<Icon v-show='menuCollapse' @click='onMenuCollapse' :name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'" <Icon
:class="menuCollapse ? 'unfold' : ''" size='18' class='fold ml10 mt20 menu-collapse' v-show="menuCollapse"
style='cursor: pointer' /> @click="onMenuCollapse"
<div class='cn-tree' :style='{ opacity: menuCollapse ? 0 : 1 }'> :name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
<div style='display: flex; align-items: center' class='mb10'> :class="menuCollapse ? 'unfold' : ''"
<el-input maxlength="32" show-word-limit v-model.trim='filterText' placeholder='请输入内容' clearable> size="18"
class="fold ml10 mt20 menu-collapse"
style="cursor: pointer"
/>
<div class="cn-tree" :style="{ opacity: menuCollapse ? 0 : 1 }">
<div style="display: flex; align-items: center" class="mb10">
<el-input maxlength="32" v-model.trim="filterText" placeholder="请输入内容" clearable>
<template #prefix> <template #prefix>
<Icon name='el-icon-Search' style='font-size: 16px' /> <Icon name="el-icon-Search" style="font-size: 16px" />
</template> </template>
</el-input> </el-input>
<el-tooltip placement="bottom" :hide-after="0" v-if="props.showPush"> <el-tooltip placement="bottom" :hide-after="0" v-if="props.showPush">
<template #content> <template #content>
<span>台账推送</span> <span>台账推送</span>
</template> </template>
<Icon <Icon
name="el-icon-Promotion" name="el-icon-Promotion"
size="20" size="20"
class="fold ml10 menu-collapse" class="fold ml10 mr10 menu-collapse"
style="cursor: pointer;" style="cursor: pointer"
:style="{ color: config.getColorVal('elementUiPrimary') }" :style="{ color: config.getColorVal('elementUiPrimary') }"
@click="onAdd" /> @click="onAdd"
/>
</el-tooltip> </el-tooltip>
<!-- <Icon @click='onMenuCollapse' :name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'" v-else <!-- <Icon @click='onMenuCollapse' :name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'" v-else
:class="menuCollapse ? 'unfold' : ''" size='18' class='fold ml10 menu-collapse' :class="menuCollapse ? 'unfold' : ''" size='18' class='fold ml10 menu-collapse'
style='cursor: pointer' v-if='props.canExpand' /> --> style='cursor: pointer' v-if='props.canExpand' /> -->
</div> </div>
<el-tree :style="{ height: 'calc(100vh - 190px)' }" <el-tree
style=' overflow: auto;' ref='treeRef' :props='defaultProps' highlight-current :default-expand-all="false" :style="{ height: 'calc(100vh - 190px)' }"
@check-change="checkTreeNodeChange" :filter-node-method='filterNode' node-key='id' v-bind='$attrs'> style="overflow: auto"
<template #default='{ node, data }'> ref="treeRef"
<span class='custom-tree-node'> :props="defaultProps"
<Icon :name='data.icon' style='font-size: 16px' :style='{ color: data.color }' highlight-current
v-if='data.icon' /> :default-expand-all="false"
<span style='margin-left: 4px'>{{ node.label }}</span> @check-change="checkTreeNodeChange"
:filter-node-method="filterNode"
node-key="id"
v-bind="$attrs"
>
<template #default="{ node, data }">
<span class="custom-tree-node">
<Icon
:name="data.icon"
style="font-size: 16px"
:style="{ color: data.color }"
v-if="data.icon"
/>
<span style="margin-left: 4px">{{ node.label }}</span>
</span> </span>
</template> </template>
</el-tree> </el-tree>
@@ -43,12 +63,10 @@
</div> </div>
</template> </template>
<script lang='ts' setup> <script lang="ts" setup>
import useCurrentInstance from '@/utils/useCurrentInstance' import useCurrentInstance from '@/utils/useCurrentInstance'
import { ElTree } from 'element-plus' import { ElTree } from 'element-plus'
import { emit } from 'process';
import { ref, watch } from 'vue' import { ref, watch } from 'vue'
import { t } from 'vxe-table';
import { useConfig } from '@/stores/config' import { useConfig } from '@/stores/config'
defineOptions({ defineOptions({
@@ -74,7 +92,7 @@ const defaultProps = {
label: 'name', label: 'name',
value: 'id' value: 'id'
} }
const emit = defineEmits(['checkTreeNodeChange','onAdd']) const emit = defineEmits(['checkTreeNodeChange', 'onAdd'])
watch(filterText, val => { watch(filterText, val => {
treeRef.value!.filter(val) treeRef.value!.filter(val)
}) })
@@ -83,18 +101,16 @@ const onMenuCollapse = () => {
proxy.eventBus.emit('cnTreeCollapse', menuCollapse) proxy.eventBus.emit('cnTreeCollapse', menuCollapse)
} }
const filterNode = (value: string, data: any, node: any) => { const filterNode = (value: string, data: any, node: any) => {
console.log(value, data, node, 'filterNode'); console.log(value, data, node, 'filterNode')
if (!value) return true if (!value) return true
// return data.name.includes(value) // return data.name.includes(value)
if (data.name) { if (data.name) {
return chooseNode(value, data, node) return chooseNode(value, data, node)
} }
} }
// 过滤父节点 / 子节点 (如果输入的参数是父节点且能匹配则返回该节点以及其下的所有子节点如果参数是子节点则返回该节点的父节点。name是中文字符enName是英文字符. // 过滤父节点 / 子节点 (如果输入的参数是父节点且能匹配则返回该节点以及其下的所有子节点如果参数是子节点则返回该节点的父节点。name是中文字符enName是英文字符.
const chooseNode = (value: string, data: any, node: any) => { const chooseNode = (value: string, data: any, node: any) => {
if (data.name.indexOf(value) !== -1) { if (data.name.indexOf(value) !== -1) {
return true return true
} }
@@ -132,13 +148,13 @@ const treeRef = ref<InstanceType<typeof ElTree>>()
defineExpose({ treeRef }) defineExpose({ treeRef })
</script> </script>
<style lang='scss' scoped> <style lang="scss" scoped>
.cn-tree { .cn-tree {
flex-shrink: 0; flex-shrink: 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
box-sizing: border-box; box-sizing: border-box;
padding: 10px; // padding: 10px;
height: 100%; height: 100%;
width: 100%; width: 100%;

View File

@@ -13,11 +13,27 @@
/> />
<div class="cn-tree" :style="{ opacity: menuCollapse ? 0 : 1, display: menuCollapse ? 'none' : '' }"> <div class="cn-tree" :style="{ opacity: menuCollapse ? 0 : 1, display: menuCollapse ? 'none' : '' }">
<div style="display: flex; align-items: center" class="mb10"> <div style="display: flex; align-items: center" class="mb10">
<el-input maxlength="32" show-word-limit v-model.trim="filterText" placeholder="请输入内容" clearable> <!-- <el-input maxlength="32" v-model.trim="filterText" placeholder="请输入内容" clearable>
<template #prefix>
<Icon name="el-icon-Search" style="font-size: 16px" />
</template>
</el-input> -->
<el-input maxlength="32" v-model.trim="filterText" placeholder="请输入内容" clearable>
<template #prepend>
<el-select v-model="treeType" @change="changeTreeType" style="min-width: 75px">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</template>
<template #prefix> <template #prefix>
<Icon name="el-icon-Search" style="font-size: 16px" /> <Icon name="el-icon-Search" style="font-size: 16px" />
</template> </template>
</el-input> </el-input>
<!-- -->
<Icon <Icon
@click="onMenuCollapse" @click="onMenuCollapse"
:name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'" :name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
@@ -34,6 +50,8 @@
v-model.trim="activeName" v-model.trim="activeName"
style="flex: 1; height: 100%" style="flex: 1; height: 100%"
@change="changeDevice" @change="changeDevice"
v-if="treeType == '1'"
v-loading="loading"
> >
<el-collapse-item title="治理设备" name="0" v-if="zlDeviceData.length != 0"> <el-collapse-item title="治理设备" name="0" v-if="zlDeviceData.length != 0">
<el-select v-model.trim="process" clearable placeholder="请选择状态" class="mb10"> <el-select v-model.trim="process" clearable placeholder="请选择状态" class="mb10">
@@ -43,7 +61,7 @@
</el-select> </el-select>
<el-tree <el-tree
:style="{ height: bxsDeviceData.length != 0 ? 'calc(100vh - 380px)' : 'calc(100vh - 278px)' }" :style="{ height: treeType.length != 0 ? 'calc(100vh - 380px)' : 'calc(100vh - 278px)' }"
ref="treeRef1" ref="treeRef1"
:props="defaultProps" :props="defaultProps"
highlight-current highlight-current
@@ -120,6 +138,33 @@
</el-tree> </el-tree>
</el-collapse-item> </el-collapse-item>
</el-collapse> </el-collapse>
<div v-if="treeType == '2'" v-loading="loading">
<el-tree
:style="{ height: 'calc(100vh - 188px)' }"
class="pt10"
ref="treeRef4"
:props="defaultProps"
highlight-current
:filter-node-method="filterNode"
node-key="id"
v-bind="$attrs"
:data="data"
style="overflow: auto"
:default-expand-all="false"
>
<template #default="{ node, data }">
<span class="custom-tree-node">
<Icon
:name="data.icon"
style="font-size: 16px"
:style="{ color: data.color }"
v-if="data.icon"
/>
<span style="margin-left: 4px">{{ node.label }}</span>
</span>
</template>
</el-tree>
</div>
</div> </div>
</div> </div>
</template> </template>
@@ -133,7 +178,7 @@ import { useRoute } from 'vue-router'
defineOptions({ defineOptions({
name: 'govern/tree' name: 'govern/tree'
}) })
const emit = defineEmits(['changePointType']) const emit = defineEmits(['changePointType', 'changeTreeType'])
interface Props { interface Props {
width?: string width?: string
canExpand?: boolean canExpand?: boolean
@@ -157,6 +202,17 @@ const defaultProps = {
label: 'name', label: 'name',
value: 'id' value: 'id'
} }
const treeType = ref('1')
const options = [
{
label: '设备',
value: '1'
},
{
label: '工程',
value: '2'
}
]
//治理设备数据 //治理设备数据
const zlDeviceData = ref<any>([]) const zlDeviceData = ref<any>([])
const zlDevList = ref<any>([]) const zlDevList = ref<any>([])
@@ -196,7 +252,9 @@ watch(
) )
watch(filterText, val => { watch(filterText, val => {
if (activeName.value == '0') { if (treeType.value == '2') {
treeRef4.value!.filter(val)
} else if (activeName.value == '0') {
treeRef1.value!.filter(val) treeRef1.value!.filter(val)
} else if (activeName.value == '1') { } else if (activeName.value == '1') {
treeRef2.value!.filter(val) treeRef2.value!.filter(val)
@@ -217,8 +275,6 @@ watch(process, val => {
}) })
const changeDevice = (val: any) => { const changeDevice = (val: any) => {
console.log('🚀 ~ changeDevice ~ val:', val)
let arr1: any = [] let arr1: any = []
//zlDeviceData //zlDeviceData
zlDevList.value.forEach((item: any) => { zlDevList.value.forEach((item: any) => {
@@ -299,7 +355,7 @@ function filterProcess(nodes: any) {
// 递归处理子节点 // 递归处理子节点
const children = node.children ? filterProcess(node.children) : [] const children = node.children ? filterProcess(node.children) : []
// 对于装置层级level=2只保留 process 值匹配的节点 // 对于设备层级level=2只保留 process 值匹配的节点
if (node.level === 2) { if (node.level === 2) {
if (node.process == process.value) { if (node.process == process.value) {
return { return {
@@ -381,27 +437,43 @@ const treeRef1 = ref<InstanceType<typeof ElTree>>()
const treeRef2 = ref<InstanceType<typeof ElTree>>() const treeRef2 = ref<InstanceType<typeof ElTree>>()
//在线 //在线
const treeRef3 = ref<InstanceType<typeof ElTree>>() const treeRef3 = ref<InstanceType<typeof ElTree>>()
defineExpose({ treeRef1, treeRef2, treeRef3 }) // 工程
const treeRef4 = ref<InstanceType<typeof ElTree>>()
defineExpose({ treeRef1, treeRef2, treeRef3, treeRef4 })
onMounted(() => { onMounted(() => {
setTimeout(() => { setTimeout(() => {
if (zlDeviceData.value.length != 0) { setActiveName()
zlDevList.value = filterProcess(JSON.parse(JSON.stringify(zlDeviceData.value)))
activeName.value = '0'
}
if (zlDeviceData.value.length === 0 && bxsDeviceData.value.length != 0) {
activeName.value = '1'
}
if (zlDeviceData.value.length === 0 && bxsDeviceData.value.length === 0) {
activeName.value = '2'
}
if (!zlDeviceData.value && !bxsDeviceData.value) {
activeName.value = '2'
}
nextTick(() => {
changeDevice(activeName.value)
})
}, 500) }, 500)
}) })
const setActiveName = () => {
if (zlDeviceData.value.length != 0) {
zlDevList.value = filterProcess(JSON.parse(JSON.stringify(zlDeviceData.value)))
activeName.value = '0'
}
if (zlDeviceData.value.length === 0 && bxsDeviceData.value.length != 0) {
activeName.value = '1'
}
if (zlDeviceData.value.length === 0 && bxsDeviceData.value.length === 0) {
activeName.value = '2'
}
if (!zlDeviceData.value && !bxsDeviceData.value) {
activeName.value = '2'
}
nextTick(() => {
changeDevice(activeName.value)
})
}
const loading = ref(false)
const changeTreeType = (val: string) => {
loading.value = true
emit('changeTreeType', val)
if (val == '1') {
setActiveName()
}
setTimeout(() => {
loading.value = false
}, 1000)
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@@ -432,4 +504,7 @@ onMounted(() => {
display: flex; display: flex;
align-items: center; align-items: center;
} }
:deep(.el-input-group__prepend) {
background-color: var(--el-fill-color-blank);
}
</style> </style>

View File

@@ -5,7 +5,7 @@
style='cursor: pointer' /> style='cursor: pointer' />
<div class='cn-tree' :style='{ opacity: menuCollapse ? 0 : 1 }'> <div class='cn-tree' :style='{ opacity: menuCollapse ? 0 : 1 }'>
<div style='display: flex; align-items: center' class='mb10'> <div style='display: flex; align-items: center' class='mb10'>
<el-input maxlength="32" show-word-limit v-model.trim='filterText' placeholder='请输入内容' clearable> <el-input maxlength="32" v-model.trim='filterText' placeholder='请输入内容' clearable>
<template #prefix> <template #prefix>
<Icon name='el-icon-Search' style='font-size: 16px' /> <Icon name='el-icon-Search' style='font-size: 16px' />
</template> </template>

View File

@@ -35,6 +35,15 @@ export const adminBaseRoute = {
title: pageTitle('router.supplementaryRecruitment') title: pageTitle('router.supplementaryRecruitment')
} }
}, },
{
// 在线补召
path: '/versionMaintenance',
name: 'versionMaintenance',
component: () => import('@/views/govern/manage/programVersion/comp/versionMaintenance.vue'),
meta: {
title: pageTitle('router.versionMaintenance')
}
},
{ {
path: 'cockpit', path: 'cockpit',
name: '项目管理', name: '项目管理',

103
src/utils/downloadFile.ts Normal file
View File

@@ -0,0 +1,103 @@
import { ElMessage, ElMessageBox, ElInput, ElSegmented } from 'element-plus'
export const downLoadFile = (name: string, key: string, res: any) => {
let blob = new Blob([res], {
type: getFileType(key)
})
const url = window.URL.createObjectURL(blob)
const link = document.createElement('a') // 创建a标签
link.href = url
link.download = name // 设置下载的文件名
document.body.appendChild(link)
link.click() //执行下载
document.body.removeChild(link)
ElMessage.success('下载成功')
}
const getFileType = (url: string) => {
const ext = url.split('.').pop()?.toLowerCase() || ''
const mimeMap: Record<string, string> = {
// Excel
xls: 'application/vnd.ms-excel',
xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
// CSV
csv: 'text/csv',
// Word
doc: 'application/msword',
docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
// PDF
pdf: 'application/pdf',
// PowerPoint
ppt: 'application/vnd.ms-powerpoint',
pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
// 图片
png: 'image/png',
gif: 'image/gif',
jpeg: 'image/jpeg',
jpg: 'image/jpeg',
bmp: 'image/bmp',
ico: 'image/vnd.microsoft.icon',
tif: 'image/tiff',
tiff: 'image/tiff',
svg: 'image/svg+xml',
webp: 'image/webp',
// 音频
mp3: 'audio/mpeg',
aac: 'audio/aac',
mid: 'audio/midi',
midi: 'audio/midi',
oga: 'audio/ogg',
wav: 'audio/wav',
weba: 'audio/webm',
// 视频
avi: 'video/x-msvideo',
mpeg: 'video/mpeg',
ogv: 'video/ogg',
webm: 'video/webm',
'3gp': 'video/3gpp',
'3g2': 'video/3gpp2',
// 网页/代码
html: 'text/html',
css: 'text/css',
js: 'text/javascript',
mjs: 'text/javascript',
json: 'application/json',
jsonld: 'application/ld+json',
xhtml: 'application/xhtml+xml',
xml: 'application/xml',
xul: 'application/vnd.mozilla.xul+xml',
// 文档
abw: 'application/x-abiword',
odp: 'application/vnd.oasis.opendocument.presentation',
ods: 'application/vnd.oasis.opendocument.spreadsheet',
odt: 'application/vnd.oasis.opendocument.text',
rtf: 'application/rtf',
txt: 'text/plain',
vsd: 'application/vnd.visio',
// 字体
otf: 'font/otf',
ttf: 'font/ttf',
woff: 'font/woff',
woff2: 'font/woff2',
eot: 'application/vnd.ms-fontobject',
// 压缩/归档
arc: 'application/x-freearc',
bz: 'application/x-bzip',
bz2: 'application/x-bzip2',
rar: 'application/x-rar-compressed',
tar: 'application/x-tar',
zip: 'application/zip',
'7z': 'application/x-7z-compressed',
// 其他
bin: 'application/octet-stream',
csh: 'application/x-csh',
epub: 'application/epub+zip',
azw: 'application/vnd.amazon.ebook',
ics: 'text/calendar',
jar: 'application/java-archive',
mpkg: 'application/vnd.apple.installer+xml',
ogx: 'application/ogg',
sh: 'application/x-sh',
swf: 'application/x-shockwave-flash'
}
return mimeMap[ext] || ''
}

View File

@@ -4,7 +4,7 @@ import { ElLoading, ElMessage, ElNotification, type LoadingOptions } from 'eleme
import { refreshToken } from '@/api/user-boot/user' import { refreshToken } from '@/api/user-boot/user'
import router from '@/router/index' import router from '@/router/index'
import { useAdminInfo } from '@/stores/adminInfo' import { useAdminInfo } from '@/stores/adminInfo'
import { useNavTabs } from '@/stores/navTabs'
window.requests = [] window.requests = []
window.tokenRefreshing = false window.tokenRefreshing = false
let loginExpireTimer: any = null let loginExpireTimer: any = null
@@ -13,7 +13,7 @@ const loadingInstance: LoadingInstance = {
target: null, target: null,
count: 0 count: 0
} }
const navTabs = useNavTabs()
/** /**
* 根据运行环境获取基础请求URL * 根据运行环境获取基础请求URL
*/ */
@@ -164,6 +164,9 @@ function createAxios<Data = any, T = ApiPromise<Data>>(
message: response.data.message message: response.data.message
}) })
adminInfo.removeToken() adminInfo.removeToken()
navTabs.closeTabs()
window.localStorage.clear()
adminInfo.reset()
router.push({ name: 'login' }) router.push({ name: 'login' })
loginExpireTimer = null // 执行后清空定时器 loginExpireTimer = null // 执行后清空定时器
}, 100) // 可根据实际情况调整延迟时间 }, 100) // 可根据实际情况调整延迟时间

View File

@@ -100,6 +100,7 @@ const tableStore = new TableStore({
} }
}, },
{ title: '设备名称', field: 'equipmentName', align: 'center', width: 120 }, { title: '设备名称', field: 'equipmentName', align: 'center', width: 120 },
{ title: '监测点名称', field: 'lineName', align: 'center', width: 140 },
{ title: '工程名称', field: 'engineeringName', align: 'center', width: 120 }, { title: '工程名称', field: 'engineeringName', align: 'center', width: 120 },
{ title: '项目名称', field: 'projectName', align: 'center', width: 120 }, { title: '项目名称', field: 'projectName', align: 'center', width: 120 },
{ title: '发生时刻', field: 'startTime', align: 'center', width: 180, sortable: true }, { title: '发生时刻', field: 'startTime', align: 'center', width: 180, sortable: true },

File diff suppressed because it is too large Load Diff

View File

@@ -1,298 +1,297 @@
<template> <template>
<div class="device-control-detail child-router"> <div class="device-control-detail child-router">
<TableHeader :showSearch="false"> <TableHeader :showSearch="false">
<template #select> <template #select>
<el-form-item label="日期"> <el-form-item label="日期">
<DatePicker ref="datePickerRef"></DatePicker> <DatePicker ref="datePickerRef"></DatePicker>
</el-form-item> </el-form-item>
<el-form-item label="值类型"> <el-form-item label="值类型">
<el-select v-model.trim="form.dataLevel" :disabled="props.dataLevel == 'Primary'"> <el-select v-model.trim="form.dataLevel" :disabled="props.dataLevel == 'Primary'">
<el-option value="Primary" label="一次值"></el-option> <el-option value="Primary" label="一次值"></el-option>
<el-option value="Secondary" label="二次值"></el-option> <el-option value="Secondary" label="二次值"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="数据类型" label-width="80px"> <el-form-item label="数据类型" label-width="80px">
<el-select v-model.trim="form.statMethod" placeholder="请选择数据类型"> <el-select v-model.trim="form.statMethod" placeholder="请选择数据类型">
<el-option v-for="item in typeOptions" :key="item.id" :label="item.name" <el-option v-for="item in typeOptions" :key="item.id" :label="item.name"
:value="item.id"></el-option> :value="item.id"></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
</template> </template>
<template #operation> <template #operation>
<el-button type="primary" icon="el-icon-Search" @click="init">查询</el-button> <el-button type="primary" icon="el-icon-Search" @click="init">查询</el-button>
<el-button icon="el-icon-Back" @click="$emit('close')">返回</el-button> <el-button icon="el-icon-Back" @click="$emit('close')">返回</el-button>
</template> </template>
</TableHeader> </TableHeader>
<MyEchart :options="echartsData" v-if="echartsData" style="flex: 1" class="mt10" /> <MyEchart :options="echartsData" v-if="echartsData" style="flex: 1" class="mt10" />
<el-empty description="暂无数据" v-else style="flex: 1" v-loading="loading"></el-empty> <el-empty description="暂无数据" v-else style="flex: 1" v-loading="loading"></el-empty>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, inject, nextTick, onMounted } from 'vue' import { ref, inject, nextTick, onMounted } from 'vue'
import { reactive } from 'vue' import { reactive } from 'vue'
import DatePicker from '@/components/form/datePicker/index.vue' import DatePicker from '@/components/form/datePicker/index.vue'
import { getDeviceDataTrend } from '@/api/cs-harmonic-boot/datatrend' import { getDeviceDataTrend } from '@/api/cs-harmonic-boot/datatrend'
import TableHeader from '@/components/table/header/index.vue' import TableHeader from '@/components/table/header/index.vue'
import MyEchart from '@/components/echarts/MyEchart.vue' import MyEchart from '@/components/echarts/MyEchart.vue'
import { yMethod, exportCSV } from '@/utils/echartMethod' import { yMethod, exportCSV } from '@/utils/echartMethod'
import { ITEM_RENDER_EVT } from 'element-plus/es/components/virtual-list/src/defaults' import { ITEM_RENDER_EVT } from 'element-plus/es/components/virtual-list/src/defaults'
interface Props { interface Props {
detail: anyObj detail: anyObj
dataLevel: string dataLevel: string
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
detail: () => { detail: () => {
return {} return {}
}, },
dataLevel: () => { dataLevel: () => {
return '' return ''
} }
}) })
const datePickerRef = ref() const datePickerRef = ref()
const form: any = reactive({ const form: any = reactive({
code: '', code: '',
icon: '', icon: '',
id: '', id: '',
name: '', name: '',
path: '', path: '',
pid: '0', pid: '0',
remark: '', remark: '',
routeName: '', routeName: '',
sort: 100, sort: 100,
dataLevel: '', dataLevel: '',
statMethod: 'avg' statMethod: 'avg'
}) })
const typeOptions = [ const typeOptions = [
{ {
name: '平均值', name: '平均值',
id: 'avg' id: 'avg'
}, },
{ {
name: '最大值', name: '最大值',
id: 'max' id: 'max'
}, },
{ {
name: '最小值', name: '最小值',
id: 'min' id: 'min'
}, },
{ {
name: 'CP95值', name: 'CP95值',
id: 'cp95' id: 'cp95'
} }
] ]
const echartsData = ref<any>(null) const echartsData = ref<any>(null)
const dialogVisible = ref(false) const dialogVisible = ref(false)
const loading = ref(true) const loading = ref(true)
onMounted(() => { onMounted(() => {
if (props.dataLevel == 'Secondary') { if (props.dataLevel == 'Secondary') {
form.dataLevel = 'Primary' form.dataLevel = 'Primary'
} else { } else {
form.dataLevel = props.dataLevel form.dataLevel = props.dataLevel
} }
init() init()
}) })
const init = () => { const init = () => {
echartsData.value = null echartsData.value = null
loading.value = true loading.value = true
// console.log(props.detail.children, 'props.detail.children') // console.log(props.detail.children, 'props.detail.children')
let statisticalParams = props.detail.children let statisticalParams = props.detail.children
statisticalParams[0].statMethod = form.statMethod statisticalParams[0].statMethod = form.statMethod
getDeviceDataTrend({ getDeviceDataTrend({
devId: props.detail.devId, devId: props.detail.devId,
endTime: datePickerRef.value.timeValue[1], endTime: datePickerRef.value.timeValue[1],
lineId: props.detail.lineId, lineId: props.detail.lineId,
startTime: datePickerRef.value.timeValue[0], startTime: datePickerRef.value.timeValue[0],
statisticalParams: statisticalParams, statisticalParams: statisticalParams,
dataLevel: form.dataLevel, dataLevel: form.dataLevel,
statMethod: form.statMethod statMethod: form.statMethod
}).then(res => { }).then(res => {
if (res.data.length && res.data[0].length) { if (res.data.length && res.data[0].length) {
let arr: any[] = [] let arr: any[] = []
res.data.forEach((item: any[]) => { res.data.forEach((item: any[]) => {
arr.push(...item) arr.push(...item)
}) })
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 = {
options: { options: {
legend: { legend: {
right: 70, right: 70,
top: 5, top: 5,
data: res.data.map((item: any[]) => { data: res.data.map((item: any[]) => {
return item[0]?.anotherName return item[0]?.anotherName
}) })
}, },
grid: { grid: {
top: '60px', top: '60px',
left: '10px', left: '10px',
right: '20px', right: '20px',
bottom: '40px', bottom: '40px',
containLabel: true containLabel: true
}, },
series: res.data.map((item: any) => { series: res.data.map((item: any) => {
return { return {
data: item.map((item: any, i: any) => { data: item.map((item: any, i: any) => {
return [res.data[0][i]?.time, item.statisticalData.toFixed(2)] return [res.data[0][i]?.time, item.statisticalData.toFixed(2)]
}), }),
// data: [ // data: [
// [1584086222000, '573'], // [1584086222000, '573'],
// [1584086342000, '57'], // [1584086342000, '57'],
// [1584086462000, '56'] // [1584086462000, '56']
// ], // ],
// markPoint: { // markPoint: {
// symbol: 'circle', // symbol: 'circle',
// symbolSize: 0, // symbolSize: 0,
// label: { // label: {
// show: false // show: false
// }, // },
// data: [ // data: [
// { type: 'max', name: 'Max' }, // { type: 'max', name: 'Max' },
// { type: 'min', name: 'Min' } // { type: 'min', name: 'Min' }
// ] // ]
// }, // },
type: 'line', type: 'line',
showSymbol: false, showSymbol: false,
smooth: true, smooth: true,
name: item[0]?.anotherName name: item[0]?.anotherName
} }
}) })
}, },
title: { title: {
text: props.detail.name?.split('(')[0], text: props.detail.name?.split('(')[0],
}, },
tooltip: { tooltip: {
axisPointer: { axisPointer: {
type: 'cross', type: 'cross',
label: { label: {
color: '#fff', color: '#fff',
fontSize: 16 fontSize: 16
} }
}, },
textStyle: { textStyle: {
color: '#fff', color: '#fff',
fontStyle: 'normal', fontStyle: 'normal',
opacity: 0.35, opacity: 0.35,
fontSize: 14 fontSize: 14
}, },
backgroundColor: 'rgba(0,0,0,0.55)', borderWidth: 0
borderWidth: 0 },
},
yAxis: {
yAxis: { name: `单位:(${arr[0].unit == null ? ' / ' : arr[0].unit})`,
name: `单位:(${arr[0].unit == null ? ' / ' : arr[0].unit})`, type: 'value',
type: 'value',
min: min,
min: min, max: max,
max: max, // interval:interval,
// interval:interval,
// min: 134,
// min: 134, // max: 500,
// max: 500, // min: Math.ceil(
// min: Math.ceil( // arr
// arr // .map((item: any) => item.statisticalData)
// .map((item: any) => item.statisticalData) // .sort((a, b) => {
// .sort((a, b) => { // return a - b
// return a - b // })[0]
// })[0] // ),
// ), // max: Math.floor(
// max: Math.floor( // arr
// arr // .map(item => item.statisticalData)
// .map(item => item.statisticalData) // .sort((a, b) => {
// .sort((a, b) => { // return b - a
// return b - a // })[0]
// })[0] // ),
// ), // interval: (Math.floor(
// interval: (Math.floor( // arr
// arr // .map(item => item.statisticalData)
// .map(item => item.statisticalData) // .sort((a, b) => {
// .sort((a, b) => { // return b - a
// return b - a // })[0]
// })[0] // ) - Math.ceil(
// ) - Math.ceil( // arr
// arr // .map((item: any) => item.statisticalData)
// .map((item: any) => item.statisticalData) // .sort((a, b) => {
// .sort((a, b) => { // return a - b
// return a - b // })[0]
// })[0] // )) / 5,
// )) / 5,
},
},
xAxis: {
xAxis: { type: 'time',
type: 'time', axisLabel: {
axisLabel: { formatter: {
formatter: { day: '{MM}-{dd}',
day: '{MM}-{dd}', month: '{MM}',
month: '{MM}', year: '{yyyy}',
year: '{yyyy}', }
} }
} // data: res.data[0].map((item: any) => {
// data: res.data[0].map((item: any) => { // return item.time
// return item.time // }),
// }),
// axisLabel: {
// axisLabel: { // formatter: function (value: string) {
// formatter: function (value: string) { // return value.split(' ').join('\n')
// return value.split(' ').join('\n') // }
// } // }
// } },
}, toolbox: {
toolbox: { featureProps: {
featureProps: { myTool1: {
myTool1: { show: true,
show: true, title: '下载csv',
title: '下载csv',
icon: 'path://M588.8 551.253333V512H352v39.253333h236.373333z m0 78.933334v-39.253334H352v39.253334h236.373333z m136.533333 78.933333V334.933333l-157.866666-157.866666H273.066667A59.306667 59.306667 0 0 0 213.333333 236.373333v551.253334a59.306667 59.306667 0 0 0 59.306667 59.306666h274.773333v42.666667H853.333333v-180.48zM568.746667 234.666667l100.266666 100.693333h-81.066666a20.053333 20.053333 0 0 1-19.626667-20.053333z m-20.48 573.013333H273.066667a19.2 19.2 0 0 1-17.493334-19.626667V236.373333a19.2 19.2 0 0 1 19.626667-19.626666h256v98.133333a58.88 58.88 0 0 0 58.88 59.306667h96.426667v334.933333h-98.133334v-39.68H352v39.68h196.266667z m100.266666 23.04a37.973333 37.973333 0 0 1-32 15.786667 38.826667 38.826667 0 0 1-32.426666-15.786667 53.76 53.76 0 0 1-10.24-32.853333 42.666667 42.666667 0 0 1 42.666666-47.786667 35.84 35.84 0 0 1 37.546667 29.866667h-12.8a23.893333 23.893333 0 0 0-24.746667-19.2c-17.066667 0-29.013333 14.08-29.013333 35.84s11.52 37.546667 28.586667 37.546666a26.453333 26.453333 0 0 0 26.453333-25.6h12.8a39.253333 39.253333 0 0 1-7.253333 22.186667z m59.733334 15.786667a35.84 35.84 0 0 1-40.106667-34.56H682.666667a23.893333 23.893333 0 0 0 26.88 23.04c12.8 0 22.613333-6.4 22.613333-15.786667s-4.266667-11.52-14.506667-13.653333l-21.333333-5.12c-17.066667-4.266667-24.32-11.52-24.32-23.893334s12.8-26.453333 34.133333-26.453333a31.573333 31.573333 0 0 1 35.413334 30.293333h-13.653334a19.626667 19.626667 0 0 0-22.613333-18.773333c-12.8 0-20.48 5.12-20.48 12.8s5.12 11.093333 17.066667 13.653333l14.933333 2.986667a42.666667 42.666667 0 0 1 20.906667 8.96 23.893333 23.893333 0 0 1 7.68 17.92c-0.426667 17.066667-14.506667 28.16-37.12 28.16z m88.746666 0h-14.506666l-32.426667-92.16h14.08l19.626667 59.733333 6.4 20.053333c0-9.386667 3.413333-12.8 5.546666-20.053333l19.2-59.733333h14.08z',
icon: 'path://M588.8 551.253333V512H352v39.253333h236.373333z m0 78.933334v-39.253334H352v39.253334h236.373333z m136.533333 78.933333V334.933333l-157.866666-157.866666H273.066667A59.306667 59.306667 0 0 0 213.333333 236.373333v551.253334a59.306667 59.306667 0 0 0 59.306667 59.306666h274.773333v42.666667H853.333333v-180.48zM568.746667 234.666667l100.266666 100.693333h-81.066666a20.053333 20.053333 0 0 1-19.626667-20.053333z m-20.48 573.013333H273.066667a19.2 19.2 0 0 1-17.493334-19.626667V236.373333a19.2 19.2 0 0 1 19.626667-19.626666h256v98.133333a58.88 58.88 0 0 0 58.88 59.306667h96.426667v334.933333h-98.133334v-39.68H352v39.68h196.266667z m100.266666 23.04a37.973333 37.973333 0 0 1-32 15.786667 38.826667 38.826667 0 0 1-32.426666-15.786667 53.76 53.76 0 0 1-10.24-32.853333 42.666667 42.666667 0 0 1 42.666666-47.786667 35.84 35.84 0 0 1 37.546667 29.866667h-12.8a23.893333 23.893333 0 0 0-24.746667-19.2c-17.066667 0-29.013333 14.08-29.013333 35.84s11.52 37.546667 28.586667 37.546666a26.453333 26.453333 0 0 0 26.453333-25.6h12.8a39.253333 39.253333 0 0 1-7.253333 22.186667z m59.733334 15.786667a35.84 35.84 0 0 1-40.106667-34.56H682.666667a23.893333 23.893333 0 0 0 26.88 23.04c12.8 0 22.613333-6.4 22.613333-15.786667s-4.266667-11.52-14.506667-13.653333l-21.333333-5.12c-17.066667-4.266667-24.32-11.52-24.32-23.893334s12.8-26.453333 34.133333-26.453333a31.573333 31.573333 0 0 1 35.413334 30.293333h-13.653334a19.626667 19.626667 0 0 0-22.613333-18.773333c-12.8 0-20.48 5.12-20.48 12.8s5.12 11.093333 17.066667 13.653333l14.933333 2.986667a42.666667 42.666667 0 0 1 20.906667 8.96 23.893333 23.893333 0 0 1 7.68 17.92c-0.426667 17.066667-14.506667 28.16-37.12 28.16z m88.746666 0h-14.506666l-32.426667-92.16h14.08l19.626667 59.733333 6.4 20.053333c0-9.386667 3.413333-12.8 5.546666-20.053333l19.2-59.733333h14.08z', onclick: (e) => {
onclick: (e) => {
let list = echartsData.value.options.series.map(item => item.data)
let list = echartsData.value.options.series.map(item => item.data) let dataList = list[0].map((item, index) => {
let dataList = list[0].map((item, index) => { const value1 = list[1] && list[1][index] ? list[1][index][1] : null;
const value1 = list[1] && list[1][index] ? list[1][index][1] : null; const value2 = list[2] && list[2][index] ? list[2][index][1] : null;
const value2 = list[2] && list[2][index] ? list[2][index][1] : null; const value3 = list[3] && list[3][index] ? list[3][index][1] : null;
const value3 = list[3] && list[3][index] ? list[3][index][1] : null;
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.title.text + '.csv')
}
} }
} }
} }
} }
} if ((echartsData.value.legend = ['A相', 'B相', 'C相'])) {
if ((echartsData.value.legend = ['A相', 'B相', 'C相'])) { echartsData.value.color = ['#DAA520', '#2E8B57', '#A52a2a']
echartsData.value.color = ['#DAA520', '#2E8B57', '#A52a2a'] }
}
} else {
} else { echartsData.value = null
echartsData.value = null }
} loading.value = false
loading.value = false })
}) }
}
defineExpose({ open })
defineExpose({ open }) </script>
</script> <style lang="scss">
<style lang="scss"> .device-control-detail {
.device-control-detail { padding-bottom: 10px;
padding-bottom: 10px; display: flex;
display: flex; flex-direction: column;
flex-direction: column; }
}
.el-form--inline .el-form-item {
.el-form--inline .el-form-item { margin-bottom: 10px !important;
margin-bottom: 10px !important; }
} </style>
</style>

View File

@@ -141,7 +141,8 @@
v-show=" v-show="
dataSet.includes('_items') || dataSet.includes('_items') ||
dataSet.indexOf('_history') != -1 || dataSet.indexOf('_history') != -1 ||
dataSet.indexOf('_moduleData') != -1 dataSet.indexOf('_moduleData') != -1||
dataSet.indexOf('_devRunTrend') != -1
" "
> >
<DatePicker ref="datePickerRef"></DatePicker> <DatePicker ref="datePickerRef"></DatePicker>
@@ -165,7 +166,7 @@
</el-select> --> </el-select> -->
<el-radio-group <el-radio-group
v-model.trim="formInline.dataLevel" v-model.trim="formInline.dataLevel"
v-if="!dataSet.includes('_moduleData') && TrendList?.lineType == 1" v-if="!dataSet.includes('_devRunTrend') &&!dataSet.includes('_moduleData') && TrendList?.lineType == 1"
:disabled="TrendList?.lineType != 1" :disabled="TrendList?.lineType != 1"
@change="handleClick" @change="handleClick"
> >
@@ -525,6 +526,14 @@
> >
<moduleData ref="moduleDataRef" @onSubmit="handleClick" /> <moduleData ref="moduleDataRef" @onSubmit="handleClick" />
</div> </div>
<!-- 运行趋势 -->
<div
style="height: calc(100vh - 395px)"
v-if="dataSet.indexOf('_devRunTrend') != -1"
v-loading="tableLoading"
>
<operatingTrend ref="operatingTrendRef" @onSubmit="handleClick" />
</div>
<div v-if="!tableData" style="height: 42px"></div> <div v-if="!tableData" style="height: 42px"></div>
</el-tabs> </el-tabs>
</div> </div>
@@ -548,7 +557,8 @@ import {
getOverLimitData, getOverLimitData,
queryDictType, queryDictType,
getById, getById,
allModelData allModelData,
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 { ref, reactive, onMounted, onUnmounted, inject, nextTick, onBeforeUnmount } from 'vue' import { ref, reactive, onMounted, onUnmounted, inject, nextTick, onBeforeUnmount } from 'vue'
@@ -557,6 +567,7 @@ import DatePicker from '@/components/form/datePicker/index.vue'
import Trend from './tabs/trend.vue' //趋势数据 import Trend from './tabs/trend.vue' //趋势数据
import realTime from './tabs/realtime.vue' //实时数据-主界面 import realTime from './tabs/realtime.vue' //实时数据-主界面
import realTrend from './tabs/components/realtrend.vue' //实时数据-实时趋势 import realTrend from './tabs/components/realtrend.vue' //实时数据-实时趋势
import operatingTrend from './tabs/operatingTrend.vue' //运行趋势
import harmonicSpectrum from './tabs/components/harmonicSpectrum.vue' //实时数据-谐波频谱子页面 import harmonicSpectrum from './tabs/components/harmonicSpectrum.vue' //实时数据-谐波频谱子页面
import recordWoves from './tabs/components/recordwoves.vue' //实时数据-实时录波子页面 import recordWoves from './tabs/components/recordwoves.vue' //实时数据-实时录波子页面
import offLineDataImport from './offLineDataImport/index.vue' import offLineDataImport from './offLineDataImport/index.vue'
@@ -660,6 +671,7 @@ const volConTypeList = dictData.getBasicData('Dev_Connect')
// } // }
//谐波频谱 //谐波频谱
const realTrendRef = ref() const realTrendRef = ref()
const operatingTrendRef = ref()
const changeTrendType = (val: any) => { const changeTrendType = (val: any) => {
trendDataTime.value = '' trendDataTime.value = ''
activeTrendName.value = val * 1 activeTrendName.value = val * 1
@@ -685,7 +697,7 @@ const handleTrend = async () => {
.then((res: any) => { .then((res: any) => {
if (res.code == 'A0000') { if (res.code == 'A0000') {
trendDataTime.value = '' trendDataTime.value = ''
ElMessage.success('装置应答成功') ElMessage.success('设备应答成功')
//每隔30s调用一下接口通知后台推送mqtt消息 //每隔30s调用一下接口通知后台推送mqtt消息
trendTimer.value = window.setInterval(() => { trendTimer.value = window.setInterval(() => {
if (!dataSet.value.includes('_realtimedata')) return if (!dataSet.value.includes('_realtimedata')) return
@@ -709,7 +721,7 @@ const handleTrend = async () => {
// } // }
}) })
} else { } else {
ElMessage.warning('装置应答失败') ElMessage.warning('设备应答失败')
} }
}) })
.catch(e => { .catch(e => {
@@ -741,7 +753,7 @@ const handleHarmonicSpectrum = async () => {
// getRealDataMqttMsg() // getRealDataMqttMsg()
await getBasicRealData(lineId.value).then((res: any) => { await getBasicRealData(lineId.value).then((res: any) => {
if (res.code == 'A0000') { if (res.code == 'A0000') {
ElMessage.success('装置应答成功') ElMessage.success('设备应答成功')
// mqttMessage.value = {} // mqttMessage.value = {}
realDataTimer.value = window.setInterval(() => { realDataTimer.value = window.setInterval(() => {
@@ -771,7 +783,7 @@ const handleReturn = async () => {
tableLoading.value = true tableLoading.value = true
await getBasicRealData(lineId.value).then((res: any) => { await getBasicRealData(lineId.value).then((res: any) => {
if (res.code == 'A0000') { if (res.code == 'A0000') {
ElMessage.success('装置应答成功') ElMessage.success('设备应答成功')
// mqttMessage.value = {} // mqttMessage.value = {}
realDataTimer.value = window.setInterval(() => { realDataTimer.value = window.setInterval(() => {
if (!dataSet.value.includes('_realtimedata')) return if (!dataSet.value.includes('_realtimedata')) return
@@ -920,6 +932,10 @@ const nodeClick = async (e: anyObj, node: any) => {
if (item.type === 'moduleData') { if (item.type === 'moduleData') {
item.id = item.id + '_moduleData' item.id = item.id + '_moduleData'
} }
// 模块数据
if (item.type === 'devRunTrend') {
item.id = item.id + '_devRunTrend'
}
}) })
res.data.dataSetList = res.data.dataSetList.filter((item: any) => item.name != '历史统计数据') res.data.dataSetList = res.data.dataSetList.filter((item: any) => item.name != '历史统计数据')
//便携式设备默认二次值 //便携式设备默认二次值
@@ -982,7 +998,7 @@ const getRealDataMqttMsg = async () => {
await getBasicRealData(lineId.value) await getBasicRealData(lineId.value)
.then((res: any) => { .then((res: any) => {
if (res.code == 'A0000') { if (res.code == 'A0000') {
ElMessage.success('装置应答成功') ElMessage.success('设备应答成功')
mqttMessage.value = {} mqttMessage.value = {}
realDataTimer.value = window.setInterval(async () => { realDataTimer.value = window.setInterval(async () => {
@@ -1146,7 +1162,7 @@ const getRealDataMqttMsg = async () => {
console.log('mqtt客户端已断开连接.....') console.log('mqtt客户端已断开连接.....')
}) })
} else { } else {
ElMessage.success('装置应答失败') ElMessage.success('设备应答失败')
tableLoading.value = false tableLoading.value = false
} }
}) })
@@ -1316,6 +1332,39 @@ const handleClick = async (tab?: any) => {
}, 0) }, 0)
}, 0) }, 0)
} }
//运行趋势
if (dataSet.value.includes('_devRunTrend')) {
setTimeout(async () => {
if (tab.props != undefined) await (datePickerRef.value && datePickerRef.value?.setInterval(5))
let obj = {
// devId: deviceId.value, //e.id
lineId: [deviceId.value], //e.pid
startTime: datePickerRef.value && datePickerRef.value.timeValue[0],
endTime: datePickerRef.value && datePickerRef.value.timeValue[1]
}
await setTimeout(() => {
getRawData(obj)
.then((res: any) => {
tableLoading.value = false
setTimeout(() => {
operatingTrendRef.value?.setData(res.data)
}, 500)
setTimeout(() => {
loading.value = false
}, 1500)
})
.catch(e => {
setTimeout(() => {
tableLoading.value = false
}, 1500)
})
}, 0)
}, 0)
}
//查询当前指标 //查询当前指标
if (!dataSet.value.includes('_')) { if (!dataSet.value.includes('_')) {

View File

@@ -241,7 +241,7 @@ const tableStore = new TableStore({
width: '180', width: '180',
render: 'buttons', render: 'buttons',
buttons: [ buttons: [
//直连装置注册 //直连设备注册
{ {
title: '注册', title: '注册',
type: 'primary', type: 'primary',

View File

@@ -0,0 +1,165 @@
<template>
<div :style="height">
<MyEchart v-if="list.length != 0" :options="options1" style="height: 100%; width: 100%" class="pt10" />
<el-empty description="暂无数据" style="width: 100%; height: 100%" v-else></el-empty>
</div>
</template>
<script setup lang="ts">
import MyEchart from '@/components/echarts/MyEchart.vue'
import { ref, reactive } from 'vue'
import { mainHeight } from '@/utils/layout'
import { max } from 'lodash'
const height = ref(mainHeight(290))
const list = ref([])
const options1 = ref({})
const setData = (data: any) => {
// list.value = [...fillDataFromFirstTime(data),...data]
list.value = data
init()
}
/**
* 补全离散数据严格从数组第一个time开始最后一个time结束
* @param {Array} data 原始离散数据数组
* @param {number} interval 补全时间间隔默认10秒
* @returns {Array} 补全后的连续数据
*/
function fillDataFromFirstTime(data, interval = 10) {
// 1. 基础校验
if (!Array.isArray(data) || data.length === 0) {
console.error('原始数据必须是非空数组')
return []
}
// 2. 锁定起始时间直接取数组第一个元素的time不做任何偏移
const firstItem = data[0]
const startTime = new Date(firstItem.time)
const startTimestamp = startTime.getTime()
// 3. 锁定结束时间取数组最后一个元素的time
const lastItem = data[data.length - 1]
const endTime = new Date(lastItem.time)
const endTimestamp = endTime.getTime()
// 4. 预处理:按时间排序(防止原始数据乱序)
const sortedData = [...data].sort((a, b) => new Date(a.time) - new Date(b.time))
// 5. 初始化状态继承第一个数据的type
let currentType = firstItem.type
let currentDesc = firstItem.description
let nextStatusIndex = 1 // 指向待切换的下一个状态点
const filledData = []
// 6. 核心循环从第一个time开始按间隔补全到最后一个time
for (let ts = startTimestamp; ts <= endTimestamp; ts += interval * 1000) {
const currentDate = new Date(ts)
// 格式化时间为和原始数据一致的 "YYYY-MM-DD HH:mm:ss" 格式
const formattedTime = `${currentDate.getFullYear()}-${String(currentDate.getMonth() + 1).padStart(
2,
'0'
)}-${String(currentDate.getDate()).padStart(2, '0')} ${String(currentDate.getHours()).padStart(
2,
'0'
)}:${String(currentDate.getMinutes()).padStart(2, '0')}:${String(currentDate.getSeconds()).padStart(2, '0')}`
// 7. 检查是否到达下一个状态切换点
if (nextStatusIndex < sortedData.length) {
const nextStatusTime = new Date(sortedData[nextStatusIndex].time).getTime()
if (ts >= nextStatusTime) {
currentType = sortedData[nextStatusIndex].type
currentDesc = sortedData[nextStatusIndex].description
nextStatusIndex++
}
}
// 8. 生成补全数据项(结构与原始数据完全一致)
filledData.push({
time: formattedTime,
devId: firstItem.devId,
description: currentDesc,
type: currentType
})
}
return filledData
}
const init = () => {
options1.value = {
title: {
text: '运行状态'
},
legend: {
show: false
},
tooltip: {
formatter: function (params: any) {
var res = params[0].data[0] + '<br/>运行状态:'
var texts = ''
if (params[0].data[1] === 1 || params[0].data[1] === '1') {
texts = '中断'
} else if (params[0].data[1] === 10 || params[0].data[1] === '10') {
texts = '正常'
}
res = res + texts
return res
}
},
xAxis: {
// type: 'category',
// data: data.updateTime
type: 'time',
name: '时间',
//
axisLabel: {
formatter: {
day: '{MM}-{dd}',
month: '{MM}',
year: '{yyyy}'
}
}
},
yAxis: {
name: '',
type: 'value',
max: 11,
interval: 1,
splitLine: {
lineStyle: {
// 使用深浅的间隔色
color: ['#ccc'],
type: 'dashed',
opacity: 0
}
},
axisLabel: {
// 这里重新定义就可以
formatter: function (value: number) {
var texts = []
if (value === 1) {
texts.push('中断')
} else if (value === 10) {
texts.push('正常')
}
return texts
}
}
},
series: [
{
name: '运行状态',
data: list.value.map((item: any, index: number) => [item.time, item.type == 0 ? 1 : 10]),
type: 'line',
showSymbol: false,
step: 'end'
}
]
}
}
defineExpose({
setData
})
</script>
<style lang="scss" scoped></style>

View File

@@ -2,7 +2,7 @@
<template> <template>
<div class="default-main main" :style="{ height: pageHeight.height }"> <div class="default-main main" :style="{ height: pageHeight.height }">
<div class="main_left"> <div class="main_left">
<DeviceTree @node-click="nodeClick" @init="nodeClick"></DeviceTree> <DeviceTree @node-click="nodeClick" @deviceTypeChange="deviceTypeChange"></DeviceTree>
</div> </div>
<div class="main_right" v-loading="loading"> <div class="main_right" v-loading="loading">
<div class="right_nav"> <div class="right_nav">
@@ -19,7 +19,7 @@
</el-breadcrumb> </el-breadcrumb>
</div> </div>
<!-- <el-button :icon="Refresh" @click="handleRestartDevice" type="primary" :loading="deviceRestartLoading"> <!-- <el-button :icon="Refresh" @click="handleRestartDevice" type="primary" :loading="deviceRestartLoading">
装置重启 设备重启
</el-button> --> </el-button> -->
</div> </div>
@@ -197,22 +197,28 @@
import DeviceTree from '@/components/tree/govern/deviceTree.vue' import DeviceTree from '@/components/tree/govern/deviceTree.vue'
import { mainHeight } from '@/utils/layout' import { mainHeight } from '@/utils/layout'
import { ref, watch, onMounted, onBeforeUnmount, h, inject } from 'vue' import { ref, watch, onMounted, onBeforeUnmount, h, inject } from 'vue'
import { ElMessage, ElMessageBox, ElInput } from 'element-plus' import { ElMessage, ElMessageBox, ElInput, ElSegmented } from 'element-plus'
import { import {
getFileServiceFileOrDir, getFileServiceFileOrDir,
uploadDeviceFile, uploadDeviceFile,
reStartDevice, reStartDevice,
addDeviceDir, addDeviceDir,
delDeviceDir delDeviceDir,
} from '@/api/cs-device-boot/fileService.ts' listDir,
downloadFileFromFrontr,
deleteCld,
uploadFileToFront,
mkdir
} from '@/api/cs-device-boot/fileService'
import { defaultAttribute } from '@/components/table/defaultAttribute' import { defaultAttribute } from '@/components/table/defaultAttribute'
import { Delete, Download, Upload, Plus, Refresh, Search } from '@element-plus/icons-vue' import { Delete, Download, Upload, Plus, Refresh, Search } from '@element-plus/icons-vue'
import popup from './popup.vue' import popup from './popup.vue'
import mqtt from 'mqtt' import mqtt from 'mqtt'
import { useAdminInfo } from '@/stores/adminInfo' import { useAdminInfo } from '@/stores/adminInfo'
import { passwordConfirm } from '@/api/user-boot/user' import { passwordConfirm } from '@/api/user-boot/user'
import { downLoadFile } from '@/utils/downloadFile.ts'
defineOptions({ defineOptions({
name: 'govern/device/fileService' name: 'govern/device/fileService/index'
}) })
const pageHeight = mainHeight(20) const pageHeight = mainHeight(20)
const tableHeight = mainHeight(130) const tableHeight = mainHeight(130)
@@ -220,31 +226,53 @@ const adminInfo = useAdminInfo()
const loading = ref(false) const loading = ref(false)
//nDid //nDid
const nDid = ref<string>('') const nDid = ref<string>('')
const devId = ref<string>('')
//当前目录 //当前目录
const activePath = ref<string>('') const activePath = ref<string>('')
//判断是否是根目录 //判断是否是根目录
const isRoot = ref<boolean>(true) const isRoot = ref<boolean>(true)
//储存所有点击过的目录 //储存所有点击过的目录
const activePathList: any = ref([]) const activePathList: any = ref([])
const devConType = ref<string>('')
const deviceTypeChange = (val: any, obj: any) => {
nodeClick(obj)
}
const nodeClick = (e: any) => { const nodeClick = (e: any) => {
if (e && (e.level == 2 || e.type == 'device')) { if (e && (e.level == 2 || e.type == 'device')) {
loading.value = true loading.value = true
nDid.value = e.ndid nDid.value = e.ndid
devId.value = e.id
dirList.value = [] dirList.value = []
activePathList.value = [] activePathList.value = []
activePath.value = '/' activePath.value = '/'
getFileServiceFileOrDir({ nDid: nDid.value, name: activePath.value, type: 'dir' }) devConType.value = e.devConType
.then((resp: any) => { if (devConType.value == 'CLD') {
if (resp.code == 'A0000') { listDir({ devId: devId.value, filePath: activePath.value })
dirList.value = resp.data .then((resp: any) => {
currentDirList.value = resp.data if (resp.code == 'A0000') {
activePathList.value = [{ path: activePath.value }] dirList.value = resp.data
currentDirList.value = resp.data
activePathList.value = [{ path: activePath.value }]
loading.value = false
}
})
.catch(e => {
loading.value = false loading.value = false
} })
}) } else {
.catch(e => { getFileServiceFileOrDir({ nDid: nDid.value, name: activePath.value, type: 'dir' })
loading.value = false .then((resp: any) => {
}) if (resp.code == 'A0000') {
dirList.value = resp.data
currentDirList.value = resp.data
activePathList.value = [{ path: activePath.value }]
loading.value = false
}
})
.catch(e => {
loading.value = false
})
}
} }
} }
//搜索文件或文件夹 //搜索文件或文件夹
@@ -291,11 +319,11 @@ const vNode = () => {
]) ])
} }
//装置重启 //设备重启
const deviceRestartLoading = ref<boolean>(false) const deviceRestartLoading = ref<boolean>(false)
const handleRestartDevice = () => { const handleRestartDevice = () => {
deviceRestartLoading.value = true deviceRestartLoading.value = true
ElMessageBox.prompt('二次校验密码确认', '装置重启', { ElMessageBox.prompt('二次校验密码确认', '设备重启', {
confirmButtonText: '确认', confirmButtonText: '确认',
cancelButtonText: '取消', cancelButtonText: '取消',
customClass: 'customInput', customClass: 'customInput',
@@ -360,21 +388,41 @@ const handleIntoDir = (row: any) => {
if (activePathList.value.indexOf(obj.name) == -1) { if (activePathList.value.indexOf(obj.name) == -1) {
activePathList.value.push({ path: obj.name }) activePathList.value.push({ path: obj.name })
} }
getFileServiceFileOrDir(obj)
.then(res => { if (devConType.value == 'CLD') {
dirList.value = res.data listDir({ devId: devId.value, filePath: row.prjDataPath })
loading.value = false .then((resp: any) => {
currentDirList.value = res.data if (resp.code == 'A0000') {
activePathList.value.map((item: any, index: any) => { dirList.value = resp.data
if (item.path.includes(activePath.value) && item.path.length > activePath.value.length) { currentDirList.value = resp.data
activePathList.value.splice(index, 1) activePathList.value.map((item: any, index: any) => {
if (item.path.includes(activePath.value) && item.path.length > activePath.value.length) {
activePathList.value.splice(index, 1)
}
})
loading.value = false
} }
}) })
isRoot.value = false .catch(e => {
}) loading.value = false
.catch(e => { })
loading.value = false } else {
}) getFileServiceFileOrDir(obj)
.then(res => {
dirList.value = res.data
loading.value = false
currentDirList.value = res.data
activePathList.value.map((item: any, index: any) => {
if (item.path.includes(activePath.value) && item.path.length > activePath.value.length) {
activePathList.value.splice(index, 1)
}
})
isRoot.value = false
})
.catch(e => {
loading.value = false
})
}
} }
//处理导航栏路径 //处理导航栏路径
@@ -406,19 +454,38 @@ const handleIntoByPath = async (val: any) => {
} }
activePath.value = val.path activePath.value = val.path
loading.value = true loading.value = true
getFileServiceFileOrDir(obj) if (devConType.value == 'CLD') {
.then(res => { listDir({ devId: devId.value, filePath: val.path })
dirList.value = res.data .then((resp: any) => {
activePathList.value.map((item: any, index: any) => { if (resp.code == 'A0000') {
if (item.path.includes(activePath.value) && item.path.length > activePath.value.length) { dirList.value = resp.data
activePathList.value.splice(index, 1)
activePathList.value.map((item: any, index: any) => {
if (item.path.includes(activePath.value) && item.path.length > activePath.value.length) {
activePathList.value.splice(index, 1)
}
})
loading.value = false
} }
}) })
loading.value = false .catch(e => {
}) loading.value = false
.catch(e => { })
loading.value = false } else {
}) getFileServiceFileOrDir(obj)
.then(res => {
dirList.value = res.data
activePathList.value.map((item: any, index: any) => {
if (item.path.includes(activePath.value) && item.path.length > activePath.value.length) {
activePathList.value.splice(index, 1)
}
})
loading.value = false
})
.catch(e => {
loading.value = false
})
}
} }
const form = ref({ const form = ref({
path: '' path: ''
@@ -437,45 +504,84 @@ const formRef = ref()
//重新加载当前页面菜单 //重新加载当前页面菜单
const reloadCurrentMenu = (msg: string) => { const reloadCurrentMenu = (msg: string) => {
loading.value = true loading.value = true
getFileServiceFileOrDir({ nDid: nDid.value, name: activePath.value, type: 'dir' })
.then((resp: any) => {
if (resp.code == 'A0000') {
loading.value = false
dirList.value = resp.data
currentDirList.value = resp.data
activePathList.value.map((item: any, index: any) => {
if (item.path.includes(activePath.value) && item.path.length > activePath.value.length) {
activePathList.value.splice(index, 1)
}
})
loading.value = false
if (!msg) return if (devConType.value == 'CLD') {
ElMessage({ message: msg, type: 'success', duration: 5000 }) listDir({ devId: devId.value, filePath: activePath.value })
} .then((resp: any) => {
}) if (resp.code == 'A0000') {
.catch(e => { dirList.value = resp.data
loading.value = false currentDirList.value = resp.data
}) activePathList.value.map((item: any, index: any) => {
if (item.path.includes(activePath.value) && item.path.length > activePath.value.length) {
activePathList.value.splice(index, 1)
}
})
loading.value = false
if (!msg) return
ElMessage({ message: msg, type: 'success', duration: 5000 })
}
})
.catch(e => {
loading.value = false
})
} else {
getFileServiceFileOrDir({ nDid: nDid.value, name: activePath.value, type: 'dir' })
.then((resp: any) => {
if (resp.code == 'A0000') {
loading.value = false
dirList.value = resp.data
currentDirList.value = resp.data
activePathList.value.map((item: any, index: any) => {
if (item.path.includes(activePath.value) && item.path.length > activePath.value.length) {
activePathList.value.splice(index, 1)
}
})
loading.value = false
if (!msg) return
ElMessage({ message: msg, type: 'success', duration: 5000 })
}
})
.catch(e => {
loading.value = false
})
}
} }
//新建文件夹 //新建文件夹
const submitDeviceDir = () => { const submitDeviceDir = () => {
formRef.value.validate((valid: any) => { formRef.value.validate((valid: any) => {
if (valid) { if (valid) {
let obj = { if (devConType.value == 'CLD') {
nDid: nDid.value, let obj = {
path: devId: devId.value,
activePath.value == '/' filePath:
? activePath.value + form.value.path activePath.value == '/'
: activePath.value + '/' + form.value.path ? activePath.value + form.value.path
} : activePath.value + '/' + form.value.path
loading.value = true
addDeviceDir(obj).then((res: any) => {
if (res.code == 'A0000') {
reloadCurrentMenu(res.message)
addDeviceDirOpen.value = false
} }
}) loading.value = true
mkdir(obj).then((res: any) => {
if (res.code == 'A0000') {
reloadCurrentMenu(res.message)
addDeviceDirOpen.value = false
}
})
} else {
let obj = {
nDid: nDid.value,
path:
activePath.value == '/'
? activePath.value + form.value.path
: activePath.value + '/' + form.value.path
}
loading.value = true
addDeviceDir(obj).then((res: any) => {
if (res.code == 'A0000') {
reloadCurrentMenu(res.message)
addDeviceDirOpen.value = false
}
})
}
} }
}) })
} }
@@ -507,13 +613,30 @@ const handleDelDirOrFile = (row: any) => {
passwordConfirm(value) passwordConfirm(value)
.then((resp: any) => { .then((resp: any) => {
if (resp.code == 'A0000') { if (resp.code == 'A0000') {
delDeviceDir({ nDid: nDid.value, path: row.prjDataPath }).then((res: any) => { if (devConType.value == 'CLD') {
if (res.code == 'A0000') { deleteCld({
reloadCurrentMenu(res.message) devId: devId.value,
filePath: row.prjDataPath
// ElMessage({ message: res.message, type: 'success', duration: 5000 }) })
} .then((res: any) => {
}) if (res.code == 'A0000') {
reloadCurrentMenu(res.message)
}
})
.catch(e => {
loading.value = false
})
} else {
delDeviceDir({ nDid: nDid.value, path: row.prjDataPath })
.then((res: any) => {
if (res.code == 'A0000') {
reloadCurrentMenu(res.message)
}
})
.catch(e => {
loading.value = false
})
}
} }
}) })
.catch(e => { .catch(e => {
@@ -526,11 +649,21 @@ const changeType = ref<any>('')
//下载文件 //下载文件
const fileRef = ref() const fileRef = ref()
const handleDownLoad = async (row: any) => { const handleDownLoad = async (row: any) => {
;(await nDid.value) && fileRef.value && fileRef.value.open(row, nDid.value) if (devConType.value == 'CLD') {
// fileName.value = row?.prjDataPath.split('/')[row?.prjDataPath.split('/').length - 1] ElMessage.info('下载中,请稍等...')
// localStorage.setItem('fileName', fileName.value) downloadFileFromFrontr({
changeType.value = 'download' devId: devId.value,
localStorage.setItem('changeType', changeType.value) filePath: row.prjDataPath
}).then(res => {
downLoadFile(row.name, row.name, res)
})
} else {
;(await nDid.value) && fileRef.value && fileRef.value.open(row, nDid.value)
// fileName.value = row?.prjDataPath.split('/')[row?.prjDataPath.split('/').length - 1]
// localStorage.setItem('fileName', fileName.value)
changeType.value = 'download'
localStorage.setItem('changeType', changeType.value)
}
} }
//上传文件 //上传文件
const fileName = ref<any>('') const fileName = ref<any>('')
@@ -540,17 +673,32 @@ const handleUpload = (e: any, fileList: any, row: any) => {
localStorage.setItem('fileName', fileName.value) localStorage.setItem('fileName', fileName.value)
changeType.value = 'upload' changeType.value = 'upload'
localStorage.setItem('changeType', changeType.value) localStorage.setItem('changeType', changeType.value)
const obj = {
id: nDid.value, if (devConType.value == 'CLD') {
file: e.raw, const obj = {
filePath: row || row.prjDataPath devId: devId.value,
} file: e.raw,
uploadDeviceFile(obj).then((res: any) => { dirPath: row || row.prjDataPath
if (res.code == 'A0000') {
reloadCurrentMenu(res.message)
status.value = 100
} }
}) uploadFileToFront(obj).then((res: any) => {
if (res.code == 'A0000') {
reloadCurrentMenu(res.message)
status.value = 100
}
})
} else {
const obj = {
id: nDid.value,
file: e.raw,
filePath: row || row.prjDataPath
}
uploadDeviceFile(obj).then((res: any) => {
if (res.code == 'A0000') {
reloadCurrentMenu(res.message)
status.value = 100
}
})
}
} }
watch( watch(
() => activePathList.value, () => activePathList.value,
@@ -598,26 +746,28 @@ const mqttMessage = ref<any>({})
const status: any = ref() const status: any = ref()
function parseStringToObject(str: string) { function parseStringToObject(str: string) {
const content = str.replace(/^{|}$/g, '') const content = str.replace(/^{|}$/g, '')
const pairs = content.split(',')
const result: any = {} const result: any = {}
pairs.forEach(pair => {
const [key, value] = pair.split(':') // 正则匹配:key:value 格式,支持 value 里带 : / 等字符
// 尝试将数字转换为Number类型 const regex = /([^,:]+):([^,]+)(?=,|$)/g
result[key.trim()] = isNaN(Number(value)) ? value.trim() : Number(value) let match
})
while ((match = regex.exec(content)) !== null) {
const key = match[1].trim()
const value = match[2].trim()
// 数字自动转 Number
result[key] = isNaN(Number(value)) ? value : Number(value)
}
return result return result
} }
mqttRef.value.on('message', (topic: any, message: any) => { mqttRef.value.on('message', (topic: any, message: any) => {
// console.log('mqtt接收到消息', JSON.parse(JSON.stringify(JSON.parse(new TextDecoder().decode(message))))) // console.log('mqtt接收到消息', JSON.parse(JSON.stringify(JSON.parse(new TextDecoder().decode(message)))))
let str = JSON.parse(JSON.stringify(JSON.parse(new TextDecoder().decode(message)))) let str = JSON.parse(JSON.stringify(JSON.parse(new TextDecoder().decode(message))))
let regex = /fileName:(.*?),allStep/
let regex1 = /allStep:(.*?),nowStep/
let regex2 = /nowStep:(.*?),userId/
let regex3 = /userId:(.*?)}/
mqttMessage.value = parseStringToObject(str) mqttMessage.value = parseStringToObject(str)
if (adminInfo.id != mqttMessage.value.userId) return
// console.log("🚀 ~ str.match(regex3)[1]:", str.match(regex3)[1]) // console.log("🚀 ~ str.match(regex3)[1]:", str.match(regex3)[1])
status.value = parseInt(Number((mqttMessage.value.nowStep / mqttMessage.value.allStep) * 100)) status.value = parseInt(Number((mqttMessage.value.nowStep / mqttMessage.value.allStep) * 100))
fileRef.value.setStatus(mqttMessage.value) fileRef.value.setStatus(mqttMessage.value)

View File

@@ -3,6 +3,7 @@
<div :class="downLoading ? 'all_disabled' : ''"> <div :class="downLoading ? 'all_disabled' : ''">
<el-dialog v-model.trim="dialogVisible" title="文件信息" width="50%" @closed="handleClose"> <el-dialog v-model.trim="dialogVisible" title="文件信息" width="50%" @closed="handleClose">
<div v-loading="loading"> <div v-loading="loading">
<div <div
class="download_progress" class="download_progress"
v-if="mqttFileName.includes(fileNameInfoMation) && status != 0 && status != 100" v-if="mqttFileName.includes(fileNameInfoMation) && status != 0 && status != 100"
@@ -57,7 +58,7 @@ import {
getFileServiceFileOrDir, getFileServiceFileOrDir,
downLoadDeviceFile, downLoadDeviceFile,
downLoadDeviceFilePath downLoadDeviceFilePath
} from '@/api/cs-device-boot/fileService.ts' } from '@/api/cs-device-boot/fileService'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { useAdminInfo } from '@/stores/adminInfo' import { useAdminInfo } from '@/stores/adminInfo'
import { downLoadFile } from '@/api/cs-system-boot/manage.ts' import { downLoadFile } from '@/api/cs-system-boot/manage.ts'

View File

@@ -20,7 +20,7 @@
type="primary" type="primary"
:loading="deviceRestartLoading" :loading="deviceRestartLoading"
> >
装置重启 设备重启
</el-button> </el-button>
</template> </template>
<el-descriptions-item label="名称"> <el-descriptions-item label="名称">
@@ -237,11 +237,11 @@ const openGroup = () => {
}) })
}) })
} }
//装置重启 //设备重启
const deviceRestartLoading = ref<boolean>(false) const deviceRestartLoading = ref<boolean>(false)
const handleRestartDevice = () => { const handleRestartDevice = () => {
deviceRestartLoading.value = true deviceRestartLoading.value = true
ElMessageBox.prompt('二次校验密码确认', '装置重启', { ElMessageBox.prompt('二次校验密码确认', '设备重启', {
confirmButtonText: '确认', confirmButtonText: '确认',
cancelButtonText: '取消', cancelButtonText: '取消',
customClass: 'customInput', customClass: 'customInput',

View File

@@ -22,7 +22,7 @@
</div> </div>
<!-- 新增设备列表 --> <!-- 新增设备列表 -->
<div class="device-list-section table-wrapper"> <!-- <div class="device-list-section table-wrapper">
<vxe-table v-bind="defaultAttribute" :data="deviceTableData" height="auto" style="width: 100%"> <vxe-table v-bind="defaultAttribute" :data="deviceTableData" height="auto" style="width: 100%">
<vxe-column field="name" title="设备名称"></vxe-column> <vxe-column field="name" title="设备名称"></vxe-column>
<vxe-column title="操作" width="200px"> <vxe-column title="操作" width="200px">
@@ -33,7 +33,7 @@
</template> </template>
</vxe-column> </vxe-column>
</vxe-table> </vxe-table>
</div> </div> -->
</div> </div>
</div> </div>
@@ -107,7 +107,7 @@
style="width: 100%" style="width: 100%"
> >
<vxe-column type="checkbox" width="60"></vxe-column> <vxe-column type="checkbox" width="60"></vxe-column>
<vxe-column field="name" title="设备名称"></vxe-column> <vxe-column field="name" title="便携式设备名称"></vxe-column>
</vxe-table> </vxe-table>
</div> </div>
</div> </div>
@@ -298,7 +298,7 @@ const addData = () => {
min-height: 0; min-height: 0;
&:first-child { &:first-child {
margin-bottom: 10px; // margin-bottom: 10px;
} }
} }
} }

View File

@@ -1,399 +1,399 @@
<template> <template>
<div> <div>
<div :style="{ width: menuCollapse ? '40px' : '280px' }" style=" overflow: hidden; height: 100%"> <div :style="{ width: menuCollapse ? '40px' : '280px' }" style=" overflow: hidden; height: 100%">
<Icon v-show="menuCollapse" @click="onMenuCollapse" :name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'" <Icon v-show="menuCollapse" @click="onMenuCollapse" :name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
:class="menuCollapse ? 'unfold' : ''" size="18" class="fold ml10 mt20 menu-collapse" :class="menuCollapse ? 'unfold' : ''" size="18" class="fold ml10 mt20 menu-collapse"
style="cursor: pointer" /> style="cursor: pointer" />
<div class="cn-tree" :style="{ opacity: menuCollapse ? 0 : 1, display: menuCollapse ? 'none' : '' }"> <div class="cn-tree" :style="{ opacity: menuCollapse ? 0 : 1, display: menuCollapse ? 'none' : '' }">
<div style="display: flex; align-items: center" class="mb10"> <div style="display: flex; align-items: center" class="mb10">
<el-input maxlength="32" show-word-limit v-model.trim="filterText" placeholder="请输入内容" clearable> <el-input maxlength="32" v-model.trim="filterText" placeholder="请输入内容" clearable>
<template #prefix> <template #prefix>
<Icon name="el-icon-Search" style="font-size: 16px" /> <Icon name="el-icon-Search" style="font-size: 16px" />
</template> </template>
</el-input> </el-input>
<el-tooltip placement="bottom" :hide-after="0"> <el-tooltip placement="bottom" :hide-after="0">
<template #content> <template #content>
<span>新增方案</span> <span>新增方案</span>
</template> </template>
<Icon name="el-icon-Plus" size="18" class="fold ml10 menu-collapse" style="cursor: pointer" <Icon name="el-icon-Plus" size="18" class="fold ml10 menu-collapse" style="cursor: pointer"
@click="onAdd" /> @click="onAdd" />
</el-tooltip> </el-tooltip>
<Icon @click="onMenuCollapse" :name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'" <Icon @click="onMenuCollapse" :name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
:class="menuCollapse ? 'unfold' : ''" size="18" class="fold ml10 menu-collapse" :class="menuCollapse ? 'unfold' : ''" size="18" class="fold ml10 menu-collapse"
style="cursor: pointer" /> style="cursor: pointer" />
</div> </div>
<el-tree style="flex: 1; overflow: auto" :props="defaultProps" highlight-current <el-tree style="flex: 1; overflow: auto" :props="defaultProps" highlight-current
:filter-node-method="filterNode" node-key="id" v-bind="$attrs" default-expand-all :data="tree" :filter-node-method="filterNode" node-key="id" v-bind="$attrs" default-expand-all :data="tree"
ref="treRef" @node-click="clickNode" :expand-on-click-node="false"> ref="treRef" @node-click="clickNode" :expand-on-click-node="false">
<template #default="{ node, data }"> <template #default="{ node, data }">
<span class="custom-tree-node"> <span class="custom-tree-node">
<div class="left"> <div class="left">
<Icon :name="data.icon" style="font-size: 16px" :style="{ color: data.color }" <Icon :name="data.icon" style="font-size: 16px" :style="{ color: data.color }"
v-if="data.icon" /> v-if="data.icon" />
<span>{{ node.label }}</span> <span>{{ node.label }}</span>
</div> </div>
<div class="right"> <div class="right">
<a :style="{ marginRight: '0.5rem' }" v-if="data?.children"> <a :style="{ marginRight: '0.5rem' }" v-if="data?.children">
<el-icon :style="{ color: '#0000FF' }"> <el-icon :style="{ color: '#0000FF' }">
<el-tooltip placement="bottom" :hide-after="0"> <el-tooltip placement="bottom" :hide-after="0">
<template #content> <template #content>
<span>新增测试项</span> <span>新增测试项</span>
</template> </template>
<Plus @click.stop="add(node, data)" /> <Plus @click.stop="add(node, data)" />
</el-tooltip> </el-tooltip>
</el-icon> </el-icon>
</a> </a>
<a :style="{ marginRight: '0.5rem' }" v-else> <a :style="{ marginRight: '0.5rem' }" v-else>
<el-icon :style="{ color: '#0000FF' }"> <el-icon :style="{ color: '#0000FF' }">
<el-tooltip placement="bottom" :hide-after="0"> <el-tooltip placement="bottom" :hide-after="0">
<template #content> <template #content>
<span>数据绑定</span> <span>数据绑定</span>
</template> </template>
<SetUp @click.stop="bind(node, data)" /> <SetUp @click.stop="bind(node, data)" />
</el-tooltip> </el-tooltip>
</el-icon> </el-icon>
</a> </a>
<a :style="{ marginRight: '0.5rem' }"> <a :style="{ marginRight: '0.5rem' }">
<el-icon :style="{ color: '#0000FF' }"> <el-icon :style="{ color: '#0000FF' }">
<el-tooltip placement="bottom" :hide-after="0"> <el-tooltip placement="bottom" :hide-after="0">
<template #content> <template #content>
<span> {{ data.pid ? '修改测试项' : ' 修改测试方案' }}</span> <span> {{ data.pid ? '修改测试项' : ' 修改测试方案' }}</span>
</template> </template>
<Edit @click.stop="edit(node, data)" /> <Edit @click.stop="edit(node, data)" />
</el-tooltip> </el-tooltip>
</el-icon> </el-icon>
</a> </a>
<a :style="{ marginRight: '0.5rem' }"> <a :style="{ marginRight: '0.5rem' }">
<el-icon :style="{ color: '#DA3434' }"> <el-icon :style="{ color: '#DA3434' }">
<Delete @click.stop="del(node, data)" /> <Delete @click.stop="del(node, data)" />
</el-icon> </el-icon>
</a> </a>
</div> </div>
</span> </span>
</template> </template>
</el-tree> </el-tree>
</div> </div>
</div> </div>
<popup ref="dialogRef" @onSubmit="getTreeList"></popup> <popup ref="dialogRef" @onSubmit="getTreeList"></popup>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, nextTick, watch, defineProps, defineEmits } from 'vue' import { ref, nextTick, watch, defineProps, defineEmits } from 'vue'
import { getSchemeTree, getTestRecordInfo } from '@/api/cs-device-boot/planData' import { getSchemeTree, getTestRecordInfo } from '@/api/cs-device-boot/planData'
import { useConfig } from '@/stores/config' import { useConfig } from '@/stores/config'
import useCurrentInstance from '@/utils/useCurrentInstance' import useCurrentInstance from '@/utils/useCurrentInstance'
import { ElTree } from 'element-plus' import { ElTree } from 'element-plus'
import { Plus, Edit, Delete, SetUp } from '@element-plus/icons-vue' import { Plus, Edit, Delete, SetUp } from '@element-plus/icons-vue'
import { delRecord } from '@/api/cs-device-boot/planData' import { delRecord } from '@/api/cs-device-boot/planData'
import popup from './popup.vue' import popup from './popup.vue'
import { getDeviceList } from '@/api/cs-device-boot/planData' import { getDeviceList } from '@/api/cs-device-boot/planData'
import { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
defineOptions({ defineOptions({
name: 'govern/schemeTree' name: 'govern/schemeTree'
}) })
interface Props { interface Props {
width?: string width?: string
canExpand?: boolean canExpand?: boolean
} }
const visible1 = ref(false) const visible1 = ref(false)
const visible2 = ref(false) const visible2 = ref(false)
const visible3 = ref(false) const visible3 = ref(false)
const visible4 = ref(false) const visible4 = ref(false)
const { proxy } = useCurrentInstance() const { proxy } = useCurrentInstance()
const menuCollapse = ref(false) const menuCollapse = ref(false)
const filterText = ref('') const filterText = ref('')
const treeRef = ref<InstanceType<typeof ElTree>>() const treeRef = ref<InstanceType<typeof ElTree>>()
watch(filterText, val => { watch(filterText, val => {
treRef.value!.filter(val) treRef.value!.filter(val)
}) })
const onMenuCollapse = () => { const onMenuCollapse = () => {
menuCollapse.value = !menuCollapse.value menuCollapse.value = !menuCollapse.value
proxy.eventBus.emit('cnTreeCollapse', menuCollapse) proxy.eventBus.emit('cnTreeCollapse', menuCollapse)
} }
const filterNode = (value: string, data: any, node: any) => { const filterNode = (value: string, data: any, node: any) => {
if (!value) return true if (!value) return true
// return data.name.includes(value) // return data.name.includes(value)
if (data.name) { if (data.name) {
return chooseNode(value, data, node) return chooseNode(value, data, node)
} }
} }
const chooseNode = (value: string, data: any, node: any) => { const chooseNode = (value: string, data: any, node: any) => {
if (data.name.indexOf(value) !== -1) { if (data.name.indexOf(value) !== -1) {
return true return true
} }
const level = node.level const level = node.level
// 如果传入的节点本身就是一级节点就不用校验了 // 如果传入的节点本身就是一级节点就不用校验了
if (level === 1) { if (level === 1) {
return false return false
} }
// 先取当前节点的父节点 // 先取当前节点的父节点
let parentData = node.parent let parentData = node.parent
// 遍历当前节点的父节点 // 遍历当前节点的父节点
let index = 0 let index = 0
while (index < level - 1) { while (index < level - 1) {
// 如果匹配到直接返回此处name值是中文字符enName是英文字符。判断匹配中英文过滤 // 如果匹配到直接返回此处name值是中文字符enName是英文字符。判断匹配中英文过滤
if (parentData.data.name.indexOf(value) !== -1) { if (parentData.data.name.indexOf(value) !== -1) {
return true return true
} }
// 否则的话再往上一层做匹配 // 否则的话再往上一层做匹配
parentData = parentData.parent parentData = parentData.parent
index++ index++
} }
// 没匹配到返回false // 没匹配到返回false
return false return false
} }
// 新增方案 // 新增方案
const onAdd = () => { const onAdd = () => {
emit('onAdd') emit('onAdd')
} }
// 绑定数据 // 绑定数据
const bind = (node: any, data: any) => { const bind = (node: any, data: any) => {
emit('bind', data) emit('bind', data)
} }
/** 树形结构数据 */ /** 树形结构数据 */
const defaultProps = { const defaultProps = {
children: 'children', children: 'children',
label: 'name', label: 'name',
value: 'id' value: 'id'
} }
const props = withDefaults( const props = withDefaults(
defineProps<{ defineProps<{
showCheckbox?: boolean showCheckbox?: boolean
defaultCheckedKeys?: any defaultCheckedKeys?: any
}>(), }>(),
{ {
showCheckbox: false, showCheckbox: false,
defaultCheckedKeys: [] defaultCheckedKeys: []
} }
) )
const emit = defineEmits(['init', 'checkChange', 'nodeChange', 'editNode', 'getChart', 'onAdd', 'bind']) const emit = defineEmits(['init', 'checkChange', 'nodeChange', 'editNode', 'getChart', 'onAdd', 'bind'])
const config = useConfig() const config = useConfig()
const tree = ref() const tree = ref()
const treRef = ref() const treRef = ref()
const id: any = ref(null) const id: any = ref(null)
const treeData = ref({}) const treeData = ref({})
//获取方案树形数据 //获取方案树形数据
const getTreeList = () => { const getTreeList = () => {
getSchemeTree().then(res => { getSchemeTree().then(res => {
let arr: any[] = [] let arr: any[] = []
res.data.forEach((item: any) => { res.data.forEach((item: any) => {
item.icon = 'el-icon-Menu' item.icon = 'el-icon-Menu'
item.color = config.getColorVal('elementUiPrimary') item.color = config.getColorVal('elementUiPrimary')
item?.children.forEach((item2: any) => { item?.children.forEach((item2: any) => {
item2.icon = 'el-icon-Document' item2.icon = 'el-icon-Document'
item2.color = config.getColorVal('elementUiPrimary') item2.color = config.getColorVal('elementUiPrimary')
arr.push(item2) arr.push(item2)
}) })
}) })
tree.value = res.data tree.value = res.data
nextTick(() => { nextTick(() => {
if (arr.length) { if (arr.length) {
treRef.value.setCurrentKey(id.value || arr[0].id) treRef.value.setCurrentKey(id.value || arr[0].id)
let list = id.value ? arr.find((item: any) => item.id == id.value) : arr[0] let list = id.value ? arr.find((item: any) => item.id == id.value) : arr[0]
// 注册父组件事件 // 注册父组件事件
emit('init', { emit('init', {
level: 2, level: 2,
...list ...list
}) })
} else { } else {
emit('init') emit('init')
} }
}) })
}) })
} }
getTreeList() getTreeList()
const dialogRef = ref() const dialogRef = ref()
const handleOpen = (val: any, id: any) => { const handleOpen = (val: any, id: any) => {
dialogRef.value.open(val, id) dialogRef.value.open(val, id)
} }
//方案id //方案id
const planId: any = ref('') const planId: any = ref('')
//测试项id //测试项id
const monitorId: any = ref('') const monitorId: any = ref('')
const planData: any = ref({}) const planData: any = ref({})
const getPlanData = (row: any) => { const getPlanData = (row: any) => {
planData.value = {} planData.value = {}
planData.value = JSON.parse(JSON.stringify(row)) planData.value = JSON.parse(JSON.stringify(row))
} }
/** 添加树节点 */ /** 添加树节点 */
// 0 新增方案 1 修改方案 2 新增测试项 3 修改测试项 4 设备信息 // 0 新增方案 1 修改方案 2 新增测试项 3 修改测试项 4 设备信息
const add = (node: any, data: any) => { const add = (node: any, data: any) => {
planId.value = data.id planId.value = data.id
//添加测试项 //添加测试项
if (data?.children) { if (data?.children) {
dialogRef.value.detailsType('tree') dialogRef.value.detailsType('tree')
handleOpen(2, planId.value) handleOpen(2, planId.value)
} }
} }
/** 编辑树节点 */ /** 编辑树节点 */
const edit = async (node: Node, data: any) => { const edit = async (node: Node, data: any) => {
planId.value = data.id planId.value = data.id
await getTestRecordInfo(planId.value) await getTestRecordInfo(planId.value)
.then(res => { .then(res => {
//修改方案 //修改方案
if (data?.children) { if (data?.children) {
dialogRef.value.detailsType('') dialogRef.value.detailsType('')
dialogRef.value.details(res.data) dialogRef.value.details(res.data)
handleOpen(1, planId.value) handleOpen(1, planId.value)
} }
//修改测试项 //修改测试项
else { else {
monitorId.value = data.id monitorId.value = data.id
dialogRef.value.detailsType('tree') dialogRef.value.detailsType('tree')
dialogRef.value.details(res.data.records[0]) dialogRef.value.details(res.data.records[0])
handleOpen(3, planId.value) handleOpen(3, planId.value)
} }
}) })
.catch(e => { }) .catch(e => { })
} }
/** 删除树节点 */ /** 删除树节点 */
const del = async (node: Node, data: any) => { const del = async (node: Node, data: any) => {
let titleList = '' let titleList = ''
planId.value = data.id planId.value = data.id
await getDeviceList({ await getDeviceList({
id: data.id, id: data.id,
isTrueFlag: 1 isTrueFlag: 1
}).then(res => { }).then(res => {
if (res.data.length > 0) { if (res.data.length > 0) {
titleList = '已绑定数据_' titleList = '已绑定数据_'
} }
}) })
//删除方案/测试项 //删除方案/测试项
ElMessageBox.confirm(titleList + '是否确认删除?', { ElMessageBox.confirm(titleList + '是否确认删除?', {
confirmButtonText: '确定', confirmButtonText: '确定',
cancelButtonText: '取消', cancelButtonText: '取消',
type: 'warning' type: 'warning'
}) })
.then(() => { .then(() => {
delRecord({ id: data.id }).then((res: any) => { delRecord({ id: data.id }).then((res: any) => {
if (res.code == 'A0000') { if (res.code == 'A0000') {
ElMessage.success('删除成功') ElMessage.success('删除成功')
id.value = null id.value = null
getTreeList() getTreeList()
} }
}) })
}) })
.catch(() => { .catch(() => {
ElMessage({ ElMessage({
type: 'info', type: 'info',
message: '已取消' message: '已取消'
}) })
}) })
} }
//取消删除 //取消删除
const cancelDel = () => { } const cancelDel = () => { }
const clickNode = (e: anyObj) => { const clickNode = (e: anyObj) => {
e?.children ? (planId.value = e.id) : (planId.value = e.pid) e?.children ? (planId.value = e.id) : (planId.value = e.pid)
id.value = e.id id.value = e.id
emit('nodeChange', e) emit('nodeChange', e)
} }
const setCheckedNode = (e: anyObj) => { const setCheckedNode = (e: anyObj) => {
// console.log('🚀 ~ setCheckedNode ~ e:', e) // console.log('🚀 ~ setCheckedNode ~ e:', e)
id.value = e id.value = e
treRef.value.setCurrentKey(e) treRef.value.setCurrentKey(e)
} }
watch( watch(
() => planData.value, () => planData.value,
(val, oldVal) => { (val, oldVal) => {
if (val && dialogRef.value) { if (val && dialogRef.value) {
const obj = JSON.parse(JSON.stringify(val)) const obj = JSON.parse(JSON.stringify(val))
obj.records = [ obj.records = [
val.records.find(item => { val.records.find(item => {
return item.id == monitorId.value return item.id == monitorId.value
}) })
] ]
dialogRef.value.details(obj) dialogRef.value.details(obj)
} }
}, },
{ {
immediate: true, immediate: true,
deep: true deep: true
} }
) )
defineExpose({ treeRef, getPlanData, getTreeList, setCheckedNode }) defineExpose({ treeRef, getPlanData, getTreeList, setCheckedNode })
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.cn-tree { .cn-tree {
flex-shrink: 0; flex-shrink: 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
box-sizing: border-box; box-sizing: border-box;
padding: 10px; padding: 10px;
height: 100%; height: 100%;
width: 100%; width: 100%;
:deep(.el-tree) { :deep(.el-tree) {
border: 1px solid var(--el-border-color); border: 1px solid var(--el-border-color);
} }
:deep(.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content) { :deep(.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content) {
background-color: var(--el-color-primary-light-7); background-color: var(--el-color-primary-light-7);
} }
.menu-collapse { .menu-collapse {
color: var(--el-color-primary); color: var(--el-color-primary);
} }
} }
.ml10 { .ml10 {
margin-bottom: 0 !important; margin-bottom: 0 !important;
} }
.add_plan { .add_plan {
width: 100%; width: 100%;
height: 40px; height: 40px;
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
align-items: center; align-items: center;
} }
.custom-tree-node { .custom-tree-node {
width: 100%; width: 100%;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
.left, .left,
.right { .right {
display: flex; display: flex;
align-items: center; align-items: center;
} }
.left { .left {
span { span {
margin-left: 2px; margin-left: 2px;
} }
} }
.right { .right {
a { a {
margin-left: 2px; margin-left: 2px;
} }
} }
} }
</style> </style>

View File

@@ -6,12 +6,13 @@
:default-checked-keys="defaultCheckedKeys" :default-checked-keys="defaultCheckedKeys"
@checkChange="checkChange" @checkChange="checkChange"
:height="35" :height="35"
:engineering="true"
></DeviceTree> ></DeviceTree>
<div class="device-manage-right" :style="{ height: pageHeight.height }"> <div class="device-manage-right" :style="{ height: pageHeight.height }">
<vxe-table v-bind="defaultAttribute" :data="tableData" height="auto" style="width: 100%"> <vxe-table v-bind="defaultAttribute" :data="tableData" height="auto" style="width: 100%">
<vxe-column field="enginerName" title="工程名称"></vxe-column> <vxe-column field="enginerName" title="工程名称"></vxe-column>
<vxe-column field="projectName" title="项目名称"></vxe-column> <vxe-column field="projectName" title="项目名称"></vxe-column>
<vxe-column field="deviceName" title="装置名称"></vxe-column> <vxe-column field="deviceName" title="设备名称"></vxe-column>
</vxe-table> </vxe-table>
</div> </div>
</div> </div>

View File

@@ -7,12 +7,12 @@
@close="emit('closePopup')" @close="emit('closePopup')"
> >
<el-form class="form-two" :model="form" label-width="100px" ref="formRef" :rules="rules"> <el-form class="form-two" :model="form" label-width="100px" ref="formRef" :rules="rules">
<el-form-item label="装置类型:" prop="type"> <el-form-item label="设备类型:" prop="type">
<!-- <el-select v-model.trim="form.type" filterable placeholder="请选择" @change="typeChange"> <!-- <el-select v-model.trim="form.type" filterable placeholder="请选择" @change="typeChange">
<el-option v-for="item in TypeOptions" :key="item.id" :label="item.name" <el-option v-for="item in TypeOptions" :key="item.id" :label="item.name"
:value="item.id"></el-option> :value="item.id"></el-option>
</el-select> --> </el-select> -->
<el-select v-model.trim="form.type" placeholder="请选择装置类型" @change="formDevTypeChange" clearable> <el-select v-model.trim="form.type" placeholder="请选择设备类型" @change="formDevTypeChange" clearable>
<el-option <el-option
v-for="item in devTypeOptions" v-for="item in devTypeOptions"
:key="item.value" :key="item.value"
@@ -21,7 +21,7 @@
></el-option> ></el-option>
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="装置型号:" prop="devType"> <el-form-item label="设备型号:" prop="devType">
<!-- <el-select v-model.trim="form.devType" placeholder="请选择" filterable @change="devTypeChange"> <!-- <el-select v-model.trim="form.devType" placeholder="请选择" filterable @change="devTypeChange">
<el-option v-for="item in DevTypeOptions" :key="item.id" :label="item.name" <el-option v-for="item in DevTypeOptions" :key="item.id" :label="item.name"
:value="item.id"></el-option> :value="item.id"></el-option>
@@ -29,7 +29,7 @@
<el-select <el-select
v-model.trim="form.devType" v-model.trim="form.devType"
filterable filterable
placeholder="请选择装置型号" placeholder="请选择设备型号"
clearable clearable
@change="devTypeChange" @change="devTypeChange"
> >
@@ -59,13 +59,13 @@
placeholder="填写特殊类型(不填默认通用类型)" placeholder="填写特殊类型(不填默认通用类型)"
></el-input> ></el-input>
</el-form-item> </el-form-item>
<el-form-item label="版本协议:" prop="versionAgreement"> <el-form-item label="协议版本:" prop="versionAgreement">
<el-input <el-input
maxlength="32" maxlength="32"
show-word-limit show-word-limit
v-model.trim="form.versionAgreement" v-model.trim="form.versionAgreement"
autocomplete="off" autocomplete="off"
placeholder="请输入版本协议" placeholder="请输入协议版本"
></el-input> ></el-input>
</el-form-item> </el-form-item>
<el-form-item label="版本日期:" prop="versionDate"> <el-form-item label="版本日期:" prop="versionDate">
@@ -154,11 +154,11 @@ const form = reactive<any>({
file: [] file: []
}) })
const rules = { const rules = {
type: [{ required: true, message: '请选择装置类型', trigger: 'change' }], type: [{ required: true, message: '请选择设备类型', trigger: 'change' }],
devType: [{ required: true, message: '请选择装置型号', trigger: 'change' }], devType: [{ required: true, message: '请选择设备型号', trigger: 'change' }],
versionNo: [{ required: true, message: '请输入版本号', trigger: 'blur' }], versionNo: [{ required: true, message: '请输入版本号', trigger: 'blur' }],
versionType: [{ required: true, message: '请输入版本类型', trigger: 'blur' }], versionType: [{ required: true, message: '请输入版本类型', trigger: 'blur' }],
versionAgreement: [{ required: true, message: '请输入版本协议', trigger: 'blur' }], versionAgreement: [{ required: true, message: '请输入协议版本', trigger: 'blur' }],
versionDate: [{ required: true, message: '请输入版本日期', trigger: 'blur' }], versionDate: [{ required: true, message: '请输入版本日期', trigger: 'blur' }],
description: [{ required: true, message: '请输入描述', trigger: 'blur' }], description: [{ required: true, message: '请输入描述', trigger: 'blur' }],
crcInfo: [{ required: true, message: '请输入CRC校验', trigger: 'blur' }], crcInfo: [{ required: true, message: '请输入CRC校验', trigger: 'blur' }],

View File

@@ -11,7 +11,7 @@
placeholder="请输入名称" placeholder="请输入名称"
></el-input> ></el-input>
</el-form-item> </el-form-item>
<el-form-item label="装置型号"> <el-form-item label="设备型号">
<el-select v-model.trim="tableStore.table.params.devType" placeholder="请选择" clearable> <el-select v-model.trim="tableStore.table.params.devType" placeholder="请选择" clearable>
<el-option <el-option
v-for="item in DevTypeOptions" v-for="item in DevTypeOptions"
@@ -71,7 +71,7 @@ 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: 'devTypeName' }, { title: '设备型号', field: 'devTypeName' },
{ title: '模板名称', field: 'name' }, { title: '模板名称', field: 'name' },
{ title: '版本号', field: 'versionNo' }, { title: '版本号', field: 'versionNo' },
{ title: '版本时间', field: 'versionDate', sortable: true }, { title: '版本时间', field: 'versionDate', sortable: true },

View File

@@ -2,8 +2,8 @@
<div class="default-main"> <div class="default-main">
<TableHeader ref="tableHeaderRef" :showReset="false" showExport> <TableHeader ref="tableHeaderRef" :showReset="false" showExport>
<template #select> <template #select>
<el-form-item label="装置型号:"> <el-form-item label="设备型号:">
<el-select v-model.trim="tableStore.table.params.devType" placeholder="请选择装置型号" clearable> <el-select v-model.trim="tableStore.table.params.devType" filterable placeholder="请选择设备型号" clearable>
<el-option <el-option
v-for="item in DevTypeOptions" v-for="item in DevTypeOptions"
:key="item.id" :key="item.id"
@@ -55,9 +55,9 @@ 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: 'devTypeName' ,minWidth: '100'}, { title: '设备型号', field: 'devTypeName' ,minWidth: '100'},
{ title: '版本号', field: 'versionNo' ,minWidth: '100'}, { title: '版本号', field: 'versionNo' ,minWidth: '100'},
{ title: '版本协议', field: 'versionAgreement' ,minWidth: '100'}, { title: '协议版本', field: 'versionAgreement' ,minWidth: '100'},
{ title: '版本日期', field: 'versionDate' ,minWidth: '100'}, { title: '版本日期', field: 'versionDate' ,minWidth: '100'},
{ title: '归档日期', field: 'updateTime',minWidth: '150' }, { title: '归档日期', field: 'updateTime',minWidth: '150' },
{ title: '描述', field: 'description',minWidth: '200' }, { title: '描述', field: 'description',minWidth: '200' },

View File

@@ -1,5 +1,5 @@
<template> <template>
<el-dialog draggable class="cn-operate-dialog" width="520px" v-model.trim="dialogVisible" :title="title"> <el-dialog draggable class="cn-operate-dialog" width="540px" v-model.trim="dialogVisible" :title="title">
<el-form :inline="false" ref="formRef" :model="form" label-width="auto" class="form-one" :rules="rules"> <el-form :inline="false" ref="formRef" :model="form" label-width="auto" class="form-one" :rules="rules">
<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 maxlength="32" show-word-limit v-model.trim="form.name" placeholder="请输入项目名称" />
@@ -23,14 +23,9 @@
<el-form-item label="排序" prop="sort"> <el-form-item label="排序" prop="sort">
<el-input maxlength="32" show-word-limit-number v-model.number="form.sort" :min="0" /> <el-input maxlength="32" show-word-limit-number v-model.number="form.sort" :min="0" />
</el-form-item> </el-form-item>
<el-form-item label="拓扑图" prop="sort"> <el-form-item label="拓扑图">
<div class="image-radio-group"> <div class="image-radio-group">
<div <div class="image-radio-item" v-for="item in images" :key="item.id" @click="handleSelect(item.id)">
class="image-radio-item"
v-for="item in images"
:key="item.id"
@click="handleSelect(item.id)"
>
<el-radio :label="item.id" v-model="form.topoIds" class="hidden-radio"> <el-radio :label="item.id" v-model="form.topoIds" class="hidden-radio">
{{ item.name }} {{ item.name }}
</el-radio> </el-radio>
@@ -64,7 +59,7 @@ import TableStore from '@/utils/tableStore'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { add, update } from '@/api/user-boot/role' import { add, update } from '@/api/user-boot/role'
import { useAdminInfo } from '@/stores/adminInfo' import { useAdminInfo } from '@/stores/adminInfo'
import { addProject, updateProject } from '@/api/cs-device-boot/edData' import { addProject, updateProjects } from '@/api/cs-device-boot/edData'
import { getTopoTemplate } from '@/api/cs-device-boot/topologyTemplate' import { getTopoTemplate } from '@/api/cs-device-boot/topologyTemplate'
import { getFileUrl } from '@/api/system-boot/file' import { getFileUrl } from '@/api/system-boot/file'
const adminInfo = useAdminInfo() const adminInfo = useAdminInfo()
@@ -123,14 +118,15 @@ const open = (text: string, List: any, data?: anyObj, id?: string) => {
} }
} }
const submit = async () => { const submit = async () => {
if (form.topoIds == '') {
return ElMessage.warning('请选择拓扑图!')
}
formRef.value.validate(async valid => { formRef.value.validate(async valid => {
console.log("🚀 ~ submit ~ form.topoIds:", form.topoIds)
if (valid) { if (valid) {
if (form.id) { if (form.id) {
await updateProject({ ...form ,topoIds:[form.topoIds]}) await updateProjects({ ...form, topoIds: [form.topoIds] })
} else { } else {
await addProject({ ...form,topoIds:[form.topoIds] }) await addProject({ ...form, topoIds: [form.topoIds] })
} }
ElMessage.success('保存成功') ElMessage.success('保存成功')
tableStore.index() tableStore.index()
@@ -150,7 +146,11 @@ const getImageList = async () => {
} }
const handleSelect = (filePath: any) => { const handleSelect = (filePath: any) => {
form.topoIds = filePath if (form.topoIds == filePath) {
form.topoIds = ''
} else {
form.topoIds = filePath
}
} }
defineExpose({ open }) defineExpose({ open })
</script> </script>

View File

@@ -1,14 +1,24 @@
<template> <template>
<div class="default-main"> <div class="default-main">
<div style="display: flex"> <el-row v-loading="tableStore.table.loading">
<div style="width: 800px"> <el-col :span="11">
<div class="custom-table-header"> <div class="custom-table-header">
<div class="title">工程列表</div> <div class="title">
工程列表
<el-input
class="ml10"
v-model="searchValue"
placeholder="请输入工程名称"
clearable
style="width: 240px"
@input="inpChaange"
/>
</div>
<el-button :icon="Plus" type="primary" @click="addRole" class="ml10">新增工程</el-button> <el-button :icon="Plus" type="primary" @click="addRole" class="ml10">新增工程</el-button>
</div> </div>
<Table ref="tableRef" @currentChange="currentChange" /> <Table ref="tableRef" @currentChange="currentChange" />
</div> </el-col>
<div style="flex: 1"> <el-col :span="13">
<div class="custom-table-header"> <div class="custom-table-header">
<div class="title">項目列表</div> <div class="title">項目列表</div>
@@ -25,17 +35,19 @@
<vxe-column field="projectName" title="项目名称"></vxe-column> <vxe-column field="projectName" title="项目名称"></vxe-column>
<vxe-column field="projectArea" title="地址"></vxe-column> <vxe-column field="projectArea" title="地址"></vxe-column>
<vxe-column title="拓扑图"> <vxe-column field="projectRemark" title="备注"></vxe-column>
<vxe-column title="拓扑图" width="100px">
<template #default="{ row }"> <template #default="{ row }">
<el-image <el-image
:hide-on-click-modal="true" :hide-on-click-modal="true"
:preview-teleported="true" :preview-teleported="true"
v-if="row.topologyInfo"
:preview-src-list="[row.topologyImageUrl]" :preview-src-list="[row.topologyImageUrl]"
:src="getUrl(row) ? row.topologyImageUrl : ''" :src="row.topologyImageUrl"
></el-image> ></el-image>
<span v-else>/</span>
</template> </template>
</vxe-column> </vxe-column>
<vxe-column field="projectRemark" title="备注"></vxe-column>
<vxe-column field="projectSort" title="排序" width="80px"></vxe-column> <vxe-column field="projectSort" title="排序" width="80px"></vxe-column>
<vxe-column title="操作" width="180px"> <vxe-column title="操作" width="180px">
<template #default="{ row }"> <template #default="{ row }">
@@ -64,8 +76,8 @@
</vxe-column> </vxe-column>
</vxe-table> </vxe-table>
</div> </div>
</div> </el-col>
</div> </el-row>
<!-- 新增工程 --> <!-- 新增工程 -->
<popup ref="popupRef" @save="save" /> <popup ref="popupRef" @save="save" />
<!-- 新增項目 --> <!-- 新增項目 -->
@@ -78,7 +90,7 @@ import { Plus } from '@element-plus/icons-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 { delTemplate, deleteSysExcel, bandRelation, queryList } from '@/api/harmonic-boot/luckyexcel' import { delTemplate, deleteSysExcel, bandRelation, queryList } from '@/api/harmonic-boot/luckyexcel'
import { deleteProject ,deleteEngineering} from '@/api/cs-device-boot/edData' import { deleteProject, deleteEngineering } from '@/api/cs-device-boot/edData'
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
import { defaultAttribute } from '@/components/table/defaultAttribute' import { defaultAttribute } from '@/components/table/defaultAttribute'
@@ -92,13 +104,16 @@ defineOptions({
const height = mainHeight(80) const height = mainHeight(80)
const volConTypeList: any = dictData.getBasicData('Dev_Connect') const volConTypeList: any = dictData.getBasicData('Dev_Connect')
import { getFileUrl } from '@/api/system-boot/file' import { getFileUrl } from '@/api/system-boot/file'
const popupRef = ref() const popupRef = ref()
const tableRef = ref() const tableRef = ref()
const tableRef1 = ref() const tableRef1 = ref()
const itemList = ref([]) const searchValue = ref('')
const itemList: any = ref([])
const menuListId = ref([]) const menuListId = ref([])
const itemAddRef = ref() const itemAddRef = ref()
const engineeringId = ref('') const engineeringId = ref('')
const tableList = ref([])
const tableStore: any = new TableStore({ const tableStore: any = new TableStore({
url: '/cs-device-boot/engineeringProjectRelation/list', url: '/cs-device-boot/engineeringProjectRelation/list',
method: 'POST', method: 'POST',
@@ -161,17 +176,35 @@ const tableStore: any = new TableStore({
], ],
loadCallback: () => { loadCallback: () => {
if (engineeringId.value == '') { tableList.value = JSON.parse(JSON.stringify(tableStore.table.data))
engineeringId.value = tableStore.table.data[0].engineeringId setTableRow()
}
let list = tableStore.table.data.filter((item: any) => item.engineeringId == engineeringId.value)
tableRef.value.getRef().setCurrentRow(list[0])
itemList.value = list[0].projectInfoList
} }
}) })
provide('tableStore', tableStore) provide('tableStore', tableStore)
// 过滤
const inpChaange = (val: any) => {
engineeringId.value = ''
if (val == '') {
tableStore.table.data = tableList.value
} else {
tableStore.table.data = tableList.value.filter((item: any) => item.engineeringName.includes(val))
}
setTableRow()
}
const setTableRow = () => {
if (engineeringId.value == '') {
engineeringId.value = tableStore.table.data[0].engineeringId
}
let list = tableStore.table.data.filter((item: any) => item.engineeringId == engineeringId.value)
tableRef.value.getRef().setCurrentRow(list[0] ?? {})
itemList.value = list?.[0]?.projectInfoList ?? []
if (itemList.value.length > 0) {
itemList.value.forEach((item: any) => {
item.topologyImageUrl = getUrl(item)
})
}
}
// 修改模版 // 修改模版
const itemModification = (row: any) => { const itemModification = (row: any) => {
itemAddRef.value.open('新增项目', tableStore.table.data, row, engineeringId.value) itemAddRef.value.open('新增项目', tableStore.table.data, row, engineeringId.value)
@@ -195,6 +228,11 @@ const add = () => {
const currentChange = (data: any) => { const currentChange = (data: any) => {
engineeringId.value = data.row.engineeringId engineeringId.value = data.row.engineeringId
itemList.value = data.row.projectInfoList itemList.value = data.row.projectInfoList
if (itemList.value.length > 0) {
itemList.value.forEach((item: any) => {
item.topologyImageUrl = getUrl(item)
})
}
} }
// 保存模版 // 保存模版
const save = () => { const save = () => {
@@ -210,14 +248,11 @@ const save = () => {
const imgList = ref([]) const imgList = ref([])
// 获取拓扑图 // 获取拓扑图
const getUrl = async (row: any) => { const getUrl = async (row: any) => {
if (!row.topologyInfo || row.topologyInfo === '/') return false if (!row.topologyInfo || row.topologyInfo === '/') return ''
try {
const res = await getFileUrl({ filePath: row.topologyInfo }) const res = await getFileUrl({ filePath: row.topologyInfo })
row.topologyImageUrl = res.data row.topologyImageUrl = res.data
return true return res.data
} catch (error) {
return false
}
} }
onMounted(() => { onMounted(() => {

View File

@@ -151,7 +151,7 @@
<el-form-item label="设备型号:" prop="devModel" class="top"> <el-form-item label="设备型号:" prop="devModel" class="top">
<el-select v-model.trim="form.devModel" filterable placeholder="请选择" clearable> <el-select v-model.trim="form.devModel" filterable placeholder="请选择" clearable>
<el-option <el-option
v-for="item in formDevModelOptionsFilter " v-for="item in formDevModelOptionsFilter"
:key="item.value" :key="item.value"
:label="item.label" :label="item.label"
:value="item.value" :value="item.value"
@@ -164,6 +164,15 @@
<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-cascader
v-model.trim="form.association"
filterable
:options="engineeringList"
:props="props"
clearable
/>
</el-form-item>
<el-form-item label="排序:" class="top" prop="sort"> <el-form-item label="排序:" class="top" prop="sort">
<el-input maxlength="32" show-word-limit-number v-model.trim="form.sort" :min="0" /> <el-input maxlength="32" show-word-limit-number v-model.trim="form.sort" :min="0" />
</el-form-item> </el-form-item>
@@ -198,7 +207,7 @@ 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 { ElMessage, ElMessageBox } from 'element-plus' import { ElMessage, ElMessageBox } from 'element-plus'
import { activateUser, deluser, passwordConfirm } from '@/api/user-boot/user' import { activateUser, deluser, passwordConfirm } from '@/api/user-boot/user'
import { downLoadFile } from '@/api/cs-system-boot/manage.ts' import { downLoadFile } from '@/api/cs-system-boot/manage'
import { import {
addEquipmentDelivery, addEquipmentDelivery,
deleteEquipmentDelivery, deleteEquipmentDelivery,
@@ -208,7 +217,8 @@ import {
governDeviceRegister, governDeviceRegister,
portableDeviceRegister, portableDeviceRegister,
portableDeviceAccess, portableDeviceAccess,
getExcelTemplate getExcelTemplate,
engineeringProject
} from '@/api/cs-system-boot/device' } from '@/api/cs-system-boot/device'
import html2canvas from 'html2canvas' import html2canvas from 'html2canvas'
import { fullUrl } from '@/utils/common' import { fullUrl } from '@/utils/common'
@@ -221,17 +231,27 @@ const showQrCode = ref(false)
const devTypeOptions: any = ref([]) const devTypeOptions: any = ref([])
const devTypeOptions2: any = ref([]) const devTypeOptions2: any = ref([])
const devModelOptions2: any = ref([]) const devModelOptions2: any = ref([])
const engineeringList: any = ref([])
const deivce: any = ref({}) const deivce: any = ref({})
const ruleFormRef = ref() const ruleFormRef = ref()
const form = reactive({ const form: any = reactive({
cntractNo: '', cntractNo: '',
devAccessMethod: 'MQTT', devAccessMethod: 'MQTT',
devModel: '', devModel: '',
devType: '', devType: '',
name: '', name: '',
ndid: '', ndid: '',
associatedEngineering: '',
associatedProject: '',
association: [],
sort: 0 sort: 0
}) })
const props = {
label: 'projectName',
value: 'projectId',
children: 'projectInfoList'
}
const rules = reactive({ const rules = reactive({
name: [{ required: true, message: '请输入设备名', trigger: 'blur' }], name: [{ required: true, message: '请输入设备名', trigger: 'blur' }],
ndid: [{ required: true, message: '请输入网络设备id', trigger: 'blur' }], ndid: [{ required: true, message: '请输入网络设备id', trigger: 'blur' }],
@@ -248,19 +268,21 @@ const dialogTitle = ref('新增设备')
const loading = ref<boolean>(false) const loading = ref<boolean>(false)
const devModelOptions: any = ref([]) const devModelOptions: any = ref([])
const queryTheDictionary = () => { const queryTheDictionary = () => {
queryByCode('DEV_CLD').then(res => { queryByCode('DEV_CLD')
.then(res => {
devTypeOptions2.value = res.data devTypeOptions2.value = res.data
return queryCsDictTree(res.data.id).then(res => { return queryCsDictTree(res.data.id).then(res => {
devModelOptions2.value = res.data.map((item: any) => { devModelOptions2.value = res.data.map((item: any) => {
return { return {
value: item.id, value: item.id,
label: item.name, label: item.name,
...item ...item
} }
}) })
}) })
}).then(() => { })
queryByCode('Device_Type').then(async res => { .then(() => {
queryByCode('Device_Type').then(async res => {
const id = res.data.id const id = res.data.id
await queryCsDictTree(id).then(res => { await queryCsDictTree(id).then(res => {
devTypeOptions.value = res.data.map((item: any) => { devTypeOptions.value = res.data.map((item: any) => {
@@ -270,7 +292,7 @@ const queryTheDictionary = () => {
...item ...item
} }
}) })
// let index = devTypeOptions.value.findIndex((item: any) => { // let index = devTypeOptions.value.findIndex((item: any) => {
// return item.name == '网关' // return item.name == '网关'
// }) // })
@@ -292,10 +314,10 @@ const queryTheDictionary = () => {
}) })
await tableStore.index() await tableStore.index()
}) })
}).catch(error => { })
.catch(error => {
console.error('查询过程中出现错误:', error) console.error('查询过程中出现错误:', error)
}) })
} }
const devModelOptionsFilter = computed(() => { const devModelOptionsFilter = computed(() => {
return devModelOptions.value.filter((item: any) => { return devModelOptions.value.filter((item: any) => {
@@ -308,7 +330,7 @@ const devModelOptionsFilter = computed(() => {
}) })
const formDevModelOptionsFilter = computed(() => { const formDevModelOptionsFilter = computed(() => {
if(form.devAccessMethod === 'CLD'){ if (form.devAccessMethod === 'CLD') {
return devModelOptions2.value.filter((item: any) => { return devModelOptions2.value.filter((item: any) => {
if (form.devType) { if (form.devType) {
return item.pid == form.devType return item.pid == form.devType
@@ -316,18 +338,17 @@ const formDevModelOptionsFilter = computed(() => {
return true return true
} }
}) })
}else{ } else {
return devModelOptions.value.filter((item: any) => { return devModelOptions.value.filter((item: any) => {
if (form.devType) { if (form.devType) {
return item.pid == form.devType return item.pid == form.devType
} else { } else {
return true return true
} }
}) })
} }
}) })
const formDevTypeOptions = computed(() => { const formDevTypeOptions = computed(() => {
// 如果协议是CLD使用devTypeOptions2否则使用devTypeOptions // 如果协议是CLD使用devTypeOptions2否则使用devTypeOptions
if (form.devAccessMethod === 'CLD') { if (form.devAccessMethod === 'CLD') {
@@ -362,13 +383,13 @@ const tableStore = new TableStore({
field: 'devType', field: 'devType',
formatter: row => { formatter: row => {
if (row.row.devAccessMethod === 'CLD') { if (row.row.devAccessMethod === 'CLD') {
// 遍历devTypeOptions2查找匹配 // 遍历devTypeOptions2查找匹配
return devTypeOptions2.value.name return devTypeOptions2.value.name
} }
// 如果是MQTT协议使用devTypeOptions查找 // 如果是MQTT协议使用devTypeOptions查找
else if (row.row.devAccessMethod === 'MQTT') { else if (row.row.devAccessMethod === 'MQTT') {
const item = devTypeOptions.value.find((item: any) => item.value == row.cellValue); const item = devTypeOptions.value.find((item: any) => item.value == row.cellValue)
return item ? item.label : '/'; return item ? item.label : '/'
} }
}, },
minWidth: 120 minWidth: 120
@@ -378,8 +399,8 @@ const tableStore = new TableStore({
field: 'devModel', field: 'devModel',
formatter: row => { formatter: row => {
const options = row.row.devAccessMethod === 'MQTT' ? devModelOptions.value : devModelOptions2.value const options = row.row.devAccessMethod === 'MQTT' ? devModelOptions.value : devModelOptions2.value
const item = options.find((item: any) => item.value == row.cellValue); const item = options.find((item: any) => item.value == row.cellValue)
return item ? item.label : '/'; return item ? item.label : '/'
}, },
minWidth: 120 minWidth: 120
}, },
@@ -488,12 +509,13 @@ const tableStore = new TableStore({
minWidth: 80 minWidth: 80
}, },
{ {
title: '操作', fixed: 'right', title: '操作',
fixed: 'right',
align: 'center', align: 'center',
width: 220, width: 220,
render: 'buttons', render: 'buttons',
buttons: [ buttons: [
//直连装置注册 //直连设备注册
// { // {
// title: '注册', // title: '注册',
// type: 'primary', // type: 'primary',
@@ -677,7 +699,6 @@ const tableStore = new TableStore({
useCORS: true useCORS: true
}).then(canvas => { }).then(canvas => {
let url = canvas.toDataURL('image/png') let url = canvas.toDataURL('image/png')
console.log('🚀 ~ html2canvas ~ url:', url)
// 下载图片 // 下载图片
let a = document.createElement('a') let a = document.createElement('a')
let event = new MouseEvent('click') let event = new MouseEvent('click')
@@ -701,6 +722,10 @@ const tableStore = new TableStore({
for (let key in form) { for (let key in form) {
form[key] = row[key] form[key] = row[key]
} }
form.association = row.associatedProject
? [row.associatedEngineering, row.associatedProject]
: []
form.id = row.id form.id = row.id
} }
}, },
@@ -741,7 +766,6 @@ const tableStore = new TableStore({
: '' : ''
} }
}) })
console.log('🚀 ~ loadCallback ~ tableStore.table:', tableStore.table)
tableKey.value += 1 tableKey.value += 1
} }
}) })
@@ -877,6 +901,9 @@ const add = () => {
const onSubmit = () => { const onSubmit = () => {
ruleFormRef.value.validate((valid: any) => { ruleFormRef.value.validate((valid: any) => {
if (valid) { if (valid) {
form.associatedEngineering = form.association ? form.association[0] : ''
form.associatedProject = form.association ? form.association[1] : ''
if (dialogTitle.value == '新增设备') { if (dialogTitle.value == '新增设备') {
addEquipmentDelivery(form).then(res => { addEquipmentDelivery(form).then(res => {
ElMessage.success('新增成功') ElMessage.success('新增成功')
@@ -923,6 +950,9 @@ const resetForm = () => {
devModel: '', devModel: '',
devType: '', devType: '',
name: '', name: '',
associatedEngineering: '',
associatedProject: '',
association: [],
ndid: '' ndid: ''
} }
Object.assign(form, user) Object.assign(form, user)
@@ -939,6 +969,15 @@ provide('tableStore', tableStore)
onMounted(() => { onMounted(() => {
queryTheDictionary() queryTheDictionary()
engineeringProject().then(res => {
engineeringList.value = res.data.filter(item => {
item.projectName = item.engineeringName
item.projectId = item.engineeringId
item.disabled = item.projectInfoList ? false : true
return item
})
})
setTimeout(() => {}, 100) setTimeout(() => {}, 100)
}) })

View File

@@ -0,0 +1,157 @@
<template>
<el-dialog class="cn-operate-dialog" width="600px" v-model.trim="dialogVisible" :title="title">
<el-form :model="form" class="form-one" label-width="auto" ref="formRef" :rules="rules">
<el-form-item label="版本号" prop="substationName">
<el-input v-model.trim="form.substationName" placeholder="请输入版本号"></el-input>
</el-form-item>
<el-form-item label="协议版本" prop="name">
<el-input v-model.trim="form.name" placeholder="请输入协议版本"></el-input>
</el-form-item>
<el-form-item label="版本日期" prop="name">
<el-input v-model.trim="form.name" placeholder="请输入版本日期"></el-input>
</el-form-item>
<el-form-item label="设备系列" prop="loadType">
<el-select v-model.trim="form.loadType" filterable clearable placeholder="请选择设备系列">
<el-option
v-for="item in DataTypeSelect"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="版本类型" prop="name">
<el-input v-model.trim="form.name" placeholder="请输入版本类型"></el-input>
</el-form-item>
<el-form-item label="描述" prop="name">
<el-input
maxlength="32"
:autosize="{ minRows: 2, maxRows: 4 }"
type="textarea"
show-word-limit
v-model.trim="form.remark"
placeholder="请输入描述"
></el-input>
</el-form-item>
<el-form-item label="上传升级文件" prop="name">
<el-upload
:limit="1"
accept=".bin"
:auto-upload="false"
:on-change="fileChange"
:on-exceed="fileExceed"
:on-remove="fileRemove"
:file-list="fileList"
>
<el-button type="primary">点击上传</el-button>
</el-upload>
</el-form-item>
<el-form-item label="CRC校验" prop="name">
<el-input v-model.trim="form.name" placeholder="请输入版本日期"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="submit">确认</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { ref, inject } from 'vue'
import { reactive } from 'vue'
import { ElMessage } from 'element-plus'
import TableStore from '@/utils/tableStore'
import { queryByCode, queryCsDictTree } from '@/api/system-boot/dictTree'
import { saveUser, updateUser } from '@/api/cs-device-boot/sensitiveLoadMange'
import { useDictData } from '@/stores/dictData'
const TypeOptions = ref()
const dictData = useDictData()
const DataTypeSelect = dictData.getBasicData('Interference_Source')
const tableStore = inject('tableStore') as TableStore
const fileList: any = ref([])
const formRef = ref()
const form = reactive<any>({
loadType: [],
substationName: null,
installedCapacity: null,
name: null,
userAgreementCapacity: null,
id: null,
sort: 100
})
const rules = {
substationName: [{ required: true, message: '请输入所属厂站名称', trigger: 'blur' }],
name: [{ required: true, message: '请输入敏感用户名称', trigger: 'blur' }],
loadType: [{ required: true, message: '请输入请选择敏感负荷类型', trigger: 'blur' }],
installedCapacity: [{ required: true, message: '请输入用户协议容量', trigger: 'blur' }],
userAgreementCapacity: [{ required: true, message: '请输入装机容量', trigger: 'blur' }],
sort: [{ required: true, message: '请输入排序', trigger: 'blur' }]
}
const dialogVisible = ref(false)
const title = ref('新增')
const open = (text: string, data?: anyObj) => {
formRef.value?.resetFields()
title.value = text
dialogVisible.value = true
if (data) {
for (let key in form) {
form[key] = data[key]
}
} else {
for (let key in form) {
form[key] = null
form.sort = 100
}
}
}
const fileRemove = (e: any) => {
form.file = null
fileList.value = []
}
const fileChange = (e: any) => {
if (!beforeUpload(e.raw)) return
form.file = e.raw
fileList.value = [e.raw]
}
const fileExceed = (e: any) => {
ElMessage.error('只能上传一个文件')
}
// 处理上传前检查
const beforeUpload = (file: any) => {
const isWord = file.name.endsWith('.bin')
if (!isWord) {
ElMessage.error('请上传(.bin)格式文件!')
fileList.value = []
return false
}
// 校验通过后允许上传,交由 http-request 处理
return true
}
const submit = () => {
formRef.value.validate(async (valid: boolean) => {
if (valid) {
if (form.id) {
await updateUser(form)
} else {
await saveUser(form)
}
ElMessage.success('操作成功')
tableStore.index()
dialogVisible.value = false
}
})
}
defineExpose({ open })
</script>

View File

@@ -0,0 +1,171 @@
<template>
<div class="default-main">
<TableHeader ref="tableHeaderRef" :showReset="false" showExport>
<template #select>
<el-form-item label="关键字筛选">
<el-input v-model="tableStore.table.params.keywords" clearable placeholder="请输入关键字" />
</el-form-item>
<el-form-item label="设备系列">
<el-select
v-model.trim="tableStore.table.params.devType"
filterable
placeholder="请选择设备系列"
clearable
>
<el-option
v-for="item in DevTypeOptions"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
</template>
<template #operation>
<el-button :icon="Plus" type="primary" @click="add">新增</el-button>
<el-button :icon="Back" @click="go(-1)">返回</el-button>
</template>
</TableHeader>
<Table ref="tableRef" />
<!-- 新增 -->
<Form ref="formRef" />
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, provide } from 'vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import { ElMessage } from 'element-plus'
import { queryByCode, queryByid } from '@/api/system-boot/dictTree'
import { useDictData } from '@/stores/dictData'
import { Plus, EditPen } from '@element-plus/icons-vue'
import { useRouter } from 'vue-router'
import { Back, Setting, Search } from '@element-plus/icons-vue'
import Form from './form.vue'
defineOptions({
name: 'govern/manage/programVersion'
})
const dictData = useDictData()
const DevTypeOptions = ref()
const tableHeaderRef = ref()
const { push, go } = useRouter()
const formRef = ref()
const tableStore = new TableStore({
url: '/cs-device-boot/edData/queryEdDataPage',
method: 'POST',
column: [
{
field: 'index',
title: '序号',
width: '80',
formatter: (row: any) => {
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
}
},
{ title: '设备系列', field: 'devTypeName', minWidth: '100' },
{ title: '版本号', field: 'versionNo', minWidth: '100' },
{ title: '协议版本', field: 'versionAgreement', minWidth: '100' },
{ title: '版本日期', field: 'versionDate', minWidth: '100' },
{ title: '修改人员', field: 'versionDate', minWidth: '100' },
{ title: '修改日期', field: 'versionDate', minWidth: '100' },
{ title: '描述', field: 'versionDate', minWidth: '100' },
{ title: '版本类型', field: 'versionDate', minWidth: '100' },
{
title: '状态',
render: 'switch',
width: 100,
field: 'usageStatus',
activeText: '启用',
inactiveText: '停用',
inactiveValue: '0',
activeValue: '1',
onChangeField: (row: any, value: any) => {
// console.log("🚀 ~ row:", row)
// ElMessageBox.prompt('二次校验密码确认', '', {
// confirmButtonText: '确认',
// cancelButtonText: '取消',
// customClass: 'customInput',
// inputType: 'text',
// beforeClose: (action, instance, done) => {
// if (action === 'confirm') {
// if (instance.inputValue == null) {
// return ElMessage.warning('请输入密码')
// } else if (instance.inputValue?.length > 32) {
// return ElMessage.warning(
// '密码长度不能超过32位,当前密码长度为' + instance.inputValue.length
// )
// } else {
// done()
// }
// } else {
// done()
// }
// }
// }).then(({ value }) => {
// passwordConfirm(value).then(res => {
// editEquipmentDelivery({
// ...row,
// status: row.status == 5 ? 1 : row.status == 6 ? 2 : row.status,
// usageStatus: row.usageStatus == 1 ? 0 : 1
// }).then(res => {
// ElMessage.success(row.usageStatus == 1 ? '设备停用成功!' : '设备启用成功!')
// tableStore.index()
// })
// })
// })
}
},
{
title: '操作',
fixed: 'right',
align: 'center',
width: '120',
render: 'buttons',
buttons: [
{
name: 'productSetting',
title: '修改',
type: 'primary',
icon: 'el-icon-EditPen',
render: 'basicButton'
},
{
name: 'productSetting',
title: '删除',
type: 'primary',
icon: 'el-icon-EditPen',
render: 'basicButton'
}
]
}
],
loadCallback: () => {}
})
queryByCode('Device_Type').then(res => {
const id = res.data.id
queryByid(id).then(res1 => {
res1.data.map((item: any, index: any) => {
if (item.pid == id) {
res1.data.splice(index, 1)
}
})
DevTypeOptions.value = res1.data
})
})
tableStore.table.params.devType = ''
provide('tableStore', tableStore)
const add = () => {
formRef.value.open('新增版本')
}
onMounted(() => {
tableHeaderRef.value.onComSearch()
})
</script>

View File

@@ -0,0 +1,183 @@
<template>
<div class="default-main">
<TableHeader ref="tableHeaderRef" :showReset="false" showExport>
<template #select>
<el-form-item label="关键字筛选">
<el-input v-model="tableStore.table.params.keywords" clearable placeholder="请输入关键字" />
</el-form-item>
<el-form-item label="通讯状态">
<el-select
v-model.trim="tableStore.table.params.devType"
filterable
placeholder="请选择通讯状态"
clearable
>
<el-option
v-for="item in DevTypeOptions"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="设备型号">
<el-select
v-model.trim="tableStore.table.params.devType"
filterable
placeholder="请选择设备型号"
clearable
>
<el-option
v-for="item in DevTypeOptions"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="设备系列">
<el-select
v-model.trim="tableStore.table.params.devType"
filterable
placeholder="请选择设备系列"
clearable
>
<el-option
v-for="item in DevTypeOptions"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
<el-form-item label="升级设备筛选">
<el-select
v-model.trim="tableStore.table.params.devType"
filterable
placeholder="请选择升级设备筛选"
clearable
>
<el-option
v-for="item in DevTypeOptions"
:key="item.id"
:label="item.name"
:value="item.id"
></el-option>
</el-select>
</el-form-item>
</template>
<template #operation>
<el-button :icon="EditPen" type="primary" class="ml10" @click="maintenance">终端版本维护</el-button>
<el-button :icon="Share" type="primary" class="ml10">批量升级</el-button>
</template>
</TableHeader>
<Table ref="tableRef" />
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, provide } from 'vue'
import TableStore from '@/utils/tableStore'
import Table from '@/components/table/index.vue'
import TableHeader from '@/components/table/header/index.vue'
import { ElMessage } from 'element-plus'
import { queryByCode, queryByid } from '@/api/system-boot/dictTree'
import { useDictData } from '@/stores/dictData'
import { Share, EditPen } from '@element-plus/icons-vue'
import { useRouter } from 'vue-router'
defineOptions({
name: 'govern/manage/programVersion'
})
const dictData = useDictData()
const DevTypeOptions = ref()
const tableHeaderRef = ref()
const { push, options, currentRoute } = useRouter()
const tableStore = new TableStore({
url: '/cs-device-boot/edData/queryEdDataPage',
method: 'POST',
column: [
{ type: 'checkbox', width: '60' },
{
field: 'index',
title: '序号',
width: '80',
formatter: (row: any) => {
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
}
},
{ title: '设备名称', field: 'devTypeName', minWidth: '100' },
{ title: '版本号', field: 'versionNo', minWidth: '100' },
{ title: '协议版本', field: 'versionAgreement', minWidth: '100' },
{ title: '版本日期', field: 'versionDate', minWidth: '100' },
{ title: '设备系列', field: 'versionDate', minWidth: '100' },
{ title: '设备型号', field: 'versionDate', minWidth: '100' },
{ title: '供电公司', field: 'versionDate', minWidth: '100' },
{ title: '变电站', field: 'versionDate', minWidth: '100' },
{
title: '状态',
field: 'status',
render: 'tag',
minWidth: '80',
custom: {
0: 'error',
1: 'success'
},
replaceValue: {
0: '禁用',
1: '启用'
}
},
{ title: '更新时间', field: 'versionDate', minWidth: '100' },
{ title: '修改人员', field: 'versionDate', minWidth: '100' },
{
title: '操作',
fixed: 'right',
align: 'center',
width: '120',
render: 'buttons',
buttons: [
{
name: 'productSetting',
title: '升级',
type: 'primary',
icon: 'el-icon-EditPen',
render: 'basicButton'
},
{
name: 'productSetting',
title: '升级日志',
type: 'primary',
icon: 'el-icon-EditPen',
render: 'basicButton'
}
]
}
],
loadCallback: () => {}
})
queryByCode('Device_Type').then(res => {
const id = res.data.id
queryByid(id).then(res1 => {
res1.data.map((item: any, index: any) => {
if (item.pid == id) {
res1.data.splice(index, 1)
}
})
DevTypeOptions.value = res1.data
})
})
// 版本维护
const maintenance = () => {
push({
// path: '/versionMaintenance'
path: '/govern/manage/basic/version'
})
}
tableStore.table.params.devType = ''
provide('tableStore', tableStore)
onMounted(() => {
tableHeaderRef.value.onComSearch()
})
</script>

View File

@@ -0,0 +1,263 @@
<template>
<div class="default-main manage-realTime" :style="{ height: pageHeight.height }">
<DeviceTree @node-click="nodeClick" @init="" @deviceTypeChange=""></DeviceTree>
<div class="manage-realTime-right">
<div class="time-container">
<div>
<div>系统时间{{ realTime }}</div>
<div>终端时间{{ deviceTime }}</div>
</div>
<el-button icon="el-icon-RefreshLeft" type="primary" @click="synchronizeTime">对时</el-button>
</div>
<div :style="echartHeight" class="pl10 pr10">
<MyEchart :options="echartsData" />
</div>
<div class="pl10 pr10">
<el-table :data="tableData" border stripe :show-header="false" class="custom-table">
<el-table-column prop="label1" />
<el-table-column prop="label2" />
<el-table-column prop="value1" />
<el-table-column prop="label3" />
<el-table-column prop="value2" />
<el-table-column prop="label4" />
<el-table-column prop="value3" />
</el-table>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue'
import { mainHeight } from '@/utils/layout'
import DeviceTree from '@/components/tree/govern/deviceTree.vue'
import MyEchart from '@/components/echarts/MyEchart.vue'
import { formatToDateTime } from '@/utils/dateUtil'
defineOptions({
name: 'govern/manage/realTime'
})
//页面属性
const pageHeight = mainHeight(20)
const echartHeight = mainHeight(180)
const realTime = ref<string>('')
const deviceTime = ref<string>('')
const timer = ref<any>(null)
const echartsData = ref<any>({
title: {
text: '终端性能'
},
tooltip: {
axisPointer: {
type: 'cross',
label: {
color: '#fff',
fontSize: 16
}
},
textStyle: {
color: '#fff',
fontStyle: 'normal',
opacity: 0.35,
fontSize: 14
},
backgroundColor: 'rgba(0,0,0,0.55)',
borderWidth: 0
},
legend: {
bottom: 0,
data: ['CPU1使用率', 'CPU2使用率', '内存使用率', '磁盘使用率']
},
xAxis: {
type: 'time',
name: '时间',
axisLabel: {
formatter: {
day: '{MM}-{dd}',
month: '{MM}',
year: '{yyyy}'
}
}
},
yAxis: {
name: '%',
type: 'value',
min: 0,
max: 100
},
series: [
{
name: 'CPU1使用率',
type: 'line',
showSymbol: false,
smooth: true,
data: [
['2025-01-01 08:00:00', 10],
['2025-01-01 09:00:00', 10],
['2025-01-01 010:00:00', 10]
]
},
{
name: 'CPU2使用率',
type: 'line',
showSymbol: false,
smooth: true,
data: [
['2025-01-01 08:00:00', 11],
['2025-01-01 09:00:00', 11],
['2025-01-01 010:00:00', 11]
]
},
{
name: '内存使用率',
type: 'line',
showSymbol: false,
smooth: true,
data: [
['2025-01-01 08:00:00', 12],
['2025-01-01 09:00:00', 12],
['2025-01-01 010:00:00', 12]
]
},
{
name: '磁盘使用率',
type: 'line',
showSymbol: false,
smooth: true,
data: [
['2025-01-01 08:00:00', 13],
['2025-01-01 09:00:00', 13],
['2025-01-01 010:00:00', 13]
]
}
]
})
const tableData = ref([
{
label1: 'cpu1负载(%)',
label2: '使用:',
value1: '43',
label3: '剩余:',
value2: '57',
label4: '',
value3: ''
},
{
label1: 'cpu2负载(%)',
label2: '使用:',
value1: '/',
label3: '剩余:',
value2: '/',
label4: '',
value3: ''
},
{
label1: '终端内存详情(MB)',
label2: '内存总量:',
value1: '489',
label3: '已使用:',
value2: '143',
label4: '未使用:',
value3: '346.00'
},
{
label1: '主存储器详情(GB)',
label2: '主存储器总量:',
value1: '6.44',
label3: '已使用:',
value2: '6.03',
label4: '未使用:',
value3: '0.41'
},
{
label1: '其余信息',
label2: '最后对时对标:',
value1: '1970-01-01 08:00:00',
label3: '信号强度(dBm):',
value2: '-',
label4: '',
value3: ''
}
])
const nodeClick = async (e: anyObj) => {
console.log('点击设备树节点')
}
const handleClose = () => {
console.log('close')
}
const synchronizeTime = async () => {
console.log('对时')
}
onMounted(() => {
timer.value = setInterval(() => {
realTime.value = formatToDateTime(new Date())
}, 1000)
})
// 在组件卸载时清除定时器
onUnmounted(() => {
if (timer.value) {
clearInterval(timer.value)
timer.value = null
}
})
</script>
<style scoped lang="scss">
.manage-realTime {
display: flex;
&-right {
height: 100%;
overflow: hidden;
flex: 1;
padding: 10px 10px 10px 0;
display: flex;
flex-direction: column;
border: 1px solid #ebeef5; // 加个边框方便查看效果
.time-container {
display: flex;
justify-content: flex-end; // 让内容靠右
align-items: center; // 让内容垂直居中(避免高度不一致时偏移)
* {
margin-right: 15px;
}
.el-button * {
margin-right: 0;
}
}
:deep(.el-table__cell) {
text-align: center;
}
/* 1. 加深表格边框线条 */
:deep(.custom-table.el-table) {
border: 1px solid #dcdfe6;
width: auto;
}
:deep(.custom-table .el-table__cell) {
border: 0.5px solid #dcdfe6;
}
/* 2. 第 1、2、4、6 列显示深色背景 */
:deep(.custom-table .el-table__row .el-table__cell:nth-child(1)) {
background-color: #f5f7fa;
font-weight: bold;
}
/* 第 3、5、7 列显示白色背景 */
:deep(.custom-table .el-table__row .el-table__cell:nth-child(3)),
:deep(.custom-table .el-table__row .el-table__cell:nth-child(5)),
:deep(.custom-table .el-table__row .el-table__cell:nth-child(7)) {
// background-color: #fff;
}
}
}
</style>

View File

@@ -1,349 +1,326 @@
// import { createCellPos } from './translateNumToLetter' // import { createCellPos } from './translateNumToLetter'
import Excel from 'exceljs' import Excel from 'exceljs'
import FileSaver from 'file-saver' import FileSaver from 'file-saver'
const exportExcel = function(luckysheet, value) { const exportExcel = function (luckysheet, value) {
// 参数为luckysheet.getluckysheetfile()获取的对象 // 参数为luckysheet.getluckysheetfile()获取的对象
// 1.创建工作簿,可以为工作簿添加属性 // 1.创建工作簿,可以为工作簿添加属性
const workbook = new Excel.Workbook() const workbook = new Excel.Workbook()
// 2.创建表格,第二个参数可以配置创建什么样的工作表 // 2.创建表格,第二个参数可以配置创建什么样的工作表
if (Object.prototype.toString.call(luckysheet) === '[object Object]') { if (Object.prototype.toString.call(luckysheet) === '[object Object]') {
luckysheet = [luckysheet] luckysheet = [luckysheet]
} }
luckysheet.forEach(function(table) { luckysheet.forEach(function (table) {
if (table.data.length === 0) return true if (table.data.length === 0) return true
// ws.getCell('B2').fill = fills. // ws.getCell('B2').fill = fills.
const worksheet = workbook.addWorksheet(table.name) const worksheet = workbook.addWorksheet(table.name)
const merge = (table.config && table.config.merge) || {} const merge = (table.config && table.config.merge) || {}
const borderInfo = (table.config && table.config.borderInfo) || {} const borderInfo = (table.config && table.config.borderInfo) || {}
// 3.设置单元格合并,设置单元格边框,设置单元格样式,设置值 // 3.设置单元格合并,设置单元格边框,设置单元格样式,设置值
setStyleAndValue(table.data, worksheet) setStyleAndValue(table.data, worksheet)
setMerge(merge, worksheet) setMerge(merge, worksheet)
setBorder(borderInfo, worksheet) setBorder(borderInfo, worksheet)
return true return true
}) })
// return // return
// 4.写入 buffer // 4.写入 buffer
const buffer = workbook.xlsx.writeBuffer().then(data => { const buffer = workbook.xlsx.writeBuffer().then(data => {
// console.log('data', data) // console.log('data', data)
const blob = new Blob([data], { const blob = new Blob([data], {
type: 'application/vnd.ms-excel;charset=utf-8' type: 'application/vnd.ms-excel;charset=utf-8'
}) })
console.log("导出成功!") console.log('导出成功!')
FileSaver.saveAs(blob, `${value}.xlsx`) FileSaver.saveAs(blob, `${value}.xlsx`)
}) })
return buffer return buffer
} }
var setMerge = function(luckyMerge = {}, worksheet) { var setMerge = function (luckyMerge = {}, worksheet) {
const mergearr = Object.values(luckyMerge) const mergearr = Object.values(luckyMerge)
mergearr.forEach(function(elem) { mergearr.forEach(function (elem) {
// elem格式{r: 0, c: 0, rs: 1, cs: 2} // elem格式{r: 0, c: 0, rs: 1, cs: 2}
// 按开始行,开始列,结束行,结束列合并(相当于 K10:M12 // 按开始行,开始列,结束行,结束列合并(相当于 K10:M12
worksheet.mergeCells( worksheet.mergeCells(elem.r + 1, elem.c + 1, elem.r + elem.rs, elem.c + elem.cs)
elem.r + 1, })
elem.c + 1, }
elem.r + elem.rs,
elem.c + elem.cs var setBorder = function (luckyBorderInfo, worksheet) {
) if (!Array.isArray(luckyBorderInfo)) return
}) // console.log('luckyBorderInfo', luckyBorderInfo)
} luckyBorderInfo.forEach(function (elem) {
// 现在只兼容到borderType 为range的情况
var setBorder = function(luckyBorderInfo, worksheet) { // console.log('ele', elem)
if (!Array.isArray(luckyBorderInfo)) return if (elem.rangeType === 'range') {
// console.log('luckyBorderInfo', luckyBorderInfo) let border = borderConvert(elem.borderType, elem.style, elem.color)
luckyBorderInfo.forEach(function(elem) { let rang = elem.range[0]
// 现在只兼容到borderType 为range的情况 // console.log('range', rang)
// console.log('ele', elem) let row = rang.row
if (elem.rangeType === 'range') { let column = rang.column
let border = borderConvert(elem.borderType, elem.style, elem.color) for (let i = row[0] + 1; i < row[1] + 2; i++) {
let rang = elem.range[0] for (let y = column[0] + 1; y < column[1] + 2; y++) {
// console.log('range', rang) worksheet.getCell(i, y).border = border
let row = rang.row }
let column = rang.column }
for (let i = row[0] + 1; i < row[1] + 2; i++) { }
for (let y = column[0] + 1; y < column[1] + 2; y++) { if (elem.rangeType === 'cell') {
worksheet.getCell(i, y).border = border // col_index: 2
} // row_index: 1
} // b: {
} // color: '#d0d4e3'
if (elem.rangeType === 'cell') { // style: 1
// col_index: 2 // }
// row_index: 1 const { col_index, row_index } = elem.value
// b: { const borderData = Object.assign({}, elem.value)
// color: '#d0d4e3' delete borderData.col_index
// style: 1 delete borderData.row_index
// } let border = addborderToCell(borderData, row_index, col_index)
const { col_index, row_index } = elem.value // console.log('bordre', border, borderData)
const borderData = Object.assign({}, elem.value) worksheet.getCell(row_index + 1, col_index + 1).border = border
delete borderData.col_index }
delete borderData.row_index // console.log(rang.column_focus + 1, rang.row_focus + 1)
let border = addborderToCell(borderData, row_index, col_index) // worksheet.getCell(rang.row_focus + 1, rang.column_focus + 1).border = border
// console.log('bordre', border, borderData) })
worksheet.getCell(row_index + 1, col_index + 1).border = border }
} var setStyleAndValue = function (cellArr, worksheet) {
// console.log(rang.column_focus + 1, rang.row_focus + 1) if (!Array.isArray(cellArr)) return
// worksheet.getCell(rang.row_focus + 1, rang.column_focus + 1).border = border cellArr.forEach(function (row, rowid) {
}) row.every(function (cell, columnid) {
} if (!cell) return true
var setStyleAndValue = function(cellArr, worksheet) { let fill = fillConvert(cell.bg)
if (!Array.isArray(cellArr)) return
cellArr.forEach(function(row, rowid) { let font = fontConvert(cell.ff, cell.fc, cell.bl, cell.it, cell.fs, cell.cl, cell.ul)
row.every(function(cell, columnid) { let alignment = alignmentConvert(cell.vt, cell.ht, cell.tb, cell.tr)
if (!cell) return true let value = ''
let fill = fillConvert(cell.bg)
if (cell.f) {
let font = fontConvert( value = { formula: cell.f, result: cell.v }
cell.ff, } else if (!cell.v && cell.ct && cell.ct.s) {
cell.fc, // xls转为xlsx之后内部存在不同的格式都会进到富文本里即值不存在与cell.v而是存在于cell.ct.s之后
cell.bl, // value = cell.ct.s[0].v
cell.it, cell.ct.s.forEach(arr => {
cell.fs, value += arr.v
cell.cl, })
cell.ul } else {
) value = cell.v
let alignment = alignmentConvert(cell.vt, cell.ht, cell.tb, cell.tr) }
let value = '' // style 填入到_value中可以实现填充色
let letter = createCellPos(columnid)
if (cell.f) { let target = worksheet.getCell(letter + (rowid + 1))
value = { formula: cell.f, result: cell.v } // console.log('1233', letter + (rowid + 1))
} else if (!cell.v && cell.ct && cell.ct.s) { for (const key in fill) {
// xls转为xlsx之后内部存在不同的格式都会进到富文本里即值不存在与cell.v而是存在于cell.ct.s之后 target.fill = fill
// value = cell.ct.s[0].v break
cell.ct.s.forEach(arr => { }
value += arr.v target.font = font
}) target.alignment = alignment
} else { target.value = value
value = cell.v
} return true
// style 填入到_value中可以实现填充色 })
let letter = createCellPos(columnid) })
let target = worksheet.getCell(letter + (rowid + 1)) }
// console.log('1233', letter + (rowid + 1))
for (const key in fill) { var fillConvert = function (bg) {
target.fill = fill if (!bg) {
break return {}
} }
target.font = font // const bgc = bg.replace('#', '')
target.alignment = alignment let fill = {
target.value = value type: 'pattern',
pattern: 'solid',
return true fgColor: { argb: bg.replace('#', '') }
}) }
}) return fill
} }
var fillConvert = function(bg) { var fontConvert = function (ff = 0, fc = '#000000', bl = 0, it = 0, fs = 10, cl = 0, ul = 0) {
if (!bg) { // luckysheetff(样式), fc(颜色), bl(粗体), it(斜体), fs(大小), cl(删除线), ul(下划线)
return {} const luckyToExcel = {
} 0: '微软雅黑',
// const bgc = bg.replace('#', '') 1: '宋体Song',
let fill = { 2: '黑体ST Heiti',
type: 'pattern', 3: '楷体ST Kaiti',
pattern: 'solid', 4: '仿宋ST FangSong',
fgColor: { argb: bg.replace('#', '') } 5: '新宋体ST Song',
} 6: '华文新魏',
return fill 7: '华文行楷',
} 8: '华文隶书',
9: 'Arial',
var fontConvert = function( 10: 'Times New Roman ',
ff = 0, 11: 'Tahoma ',
fc = '#000000', 12: 'Verdana',
bl = 0, num2bl: function (num) {
it = 0, return num === 0 ? false : true
fs = 10, }
cl = 0, }
ul = 0 // 出现Bug导入的时候ff为luckyToExcel的val
) {
// luckysheetff(样式), fc(颜色), bl(粗体), it(斜体), fs(大小), cl(删除线), ul(下划线) let font = {
const luckyToExcel = { name: typeof ff === 'number' ? luckyToExcel[ff] : ff,
0: '微软雅黑', family: 1,
1: '宋体Song', size: fs,
2: '黑体ST Heiti', color: { argb: fc.replace('#', '') },
3: '楷体ST Kaiti', bold: luckyToExcel.num2bl(bl),
4: '仿宋ST FangSong', italic: luckyToExcel.num2bl(it),
5: '新宋体ST Song', underline: luckyToExcel.num2bl(ul),
6: '华文新魏', strike: luckyToExcel.num2bl(cl)
7: '华文行楷', }
8: '华文隶书',
9: 'Arial', return font
10: 'Times New Roman ', }
11: 'Tahoma ',
12: 'Verdana', var alignmentConvert = function (vt = 'default', ht = 'default', tb = 'default', tr = 'default') {
num2bl: function(num) { // luckysheet:vt(垂直), ht(水平), tb(换行), tr(旋转)
return num === 0 ? false : true const luckyToExcel = {
} vertical: {
} 0: 'middle',
// 出现Bug导入的时候ff为luckyToExcel的val 1: 'top',
2: 'bottom',
let font = { default: 'top'
name: typeof ff === 'number' ? luckyToExcel[ff] : ff, },
family: 1, horizontal: {
size: fs, 0: 'center',
color: { argb: fc.replace('#', '') }, 1: 'left',
bold: luckyToExcel.num2bl(bl), 2: 'right',
italic: luckyToExcel.num2bl(it), default: 'left'
underline: luckyToExcel.num2bl(ul), },
strike: luckyToExcel.num2bl(cl) wrapText: {
} 0: false,
1: false,
return font 2: true,
} default: false
},
var alignmentConvert = function( textRotation: {
vt = 'default', 0: 0,
ht = 'default', 1: 45,
tb = 'default', 2: -45,
tr = 'default' 3: 'vertical',
) { 4: 90,
// luckysheet:vt(垂直), ht(水平), tb(换行), tr(旋转) 5: -90,
const luckyToExcel = { default: 0
vertical: { }
0: 'middle', }
1: 'top',
2: 'bottom', let alignment = {
default: 'top' vertical: luckyToExcel.vertical[vt],
}, horizontal: luckyToExcel.horizontal[ht],
horizontal: { wrapText: luckyToExcel.wrapText[tb],
0: 'center', textRotation: luckyToExcel.textRotation[tr]
1: 'left', }
2: 'right', return alignment
default: 'left' }
},
wrapText: { var borderConvert = function (borderType, style = 1, color = '#000') {
0: false, // 对应luckysheet的config中borderinfo的的参数
1: false, if (!borderType) {
2: true, return {}
default: false }
}, const luckyToExcel = {
textRotation: { type: {
0: 0, 'border-all': 'all',
1: 45, 'border-top': 'top',
2: -45, 'border-right': 'right',
3: 'vertical', 'border-bottom': 'bottom',
4: 90, 'border-left': 'left'
5: -90, },
default: 0 style: {
} 0: 'none',
} 1: 'thin',
2: 'hair',
let alignment = { 3: 'dotted',
vertical: luckyToExcel.vertical[vt], 4: 'dashDot', // 'Dashed',
horizontal: luckyToExcel.horizontal[ht], 5: 'dashDot',
wrapText: luckyToExcel.wrapText[tb], 6: 'dashDotDot',
textRotation: luckyToExcel.textRotation[tr] 7: 'double',
} 8: 'medium',
return alignment 9: 'mediumDashed',
} 10: 'mediumDashDot',
11: 'mediumDashDotDot',
var borderConvert = function(borderType, style = 1, color = '#000') { 12: 'slantDashDot',
// 对应luckysheet的config中borderinfo的的参数 13: 'thick'
if (!borderType) { }
return {} }
} let template = {
const luckyToExcel = { style: luckyToExcel.style[style],
type: { color: { argb: color.replace('#', '') }
'border-all': 'all', }
'border-top': 'top', let border = {}
'border-right': 'right', if (luckyToExcel.type[borderType] === 'all') {
'border-bottom': 'bottom', border['top'] = template
'border-left': 'left' border['right'] = template
}, border['bottom'] = template
style: { border['left'] = template
0: 'none', } else {
1: 'thin', border[luckyToExcel.type[borderType]] = template
2: 'hair', }
3: 'dotted', // console.log('border', border)
4: 'dashDot', // 'Dashed', return border
5: 'dashDot', }
6: 'dashDotDot',
7: 'double', function addborderToCell(borders, row_index, col_index) {
8: 'medium', let border = {}
9: 'mediumDashed', const luckyExcel = {
10: 'mediumDashDot', type: {
11: 'mediumDashDotDot', l: 'left',
12: 'slantDashDot', r: 'right',
13: 'thick' b: 'bottom',
} t: 'top'
} },
let template = { style: {
style: luckyToExcel.style[style], 0: 'none',
color: { argb: color.replace('#', '') } 1: 'thin',
} 2: 'hair',
let border = {} 3: 'dotted',
if (luckyToExcel.type[borderType] === 'all') { 4: 'dashDot', // 'Dashed',
border['top'] = template 5: 'dashDot',
border['right'] = template 6: 'dashDotDot',
border['bottom'] = template 7: 'double',
border['left'] = template 8: 'medium',
} else { 9: 'mediumDashed',
border[luckyToExcel.type[borderType]] = template 10: 'mediumDashDot',
} 11: 'mediumDashDotDot',
// console.log('border', border) 12: 'slantDashDot',
return border 13: 'thick'
} }
}
function addborderToCell(borders, row_index, col_index) { // console.log('borders', borders)
let border = {} for (const bor in borders) {
const luckyExcel = { const borderItem = borders[bor]
type: { // 同时判断边框对象 和 color 属性都存在
l: 'left', if (!borderItem || !borderItem.color) {
r: 'right', continue
b: 'bottom', }
t: 'top'
}, if (borderItem.color.indexOf('rgb') === -1) {
style: { border[luckyExcel.type[bor]] = {
0: 'none', style: luckyExcel.style[borderItem.style],
1: 'thin', color: { argb: borderItem.color.replace('#', '') }
2: 'hair', }
3: 'dotted', } else {
4: 'dashDot', // 'Dashed', border[luckyExcel.type[bor]] = {
5: 'dashDot', style: luckyExcel.style[borderItem.style],
6: 'dashDotDot', color: { argb: borderItem.color }
7: 'double', }
8: 'medium', }
9: 'mediumDashed', }
10: 'mediumDashDot',
11: 'mediumDashDotDot', return border
12: 'slantDashDot', }
13: 'thick'
} function createCellPos(n) {
} let ordA = 'A'.charCodeAt(0)
// console.log('borders', borders)
for (const bor in borders) { let ordZ = 'Z'.charCodeAt(0)
// console.log(bor) let len = ordZ - ordA + 1
if (borders[bor].color.indexOf('rgb') === -1) { let s = ''
border[luckyExcel.type[bor]] = { while (n >= 0) {
style: luckyExcel.style[borders[bor].style], s = String.fromCharCode((n % len) + ordA) + s
color: { argb: borders[bor].color.replace('#', '') }
} n = Math.floor(n / len) - 1
} else { }
border[luckyExcel.type[bor]] = { return s
style: luckyExcel.style[borders[bor].style], }
color: { argb: borders[bor].color }
} export { exportExcel }
}
}
return border
}
function createCellPos(n) {
let ordA = 'A'.charCodeAt(0)
let ordZ = 'Z'.charCodeAt(0)
let len = ordZ - ordA + 1
let s = ''
while (n >= 0) {
s = String.fromCharCode((n % len) + ordA) + s
n = Math.floor(n / len) - 1
}
return s
}
export {
exportExcel
}

View File

@@ -1,14 +1,14 @@
<template> <template>
<div class="default-main"> <div class="default-main">
<div v-show="show && lookShow" style="display: flex"> <el-row v-show="show && lookShow">
<div style="width: 600px"> <el-col :span="10">
<div class="custom-table-header"> <div class="custom-table-header">
<div class="title">报表列表</div> <div class="title">报表列表</div>
<el-button :icon="Plus" type="primary" @click="addRole" class="ml10">新增报表</el-button> <el-button :icon="Plus" type="primary" @click="addRole" class="ml10">新增报表</el-button>
</div> </div>
<Table ref="tableRef" @currentChange="currentChange" /> <Table ref="tableRef" @currentChange="currentChange" />
</div> </el-col>
<div style="flex: 1"> <el-col :span="14">
<div class="custom-table-header"> <div class="custom-table-header">
<div class="title">模版绑定</div> <div class="title">模版绑定</div>
@@ -61,8 +61,9 @@
</vxe-column> </vxe-column>
</vxe-table> </vxe-table>
</div> </div>
</div> </el-col>
</div> </el-row>
<luckysheet ref="luckysheetRef" v-if="!show" @shutDown="shutDown" /> <luckysheet ref="luckysheetRef" v-if="!show" @shutDown="shutDown" />
<!-- 查看 --> <!-- 查看 -->
<look ref="lookRef" v-if="!lookShow" @shutDown="shutDown" /> <look ref="lookRef" v-if="!lookShow" @shutDown="shutDown" />

View File

@@ -8,7 +8,7 @@
<el-input v-model.trim="form.name" placeholder="请输入敏感用户名称"></el-input> <el-input 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="请选择敏感负荷类型">
<el-option <el-option
v-for="item in DataTypeSelect" v-for="item in DataTypeSelect"
:key="item.id" :key="item.id"

View File

@@ -1,6 +1,18 @@
<template> <template>
<div class="default-main"> <div class="default-main">
<TableHeader :showReset="false" showExport> <TableHeader :showReset="false" showExport>
<template #select>
<el-form-item label="关键字筛选">
<el-input
maxlength="32"
show-word-limit
style="width: 240px"
v-model.trim="tableStore.table.params.searchValue"
clearable
placeholder="请输入敏感负荷名称"
/>
</el-form-item>
</template>
<template #operation> <template #operation>
<el-button :icon="Plus" type="primary" @click="addMenu" class="ml10">新增</el-button> <el-button :icon="Plus" type="primary" @click="addMenu" class="ml10">新增</el-button>
</template> </template>

View File

@@ -1,469 +1,469 @@
<template> <template>
<div class="flex" style="margin: 15px 0"> <div class="flex" style="margin: 15px 0">
<span style="width: 100px; margin-top: 3px">电压等级:</span> <span style="width: 100px; margin-top: 3px">电压等级:</span>
<el-checkbox :indeterminate="isIndeterminate" v-model.trim="checkAll" @change="handleCheckAllChange" <el-checkbox :indeterminate="isIndeterminate" v-model.trim="checkAll" @change="handleCheckAllChange"
style="margin-right: 28px"> style="margin-right: 28px">
全选 全选
</el-checkbox> </el-checkbox>
<el-checkbox-group v-model.trim="checkedVoltage" @change="handleCheckedVoltageChange" <el-checkbox-group v-model.trim="checkedVoltage" @change="handleCheckedVoltageChange"
style="height: 72px; overflow-y: auto"> style="height: 72px; overflow-y: auto">
<el-checkbox v-for="(item, index) in grade" :label="item" :key="index">{{ item.name }}</el-checkbox> <el-checkbox v-for="(item, index) in grade" :label="item" :key="index">{{ item.name }}</el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
<div class="flex" style="margin: 15px 0"> <div class="flex" style="margin: 15px 0">
<span style="width: 100px; margin-top: 3px">干扰源类型:</span> <span style="width: 100px; margin-top: 3px">干扰源类型:</span>
<el-checkbox :indeterminate="isIndeterminate1" v-model.trim="checkAll1" @change="handleCheckAllChange1" <el-checkbox :indeterminate="isIndeterminate1" v-model.trim="checkAll1" @change="handleCheckAllChange1"
style="margin-right: 28px"> style="margin-right: 28px">
全选 全选
</el-checkbox> </el-checkbox>
<el-checkbox-group v-model.trim="checkedSource" @change="handleCheckedSourceChange" <el-checkbox-group v-model.trim="checkedSource" @change="handleCheckedSourceChange"
style="height: 72px; overflow-y: auto"> style="height: 72px; overflow-y: auto">
<el-checkbox v-for="(item, index) in type" :label="item" :key="index">{{ item.name }}</el-checkbox> <el-checkbox v-for="(item, index) in type" :label="item" :key="index">{{ item.name }}</el-checkbox>
</el-checkbox-group> </el-checkbox-group>
</div> </div>
<div class="flex" style="margin: 15px 0"> <div class="flex" style="margin: 15px 0">
<span style="width: 100px; line-height: 32px">兼容曲线:</span> <span style="width: 100px; line-height: 32px">兼容曲线:</span>
<el-radio-group v-model.trim="radio" @change="radioChange"> <el-radio-group v-model.trim="radio" @change="radioChange">
<el-radio label="ITIC">ITIC</el-radio> <el-radio label="ITIC">ITIC</el-radio>
<el-radio label="F47">F47</el-radio> <el-radio label="F47">F47</el-radio>
</el-radio-group> </el-radio-group>
</div> </div>
<my-echart class="bars_w" :options="echartList" /> <my-echart class="bars_w" :options="echartList" />
<vxe-table class="dw" :data="TableData" height="50px" v-bind="defaultAttribute"> <vxe-table class="dw" :data="TableData" height="50px" v-bind="defaultAttribute">
<vxe-column field="name" title="名称" width="100px"></vxe-column> <vxe-column field="name" title="名称" width="100px"></vxe-column>
<vxe-column field="totalEvents" title="事件总数" width="100px"></vxe-column> <vxe-column field="totalEvents" title="事件总数" width="100px"></vxe-column>
<vxe-column field="tolerable" title="可容忍" width="100px"></vxe-column> <vxe-column field="tolerable" title="可容忍" width="100px"></vxe-column>
<vxe-column field="Intolerable" title="不可容忍" width="100px"></vxe-column> <vxe-column field="Intolerable" title="不可容忍" width="100px"></vxe-column>
</vxe-table> </vxe-table>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { useDictData } from '@/stores/dictData' import { useDictData } from '@/stores/dictData'
import MyEchart from '@/components/echarts/MyEchart.vue' import MyEchart from '@/components/echarts/MyEchart.vue'
import { mainHeight } from '@/utils/layout' import { mainHeight } from '@/utils/layout'
import { defaultAttribute } from '@/components/table/defaultAttribute' import { defaultAttribute } from '@/components/table/defaultAttribute'
import { ref, reactive } from 'vue' import { ref, reactive } from 'vue'
const dictData = useDictData() const dictData = useDictData()
const isIndeterminate = ref(false) const isIndeterminate = ref(false)
const isIndeterminate1 = ref(false) const isIndeterminate1 = ref(false)
const checkAll = ref(true) const checkAll = ref(true)
const checkAll1 = ref(true) const checkAll1 = ref(true)
const radio = ref('ITIC') const radio = ref('ITIC')
const echartList = ref({}) const echartList = ref({})
const ITIC = ref({}) const ITIC = ref({})
const F47 = ref({}) const F47 = ref({})
const pointI: any = ref([]) const pointI: any = ref([])
const pointIun: any = ref([]) const pointIun: any = ref([])
const pointF: any = ref([]) const pointF: any = ref([])
const pointFun: any = ref([]) const pointFun: any = ref([])
const datalist: any = ref([]) const datalist: any = ref([])
const TableData = ref([ const TableData = ref([
{ {
name: '事件个数', name: '事件个数',
totalEvents: '', totalEvents: '',
tolerable: '', tolerable: '',
Intolerable: '' Intolerable: ''
} }
]) ])
const checkedVoltage: any = ref(ref(dictData.getBasicData('Dev_Voltage_Stand'))) const checkedVoltage: any = ref(ref(dictData.getBasicData('Dev_Voltage_Stand')))
const checkedSource: any = ref(dictData.getBasicData('Interference_Source')) const checkedSource: any = ref(dictData.getBasicData('Interference_Source'))
const grade = ref(dictData.getBasicData('Dev_Voltage_Stand')) const grade = ref(dictData.getBasicData('Dev_Voltage_Stand'))
const type = ref(dictData.getBasicData('Interference_Source')) const type = ref(dictData.getBasicData('Interference_Source'))
// 电压等级多选 // 电压等级多选
const handleCheckedVoltageChange = (val: any) => { const handleCheckedVoltageChange = (val: any) => {
const checkedCount = val.length const checkedCount = val.length
checkAll.value = checkedCount === grade.value.length checkAll.value = checkedCount === grade.value.length
isIndeterminate.value = checkedCount > 0 && checkedCount < grade.value.length isIndeterminate.value = checkedCount > 0 && checkedCount < grade.value.length
} }
const handleCheckAllChange = (val: any) => { const handleCheckAllChange = (val: any) => {
checkedVoltage.value = val ? grade.value : [] checkedVoltage.value = val ? grade.value : []
isIndeterminate.value = false isIndeterminate.value = false
} }
// 干扰源类型多选 // 干扰源类型多选
const handleCheckAllChange1 = (val: any) => { const handleCheckAllChange1 = (val: any) => {
checkedSource.value = val ? type.value : [] checkedSource.value = val ? type.value : []
isIndeterminate.value = false isIndeterminate.value = false
} }
const handleCheckedSourceChange = (val: any) => { const handleCheckedSourceChange = (val: any) => {
const checkedCount = val.length const checkedCount = val.length
checkAll1.value = checkedCount === type.value.length checkAll1.value = checkedCount === type.value.length
isIndeterminate1.value = checkedCount > 0 && checkedCount < type.value.length isIndeterminate1.value = checkedCount > 0 && checkedCount < type.value.length
} }
const info = async (list: any) => { const info = async (list: any) => {
datalist.value = [] datalist.value = []
list.forEach((item: any) => { list.forEach((item: any) => {
if (item.eventValue < 2 && item.eventValue > 0) { if (item.eventValue < 2 && item.eventValue > 0) {
datalist.value.push(item) datalist.value.push(item)
} }
}) })
await gongfunction() await gongfunction()
ITIC.value = { ITIC.value = {
title: { title: {
text: 'ITIC曲线' text: 'ITIC曲线'
}, },
tooltip: { tooltip: {
formatter: function (a: any) { formatter: function (a: any) {
if (a[0].value[4] == undefined) { if (a[0].value[4] == undefined) {
return return
} }
let relVal = '' var relVal = `<strong>${a.seriesName}</strong><br/>`
relVal = "<font style='color:" + "'>供电公司:" + '&nbsp' + '&nbsp' + a[0].value[3] + '</font><br/>' relVal += "<font style='color:" + "'>供电公司:" + '&nbsp' + '&nbsp' + a[0].value[3] + '</font><br/>'
relVal += "<font style='color:" + "'>变电站:" + '&nbsp' + '&nbsp' + a[0].value[4] + '</font><br/>' relVal += "<font style='color:" + "'>变电站:" + '&nbsp' + '&nbsp' + a[0].value[4] + '</font><br/>'
relVal += "<font style='color:" + "'>发生时刻:" + '&nbsp' + '&nbsp' + a[0].value[2] + '</font><br/>' relVal += "<font style='color:" + "'>发生时刻:" + '&nbsp' + '&nbsp' + a[0].value[2] + '</font><br/>'
relVal += relVal +=
"<font style='color:" + "<font style='color:" +
"'>持续时间:" + "'>持续时间:" +
'&nbsp' + '&nbsp' +
'&nbsp' + '&nbsp' +
a[0].value[0].toFixed(3) + a[0].value[0].toFixed(3) +
's</font><br/>' 's</font><br/>'
relVal += relVal +=
"<font style='color:" + "'>特征幅值:" + '&nbsp' + '&nbsp' + a[0].value[1].toFixed(3) + '%</font>' "<font style='color:" + "'>特征幅值:" + '&nbsp' + '&nbsp' + a[0].value[1].toFixed(3) + '%</font>'
return relVal return relVal
} }
}, },
legend: { legend: {
data: ['上限', '下限', '可容忍事件', '不可容忍事件'], data: ['上限', '下限', '可容忍事件', '不可容忍事件'],
// selectedMode: false, // selectedMode: false,
left: '10px' left: '10px'
}, },
color: ['#FF8C00', '#00BFFF', 'green', 'red'], color: ['#FF8C00', '#00BFFF', 'green', 'red'],
xAxis: { xAxis: {
type: 'log', type: 'log',
min: '0.001', min: '0.001',
max: '1000', max: '1000',
name: 's', name: 's',
splitLine: { show: false } splitLine: { show: false }
}, },
yAxis: { yAxis: {
type: 'value', type: 'value',
splitNumber: 10, splitNumber: 10,
minInterval: 3, minInterval: 3,
name: '%' name: '%'
}, },
dataZoom: { dataZoom: {
type: null, type: null,
show: false show: false
}, },
options: { options: {
series: [ series: [
{ {
name: '上限', name: '上限',
type: 'line', type: 'line',
data: [ data: [
[0.001, 200], [0.001, 200],
[0.003, 140], [0.003, 140],
[0.003, 120], [0.003, 120],
[0.5, 120], [0.5, 120],
[0.5, 110], [0.5, 110],
[10, 110], [10, 110],
[1000, 110] [1000, 110]
], ],
showSymbol: false, showSymbol: false,
tooltips: { tooltips: {
show: false show: false
} }
}, },
{ {
name: '下限', name: '下限',
type: 'line', type: 'line',
data: [ data: [
[0.02, 0], [0.02, 0],
[0.02, 70], [0.02, 70],
[0.5, 70], [0.5, 70],
[0.5, 80], [0.5, 80],
[10, 80], [10, 80],
[10, 90], [10, 90],
[1000, 90] [1000, 90]
], ],
showSymbol: false, showSymbol: false,
tooltips: { tooltips: {
show: false show: false
} }
}, },
{ {
name: '可容忍事件', name: '可容忍事件',
type: 'scatter', type: 'scatter',
symbol: 'circle', symbol: 'circle',
data: pointI.value data: pointI.value
}, },
{ {
name: '不可容忍事件', name: '不可容忍事件',
type: 'scatter', type: 'scatter',
symbol: 'circle', symbol: 'circle',
data: pointIun.value data: pointIun.value
} }
] ]
} }
} }
F47.value = { F47.value = {
title: { title: {
text: 'F47曲线' text: 'F47曲线'
}, },
tooltip: { tooltip: {
formatter: function (a: any) { formatter: function (a: any) {
if (a[0].value[4] == undefined) { if (a[0].value[4] == undefined) {
return return
} }
let relVal = '' let relVal = ''
relVal = "<font style='color:" + "'>供电公司:" + '&nbsp' + '&nbsp' + a[0].value[3] + '</font><br/>' relVal = "<font style='color:" + "'>供电公司:" + '&nbsp' + '&nbsp' + a[0].value[3] + '</font><br/>'
relVal += "<font style='color:" + "'>变电站:" + '&nbsp' + '&nbsp' + a[0].value[4] + '</font><br/>' relVal += "<font style='color:" + "'>变电站:" + '&nbsp' + '&nbsp' + a[0].value[4] + '</font><br/>'
relVal += "<font style='color:" + "'>发生时刻:" + '&nbsp' + '&nbsp' + a[0].value[2] + '</font><br/>' relVal += "<font style='color:" + "'>发生时刻:" + '&nbsp' + '&nbsp' + a[0].value[2] + '</font><br/>'
relVal += relVal +=
"<font style='color:" + "<font style='color:" +
"'>持续时间:" + "'>持续时间:" +
'&nbsp' + '&nbsp' +
'&nbsp' + '&nbsp' +
a[0].value[0].toFixed(3) + a[0].value[0].toFixed(3) +
's</font><br/>' 's</font><br/>'
relVal += relVal +=
"<font style='color:" + "'>特征幅值:" + '&nbsp' + '&nbsp' + a[0].value[1].toFixed(3) + '%</font>' "<font style='color:" + "'>特征幅值:" + '&nbsp' + '&nbsp' + a[0].value[1].toFixed(3) + '%</font>'
return relVal return relVal
} }
}, },
legend: { legend: {
data: ['分割线', '可容忍事件', '不可容忍事件'], data: ['分割线', '可容忍事件', '不可容忍事件'],
// selectedMode: false, // selectedMode: false,
left: '10px' left: '10px'
}, },
color: ['yellow', 'green', 'red'], color: ['yellow', 'green', 'red'],
xAxis: { xAxis: {
type: 'log', type: 'log',
min: '0.001', min: '0.001',
max: '1000', max: '1000',
name: 's', name: 's',
splitLine: { show: false } splitLine: { show: false }
}, },
yAxis: { yAxis: {
type: 'value', type: 'value',
splitNumber: 10, splitNumber: 10,
minInterval: 3, minInterval: 3,
name: '%' name: '%'
}, },
dataZoom: { dataZoom: {
type: null, type: null,
show: false show: false
}, },
options: { options: {
series: [ series: [
{ {
name: '分割线', name: '分割线',
type: 'line', type: 'line',
data: [ data: [
[0.05, 0], [0.05, 0],
[0.05, 50], [0.05, 50],
[0.2, 50], [0.2, 50],
[0.2, 70], [0.2, 70],
[0.5, 70], [0.5, 70],
[0.5, 80], [0.5, 80],
[10, 80], [10, 80],
[1000, 80] [1000, 80]
], ],
showSymbol: false, showSymbol: false,
tooltips: { tooltips: {
show: false show: false
} }
}, },
{ {
name: '可容忍事件', name: '可容忍事件',
type: 'scatter', type: 'scatter',
symbol: 'circle', symbol: 'circle',
data: pointF.value data: pointF.value
}, },
{ {
name: '不可容忍事件', name: '不可容忍事件',
type: 'scatter', type: 'scatter',
symbol: 'circle', symbol: 'circle',
data: pointFun.value data: pointFun.value
} }
] ]
} }
} }
radioChange(radio.value) radioChange(radio.value)
} }
const radioChange = (e: any) => { const radioChange = (e: any) => {
if (e == 'ITIC') { if (e == 'ITIC') {
echartList.value = ITIC.value echartList.value = ITIC.value
TableData.value[0].totalEvents = pointI.value.length + pointIun.value.length TableData.value[0].totalEvents = pointI.value.length + pointIun.value.length
TableData.value[0].tolerable = pointI.value.length TableData.value[0].tolerable = pointI.value.length
TableData.value[0].Intolerable = pointIun.value.length TableData.value[0].Intolerable = pointIun.value.length
} else if (e == 'F47') { } else if (e == 'F47') {
echartList.value = F47.value echartList.value = F47.value
TableData.value[0].totalEvents = pointF.value.length + pointFun.value.length TableData.value[0].totalEvents = pointF.value.length + pointFun.value.length
TableData.value[0].tolerable = pointF.value.length TableData.value[0].tolerable = pointF.value.length
TableData.value[0].Intolerable = pointFun.value.length TableData.value[0].Intolerable = pointFun.value.length
} }
} }
const gongfunction = () => { const gongfunction = () => {
var standI = 0 var standI = 0
var unstandI = 0 var unstandI = 0
var standF = 0 var standF = 0
var unstandF = 0 var unstandF = 0
pointI.value = [] pointI.value = []
pointIun.value = [] pointIun.value = []
pointF.value = [] pointF.value = []
pointFun.value = [] pointFun.value = []
var total = 0 var total = 0
total = datalist.value.length total = datalist.value.length
if (total == 0) { if (total == 0) {
} else { } else {
for (var i = 0; i < datalist.value.length; i++) { for (var i = 0; i < datalist.value.length; i++) {
var point = [] var point = []
var xx = datalist.value[i].persistTime var xx = datalist.value[i].persistTime
var yy = datalist.value[i].eventValue * 100 var yy = datalist.value[i].eventValue * 100
var time = datalist.value[i].time.replace('T', ' ') var time = datalist.value[i].time.replace('T', ' ')
var company = datalist.value[i].gdName var company = datalist.value[i].gdName
var substation = datalist.value[i].subName var substation = datalist.value[i].subName
var index = datalist.value[i].lineId var index = datalist.value[i].lineId
var eventId = datalist.value[i].eventId var eventId = datalist.value[i].eventId
point = [xx, yy, time, company, substation, index, eventId] point = [xx, yy, time, company, substation, index, eventId]
if (xx <= 0.003) { if (xx <= 0.003) {
var line = 0 var line = 0
line = 230 - 30000 * xx line = 230 - 30000 * xx
if (yy > line) { if (yy > line) {
unstandI++ unstandI++
pointIun.value.push({ pointIun.value.push({
value: point, value: point,
itemStyle: { normal: { color: 'red' } } itemStyle: { normal: { color: 'red' } }
}) })
} else { } else {
standI++ standI++
pointI.value.push({ pointI.value.push({
value: point, value: point,
itemStyle: { normal: { color: 'green' } } itemStyle: { normal: { color: 'green' } }
}) })
} }
} else if (xx <= 0.02) { } else if (xx <= 0.02) {
if (yy > 120) { if (yy > 120) {
unstandI++ unstandI++
pointIun.value.push({ pointIun.value.push({
value: point, value: point,
itemStyle: { normal: { color: 'red' } } itemStyle: { normal: { color: 'red' } }
}) })
} else { } else {
standI++ standI++
pointI.value.push({ pointI.value.push({
value: point, value: point,
itemStyle: { normal: { color: 'green' } } itemStyle: { normal: { color: 'green' } }
}) })
} }
} else if (xx <= 0.5) { } else if (xx <= 0.5) {
if (yy > 120 || yy < 70) { if (yy > 120 || yy < 70) {
unstandI++ unstandI++
pointIun.value.push({ pointIun.value.push({
value: point, value: point,
itemStyle: { normal: { color: 'red' } } itemStyle: { normal: { color: 'red' } }
}) })
} else { } else {
standI++ standI++
pointI.value.push({ pointI.value.push({
value: point, value: point,
itemStyle: { normal: { color: 'green' } } itemStyle: { normal: { color: 'green' } }
}) })
} }
} else if (xx <= 10) { } else if (xx <= 10) {
if (yy > 110 || yy < 80) { if (yy > 110 || yy < 80) {
unstandI++ unstandI++
pointIun.value.push({ pointIun.value.push({
value: point, value: point,
itemStyle: { normal: { color: 'red' } } itemStyle: { normal: { color: 'red' } }
}) })
} else { } else {
standI++ standI++
pointI.value.push({ pointI.value.push({
value: point, value: point,
itemStyle: { normal: { color: 'green' } } itemStyle: { normal: { color: 'green' } }
}) })
} }
} else { } else {
if (yy > 110 || yy < 90) { if (yy > 110 || yy < 90) {
unstandI++ unstandI++
pointIun.value.push({ pointIun.value.push({
value: point, value: point,
itemStyle: { normal: { color: 'red' } } itemStyle: { normal: { color: 'red' } }
}) })
} else { } else {
standI++ standI++
pointI.value.push({ pointI.value.push({
value: point, value: point,
itemStyle: { normal: { color: 'green' } } itemStyle: { normal: { color: 'green' } }
}) })
} }
} }
if (xx < 0.05) { if (xx < 0.05) {
standF++ standF++
pointF.value.push({ pointF.value.push({
value: point, value: point,
itemStyle: { normal: { color: 'green' } } itemStyle: { normal: { color: 'green' } }
}) })
} else if (xx < 0.2) { } else if (xx < 0.2) {
if (yy > 50) { if (yy > 50) {
standF++ standF++
pointF.value.push({ pointF.value.push({
value: point, value: point,
itemStyle: { normal: { color: 'green' } } itemStyle: { normal: { color: 'green' } }
}) })
} else { } else {
unstandF++ unstandF++
pointFun.value.push({ pointFun.value.push({
value: point, value: point,
itemStyle: { normal: { color: 'red' } } itemStyle: { normal: { color: 'red' } }
}) })
} }
} else if (xx < 0.5) { } else if (xx < 0.5) {
if (yy > 70) { if (yy > 70) {
standF++ standF++
pointF.value.push({ pointF.value.push({
value: point, value: point,
itemStyle: { normal: { color: 'green' } } itemStyle: { normal: { color: 'green' } }
}) })
} else { } else {
unstandF++ unstandF++
pointFun.value.push({ pointFun.value.push({
value: point, value: point,
itemStyle: { normal: { color: 'red' } } itemStyle: { normal: { color: 'red' } }
}) })
} }
} else { } else {
if (yy > 80) { if (yy > 80) {
standF++ standF++
pointF.value.push({ pointF.value.push({
value: point, value: point,
itemStyle: { normal: { color: 'green' } } itemStyle: { normal: { color: 'green' } }
}) })
} else { } else {
unstandF++ unstandF++
pointFun.value.push({ pointFun.value.push({
value: point, value: point,
itemStyle: { normal: { color: 'red' } } itemStyle: { normal: { color: 'red' } }
}) })
} }
} }
} }
} }
} }
defineExpose({ checkedVoltage, checkedSource, info }) defineExpose({ checkedVoltage, checkedSource, info })
const layout = mainHeight(390) as any const layout = mainHeight(390) as any
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.flex { .flex {
display: flex; display: flex;
} }
.bars_w { .bars_w {
height: calc(v-bind('layout.height')); height: calc(v-bind('layout.height'));
} }
.dw { .dw {
position: absolute; position: absolute;
top: 210px; top: 210px;
right: 70px; right: 70px;
} }
</style> </style>

File diff suppressed because one or more lines are too long