Compare commits
163 Commits
ed0800359d
...
2025-12
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a765cdf9ee | ||
|
|
cc0f8bc8b6 | ||
|
|
7e4db9d4cd | ||
|
|
67e2fa57d0 | ||
|
|
ad1fc11e61 | ||
|
|
6824864db2 | ||
|
|
37ed693cea | ||
|
|
0419af8e50 | ||
|
|
5268b93dd0 | ||
|
|
4e6bd55089 | ||
|
|
4e0db29ab1 | ||
|
|
9b0fd76f48 | ||
|
|
f92b07c555 | ||
|
|
a77db278ac | ||
|
|
51a0ae49a9 | ||
|
|
814e9917d6 | ||
|
|
21f1c41196 | ||
|
|
c188446e76 | ||
|
|
e2a5d084a5 | ||
|
|
4ae27a9d6d | ||
|
|
7783569f91 | ||
|
|
f1ac67070f | ||
|
|
77a9a2adfc | ||
|
|
accc1f30f6 | ||
|
|
94649b3348 | ||
|
|
e3de350dc5 | ||
|
|
4963dd495a | ||
|
|
40fa6eba20 | ||
|
|
f32934e0e6 | ||
|
|
460962cead | ||
|
|
fa75fc2923 | ||
|
|
f953b560c7 | ||
|
|
8f3426eb1f | ||
|
|
c2a2a4afd6 | ||
|
|
d2357d4ad2 | ||
|
|
1b23355134 | ||
|
|
ce9caa8729 | ||
|
|
2d0349c1b6 | ||
|
|
8355fc6aed | ||
|
|
23bc2d8f05 | ||
|
|
43caddffa3 | ||
|
|
3accaf3079 | ||
|
|
5687367602 | ||
|
|
b8ee530557 | ||
|
|
0518127792 | ||
|
|
5db43cd4b1 | ||
|
|
bf0657cbbc | ||
|
|
bcb1535d4d | ||
|
|
aa07112605 | ||
|
|
c09bea9e04 | ||
|
|
22cd6088a3 | ||
|
|
faf7ba98a6 | ||
|
|
b90f70c72d | ||
|
|
d38b426527 | ||
|
|
79a246cd87 | ||
|
|
58ee36c6a5 | ||
|
|
515dcfe76c | ||
|
|
031fab286b | ||
|
|
58bc269940 | ||
|
|
80182cdc6f | ||
|
|
8ce2968bee | ||
|
|
1a146afcd7 | ||
|
|
800ec7f0cf | ||
|
|
e824f4823a | ||
|
|
2476d2401e | ||
|
|
f043b6dc1a | ||
|
|
09bf34700a | ||
|
|
f32673c92a | ||
|
|
2c7b5a8583 | ||
|
|
3745d91a9d | ||
|
|
9117a6e3c6 | ||
|
|
e759f443d3 | ||
|
|
af3f9fe607 | ||
|
|
d97e97f51c | ||
|
|
5e1a628d53 | ||
|
|
acc5e93731 | ||
|
|
93586255fc | ||
|
|
cf51ba9ff0 | ||
|
|
67d9aaf958 | ||
|
|
f1439e0464 | ||
|
|
29c88b56dc | ||
|
|
0c71b2ac32 | ||
|
|
f916721b6a | ||
|
|
f2d02ff7f5 | ||
|
|
2de28c0067 | ||
|
|
09326b287e | ||
|
|
d365932648 | ||
|
|
925c9c6f15 | ||
|
|
b0df1157ad | ||
|
|
d450383cfd | ||
|
|
e603ba9f8c | ||
|
|
704f735744 | ||
|
|
0249ccac48 | ||
|
|
e49e34df6d | ||
|
|
042798c6a7 | ||
|
|
3827490cd1 | ||
|
|
da7cb2cb90 | ||
|
|
36e182a99a | ||
|
|
05e0287407 | ||
|
|
7a68a4114b | ||
|
|
ddc8f81196 | ||
|
|
5bed340320 | ||
|
|
2048da5e52 | ||
|
|
4184d35854 | ||
|
|
59b56d4a19 | ||
|
|
0a6bd2e453 | ||
|
|
60e9685b7e | ||
|
|
d8433d8d9c | ||
|
|
0f090666e9 | ||
|
|
1d849bcff9 | ||
|
|
e9b09e2193 | ||
|
|
f66dd649c7 | ||
|
|
af05b9c810 | ||
|
|
0af955d05c | ||
|
|
49dcf440ff | ||
|
|
d6bfd8b958 | ||
|
|
ea6aed9b99 | ||
|
|
cd565c03ca | ||
|
|
f82ef923ae | ||
|
|
4c2ed4aade | ||
|
|
8cd3e14922 | ||
|
|
5580d0618e | ||
|
|
c1ebcfed6f | ||
|
|
6303bd1e2c | ||
|
|
d9efb37083 | ||
|
|
e271a3be06 | ||
|
|
078488a842 | ||
|
|
384ea90acd | ||
|
|
25971e5239 | ||
|
|
c3d7e91f4e | ||
|
|
72c37c2759 | ||
|
|
d1eb7f2dad | ||
|
|
308ceb1a03 | ||
|
|
ad7b77ff92 | ||
|
|
0e76ab66f3 | ||
|
|
24afa84f29 | ||
|
|
a5f3571906 | ||
|
|
d16d262d1a | ||
|
|
593f2e2c66 | ||
|
|
d1e7aab876 | ||
|
|
8a3e0263d2 | ||
|
|
35ce7314b0 | ||
|
|
5538d18127 | ||
|
|
00dd79e000 | ||
|
|
b5aff1a837 | ||
|
|
1ec3bd11a0 | ||
|
|
d553754847 | ||
|
|
dc44e16d4d | ||
|
|
13c0a28c95 | ||
|
|
443d5ab2bd | ||
|
|
288f4254b0 | ||
|
|
130db82e41 | ||
|
|
55a30a323d | ||
|
|
608be23687 | ||
|
|
8f8f2aad6e | ||
|
|
a9dcb54286 | ||
|
|
dede918f34 | ||
|
|
d113df832d | ||
|
|
f41af33413 | ||
|
|
f2e328826d | ||
|
|
b3154e894a | ||
|
|
f3252f8a15 | ||
|
|
7f5296daee |
10908
package-lock.json
generated
10908
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
18
package.json
18
package.json
@@ -6,8 +6,10 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"dev:zl": "vite --mode zl",
|
"dev:zl": "vite --mode zl",
|
||||||
|
"dev:ypt": "vite --mode ypt",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"build:zl": "vite build --mode zl",
|
"build:zl": "vite build --mode zl",
|
||||||
|
"build:ypt": "vite build --mode ypt",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -26,8 +28,10 @@
|
|||||||
"element-plus": "^2.7.5",
|
"element-plus": "^2.7.5",
|
||||||
"exceljs": "v4.4.0",
|
"exceljs": "v4.4.0",
|
||||||
"file-saver": "v2.0.5",
|
"file-saver": "v2.0.5",
|
||||||
|
"grid-layout-plus": "^1.1.0",
|
||||||
"html2canvas": "^1.4.1",
|
"html2canvas": "^1.4.1",
|
||||||
"jquery": "^3.7.1",
|
"jquery": "^3.7.1",
|
||||||
|
"jsencrypt": "^3.3.2",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"lodash-es": "^4.17.21",
|
"lodash-es": "^4.17.21",
|
||||||
@@ -38,20 +42,18 @@
|
|||||||
"nprogress": "^0.2.0",
|
"nprogress": "^0.2.0",
|
||||||
"pinia": "^2.1.7",
|
"pinia": "^2.1.7",
|
||||||
"pinia-plugin-persistedstate": "^3.2.1",
|
"pinia-plugin-persistedstate": "^3.2.1",
|
||||||
|
"qs": "^6.12.0",
|
||||||
"screenfull": "^6.0.2",
|
"screenfull": "^6.0.2",
|
||||||
"splitpanes": "3.1.5",
|
"splitpanes": "^3.1.5",
|
||||||
"use-element-plus-theme": "^0.0.5",
|
"use-element-plus-theme": "^0.0.5",
|
||||||
"vue": "^3.3.11",
|
"vue": "^3.3.11",
|
||||||
"vue-draggable-resizable": "3.0.0-beta.2",
|
"vue-draggable-resizable": "^3.0.0-beta.2",
|
||||||
|
"vue-i18n": "9.10.2",
|
||||||
"vue-router": "4",
|
"vue-router": "4",
|
||||||
|
"vue-types": "^5.1.1",
|
||||||
"vxe-table": "^4.5.17",
|
"vxe-table": "^4.5.17",
|
||||||
"vxe-table-plugin-export-xlsx": "^4.0.7",
|
"vxe-table-plugin-export-xlsx": "^4.0.7",
|
||||||
"grid-layout-plus": "^1.1.0",
|
|
||||||
"vue-i18n": "9.10.2",
|
|
||||||
"qs": "^6.12.0",
|
|
||||||
"vue-types": "^5.1.1",
|
|
||||||
"web-storage-cache": "^1.1.1",
|
"web-storage-cache": "^1.1.1",
|
||||||
"jsencrypt": "^3.3.2",
|
|
||||||
"xe-utils": "^3.5.14"
|
"xe-utils": "^3.5.14"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -61,9 +63,9 @@
|
|||||||
"@types/splitpanes": "2.2.6",
|
"@types/splitpanes": "2.2.6",
|
||||||
"@vitejs/plugin-vue": "^4.5.2",
|
"@vitejs/plugin-vue": "^4.5.2",
|
||||||
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||||
"unplugin-auto-import": "^0.16.7",
|
|
||||||
"sass": "^1.69.5",
|
"sass": "^1.69.5",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.2.2",
|
||||||
|
"unplugin-auto-import": "^0.16.7",
|
||||||
"vite": "^5.0.8",
|
"vite": "^5.0.8",
|
||||||
"vue-tsc": "^1.8.25"
|
"vue-tsc": "^1.8.25"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,13 @@ export function getLineTree() {
|
|||||||
method: 'POST'
|
method: 'POST'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 监测点列表治理
|
||||||
|
export function objTree() {
|
||||||
|
return createAxios({
|
||||||
|
url: '/cs-device-boot/csLedger/objTree',
|
||||||
|
method: 'POST'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//云设备录入树
|
//云设备录入树
|
||||||
|
|||||||
@@ -47,11 +47,13 @@ export function restartProcess(data: any) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//更新进程号
|
//更新进程号
|
||||||
export function updateProcess(data: any) {
|
export function updateProcess(data:any) {
|
||||||
return createAxios({
|
return createAxios({
|
||||||
url: '/cs-device-boot/node/updateDevProcessNo',
|
url: '/cs-device-boot/node/updateDevNode',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
params: data
|
data: data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
28
src/api/cs-device-boot/sensitiveLoadMange.ts
Normal file
28
src/api/cs-device-boot/sensitiveLoadMange.ts
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 新增敏感用户
|
||||||
|
export function saveUser(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/pqSensitiveUser/save',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 修改敏感用户
|
||||||
|
export function updateUser(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/pqSensitiveUser/update',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除敏感用户
|
||||||
|
export function deleteUser(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/pqSensitiveUser/delete',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -53,3 +53,25 @@ export const removeMarketData = (data: any) => {
|
|||||||
params: data
|
params: data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户未绑定的在运的便携式设备
|
||||||
|
*/
|
||||||
|
export const queryRunPortableDevByUseId = (data: any) => {
|
||||||
|
return createAxios({
|
||||||
|
url: '/cs-device-boot/EquipmentDelivery/getRunPortableDev',
|
||||||
|
method: 'post',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取用户未绑定的工程信息
|
||||||
|
*/
|
||||||
|
export const queryUnlinkEngineeringByUseId = (data: any) => {
|
||||||
|
return createAxios({
|
||||||
|
url: '/cs-device-boot/engineering/getUnlinkedEngineering',
|
||||||
|
method: 'post',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -20,3 +20,12 @@ export function getFileZip(params: any) {
|
|||||||
responseType: 'blob'
|
responseType: 'blob'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function exportModel(data: any) {
|
||||||
|
return createAxios({
|
||||||
|
url: '/cs-harmonic-boot/exportmodel/exportModel',
|
||||||
|
method: 'post',
|
||||||
|
data: data,
|
||||||
|
responseType: 'blob'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -48,3 +48,20 @@ export function getztProjectTree() {
|
|||||||
method: 'post',
|
method: 'post',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//根据用户id获取组件信息
|
||||||
|
export function getByUserId(data: any) {
|
||||||
|
return createAxios({
|
||||||
|
url: '/cs-harmonic-boot/cspage/getByUserId',
|
||||||
|
method: 'post',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//c保存组态界面与用户的关系
|
||||||
|
export function savePageIdWithUser(data: any) {
|
||||||
|
return createAxios({
|
||||||
|
url: '/cs-harmonic-boot/cspage/savePageIdWithUser',
|
||||||
|
method: 'post',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -25,3 +25,12 @@ export function offlineDataUploadMakeUp(data: any) {
|
|||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
//设备补召操作
|
||||||
|
// 根据id集合获取敏感负荷用户列表
|
||||||
|
export function getListByIds() {
|
||||||
|
return createAxios({
|
||||||
|
url: '/cs-harmonic-boot/pqSensitiveUser/getListByIds',
|
||||||
|
method: 'POST',
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
29
src/api/cs-system-boot/official.ts
Normal file
29
src/api/cs-system-boot/official.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import createAxios from '@/utils/request'
|
||||||
|
|
||||||
|
// * 根据用户id查询工程和便携式设备
|
||||||
|
export const queryDevByUseId = (data: any) => {
|
||||||
|
return createAxios({
|
||||||
|
url: '/cs-system-boot/wlUser/selectDevByUserId',
|
||||||
|
method: 'POST',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// * 用户绑定工程和便携式设备
|
||||||
|
export const add = (data: any) => {
|
||||||
|
return createAxios({
|
||||||
|
url: '/cs-system-boot/wlUser/addUserDev',
|
||||||
|
method: 'POST',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* 用户取消绑定工程和便携式设备
|
||||||
|
*/
|
||||||
|
export const removeUserDev = (data: any) => {
|
||||||
|
return createAxios({
|
||||||
|
url: '/cs-system-boot/wlUser/deleteUserDev',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
273
src/api/harmonic-boot/cockpit/cockpit.ts
Normal file
273
src/api/harmonic-boot/cockpit/cockpit.ts
Normal file
@@ -0,0 +1,273 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
|
||||||
|
// 主要监测点列表查询>>分页
|
||||||
|
export function mainLineList(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/mainLine/list',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 主要监测点指标越限详情
|
||||||
|
export function statLimitRateDetails(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/mainLine/statLimitRateDetails',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询监测点列表=全部>>不分页
|
||||||
|
export function cslineList(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-device-boot/csline/list',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监测点详情 趋势图数据
|
||||||
|
export function trendData(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-device-boot/csGroup/trendData',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每日越限占比统计
|
||||||
|
export function totalLimitStatisticsDetails(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/totalLimitStatistics/details',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 总体指标越限统计列表
|
||||||
|
export function totalLimitStatisticsList(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/totalLimitStatistics/list',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 总体指标越限统计数据
|
||||||
|
export function totalLimitStatisticsData(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/totalLimitStatistics/data',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 指标越限程度数据
|
||||||
|
export function limitExtentData(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/limitRateDetailD/limitExtentData',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 指标日趋势图数据
|
||||||
|
export function limitExtentDayData(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/limitRateDetailD/limitExtentDayData',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 指标越限明细日历数据
|
||||||
|
export function limitCalendarData(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/limitRateDetailD/limitCalendarData',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//指标拟合图数据
|
||||||
|
export function fittingData(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-device-boot/csGroup/fittingData',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//指标越限时间概率分布
|
||||||
|
export function limitTimeProbabilityData(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/limitRateDetailD/limitTimeProbabilityData',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
//指标越限程度概率分布
|
||||||
|
export function limitProbabilityData(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/limitRateDetailD/limitProbabilityData',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 电网侧指标越限统计列表
|
||||||
|
export function gridSideLimitStatisticsList(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/gridSideLimitStatistics/list',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 电网侧指标越限统计数据
|
||||||
|
export function gridSideLimitStatisticsData(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/gridSideLimitStatistics/data',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 敏感负荷用户监测点列表
|
||||||
|
export function governLineList(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-device-boot/csline/getSensitiveUserLineList',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据id集合获取敏感负荷用户列表
|
||||||
|
export function getListByIds(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/pqSensitiveUser/getListByIds',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// 上传治理报告
|
||||||
|
export function uploadReport(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-device-boot/csline/uploadReport',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取治理报告链接
|
||||||
|
export function getReportUrl(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-device-boot/csline/getReportUrl',
|
||||||
|
method: 'post',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查询监测对象电网侧和负载侧监测点指标趋势对比数据
|
||||||
|
export function sensitiveUserTrendData(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-device-boot/csGroup/sensitiveUserTrendData',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取敏感负荷用户列表
|
||||||
|
export function getList(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/pqSensitiveUser/getList',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// F47曲线
|
||||||
|
export function f47Curve(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/csevent/f47Curve',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取电压暂态表及密度坐标图
|
||||||
|
export function getEventCoords(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/csevent/getEventCoords',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 日历暂降事件详情
|
||||||
|
export function getEventDate(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/csevent/getEventDate',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暂降类型分类统计Echart
|
||||||
|
export function netEventEcharts(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/csevent/netEventEcharts',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暂降类型分类统计表格
|
||||||
|
export function netEventTable(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/csevent/netEventTable',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 分页查询暂降事件
|
||||||
|
export function pageEvent(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/event/pageEvent',
|
||||||
|
method: 'post',
|
||||||
|
data: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暂态事件波形分析
|
||||||
|
export function analyseWave(data: any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/event/analyseWave',
|
||||||
|
method: 'get',
|
||||||
|
params: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暂态监测点下拉框接口
|
||||||
|
export function getSimpleLine() {
|
||||||
|
return request({
|
||||||
|
url: '/cs-device-boot/csline/getSimpleLine',
|
||||||
|
method: 'get'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function getLineExport(data:any) {
|
||||||
|
return request({
|
||||||
|
url: '/cs-harmonic-boot/eventReport/getLineExport',
|
||||||
|
method: 'post',
|
||||||
|
data: data,
|
||||||
|
responseType: 'blob'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -3,14 +3,15 @@ import createAxios from '@/utils/request'
|
|||||||
// 获取参数指标
|
// 获取参数指标
|
||||||
export function getIndex() {
|
export function getIndex() {
|
||||||
return createAxios({
|
return createAxios({
|
||||||
url: '/harmonic-boot/customReport/reportChooseTree',
|
// url: '/harmonic-boot/customReport/reportChooseTree',
|
||||||
|
url: '/cs-harmonic-boot/customReport/reportChooseTree',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
//、查询数据激活报表模板
|
//、查询数据激活报表模板
|
||||||
export function updateTemplateActive(data) {
|
export function updateTemplateActive(data) {
|
||||||
return createAxios({
|
return createAxios({
|
||||||
url: '/harmonic-boot/customReport/updateTemplateActive',
|
url: '/cs-harmonic-boot/customReport/updateTemplateActive',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
@@ -19,7 +20,8 @@ export function updateTemplateActive(data) {
|
|||||||
//获取报表模板 //部门树查询
|
//获取报表模板 //部门树查询
|
||||||
export function getTemplateList(data:any) {
|
export function getTemplateList(data:any) {
|
||||||
return createAxios({
|
return createAxios({
|
||||||
url: '/harmonic-boot/customReport/getTemplateList',
|
// url: '/harmonic-boot/customReport/getTemplateList',
|
||||||
|
url: '/cs-harmonic-boot/customReport/getTemplateList',
|
||||||
// url:'/api3/harmonic-boot/customReport/getTemplateList',
|
// url:'/api3/harmonic-boot/customReport/getTemplateList',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
@@ -28,7 +30,7 @@ export function getTemplateList(data:any) {
|
|||||||
//删除报表模板
|
//删除报表模板
|
||||||
export function delTemplate(data:any) {
|
export function delTemplate(data:any) {
|
||||||
return createAxios({
|
return createAxios({
|
||||||
url: '/harmonic-boot/customReport/delTemplate',
|
url: '/cs-harmonic-boot/customReport/delTemplate',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
@@ -37,7 +39,7 @@ export function delTemplate(data:any) {
|
|||||||
//修改获取数据
|
//修改获取数据
|
||||||
export function getCustomReportTemplateById(params) {
|
export function getCustomReportTemplateById(params) {
|
||||||
return createAxios({
|
return createAxios({
|
||||||
url: '/harmonic-boot/customReport/getCustomReportTemplateById',
|
url: '/cs-harmonic-boot/customReport/getCustomReportTemplateById',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params
|
params
|
||||||
})
|
})
|
||||||
@@ -46,7 +48,7 @@ export function getCustomReportTemplateById(params) {
|
|||||||
//修改获取数据
|
//修改获取数据
|
||||||
export function viewCustomReportTemplateById(params) {
|
export function viewCustomReportTemplateById(params) {
|
||||||
return createAxios({
|
return createAxios({
|
||||||
url: '/harmonic-boot/customReport/viewCustomReportTemplateById',
|
url: '/cs-harmonic-boot/customReport/viewCustomReportTemplateById',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params
|
params
|
||||||
})
|
})
|
||||||
@@ -54,16 +56,17 @@ export function viewCustomReportTemplateById(params) {
|
|||||||
//修改模板
|
//修改模板
|
||||||
export function dateTemplateup(data) {
|
export function dateTemplateup(data) {
|
||||||
return createAxios({
|
return createAxios({
|
||||||
url: '/harmonic-boot/customReport/updateTemplate',
|
url: '/cs-harmonic-boot/customReport/updateTemplate',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
//新增报表模板
|
//新增报表模板
|
||||||
export function addTemplate(data) {
|
export function addTemplate(data:any) {
|
||||||
return createAxios({
|
return createAxios({
|
||||||
url: '/harmonic-boot/customReport/addTemplate',
|
// url: '/harmonic-boot/customReport/addTemplate',
|
||||||
|
url: '/cs-harmonic-boot/customReport/addTemplate',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: data
|
data: data
|
||||||
})
|
})
|
||||||
@@ -71,7 +74,7 @@ export function addTemplate(data) {
|
|||||||
//模板对应指标替换
|
//模板对应指标替换
|
||||||
export function getCustomReport(data: any) {
|
export function getCustomReport(data: any) {
|
||||||
return createAxios({
|
return createAxios({
|
||||||
url: '/harmonic-boot/customReport/getCustomReport',
|
url: '/cs-harmonic-boot/customReport/getCustomReport',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
@@ -79,7 +82,7 @@ export function getCustomReport(data: any) {
|
|||||||
//绑定模板
|
//绑定模板
|
||||||
export function updateBindTemplate(data) {
|
export function updateBindTemplate(data) {
|
||||||
return createAxios({
|
return createAxios({
|
||||||
url: '/harmonic-boot/customReport/updateBindTemplate',
|
url: '/cs-harmonic-boot/customReport/updateBindTemplate',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
@@ -87,7 +90,7 @@ export function updateBindTemplate(data) {
|
|||||||
//根据模板ID查询数据
|
//根据模板ID查询数据
|
||||||
export function getDataByTempId(params) {
|
export function getDataByTempId(params) {
|
||||||
return createAxios({
|
return createAxios({
|
||||||
url: '/harmonic-boot/customReport/getDataByTempId',
|
url: '/cs-harmonic-boot/customReport/getDataByTempId',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params
|
params
|
||||||
})
|
})
|
||||||
@@ -95,7 +98,7 @@ export function getDataByTempId(params) {
|
|||||||
//根据部门查询模板
|
//根据部门查询模板
|
||||||
export function getTemplateByDept(params) {
|
export function getTemplateByDept(params) {
|
||||||
return createAxios({
|
return createAxios({
|
||||||
url: '/harmonic-boot/customReport/getTemplateByDept',
|
url: '/cs-harmonic-boot/customReport/getTemplateByDept',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
params
|
params
|
||||||
})
|
})
|
||||||
@@ -144,7 +147,7 @@ export function updateFile(data) {
|
|||||||
//合格率报告
|
//合格率报告
|
||||||
export function pageTable(data) {
|
export function pageTable(data) {
|
||||||
return createAxios({
|
return createAxios({
|
||||||
url: '/harmonic-boot/qualifiedReport/pageTable',
|
url: '/cs-harmonic-boot/qualifiedReport/pageTable',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data
|
data
|
||||||
})
|
})
|
||||||
@@ -152,14 +155,16 @@ export function pageTable(data) {
|
|||||||
//合格率报告
|
//合格率报告
|
||||||
export function targetLimitChooseTree() {
|
export function targetLimitChooseTree() {
|
||||||
return createAxios({
|
return createAxios({
|
||||||
url: '/harmonic-boot/customReport/targetLimitChooseTree',
|
// url: '/harmonic-boot/customReport/targetLimitChooseTree',
|
||||||
|
url: '/cs-harmonic-boot/customReport/targetLimitChooseTree',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
//监测点指标
|
//监测点指标
|
||||||
export function terminalChooseTree() {
|
export function terminalChooseTree() {
|
||||||
return createAxios({
|
return createAxios({
|
||||||
url: '/harmonic-boot/customReport/terminalChooseTree',
|
// url: '/harmonic-boot/customReport/terminalChooseTree',
|
||||||
|
url: '/cs-harmonic-boot/customReport/terminalChooseTree',
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,3 +116,11 @@ export const start = (params: any) => {
|
|||||||
params
|
params
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 查询监测对象类型
|
||||||
|
export const getDicDataByTypeCode = (params: any) => {
|
||||||
|
return request({
|
||||||
|
url: '/system-boot/dictData/getDicDataByTypeCode',
|
||||||
|
method: 'get',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -54,6 +54,14 @@ export const activatePage = (params: any) => {
|
|||||||
params
|
params
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 全局的驾驶舱页面
|
||||||
|
export const scopePage = (params: any) => {
|
||||||
|
return createAxios({
|
||||||
|
url: '/system-boot/dashboard/scopePage',
|
||||||
|
method: 'post',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
// 查询激活的驾驶舱页面
|
// 查询激活的驾驶舱页面
|
||||||
export const queryActivatePage = () => {
|
export const queryActivatePage = () => {
|
||||||
return createAxios({
|
return createAxios({
|
||||||
@@ -77,3 +85,11 @@ export const queryByPagePath = (params: any) => {
|
|||||||
params
|
params
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
// 根据用户id查询用户驾驶舱
|
||||||
|
export const getDashboardPageByUserId = (params: any) => {
|
||||||
|
return createAxios({
|
||||||
|
url: '/system-boot/dashboard/getDashboardPageByUserId',
|
||||||
|
method: 'post',
|
||||||
|
params
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -88,8 +88,9 @@ export const updateStatistical = (data: any) => {
|
|||||||
// 单位绑定
|
// 单位绑定
|
||||||
export function codeDicTree(data: any) {
|
export function codeDicTree(data: any) {
|
||||||
return createAxios({
|
return createAxios({
|
||||||
url: '/system-boot/dictTree/codeDicTree',
|
// url: '/system-boot/dictTree/codeDicTree',
|
||||||
method: 'get',
|
url: '/system-boot/dictTree/queryByCodeList',
|
||||||
|
method: 'post',
|
||||||
params: data
|
params: data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
11
src/api/user-boot/official.ts
Normal file
11
src/api/user-boot/official.ts
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import request from '@/utils/request'
|
||||||
|
/**
|
||||||
|
* 获取移动端、便携式正式用户列表
|
||||||
|
* @returns {AxiosPromise}
|
||||||
|
*/
|
||||||
|
export const getFormalUserList = () => {
|
||||||
|
return request({
|
||||||
|
url: '/user-boot/user/getFormalUserList',
|
||||||
|
method: 'post'
|
||||||
|
})
|
||||||
|
}
|
||||||
BIN
src/assets/img/jss.png
Normal file
BIN
src/assets/img/jss.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 124 KiB |
BIN
src/assets/img/lightning.png
Normal file
BIN
src/assets/img/lightning.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 7.9 KiB |
@@ -1,6 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!--F47曲线 -->
|
<!--F47曲线 -->
|
||||||
|
<TableHeader ref="TableHeaderRef" :showReset="false" :timeKeyList="prop.timeKey" @selectChange="selectChange" datePicker v-if="fullscreen"></TableHeader>
|
||||||
<el-descriptions class="mt2" direction="vertical" :column="4" border>
|
<el-descriptions class="mt2" direction="vertical" :column="4" border>
|
||||||
<el-descriptions-item align="center" label="名称">{{ data.name }}</el-descriptions-item>
|
<el-descriptions-item align="center" label="名称">{{ data.name }}</el-descriptions-item>
|
||||||
<el-descriptions-item align="center" label="事件总数">{{ data.gs }}</el-descriptions-item>
|
<el-descriptions-item align="center" label="事件总数">{{ data.gs }}</el-descriptions-item>
|
||||||
@@ -8,29 +9,87 @@
|
|||||||
<el-descriptions-item align="center" label="不可容忍">{{ data.bkrr }}</el-descriptions-item>
|
<el-descriptions-item align="center" label="不可容忍">{{ data.bkrr }}</el-descriptions-item>
|
||||||
</el-descriptions>
|
</el-descriptions>
|
||||||
<my-echart
|
<my-echart
|
||||||
|
v-loading="tableStore.table.loading"
|
||||||
|
ref="chartRef"
|
||||||
class="tall"
|
class="tall"
|
||||||
:options="echartList"
|
:options="echartList"
|
||||||
:style="{ width: prop.width, height: `calc(${prop.height} - 80px)` }"
|
:style="{
|
||||||
|
width: prop.width,
|
||||||
|
height: `calc(${prop.height} - 80px - ${headerHeight}px + ${fullscreen ? 0 : 56}px)`
|
||||||
|
}"
|
||||||
|
@chart-click="handleChartClick"
|
||||||
/>
|
/>
|
||||||
|
<el-dialog v-model="isWaveCharts" v-if="isWaveCharts" draggable :title="dialogTitle" append-to-body width="70%">
|
||||||
|
<waveFormAnalysis
|
||||||
|
v-loading="loading"
|
||||||
|
ref="waveFormAnalysisRef"
|
||||||
|
@handleHideCharts="isWaveCharts = false"
|
||||||
|
:wp="wp"
|
||||||
|
/>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
||||||
import TableStore from '@/utils/tableStore'
|
import TableStore from '@/utils/tableStore'
|
||||||
import Table from '@/components/table/index.vue'
|
|
||||||
import MyEchart from '@/components/echarts/MyEchart.vue'
|
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||||
import { useDictData } from '@/stores/dictData'
|
import waveFormAnalysis from '@/views/govern/device/control/tabs/components/waveFormAnalysis.vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
import { getTimeOfTheMonth } from '@/utils/formatTime'
|
import { analyseWave } from '@/api/common'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { getTime } from '@/utils/formatTime'
|
||||||
|
|
||||||
const prop = defineProps({
|
const prop = defineProps({
|
||||||
width: { type: String },
|
w: { type: [String, Number] },
|
||||||
height: { type: String },
|
h: { type: [String, Number] },
|
||||||
timeKey: { type: String },
|
width: { type: [String, Number] },
|
||||||
timeValue: { type: Object }
|
height: { type: [String, Number] },
|
||||||
|
timeKey: { type: Array as () => string[] },
|
||||||
|
timeValue: { type: Object },
|
||||||
|
interval: { type: Number }
|
||||||
})
|
})
|
||||||
|
|
||||||
const echartList = ref({})
|
const TableHeaderRef = ref()
|
||||||
const OverLimitDetailsRef = ref()
|
|
||||||
|
const headerHeight = ref(57)
|
||||||
|
|
||||||
|
const dialogTitle = ref('波形分析')
|
||||||
|
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
|
||||||
|
headerHeight.value = height
|
||||||
|
|
||||||
|
if (datePickerValue && datePickerValue.timeValue) {
|
||||||
|
// 更新时间参数
|
||||||
|
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
|
||||||
|
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算是否全屏展示
|
||||||
|
const fullscreen = computed(() => {
|
||||||
|
const w = Number(prop.w)
|
||||||
|
const h = Number(prop.h)
|
||||||
|
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
|
||||||
|
// 执行相应逻辑
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const echartList = ref()
|
||||||
|
|
||||||
|
const chartRef = ref()
|
||||||
|
// 波形
|
||||||
|
const isWaveCharts = ref(false)
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
const wp = ref({})
|
||||||
|
|
||||||
|
const boxoList: any = ref({})
|
||||||
|
|
||||||
|
const waveFormAnalysisRef: any = ref(null)
|
||||||
|
|
||||||
const data = reactive({
|
const data = reactive({
|
||||||
name: '事件个数',
|
name: '事件个数',
|
||||||
gs: 0,
|
gs: 0,
|
||||||
@@ -38,33 +97,29 @@ const data = reactive({
|
|||||||
bkrr: 0
|
bkrr: 0
|
||||||
})
|
})
|
||||||
const tableStore: any = new TableStore({
|
const tableStore: any = new TableStore({
|
||||||
url: '/user-boot/dept/deptTree',
|
url: '/cs-harmonic-boot/csevent/f47Curve',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|
||||||
showPage: false,
|
showPage: false,
|
||||||
|
|
||||||
column: [],
|
column: [],
|
||||||
beforeSearchFun: () => {
|
beforeSearchFun: () => {
|
||||||
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
|
setTime()
|
||||||
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
|
|
||||||
},
|
},
|
||||||
loadCallback: () => {
|
loadCallback: () => {
|
||||||
let res = {
|
const gongData = gongfunction(tableStore.table.data)
|
||||||
data: { totalNumberOfEvents: 0, voltageToleranceCurveDataList: [] }
|
data.gs = tableStore.table.data.length
|
||||||
}
|
|
||||||
|
|
||||||
const gongData = gongfunction(res.data.voltageToleranceCurveDataList)
|
|
||||||
data.gs = res.data.voltageToleranceCurveDataList.length
|
|
||||||
data.krr = gongData.pointI.length
|
data.krr = gongData.pointI.length
|
||||||
data.bkrr = gongData.pointIun.length
|
data.bkrr = gongData.pointIun.length
|
||||||
console.log(gongData)
|
|
||||||
echartList.value = {
|
echartList.value = {
|
||||||
// backgroundColor: "#f9f9f9", //地图背景色深蓝
|
|
||||||
title: {
|
title: {
|
||||||
text: `F47曲线`
|
text: `F47曲线`
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
data: ['上限', '下限', '可容忍事件', '不可容忍事件']
|
data: ['可容忍事件', '不可容忍事件'],
|
||||||
|
itemWidth: 10,
|
||||||
|
itemHeight: 10,
|
||||||
|
itemGap: 15
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
trigger: 'item',
|
trigger: 'item',
|
||||||
@@ -141,13 +196,40 @@ const tableStore: any = new TableStore({
|
|||||||
name: '可容忍事件',
|
name: '可容忍事件',
|
||||||
type: 'scatter',
|
type: 'scatter',
|
||||||
symbol: 'circle',
|
symbol: 'circle',
|
||||||
data: gongData.pointF
|
symbolSize: 8,
|
||||||
|
data: gongData.pointF,
|
||||||
|
// data: [
|
||||||
|
// [0.2, 10, '2023-01-01 10:00:00'],
|
||||||
|
// [0.4, 50, '2023-01-01 11:00:00']
|
||||||
|
// ],
|
||||||
|
legendSymbol: 'circle',
|
||||||
|
emphasis: {
|
||||||
|
focus: 'series',
|
||||||
|
itemStyle: {
|
||||||
|
borderColor: '#fff',
|
||||||
|
borderWidth: 2,
|
||||||
|
shadowBlur: 10,
|
||||||
|
shadowColor: 'rgba(0, 0, 0, 0.5)'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
show: true,
|
||||||
|
trigger: 'item',
|
||||||
|
formatter: function (params: any) {
|
||||||
|
return `<strong>可容忍事件</strong><br/>
|
||||||
|
持续时间: ${params.value[0]}s<br/>
|
||||||
|
特征幅值: ${params.value[1].toFixed(2)}%<br/>
|
||||||
|
发生时间: ${params.value[2] || 'N/A'}`
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '不可容忍事件',
|
name: '不可容忍事件',
|
||||||
type: 'scatter',
|
type: 'scatter',
|
||||||
symbol: 'circle',
|
symbol: 'circle',
|
||||||
data: gongData.pointFun
|
symbolSize: 8,
|
||||||
|
data: gongData.pointFun,
|
||||||
|
legendSymbol: 'rect'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -159,6 +241,25 @@ const tableRef = ref()
|
|||||||
provide('tableRef', tableRef)
|
provide('tableRef', tableRef)
|
||||||
provide('tableStore', tableStore)
|
provide('tableStore', tableStore)
|
||||||
|
|
||||||
|
const setTime = () => {
|
||||||
|
const time = getTime(
|
||||||
|
(TableHeaderRef.value?.datePickerRef.interval || prop.interval) ?? 0,
|
||||||
|
prop.timeKey,
|
||||||
|
fullscreen.value
|
||||||
|
? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
|
||||||
|
: prop.timeValue
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(time)) {
|
||||||
|
tableStore.table.params.searchBeginTime = time[0]
|
||||||
|
tableStore.table.params.searchEndTime = time[1]
|
||||||
|
TableHeaderRef.value?.setInterval(time[2] - 0)
|
||||||
|
TableHeaderRef.value?.setTimeInterval([time[0], time[1]])
|
||||||
|
} else {
|
||||||
|
console.warn('获取时间失败,time 不是一个有效数组')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function gongfunction(arr: any) {
|
function gongfunction(arr: any) {
|
||||||
let standI = 0
|
let standI = 0
|
||||||
let unstandI = 0
|
let unstandI = 0
|
||||||
@@ -178,8 +279,9 @@ function gongfunction(arr: any) {
|
|||||||
let yy = arr[i].eventValue
|
let yy = arr[i].eventValue
|
||||||
let time = arr[i].time
|
let time = arr[i].time
|
||||||
let eventId = arr[i].eventId
|
let eventId = arr[i].eventId
|
||||||
|
let lineName = arr[i].lineName
|
||||||
// let index =arr[i].eventDetailIndex;
|
// let index =arr[i].eventDetailIndex;
|
||||||
point = [xx, yy, time, eventId]
|
point = [xx, yy, time, eventId, lineName]
|
||||||
|
|
||||||
if (xx <= 0.003) {
|
if (xx <= 0.003) {
|
||||||
let line = 0
|
let line = 0
|
||||||
@@ -323,6 +425,65 @@ onMounted(() => {
|
|||||||
tableStore.index()
|
tableStore.index()
|
||||||
}, 100)
|
}, 100)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 点击事件处理函数
|
||||||
|
const handleChartClick = (params: any) => {
|
||||||
|
if (params.seriesName === '可容忍事件') {
|
||||||
|
// 处理可容忍事件点击
|
||||||
|
dialogTitle.value = '可容忍事件波形分析'
|
||||||
|
handleTolerableEventClick(params)
|
||||||
|
} else if (params.seriesName === '不可容忍事件') {
|
||||||
|
dialogTitle.value = '不可容忍事件波形分析'
|
||||||
|
// 处理不可容忍事件点击
|
||||||
|
// ElMessage.info(`点击了不可容忍事件: 持续时间${params.value[0]}s, 幅值${params.value[1].toFixed(2)}%`)
|
||||||
|
handleTolerableEventClick(params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 可容忍事件点击处理函数
|
||||||
|
const handleTolerableEventClick = async (row: any) => {
|
||||||
|
loading.value = true
|
||||||
|
nextTick(() => {
|
||||||
|
if (waveFormAnalysisRef.value) {
|
||||||
|
//waveFormAnalysisRef.value.setHeight(false, 360)
|
||||||
|
// waveFormAnalysisRef.value.setHeight(999, 130, 1.6666666)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const messageInstance = ElMessage.info(`正在加载,请稍等...`)
|
||||||
|
await analyseWave(row.value[3]) //eventId
|
||||||
|
.then(res => {
|
||||||
|
row.loading1 = false
|
||||||
|
if (res != undefined) {
|
||||||
|
boxoList.value = {
|
||||||
|
persistTime: row.value[0], //持续时间
|
||||||
|
featureAmplitude: (row.value[1] / 100).toFixed(2), //残余电压
|
||||||
|
startTime: row.value[2], //时间
|
||||||
|
lineName: row.value[4] //监测点名称
|
||||||
|
}
|
||||||
|
boxoList.value.systemType = 'YPT'
|
||||||
|
wp.value = res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
isWaveCharts.value = true
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
messageInstance.close()
|
||||||
|
row.loading1 = false
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
waveFormAnalysisRef.value && waveFormAnalysisRef.value.setHeight(999, 130, 1.6666666)
|
||||||
|
waveFormAnalysisRef.value && waveFormAnalysisRef.value.getWpData(wp.value, boxoList.value, true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 不可容忍事件点击处理函数
|
||||||
|
const handleIntolerableEventClick = (params: any) => {
|
||||||
|
console.log('不可容忍事件详情:', params)
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeKey,
|
() => prop.timeKey,
|
||||||
val => {
|
val => {
|
||||||
@@ -330,12 +491,17 @@ watch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeValue, // 监听的目标(函数形式避免直接传递 props 导致的警告)
|
() => prop.timeValue,
|
||||||
(newVal, oldVal) => {
|
(newVal, oldVal) => {
|
||||||
tableStore.index()
|
// 当外部时间值变化时,更新表格的时间参数
|
||||||
|
if (newVal && (!oldVal || newVal[0] !== oldVal[0] || newVal[1] !== oldVal[1])) {
|
||||||
|
tableStore.table.params.searchBeginTime = newVal[0]
|
||||||
|
tableStore.table.params.searchEndTime = newVal[1]
|
||||||
|
tableStore.index()
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
deep: true // 若 timeValue 是对象/数组,需开启深度监听
|
deep: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
308
src/components/cockpit/crossingTime/index.vue
Normal file
308
src/components/cockpit/crossingTime/index.vue
Normal file
@@ -0,0 +1,308 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<!--暂态越限时间分布 -->
|
||||||
|
<TableHeader
|
||||||
|
ref="TableHeaderRef"
|
||||||
|
:timeKeyList="prop.timeKey"
|
||||||
|
:showReset="false"
|
||||||
|
@selectChange="selectChange"
|
||||||
|
datePicker
|
||||||
|
v-if="fullscreen"
|
||||||
|
></TableHeader>
|
||||||
|
<my-echart
|
||||||
|
class="tall"
|
||||||
|
:options="echartList1"
|
||||||
|
:style="{
|
||||||
|
width: prop.width,
|
||||||
|
height: `calc(${prop.height} - ${headerHeight}px + ${fullscreen ? 0 : 56}px)`
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<!-- <my-echart
|
||||||
|
class="mt10"
|
||||||
|
:options="echartList1"
|
||||||
|
:style="{
|
||||||
|
width: prop.width,
|
||||||
|
height: `calc(${prop.height} / 2 - ${headerHeight / 2}px + ${fullscreen ? 0 : 28}px )`
|
||||||
|
}"
|
||||||
|
/> -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, provide, reactive, watch } from 'vue'
|
||||||
|
import TableStore from '@/utils/tableStore'
|
||||||
|
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||||
|
import { useConfig } from '@/stores/config'
|
||||||
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
|
import { getTime } from '@/utils/formatTime'
|
||||||
|
|
||||||
|
const prop = defineProps({
|
||||||
|
w: { type: [String, Number] },
|
||||||
|
h: { type: [String, Number] },
|
||||||
|
width: { type: [String, Number] },
|
||||||
|
height: { type: [String, Number] },
|
||||||
|
timeKey: { type: Array as () => string[] },
|
||||||
|
timeValue: { type: Object },
|
||||||
|
interval: { type: Number }
|
||||||
|
})
|
||||||
|
|
||||||
|
const TableHeaderRef = ref()
|
||||||
|
|
||||||
|
const headerHeight = ref(57)
|
||||||
|
|
||||||
|
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
|
||||||
|
headerHeight.value = height
|
||||||
|
|
||||||
|
if (datePickerValue && datePickerValue.timeValue) {
|
||||||
|
// 更新时间参数
|
||||||
|
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
|
||||||
|
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算是否全屏展示
|
||||||
|
const fullscreen = computed(() => {
|
||||||
|
const w = Number(prop.w)
|
||||||
|
const h = Number(prop.h)
|
||||||
|
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
|
||||||
|
// 执行相应逻辑
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const config = useConfig()
|
||||||
|
|
||||||
|
const echartList = ref({})
|
||||||
|
|
||||||
|
const echartList1 = ref({})
|
||||||
|
|
||||||
|
const processDataForChart = (rawData: any[]) => {
|
||||||
|
// 将后端返回的扁平数据转换为 ECharts 需要的三维坐标格式 [x, y, z]
|
||||||
|
const chartData = rawData.map(item => [item.x, item.y, item.z])
|
||||||
|
|
||||||
|
return chartData
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableStore: any = new TableStore({
|
||||||
|
url: '/cs-harmonic-boot/csevent/getEventCoords',
|
||||||
|
method: 'POST',
|
||||||
|
showPage: false,
|
||||||
|
column: [],
|
||||||
|
beforeSearchFun: () => {
|
||||||
|
setTime()
|
||||||
|
},
|
||||||
|
loadCallback: () => {
|
||||||
|
const processedData = processDataForChart(tableStore.table.data.innerList || [])
|
||||||
|
const trendList = tableStore.table.data.trendList || []
|
||||||
|
const xlist = tableStore.table.data.xlist || []
|
||||||
|
|
||||||
|
// 处理趋势图数据
|
||||||
|
const seriesData = trendList.map((item: any) => {
|
||||||
|
// 根据接口返回的name字段确定系列名称和颜色
|
||||||
|
let name = ''
|
||||||
|
let color = ''
|
||||||
|
|
||||||
|
switch (item.name) {
|
||||||
|
case 'Evt_Sys_DipStr':
|
||||||
|
name = '电压暂降'
|
||||||
|
color = '#FFBF00'
|
||||||
|
break
|
||||||
|
case 'Evt_Sys_IntrStr':
|
||||||
|
name = '电压中断'
|
||||||
|
color = '#FF9100'
|
||||||
|
break
|
||||||
|
case 'Evt_Sys_SwlStr':
|
||||||
|
name = '电压暂升'
|
||||||
|
color = config.layout.elementUiPrimary[0]
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
name = item.name
|
||||||
|
color = '#000000'
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: name,
|
||||||
|
type: 'line',
|
||||||
|
showSymbol: false,
|
||||||
|
color: color,
|
||||||
|
data: item.trendList?.map((value: number, index: number) => [xlist[index], value]) || []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 获取x轴和y轴的标签值
|
||||||
|
const xLabels = [
|
||||||
|
'0-10%',
|
||||||
|
'10%-20%',
|
||||||
|
'20%-30%',
|
||||||
|
'30%-40%',
|
||||||
|
'40%-50%',
|
||||||
|
'50%-60%',
|
||||||
|
'60%-70%',
|
||||||
|
'70%-80%',
|
||||||
|
'80%-90%',
|
||||||
|
'90%-100%'
|
||||||
|
]
|
||||||
|
const yLabels = ['0-0.01s', '0.01s-0.1s', '0.1s-1s', '1s-10s', '10s']
|
||||||
|
|
||||||
|
echartList.value = {
|
||||||
|
options: {
|
||||||
|
xAxis: null,
|
||||||
|
yAxis: null,
|
||||||
|
dataZoom: null,
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
tooltip: {
|
||||||
|
textStyle: {
|
||||||
|
color: '#fff',
|
||||||
|
fontStyle: 'normal',
|
||||||
|
opacity: 0.35,
|
||||||
|
fontSize: 14
|
||||||
|
},
|
||||||
|
backgroundColor: 'rgba(0,0,0,0.55)',
|
||||||
|
borderWidth: 0,
|
||||||
|
formatter: function (params: any) {
|
||||||
|
var tips = ''
|
||||||
|
tips += '持续时间: ' + yLabels[params.value[1]] + '</br>'
|
||||||
|
tips += '特征幅值: ' + xLabels[params.value[0]] + '</br>'
|
||||||
|
tips += '事件次数: ' + params.value[2] + '</br>'
|
||||||
|
return tips
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: '暂态事件概率分布',
|
||||||
|
x: 'center'
|
||||||
|
},
|
||||||
|
visualMap: {
|
||||||
|
max: 500,
|
||||||
|
show: false,
|
||||||
|
inRange: {
|
||||||
|
color: ['#313695', '#00BB00', '#ff8000', '#a50026']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xAxis3D: {
|
||||||
|
type: 'category',
|
||||||
|
name: '特征幅值',
|
||||||
|
data: xLabels,
|
||||||
|
nameGap: 40
|
||||||
|
},
|
||||||
|
yAxis3D: {
|
||||||
|
type: 'category',
|
||||||
|
name: '持续时间',
|
||||||
|
data: yLabels,
|
||||||
|
nameGap: 40,
|
||||||
|
|
||||||
|
splitLine: {
|
||||||
|
lineStyle: {
|
||||||
|
type: 'dashed',
|
||||||
|
opacity: 0.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
zAxis3D: {
|
||||||
|
type: 'value',
|
||||||
|
minInterval: 10,
|
||||||
|
name: '暂态事件次数',
|
||||||
|
nameGap: 30
|
||||||
|
},
|
||||||
|
grid3D: {
|
||||||
|
viewControl: {
|
||||||
|
projection: 'perspective',
|
||||||
|
distance: 260
|
||||||
|
},
|
||||||
|
boxWidth: 200,
|
||||||
|
boxDepth: 80,
|
||||||
|
light: {
|
||||||
|
main: {
|
||||||
|
intensity: 1.2
|
||||||
|
},
|
||||||
|
ambient: {
|
||||||
|
intensity: 0.3
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'bar3D',
|
||||||
|
data: processedData,
|
||||||
|
shading: 'realistic',
|
||||||
|
label: {
|
||||||
|
show: false,
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 16,
|
||||||
|
borderWidth: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echartList1.value = {
|
||||||
|
title: {
|
||||||
|
text: '暂态越限时间概率分布'
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: xlist,
|
||||||
|
axisLabel: {
|
||||||
|
formatter: '{value}'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
name: '次'
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '10px',
|
||||||
|
right: '20px'
|
||||||
|
},
|
||||||
|
series: seriesData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const tableRef = ref()
|
||||||
|
provide('tableRef', tableRef)
|
||||||
|
|
||||||
|
provide('tableStore', tableStore)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
tableStore.index()
|
||||||
|
})
|
||||||
|
|
||||||
|
const setTime = () => {
|
||||||
|
const time = getTime(
|
||||||
|
(TableHeaderRef.value?.datePickerRef.interval || prop.interval) ?? 0,
|
||||||
|
prop.timeKey,
|
||||||
|
fullscreen.value
|
||||||
|
? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
|
||||||
|
: prop.timeValue
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(time)) {
|
||||||
|
tableStore.table.params.searchBeginTime = time[0]
|
||||||
|
tableStore.table.params.searchEndTime = time[1]
|
||||||
|
TableHeaderRef.value?.setInterval(time[2] - 0)
|
||||||
|
TableHeaderRef.value?.setTimeInterval([time[0], time[1]])
|
||||||
|
} else {
|
||||||
|
console.warn('获取时间失败,time 不是一个有效数组')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => prop.timeKey,
|
||||||
|
val => {
|
||||||
|
tableStore.index()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => prop.timeValue,
|
||||||
|
(newVal, oldVal) => {
|
||||||
|
tableStore.index()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@@ -1,102 +1,158 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!--暂降方向统计 -->
|
<!--暂降方向统计 -->
|
||||||
<my-echart class="tall" :options="echartList" :style="{ width: prop.width, height: `calc(${prop.height} )` }" />
|
<TableHeader
|
||||||
|
ref="TableHeaderRef"
|
||||||
|
:showReset="false"
|
||||||
|
@selectChange="selectChange"
|
||||||
|
datePicker
|
||||||
|
:timeKeyList="prop.timeKey"
|
||||||
|
v-if="fullscreen"
|
||||||
|
></TableHeader>
|
||||||
|
<my-echart
|
||||||
|
v-loading="tableStore.table.loading"
|
||||||
|
class="tall"
|
||||||
|
:options="echartList"
|
||||||
|
:style="{ width: prop.width, height: `calc(${prop.height} )` }"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
||||||
import TableStore from '@/utils/tableStore'
|
import TableStore from '@/utils/tableStore'
|
||||||
import Table from '@/components/table/index.vue'
|
|
||||||
import MyEchart from '@/components/echarts/MyEchart.vue'
|
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||||
import { useDictData } from '@/stores/dictData'
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { getTime } from '@/utils/formatTime'
|
||||||
import { getTimeOfTheMonth } from '@/utils/formatTime'
|
|
||||||
const prop = defineProps({
|
const prop = defineProps({
|
||||||
width: { type: String },
|
w: { type: [String, Number] },
|
||||||
height: { type: String },
|
h: { type: [String, Number] },
|
||||||
timeKey: { type: String },
|
width: { type: [String, Number] },
|
||||||
timeValue: { type: Object }
|
height: { type: [String, Number] },
|
||||||
|
timeKey: { type: Array as () => string[] },
|
||||||
|
timeValue: { type: Object },
|
||||||
|
interval: { type: Number }
|
||||||
})
|
})
|
||||||
const data = [
|
|
||||||
{
|
const headerHeight = ref(57)
|
||||||
name: '来自电网',
|
|
||||||
value: 4
|
const TableHeaderRef = ref()
|
||||||
},
|
|
||||||
{
|
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
|
||||||
name: '来自负荷',
|
headerHeight.value = height
|
||||||
value: 41
|
|
||||||
|
if (datePickerValue && datePickerValue.timeValue) {
|
||||||
|
// 更新时间参数
|
||||||
|
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
|
||||||
|
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
const echartList = ref({
|
|
||||||
title: {},
|
|
||||||
|
|
||||||
tooltip: {
|
// 计算是否全屏展示
|
||||||
trigger: 'item'
|
const fullscreen = computed(() => {
|
||||||
},
|
const w = Number(prop.w)
|
||||||
legend: {
|
const h = Number(prop.h)
|
||||||
orient: 'vertical',
|
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
|
||||||
top: 'center',
|
// 执行相应逻辑
|
||||||
right: '5%',
|
return true
|
||||||
formatter: function (e: any) {
|
} else {
|
||||||
return e + ' ' + data.filter(item => item.name == e)[0].value + '次'
|
return false
|
||||||
}
|
|
||||||
},
|
|
||||||
xAxis: {
|
|
||||||
show: false
|
|
||||||
},
|
|
||||||
yAxis: {
|
|
||||||
show: false
|
|
||||||
},
|
|
||||||
grid: {
|
|
||||||
left: '10px',
|
|
||||||
right: '20px'
|
|
||||||
},
|
|
||||||
|
|
||||||
options: {
|
|
||||||
dataZoom: null,
|
|
||||||
title: [
|
|
||||||
{
|
|
||||||
text: '暂降方向统计',
|
|
||||||
left: 'center'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: data[0].value + data[1].value + '次',
|
|
||||||
left: 'center',
|
|
||||||
top: 'center'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
type: 'pie',
|
|
||||||
center: 'center',
|
|
||||||
radius: ['55%', '75%'],
|
|
||||||
label: {
|
|
||||||
show: false,
|
|
||||||
position: 'outside',
|
|
||||||
textStyle: {
|
|
||||||
//数值样式
|
|
||||||
}
|
|
||||||
},
|
|
||||||
name: '事件统计',
|
|
||||||
data: data
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const echartList = ref({})
|
||||||
|
|
||||||
|
// const data = [
|
||||||
|
// {
|
||||||
|
// name: '来自电网',
|
||||||
|
// value: 4
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: '来自负荷',
|
||||||
|
// value: 41
|
||||||
|
// }
|
||||||
|
// ]
|
||||||
|
|
||||||
const OverLimitDetailsRef = ref()
|
const OverLimitDetailsRef = ref()
|
||||||
const tableStore: any = new TableStore({
|
const tableStore: any = new TableStore({
|
||||||
url: '/user-boot/dept/deptTree',
|
url: '/cs-harmonic-boot/csevent/getEventDirectionData',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|
||||||
showPage: false,
|
showPage: false,
|
||||||
|
|
||||||
column: [],
|
column: [],
|
||||||
beforeSearchFun: () => {
|
beforeSearchFun: () => {
|
||||||
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
|
setTime()
|
||||||
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
|
|
||||||
},
|
},
|
||||||
loadCallback: () => {}
|
loadCallback: () => {
|
||||||
|
if (!tableStore.table.data || !Array.isArray(tableStore.table.data)) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
const chartData = ref(
|
||||||
|
tableStore.table.data.map((item: any) => ({
|
||||||
|
name: item.source === 'load' ? '来自负荷' : '来自电网',
|
||||||
|
value: item.times
|
||||||
|
}))
|
||||||
|
)
|
||||||
|
|
||||||
|
const total = chartData.value.reduce((sum: any, item: any) => sum + item.value, 0)
|
||||||
|
|
||||||
|
echartList.value = {
|
||||||
|
title: {},
|
||||||
|
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item'
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
orient: 'vertical',
|
||||||
|
top: '50',
|
||||||
|
right: '10',
|
||||||
|
formatter: function (name: string) {
|
||||||
|
const item = chartData.value.find((i: any) => i.name === name)
|
||||||
|
return item ? `${name} ${item.value}次` : name
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '10px',
|
||||||
|
right: '20px'
|
||||||
|
},
|
||||||
|
|
||||||
|
options: {
|
||||||
|
dataZoom: null,
|
||||||
|
title: [
|
||||||
|
{
|
||||||
|
text: '暂降方向统计',
|
||||||
|
left: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: total + '次',
|
||||||
|
left: 'center',
|
||||||
|
top: 'center'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'pie',
|
||||||
|
center: 'center',
|
||||||
|
radius: ['55%', '75%'],
|
||||||
|
label: {
|
||||||
|
show: false,
|
||||||
|
position: 'outside',
|
||||||
|
textStyle: {
|
||||||
|
//数值样式
|
||||||
|
}
|
||||||
|
},
|
||||||
|
name: '事件统计',
|
||||||
|
data: chartData.value
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const tableRef = ref()
|
const tableRef = ref()
|
||||||
@@ -104,10 +160,28 @@ provide('tableRef', tableRef)
|
|||||||
|
|
||||||
provide('tableStore', tableStore)
|
provide('tableStore', tableStore)
|
||||||
|
|
||||||
|
const setTime = () => {
|
||||||
|
const time = getTime(
|
||||||
|
(TableHeaderRef.value?.datePickerRef.interval || prop.interval) ?? 0,
|
||||||
|
prop.timeKey,
|
||||||
|
fullscreen.value
|
||||||
|
? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
|
||||||
|
: prop.timeValue
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(time)) {
|
||||||
|
tableStore.table.params.searchBeginTime = time[0]
|
||||||
|
tableStore.table.params.searchEndTime = time[1]
|
||||||
|
TableHeaderRef.value?.setInterval(time[2] - 0)
|
||||||
|
TableHeaderRef.value?.setTimeInterval([time[0], time[1]])
|
||||||
|
} else {
|
||||||
|
console.warn('获取时间失败,time 不是一个有效数组')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 点击行
|
// 点击行
|
||||||
const cellClickEvent = ({ row, column }: any) => {
|
const cellClickEvent = ({ row, column }: any) => {
|
||||||
if (column.field != 'name') {
|
if (column.field != 'name') {
|
||||||
console.log(row)
|
|
||||||
OverLimitDetailsRef.value.open(row)
|
OverLimitDetailsRef.value.open(row)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -122,12 +196,12 @@ watch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeValue, // 监听的目标(函数形式避免直接传递 props 导致的警告)
|
() => prop.timeValue,
|
||||||
(newVal, oldVal) => {
|
(newVal, oldVal) => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
deep: true // 若 timeValue 是对象/数组,需开启深度监听
|
deep: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,150 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 指标日趋势图 -->
|
||||||
|
<el-dialog draggable :title="dialogTitle" v-model="dialogVisible" append-to-body width="70%">
|
||||||
|
<div :style="pageHeight">
|
||||||
|
<my-echart class="tall" :options="echartList" style="width: 100%" />
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
||||||
|
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||||
|
import { useConfig } from '@/stores/config'
|
||||||
|
import { mainHeight } from '@/utils/layout'
|
||||||
|
import { limitExtentDayData } from '@/api/harmonic-boot/cockpit/cockpit'
|
||||||
|
import { yMethod } from '@/utils/echartMethod'
|
||||||
|
const prop = defineProps({
|
||||||
|
width: { type: [String, Number] },
|
||||||
|
height: { type: [String, Number] },
|
||||||
|
timeKey: { type: Array as () => string[] },
|
||||||
|
timeValue: { type: Object }
|
||||||
|
})
|
||||||
|
|
||||||
|
const pageHeight = mainHeight(0, 2)
|
||||||
|
|
||||||
|
const dialogVisible: any = ref(false)
|
||||||
|
|
||||||
|
const dialogTitle = ref('')
|
||||||
|
|
||||||
|
const config = useConfig()
|
||||||
|
|
||||||
|
const dialogText = ref('')
|
||||||
|
|
||||||
|
const echartList = ref()
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
echartList.value = {
|
||||||
|
title: {
|
||||||
|
text: dialogText.value
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
itemWidth: 20,
|
||||||
|
itemHeight: 20,
|
||||||
|
itemStyle: { opacity: 0 }, //去圆点
|
||||||
|
right: 70
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
formatter: (params: any) => {
|
||||||
|
if (!params || params.length === 0) return ''
|
||||||
|
|
||||||
|
// 使用第一个项目的轴标签作为时间标题
|
||||||
|
let tooltipText = params[0].axisValueLabel + '<br/>'
|
||||||
|
|
||||||
|
// 遍历所有项目并累加到tooltipText中
|
||||||
|
params.forEach((item: any) => {
|
||||||
|
// 将数值格式化为保留两位小数
|
||||||
|
const formattedValue = Math.round(item.value[1] * 100) / 100
|
||||||
|
tooltipText += `${item.marker} ${item.seriesName}: ${formattedValue}<br/>`
|
||||||
|
})
|
||||||
|
|
||||||
|
return tooltipText
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'time',
|
||||||
|
axisLabel: {
|
||||||
|
formatter: {
|
||||||
|
day: '{MM}-{dd}',
|
||||||
|
month: '{MM}',
|
||||||
|
year: '{yyyy}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
yAxis: {},
|
||||||
|
|
||||||
|
options: {
|
||||||
|
series: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const initData = async (row: any) => {
|
||||||
|
limitExtentDayData({ code: row.code, lineId: row.lineId, time: row.time }).then(res => {
|
||||||
|
if (res.data && res.data.length > 0) {
|
||||||
|
// 重新初始化图表
|
||||||
|
init()
|
||||||
|
let [min, max] = yMethod(res.data.map((item: any) => item.value.split(',')).flat())
|
||||||
|
|
||||||
|
// 从第一条数据中提取时间作为x轴数据
|
||||||
|
const firstItem = res.data[0]
|
||||||
|
const xAxisData = firstItem.time.split(',')
|
||||||
|
|
||||||
|
// 定义相位颜色映射
|
||||||
|
const phaseColors: any = {
|
||||||
|
A: '#DAA520',
|
||||||
|
B: '#2E8B57',
|
||||||
|
C: '#A52a2a'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理每条相位数据
|
||||||
|
const seriesData = res.data.map((item: any) => {
|
||||||
|
const values = xAxisData.map((time: string, index: number) => {
|
||||||
|
// 将传入的日期与时间拼接成完整的时间字符串
|
||||||
|
const fullTime = `${row.time} ${time}`
|
||||||
|
const value = parseFloat(item.value.split(',')[index]) || 0
|
||||||
|
return [fullTime, value]
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: `${item.phasic}相`,
|
||||||
|
type: 'line',
|
||||||
|
showSymbol: false,
|
||||||
|
smooth: true,
|
||||||
|
data: values,
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
// 根据相位设置对应颜色
|
||||||
|
color: phaseColors[item.phasic] || config.layout.elementUiPrimary[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
echartList.value.yAxis.max = max
|
||||||
|
echartList.value.yAxis.min = min
|
||||||
|
// 更新图表配置
|
||||||
|
echartList.value.options.series = seriesData
|
||||||
|
// 注意:使用时间轴时不需要设置 xAxis.data
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
onMounted(() => {})
|
||||||
|
|
||||||
|
const open = async (row: any) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
dialogTitle.value = row.name + '日趋势图'
|
||||||
|
dialogText.value = `监测点名称:${row.lineName}_越限时间:${row.time}_指标名称:${row.name}`
|
||||||
|
nextTick(() => {
|
||||||
|
initData(row)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ open })
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.el-select) {
|
||||||
|
min-width: 80px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,74 +1,81 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!--指标越限程度 -->
|
<!--指标越限程度 -->
|
||||||
|
<TableHeader
|
||||||
|
ref="TableHeaderRef"
|
||||||
|
:showReset="false"
|
||||||
|
@selectChange="selectChange"
|
||||||
|
datePicker
|
||||||
|
:timeKeyList="prop.timeKey"
|
||||||
|
v-if="fullscreen"
|
||||||
|
></TableHeader>
|
||||||
<my-echart
|
<my-echart
|
||||||
class="tall"
|
class="tall"
|
||||||
:options="echartList"
|
:options="echartList"
|
||||||
:style="{ width: prop.width, height: `calc(${prop.height} / 2 )` }"
|
:style="{ width: prop.width, height: `calc(${prop.height} / 2 )` }"
|
||||||
/>
|
/>
|
||||||
<Table ref="tableRef" @cell-click="cellClickEvent" :height="`calc(${prop.height} / 2 )`" isGroup></Table>
|
<Table
|
||||||
<!-- 指标越限详情 -->
|
ref="tableRef"
|
||||||
<OverLimitDetails ref="OverLimitDetailsRef" />
|
@cell-click="cellClickEvent"
|
||||||
|
:height="`calc(${prop.height} / 2 - ${headerHeight}px + ${fullscreen ? 0 : 56}px )`"
|
||||||
|
isGroup
|
||||||
|
></Table>
|
||||||
|
<!-- 指标日趋势图 -->
|
||||||
|
<DailyTrendChart v-if="dialogTrendChart" ref="dailyTrendChartRef" @close="dialogTrendChart = false" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
||||||
import TableStore from '@/utils/tableStore'
|
import TableStore from '@/utils/tableStore'
|
||||||
import Table from '@/components/table/index.vue'
|
import Table from '@/components/table/index.vue'
|
||||||
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
import MyEchart from '@/components/echarts/MyEchart.vue'
|
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||||
import { useDictData } from '@/stores/dictData'
|
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
||||||
import { getTimeOfTheMonth } from '@/utils/formatTime'
|
import { getTimeOfTheMonth } from '@/utils/formatTime'
|
||||||
import OverLimitDetails from '@/components/cockpit/listOfMainMonitoringPoints/components/overLimitDetails.vue'
|
import DailyTrendChart from '@/components/cockpit/exceedanceLevel/components/dailyTrendChart.vue'
|
||||||
|
import { getTime } from '@/utils/formatTime'
|
||||||
|
|
||||||
const prop = defineProps({
|
const prop = defineProps({
|
||||||
width: { type: String },
|
w: { type: [String, Number] },
|
||||||
height: { type: String },
|
h: { type: [String, Number] },
|
||||||
timeKey: { type: String },
|
width: { type: [String, Number] },
|
||||||
timeValue: { type: Object }
|
height: { type: [String, Number] },
|
||||||
|
timeKey: { type: Array as () => string[] },
|
||||||
|
timeValue: { type: Object },
|
||||||
|
interval: { type: Number }
|
||||||
})
|
})
|
||||||
const echartList = ref({
|
|
||||||
title: {
|
|
||||||
text: '指标越限严重度'
|
|
||||||
},
|
|
||||||
|
|
||||||
xAxis: {
|
const TableHeaderRef = ref()
|
||||||
// name: '(区域)',
|
|
||||||
data: ['闪变', '谐波电压', '谐波电流', '电压偏差', '三相不平衡']
|
|
||||||
},
|
|
||||||
|
|
||||||
yAxis: {
|
const headerHeight = ref(57)
|
||||||
name: '%', // 给X轴加单位
|
|
||||||
interval: 20
|
|
||||||
},
|
|
||||||
grid: {
|
|
||||||
left: '10px',
|
|
||||||
right: '20px'
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
// name: '暂降次数',
|
|
||||||
type: 'bar',
|
|
||||||
name: '越限占比',
|
|
||||||
data: [0, 7.5, 36, 0, 80],
|
|
||||||
barMaxWidth: 30
|
|
||||||
|
|
||||||
// label: {
|
const dialogTrendChart = ref(false)
|
||||||
// show: true,
|
|
||||||
// position: 'top',
|
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
|
||||||
// textStyle: {
|
headerHeight.value = height
|
||||||
// //数值样式
|
|
||||||
// color: '#000'
|
if (datePickerValue && datePickerValue.timeValue) {
|
||||||
// },
|
// 更新时间参数
|
||||||
// fontSize: 12
|
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
|
||||||
// }
|
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
// 计算是否全屏展示
|
||||||
|
const fullscreen = computed(() => {
|
||||||
|
const w = Number(prop.w)
|
||||||
|
const h = Number(prop.h)
|
||||||
|
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
|
||||||
|
// 执行相应逻辑
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const OverLimitDetailsRef = ref()
|
|
||||||
|
const echartList = ref()
|
||||||
|
|
||||||
|
const dailyTrendChartRef = ref()
|
||||||
const tableStore: any = new TableStore({
|
const tableStore: any = new TableStore({
|
||||||
url: '/user-boot/dept/deptTree',
|
url: '/cs-harmonic-boot/limitRateDetailD/limitExtentData',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|
||||||
showPage: false,
|
showPage: false,
|
||||||
@@ -90,82 +97,106 @@ const tableStore: any = new TableStore({
|
|||||||
|
|
||||||
{
|
{
|
||||||
title: '越限最大值',
|
title: '越限最大值',
|
||||||
field: 'type',
|
field: 'maxValue',
|
||||||
minWidth: '60',
|
minWidth: '70',
|
||||||
render: 'customTemplate',
|
render: 'customTemplate',
|
||||||
customTemplate: (row: any) => {
|
customTemplate: (row: any) => {
|
||||||
return `<span style='cursor: pointer;text-decoration: underline;'>${row.type}</span>`
|
const extentValue =
|
||||||
|
row.maxValue !== null && row.maxValue !== undefined && row.maxValue !== ''
|
||||||
|
? Math.floor(row.maxValue * 100) / 100
|
||||||
|
: '/'
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${extentValue}</span>`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '国标限值',
|
title: '国标限值',
|
||||||
field: 'type1',
|
field: 'internationalValue',
|
||||||
minWidth: '60'
|
minWidth: '60'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '越限程度(%)',
|
title: '越限程度(%)',
|
||||||
field: 'type2',
|
field: 'extent',
|
||||||
minWidth: '60'
|
minWidth: '70',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
// 保留两个小数
|
||||||
|
const extentValue =
|
||||||
|
row.extent !== null && row.extent !== undefined && row.extent !== ''
|
||||||
|
? Math.floor(row.extent * 100) / 100
|
||||||
|
: '/'
|
||||||
|
return `<span>${extentValue}</span>`
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '发生日期',
|
title: '越限时间',
|
||||||
field: 'type3',
|
field: 'time',
|
||||||
minWidth: '100'
|
minWidth: '60',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
if (row.time !== null && row.time !== undefined && row.time !== '') {
|
||||||
|
return `<span>${row.time}</span>`
|
||||||
|
} else {
|
||||||
|
return `<span>/</span>`
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '越限最高监测点',
|
title: '越限最高监测点',
|
||||||
field: 'type4',
|
field: 'lineName',
|
||||||
minWidth: '90'
|
minWidth: '90',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
if (row.lineName !== null && row.lineName !== undefined && row.lineName !== '') {
|
||||||
|
return `<span>${row.lineName}</span>`
|
||||||
|
} else {
|
||||||
|
return `<span>/</span>`
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
beforeSearchFun: () => {
|
beforeSearchFun: () => {
|
||||||
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
|
setTime()
|
||||||
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
|
|
||||||
},
|
},
|
||||||
loadCallback: () => {
|
loadCallback: () => {
|
||||||
tableStore.table.data = [
|
// 定义 x 轴标签顺序
|
||||||
{
|
const xAxisLabels = ['闪变', '谐波电压', '谐波电流', '电压偏差', '三相不平衡']
|
||||||
name: '闪变',
|
|
||||||
type: '0.0',
|
|
||||||
type1: '2.0',
|
|
||||||
type2: '0.0',
|
|
||||||
type3: '/',
|
|
||||||
type4: '/'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '谐波电压',
|
|
||||||
type: '1.72',
|
|
||||||
type1: '1.6',
|
|
||||||
type2: '7.5',
|
|
||||||
type3: '2025-03-09',
|
|
||||||
type4: '10kV1#电动机'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '谐波电流',
|
|
||||||
type: '27.2',
|
|
||||||
type1: '20.0',
|
|
||||||
type2: '36.0',
|
|
||||||
type3: '2025-03-16',
|
|
||||||
type4: '380V电焊机(治理前)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '电压偏差',
|
|
||||||
type: '0.0',
|
|
||||||
type1: '2.0',
|
|
||||||
type2: '0.0',
|
|
||||||
type3: '/',
|
|
||||||
type4: '/'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '三相不平衡',
|
|
||||||
type: '3.6',
|
|
||||||
type1: '2.0',
|
|
||||||
type2: '80.0',
|
|
||||||
type3: '2025-03-01',
|
|
||||||
type4: '380V电焊机(治理前)'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
|
// 根据指标名称顺序提取对应的 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 = {
|
||||||
|
title: {
|
||||||
|
text: '指标越限严重度'
|
||||||
|
},
|
||||||
|
|
||||||
|
xAxis: {
|
||||||
|
data: xAxisLabels
|
||||||
|
},
|
||||||
|
|
||||||
|
yAxis: {
|
||||||
|
name: '%' // 给X轴加单位
|
||||||
|
// interval: 20
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '10px',
|
||||||
|
right: '20px'
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'bar',
|
||||||
|
name: '越限占比',
|
||||||
|
data: chartData,
|
||||||
|
barMaxWidth: 30
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -176,9 +207,30 @@ provide('tableStore', tableStore)
|
|||||||
|
|
||||||
// 点击行
|
// 点击行
|
||||||
const cellClickEvent = ({ row, column }: any) => {
|
const cellClickEvent = ({ row, column }: any) => {
|
||||||
if (column.field != 'name') {
|
dialogTrendChart.value = true
|
||||||
console.log(row)
|
if (column.field == 'maxValue' && row.lineId) {
|
||||||
OverLimitDetailsRef.value.open(row)
|
nextTick(() => {
|
||||||
|
dailyTrendChartRef.value.open(row)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const setTime = () => {
|
||||||
|
const time = getTime(
|
||||||
|
(TableHeaderRef.value?.datePickerRef.interval || prop.interval) ?? 0,
|
||||||
|
prop.timeKey,
|
||||||
|
fullscreen.value
|
||||||
|
? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
|
||||||
|
: prop.timeValue
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(time)) {
|
||||||
|
tableStore.table.params.searchBeginTime = time[0]
|
||||||
|
tableStore.table.params.searchEndTime = time[1]
|
||||||
|
TableHeaderRef.value?.setInterval(time[2] - 0)
|
||||||
|
TableHeaderRef.value?.setTimeInterval([time[0], time[1]])
|
||||||
|
} else {
|
||||||
|
console.warn('获取时间失败,time 不是一个有效数组')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -192,12 +244,12 @@ watch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeValue, // 监听的目标(函数形式避免直接传递 props 导致的警告)
|
() => prop.timeValue,
|
||||||
(newVal, oldVal) => {
|
(newVal, oldVal) => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
deep: true // 若 timeValue 是对象/数组,需开启深度监听
|
deep: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,103 +1,170 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!--治理效果报表 -->
|
<!--治理效果报表 -->
|
||||||
<TableHeader :showReset="false">
|
<TableHeader :showReset="false" :timeKeyList="prop.timeKey" ref="TableHeaderRef" datePicker @selectChange="selectChange" v-if="fullscreen">
|
||||||
<template v-slot:select>
|
<template v-slot:select>
|
||||||
<el-form-item label="治理对象">
|
<el-form-item label="报表模板">
|
||||||
<el-select
|
<el-select filterable v-model="tableStore.table.params.tempId" placeholder="请选择报表模板" clearable>
|
||||||
v-model="tableStore.table.params.power"
|
<el-option v-for="item in templateList" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
placeholder="请选择治理对象"
|
</el-select>
|
||||||
clearable
|
</el-form-item>
|
||||||
style="width: 130px"
|
<el-form-item label="监测对象">
|
||||||
>
|
<el-select filterable v-model="tableStore.table.params.sensitiveUserId" placeholder="请选择监测对象" clearable>
|
||||||
<el-option
|
<el-option v-for="item in idList" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
v-for="item in powerList"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value"
|
|
||||||
/>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
<template v-slot:operation>
|
<template v-slot:operation>
|
||||||
<el-button @click="downloadExcel" class="" type="primary" icon="el-icon-Download">导出excel</el-button>
|
<el-button @click="downloadExcel" class="" type="primary" icon="el-icon-Download">导出</el-button>
|
||||||
</template>
|
</template>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<div style="display: flex">
|
<div style="display: flex">
|
||||||
<div
|
<div
|
||||||
id="luckysheet"
|
id="luckysheet"
|
||||||
:style="{ width: `calc(${prop.width} )`, height: `calc(${prop.height} - 57px )` }"
|
:style="{
|
||||||
|
width: `calc(${prop.width} )`,
|
||||||
|
height: `calc(${prop.height} - 57px + ${fullscreen ? 0 : 56}px)`
|
||||||
|
}"
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
import { ref, onMounted, provide, reactive, watch, h, computed, nextTick } from 'vue'
|
||||||
import TableStore from '@/utils/tableStore'
|
import TableStore from '@/utils/tableStore'
|
||||||
import { exportExcel } from '@/views/govern/reportForms/export.js'
|
import { exportExcel } from '@/views/govern/reportForms/export.js'
|
||||||
import TableHeader from '@/components/table/header/index.vue'
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
import { useDictData } from '@/stores/dictData'
|
import { getTemplateList } from '@/api/harmonic-boot/luckyexcel'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { getListByIds } from '@/api/harmonic-boot/cockpit/cockpit'
|
||||||
import { getTimeOfTheMonth } from '@/utils/formatTime'
|
import { getTime } from '@/utils/formatTime'
|
||||||
import MyEchart from '@/components/echarts/MyEchart.vue'
|
|
||||||
import { useConfig } from '@/stores/config'
|
|
||||||
import Json from './index.json'
|
|
||||||
|
|
||||||
const prop = defineProps({
|
const prop = defineProps({
|
||||||
width: { type: String },
|
w: { type: [String, Number] },
|
||||||
height: { type: String },
|
h: { type: [String, Number] },
|
||||||
timeKey: { type: String },
|
width: { type: [String, Number] },
|
||||||
timeValue: { type: Object }
|
height: { type: [String, Number] },
|
||||||
})
|
timeKey: { type: Array as () => string[] },
|
||||||
const config = useConfig()
|
timeValue: { type: Object },
|
||||||
const powerList: any = ref([
|
interval: { type: Number }
|
||||||
{
|
|
||||||
label: '1#变压器',
|
|
||||||
value: '1'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '2#变压器',
|
|
||||||
value: '2'
|
|
||||||
}
|
|
||||||
])
|
|
||||||
|
|
||||||
const tableStore: any = new TableStore({
|
|
||||||
url: '/user-boot/role/selectRoleDetail?id=0',
|
|
||||||
method: 'POST',
|
|
||||||
|
|
||||||
showPage: false,
|
|
||||||
exportName: '主要监测点列表',
|
|
||||||
column: [],
|
|
||||||
beforeSearchFun: () => {
|
|
||||||
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
|
|
||||||
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
|
|
||||||
},
|
|
||||||
loadCallback: () => {}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const tableRef = ref()
|
const TableHeaderRef = ref()
|
||||||
provide('tableRef', tableRef)
|
|
||||||
tableStore.table.params.power = '1'
|
|
||||||
|
|
||||||
provide('tableStore', tableStore)
|
// 报表模板列表
|
||||||
|
const templateList = ref()
|
||||||
|
|
||||||
|
// 监测对象
|
||||||
|
const idList = ref()
|
||||||
|
|
||||||
|
// 监测对象
|
||||||
|
const initListByIds = () => {
|
||||||
|
getListByIds({}).then((res: any) => {
|
||||||
|
if (res.data.length > 0) {
|
||||||
|
idList.value = res.data
|
||||||
|
|
||||||
|
if (!tableStore.table.params.sensitiveUserId && idList.value?.length > 0) {
|
||||||
|
tableStore.table.params.sensitiveUserId = idList.value[0].id
|
||||||
|
}
|
||||||
|
templateListData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const templateListData = () => {
|
||||||
|
getTemplateList({}).then(res => {
|
||||||
|
templateList.value = res.data.filter(item => item.name === '稳态治理报表')
|
||||||
|
if (!tableStore.table.params.tempId && templateList.value?.length > 0) {
|
||||||
|
tableStore.table.params.tempId = templateList.value[0].id
|
||||||
|
}
|
||||||
|
nextTick(() => {
|
||||||
|
tableStore.index()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
// 下载表格
|
// 下载表格
|
||||||
const downloadExcel = () => {
|
const downloadExcel = () => {
|
||||||
exportExcel(luckysheet.getAllSheets(), '治理效果报表')
|
exportExcel(luckysheet.getAllSheets(), '治理效果报表')
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
|
||||||
luckysheet.create({
|
|
||||||
container: 'luckysheet',
|
|
||||||
title: '', // 表 头名
|
|
||||||
lang: 'zh', // 中文
|
|
||||||
showtoolbar: false, // 是否显示工具栏
|
|
||||||
showinfobar: false, // 是否显示顶部信息栏
|
|
||||||
showsheetbar: true, // 是否显示底部sheet按钮
|
|
||||||
allowEdit: false, // 禁止所有编辑操作(必填)
|
|
||||||
data: Json
|
|
||||||
})
|
|
||||||
|
|
||||||
tableStore.index()
|
onMounted(() => {
|
||||||
|
initListByIds()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
|
||||||
|
if (datePickerValue && datePickerValue.timeValue) {
|
||||||
|
// 更新时间参数
|
||||||
|
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
|
||||||
|
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算是否全屏展示
|
||||||
|
const fullscreen = computed(() => {
|
||||||
|
const w = Number(prop.w)
|
||||||
|
const h = Number(prop.h)
|
||||||
|
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
|
||||||
|
// 执行相应逻辑
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const tableStore: any = new TableStore({
|
||||||
|
url: '/cs-harmonic-boot/customReport/getSensitiveUserReport',
|
||||||
|
method: 'POST',
|
||||||
|
showPage: false,
|
||||||
|
exportName: '治理效果报表',
|
||||||
|
column: [],
|
||||||
|
beforeSearchFun: () => {
|
||||||
|
setTime()
|
||||||
|
if (!tableStore.table.params.sensitiveUserId && idList.value?.length > 0) {
|
||||||
|
tableStore.table.params.sensitiveUserId = idList.value[0].id
|
||||||
|
}
|
||||||
|
if (!tableStore.table.params.tempId && templateList.value?.length > 0) {
|
||||||
|
tableStore.table.params.tempId = templateList.value[0].id
|
||||||
|
}
|
||||||
|
},
|
||||||
|
loadCallback: () => {
|
||||||
|
luckysheet.create({
|
||||||
|
container: 'luckysheet',
|
||||||
|
title: '', // 表 头名
|
||||||
|
lang: 'zh', // 中文
|
||||||
|
showtoolbar: false, // 是否显示工具栏
|
||||||
|
showinfobar: false, // 是否显示顶部信息栏
|
||||||
|
showsheetbar: true, // 是否显示底部sheet按钮
|
||||||
|
allowEdit: false, // 禁止所有编辑操作(必填)
|
||||||
|
data: tableStore.table.data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const tableRef = ref()
|
||||||
|
provide('tableRef', tableRef)
|
||||||
|
|
||||||
|
provide('tableStore', tableStore)
|
||||||
|
|
||||||
|
const setTime = () => {
|
||||||
|
const time = getTime(
|
||||||
|
(TableHeaderRef.value?.datePickerRef.interval || prop.interval) ?? 0,
|
||||||
|
prop.timeKey,
|
||||||
|
fullscreen.value
|
||||||
|
? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
|
||||||
|
: prop.timeValue
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(time)) {
|
||||||
|
tableStore.table.params.searchBeginTime = time[0]
|
||||||
|
tableStore.table.params.searchEndTime = time[1]
|
||||||
|
tableStore.table.params.startTime = time[0]
|
||||||
|
tableStore.table.params.endTime = time[1]
|
||||||
|
TableHeaderRef.value?.setInterval(time[2] - 0)
|
||||||
|
TableHeaderRef.value?.setTimeInterval([time[0], time[1]])
|
||||||
|
} else {
|
||||||
|
console.warn('获取时间失败,time 不是一个有效数组')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeKey,
|
() => prop.timeKey,
|
||||||
val => {
|
val => {
|
||||||
@@ -105,20 +172,17 @@ watch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeValue, // 监听的目标(函数形式避免直接传递 props 导致的警告)
|
() => prop.timeValue,
|
||||||
(newVal, oldVal) => {
|
(newVal, oldVal) => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
deep: true // 若 timeValue 是对象/数组,需开启深度监听
|
deep: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const addMenu = () => {}
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
:deep(.el-select) {
|
// :deep(.el-select) {
|
||||||
min-width: 80px;
|
// min-width: 80px;
|
||||||
}
|
// }
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -0,0 +1,708 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog draggable title="趋势图" v-model="dialogVisible" append-to-body width="70%">
|
||||||
|
<!-- 总体指标占比详情谐波含有率 -->
|
||||||
|
<div>
|
||||||
|
<TableHeader ref="tableHeaderRef" :showSearch="false" @selectChange="selectChange">
|
||||||
|
<template v-slot:select>
|
||||||
|
<el-form-item>
|
||||||
|
<DatePicker ref="datePickerRef"></DatePicker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="统计指标" label-width="80px">
|
||||||
|
<el-select
|
||||||
|
multiple
|
||||||
|
:multiple-limit="2"
|
||||||
|
collapse-tags
|
||||||
|
collapse-tags-tooltip
|
||||||
|
v-model="searchForm.index"
|
||||||
|
placeholder="请选择统计指标"
|
||||||
|
@change="onIndexChange($event)"
|
||||||
|
filterable
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in indexOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-radio-group v-model="searchForm.dataLevel" @change="init()">
|
||||||
|
<el-radio-button label="一次值" value="Primary" />
|
||||||
|
<el-radio-button label="二次值" value="Secondary" />
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="统计类型">
|
||||||
|
<el-select
|
||||||
|
style="min-width: 120px !important"
|
||||||
|
placeholder="请选择"
|
||||||
|
v-model="searchForm.valueType"
|
||||||
|
filterable
|
||||||
|
>
|
||||||
|
<el-option value="max" label="最大值"></el-option>
|
||||||
|
<el-option value="min" label="最小值"></el-option>
|
||||||
|
<el-option value="avg" label="平均值"></el-option>
|
||||||
|
<el-option value="cp95" label="cp95"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<div
|
||||||
|
class="history_count"
|
||||||
|
v-for="(item, index) in countData"
|
||||||
|
:key="index"
|
||||||
|
v-show="item.countOptions.length != 0"
|
||||||
|
>
|
||||||
|
<span class="mr12">
|
||||||
|
{{ item.name.includes('次数') ? item.name : item.name + '谐波次数' }}
|
||||||
|
</span>
|
||||||
|
<el-select
|
||||||
|
v-model="item.count"
|
||||||
|
@change="onCountChange($event, index)"
|
||||||
|
placeholder="请选择谐波次数"
|
||||||
|
style="width: 100px"
|
||||||
|
class="mr20"
|
||||||
|
filterable
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="vv in item.countOptions"
|
||||||
|
:key="vv"
|
||||||
|
:label="vv"
|
||||||
|
:value="vv"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
<template #operation>
|
||||||
|
<el-button type="primary" icon="el-icon-Search" @click="init()">查询</el-button>
|
||||||
|
<el-button :type="timeControl ? 'primary' : ''" icon="el-icon-Sort" @click="setTimeControl">
|
||||||
|
缺失数据
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</TableHeader>
|
||||||
|
</div>
|
||||||
|
<div class="history_chart" :style="pageHeight" v-loading="loading">
|
||||||
|
<MyEchart
|
||||||
|
ref="historyChart"
|
||||||
|
:options="echartsData"
|
||||||
|
v-if="showEchart"
|
||||||
|
/>
|
||||||
|
<el-empty :style="pageHeight" v-else description="暂无数据" />
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { mainHeight } from '@/utils/layout'
|
||||||
|
import { queryByCode, queryCsDictTree } from '@/api/system-boot/dictTree'
|
||||||
|
import { ref, onMounted, watch } from 'vue'
|
||||||
|
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||||
|
import { useDictData } from '@/stores/dictData'
|
||||||
|
import { queryStatistical } from '@/api/system-boot/csstatisticalset'
|
||||||
|
import { yMethod, exportCSV, completeTimeSeries } from '@/utils/echartMethod'
|
||||||
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
|
import { trendData } from '@/api/harmonic-boot/cockpit/cockpit'
|
||||||
|
import DatePicker from '@/components/form/datePicker/index.vue'
|
||||||
|
import { color } from '@/components/echarts/color'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
const dictData = useDictData()
|
||||||
|
defineOptions({
|
||||||
|
// name: 'govern/device/control'
|
||||||
|
})
|
||||||
|
const props = defineProps({
|
||||||
|
TrendList: {
|
||||||
|
type: Array
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const dialogVisible: any = ref(false)
|
||||||
|
// console.log("🚀 ~ props:", props.TrendList)
|
||||||
|
const showEchart = ref(true)
|
||||||
|
const num = ref(0)
|
||||||
|
const timeControl = ref(false)
|
||||||
|
//值类型
|
||||||
|
const pageHeight = ref(mainHeight(57 * 1.6, 1.6))
|
||||||
|
const loading = ref(true)
|
||||||
|
const searchForm: any = ref({})
|
||||||
|
const tableHeaderRef = ref()
|
||||||
|
const typeOptions = [
|
||||||
|
{
|
||||||
|
name: '平均值',
|
||||||
|
id: 'avg'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '最大值',
|
||||||
|
id: 'max'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '最小值',
|
||||||
|
id: 'min'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'CP95值',
|
||||||
|
id: 'cp95'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
searchForm.value = {
|
||||||
|
index: [],
|
||||||
|
type: typeOptions[0].id,
|
||||||
|
count: '',
|
||||||
|
searchBeginTime: '',
|
||||||
|
searchEndTime: '',
|
||||||
|
dataLevel: 'Primary',
|
||||||
|
valueType: 'avg'
|
||||||
|
}
|
||||||
|
//统计指标
|
||||||
|
const indexOptions: any = ref([])
|
||||||
|
//谐波次数
|
||||||
|
const countOptions: any = ref([])
|
||||||
|
// Harmonic_Type
|
||||||
|
// portable-harmonic
|
||||||
|
const legendDictList: any = ref([])
|
||||||
|
|
||||||
|
const initCode = (field: string, title: string) => {
|
||||||
|
queryByCode('steady_state_limit_trend').then(res => {
|
||||||
|
queryCsDictTree(res.data.id).then(item => {
|
||||||
|
//排序
|
||||||
|
indexOptions.value = item.data.sort((a: any, b: any) => {
|
||||||
|
return a.sort - b.sort
|
||||||
|
})
|
||||||
|
const titleMap: Record<string, number> = {
|
||||||
|
flickerOvertime: 0,
|
||||||
|
uaberranceOvertime: 3,
|
||||||
|
ubalanceOvertime: 4,
|
||||||
|
freqDevOvertime: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
let defaultIndex = 0 // 默认值
|
||||||
|
|
||||||
|
if (field in titleMap) {
|
||||||
|
defaultIndex = titleMap[field]
|
||||||
|
} else if (field.includes('uharm')) {
|
||||||
|
defaultIndex = 1
|
||||||
|
} else if (field.includes('iharm')) {
|
||||||
|
defaultIndex = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
searchForm.value.index[0] = indexOptions.value[defaultIndex].id
|
||||||
|
})
|
||||||
|
queryStatistical(res.data.id).then(vv => {
|
||||||
|
legendDictList.value = vv.data
|
||||||
|
indexOptions.value.map((item: any, index: any) => {
|
||||||
|
if (!countDataCopy.value[index]) {
|
||||||
|
countDataCopy.value[index] = {
|
||||||
|
index: item.id,
|
||||||
|
countOptions: [],
|
||||||
|
count: [],
|
||||||
|
name: indexOptions.value.find((vv: any) => {
|
||||||
|
return vv.id == item.id
|
||||||
|
})?.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
legendDictList.value?.selectedList?.map((vv: any, vvs: any) => {
|
||||||
|
//查找相等的指标
|
||||||
|
if (item.id == vv.dataType) {
|
||||||
|
vv.eleEpdPqdVOS.map((kk: any, kks: any) => {
|
||||||
|
if (kk.harmStart && kk.harmEnd) {
|
||||||
|
range(0, 0, 0)
|
||||||
|
|
||||||
|
if (kk.showName == '间谐波电压含有率') {
|
||||||
|
countDataCopy.value[index].countOptions = range(kk.harmStart, kk.harmEnd, 1).map(
|
||||||
|
(item: any) => {
|
||||||
|
return item - 0.5
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
countDataCopy.value[index].countOptions = range(kk.harmStart, kk.harmEnd, 1)
|
||||||
|
}
|
||||||
|
if (title && countDataCopy.value[index].countOptions.includes(Number(title))) {
|
||||||
|
countDataCopy.value[index].count = Number(title)
|
||||||
|
} else if (title && countDataCopy.value[index].countOptions.includes(title)) {
|
||||||
|
countDataCopy.value[index].count = title
|
||||||
|
} else if (
|
||||||
|
!countDataCopy.value[index].count ||
|
||||||
|
countDataCopy.value[index].count.length == 0
|
||||||
|
) {
|
||||||
|
// 只有当count为空时才设置默认值
|
||||||
|
countDataCopy.value[index].count = countDataCopy.value[index].countOptions[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
nextTick(() => {
|
||||||
|
formatCountOptions()
|
||||||
|
})
|
||||||
|
init()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const chartsList = ref<any>([])
|
||||||
|
const chartTitle: any = ref('')
|
||||||
|
const echartsData = ref<any>(null)
|
||||||
|
//加载echarts图表
|
||||||
|
//历史趋势数据
|
||||||
|
const historyDataList: any = ref([])
|
||||||
|
const range = (start: any, end: any, step: any) => {
|
||||||
|
return Array.from({ length: (end - start) / step + 1 }, (_, i) => start + i * step)
|
||||||
|
}
|
||||||
|
//获取请求趋势数据参数
|
||||||
|
const trendRequestData = ref()
|
||||||
|
const getTrendRequest = (val: any) => {
|
||||||
|
trendRequestData.value = val
|
||||||
|
// init()
|
||||||
|
}
|
||||||
|
//初始化趋势图
|
||||||
|
const headerRef = ref()
|
||||||
|
const datePickerRef = ref()
|
||||||
|
const lineStyle = [{ type: 'solid' }, { type: 'dashed' }, { type: 'dotted' }]
|
||||||
|
const init = async () => {
|
||||||
|
loading.value = true
|
||||||
|
// 选择指标的时候切换legend内容和data数据
|
||||||
|
let list: any = []
|
||||||
|
legendDictList.value?.selectedList?.map((item: any) => {
|
||||||
|
searchForm.value.index.map((vv: any) => {
|
||||||
|
if (item.dataType == vv) {
|
||||||
|
list.push(item.eleEpdPqdVOS)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
//颜色数组
|
||||||
|
const colorList = color
|
||||||
|
//选择的指标使用方法处理
|
||||||
|
formatCountOptions()
|
||||||
|
//查询历史趋势
|
||||||
|
historyDataList.value = []
|
||||||
|
chartTitle.value = ''
|
||||||
|
|
||||||
|
searchForm.value.index.map((item: any, indexs: any) => {
|
||||||
|
indexOptions.value.map((vv: any) => {
|
||||||
|
if (vv.id == item) {
|
||||||
|
chartTitle.value += indexs == searchForm.value.index.length - 1 ? vv.name : vv.name + '/'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
let lists: any = []
|
||||||
|
let frequencys: any = null
|
||||||
|
countData.value.map((item: any, index: any) => {
|
||||||
|
if (item.name.includes('谐波含有率')) {
|
||||||
|
frequencys = item.count
|
||||||
|
} else {
|
||||||
|
frequencys = ''
|
||||||
|
}
|
||||||
|
lists[index] = {
|
||||||
|
statisticalId: item.index,
|
||||||
|
frequency: frequencys !== null && frequencys !== undefined ? String(frequencys) : ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
let obj = {
|
||||||
|
//...trendRequestData.value,
|
||||||
|
lineId: trendRequestData.value.lineId,
|
||||||
|
list: lists,
|
||||||
|
dataLevel: searchForm.value.dataLevel,
|
||||||
|
valueType: searchForm.value.valueType,
|
||||||
|
searchBeginTime: datePickerRef.value && datePickerRef.value.timeValue[0],
|
||||||
|
searchEndTime: datePickerRef.value && datePickerRef.value.timeValue[1]
|
||||||
|
}
|
||||||
|
if (searchForm.value.index.length == 0) {
|
||||||
|
ElMessage.warning('请选择统计指标')
|
||||||
|
loading.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (obj.list.length != 0) {
|
||||||
|
try {
|
||||||
|
showEchart.value = true
|
||||||
|
await trendData(obj)
|
||||||
|
.then((res: any) => {
|
||||||
|
if (res.code == 'A0000') {
|
||||||
|
if (res.data.length == 0) {
|
||||||
|
loading.value = false
|
||||||
|
showEchart.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
historyDataList.value = res.data
|
||||||
|
chartsList.value = JSON.parse(JSON.stringify(res.data))
|
||||||
|
loading.value = false
|
||||||
|
setEchart()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const setEchart = () => {
|
||||||
|
loading.value = true
|
||||||
|
echartsData.value = {}
|
||||||
|
//icon图标替换legend图例
|
||||||
|
|
||||||
|
// y轴单位数组
|
||||||
|
let unitList: any = []
|
||||||
|
|
||||||
|
let groupedData = chartsList.value.reduce((acc: any, item: any) => {
|
||||||
|
let key = ''
|
||||||
|
if (item.phase == null) {
|
||||||
|
key = item.unit
|
||||||
|
} else {
|
||||||
|
key = item.anotherName
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!acc[key]) {
|
||||||
|
acc[key] = []
|
||||||
|
}
|
||||||
|
acc[key].push(item)
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
let result = Object.values(groupedData)
|
||||||
|
if (chartsList.value.length > 0) {
|
||||||
|
unitList = result.map((item: any) => {
|
||||||
|
return item[0].unit
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
echartsData.value = {
|
||||||
|
legend: {
|
||||||
|
itemWidth: 20,
|
||||||
|
itemHeight: 20,
|
||||||
|
itemStyle: { opacity: 0 }, //去圆点
|
||||||
|
type: 'scroll', // 开启滚动分页
|
||||||
|
// orient: 'vertical', // 垂直排列
|
||||||
|
top: 5,
|
||||||
|
right: 70
|
||||||
|
// width: 550,
|
||||||
|
// height: 50
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
top: '80px'
|
||||||
|
},
|
||||||
|
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,
|
||||||
|
formatter(params: any) {
|
||||||
|
const xname = params[0].value[0]
|
||||||
|
let str = `${xname}<br>`
|
||||||
|
params.forEach((el: any, index: any) => {
|
||||||
|
let marker = ''
|
||||||
|
|
||||||
|
if (el.value[3] == 'dashed') {
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
marker += `<span style="display:inline-block;border: 2px ${el.color} solid;margin-right:5px;width:10px;height:0px;background-color:#ffffff00;"></span>`
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
marker = `<span style="display:inline-block;border: 2px ${el.color} ${el.value[3]};margin-right:5px;width:40px;height:0px;background-color:#ffffff00;"></span>`
|
||||||
|
}
|
||||||
|
let unit = el.value[2] ? el.value[2] : ''
|
||||||
|
str += `${marker}${el.seriesName.split('(')[0]}:${el.value[1]}${unit}
|
||||||
|
<br>`
|
||||||
|
})
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
},
|
||||||
|
color: ['#DAA520', '#2E8B57', '#A52a2a', ...color],
|
||||||
|
xAxis: {
|
||||||
|
type: 'time',
|
||||||
|
axisLabel: {
|
||||||
|
formatter: {
|
||||||
|
day: '{MM}-{dd}',
|
||||||
|
month: '{MM}',
|
||||||
|
year: '{yyyy}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: [{}],
|
||||||
|
toolbox: {
|
||||||
|
featureProps: {
|
||||||
|
myTool1: {
|
||||||
|
show: true,
|
||||||
|
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',
|
||||||
|
onclick: e => {
|
||||||
|
// console.log("🚀 ~ init ~ echartsData.value:", echartsData.value.options.series.map(item => item.data))
|
||||||
|
|
||||||
|
let list = echartsData.value.options.series?.map((item: any) => item.data)
|
||||||
|
let dataList = list[0]?.map((item: any, index: any) => {
|
||||||
|
let value = [item[0], item[1]]
|
||||||
|
list.forEach((item1: any, index1: any) => {
|
||||||
|
if (index1 > 0) {
|
||||||
|
value.push(item1 && item1[index] ? item1[index][1] : null)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return value
|
||||||
|
})
|
||||||
|
exportCSV(
|
||||||
|
echartsData.value.options.series.map((item: any) => item.name),
|
||||||
|
dataList,
|
||||||
|
'监测点指标趋势.csv'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
series: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// console.log("🚀 ~ unitList.forEach ~ unitList:", unitList)
|
||||||
|
|
||||||
|
if (chartsList.value.length > 0) {
|
||||||
|
let yData: any = []
|
||||||
|
echartsData.value.yAxis = []
|
||||||
|
let setList = [...new Set(unitList)]
|
||||||
|
|
||||||
|
setList.forEach((item: any, index: any) => {
|
||||||
|
if (index > 2) {
|
||||||
|
echartsData.value.grid.right = (index - 1) * 80
|
||||||
|
}
|
||||||
|
yData.push([])
|
||||||
|
let right = {
|
||||||
|
position: 'right',
|
||||||
|
offset: (index - 1) * 80
|
||||||
|
}
|
||||||
|
// console.log("🚀 ~ unitList.forEach ~ right.index:", index)
|
||||||
|
echartsData.value.yAxis.push({
|
||||||
|
name: item,
|
||||||
|
yAxisIndex: index,
|
||||||
|
splitNumber: 5,
|
||||||
|
minInterval: 1,
|
||||||
|
splitLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
...(index > 0 ? right : null)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// console.log("🚀 ~ result.forEach ~ result:", result)
|
||||||
|
// '电压负序分量', '电压正序分量', '电压零序分量'
|
||||||
|
let ABCName = [
|
||||||
|
...new Set(
|
||||||
|
chartsList.value.map((item: any) => {
|
||||||
|
return item.anotherName == '电压负序分量'
|
||||||
|
? '电压不平衡'
|
||||||
|
: item.anotherName == '电压正序分量'
|
||||||
|
? '电压不平衡'
|
||||||
|
: item.anotherName == '电压零序分量'
|
||||||
|
? '电压不平衡'
|
||||||
|
: item.anotherName
|
||||||
|
})
|
||||||
|
)
|
||||||
|
]
|
||||||
|
// console.log("🚀 ~ .then ~ ABCName:", ABCName)
|
||||||
|
result.forEach((item: any, index: any) => {
|
||||||
|
let yMethodList: any = []
|
||||||
|
|
||||||
|
let ABCList = Object.values(
|
||||||
|
item.reduce((acc, item) => {
|
||||||
|
let key = ''
|
||||||
|
if (item.phase == null) {
|
||||||
|
key = item.anotherName
|
||||||
|
} else {
|
||||||
|
key = item.phase
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!acc[key]) {
|
||||||
|
acc[key] = []
|
||||||
|
}
|
||||||
|
acc[key].push(item)
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
)
|
||||||
|
// console.log("🚀 ~ ABCList.forEach ~ ABCList:", ABCList)
|
||||||
|
|
||||||
|
ABCList.forEach((kk: any) => {
|
||||||
|
let colorName = kk[0].phase?.charAt(0).toUpperCase()
|
||||||
|
let lineS = ABCName.findIndex(
|
||||||
|
item =>
|
||||||
|
item ===
|
||||||
|
(kk[0].anotherName == '电压负序分量'
|
||||||
|
? '电压不平衡'
|
||||||
|
: kk[0].anotherName == '电压正序分量'
|
||||||
|
? '电压不平衡'
|
||||||
|
: kk[0].anotherName == '电压零序分量'
|
||||||
|
? '电压不平衡'
|
||||||
|
: kk[0].anotherName)
|
||||||
|
)
|
||||||
|
|
||||||
|
let seriesList: any = []
|
||||||
|
kk.forEach((cc: any) => {
|
||||||
|
if (cc.statisticalData !== null) {
|
||||||
|
yData[setList.indexOf(kk[0].unit)].push(cc.statisticalData?.toFixed(2))
|
||||||
|
}
|
||||||
|
|
||||||
|
seriesList.push([cc.time, cc.statisticalData?.toFixed(2), cc.unit, lineStyle[lineS].type])
|
||||||
|
})
|
||||||
|
// console.log(kk);
|
||||||
|
|
||||||
|
echartsData.value.options.series.push({
|
||||||
|
name: kk[0].phase ? kk[0].phase + '相' + kk[0].anotherName : kk[0].anotherName,
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
color:
|
||||||
|
colorName == 'A' ? '#DAA520' : colorName == 'B' ? '#2E8B57' : colorName == 'C' ? '#A52a2a' : '',
|
||||||
|
symbol: 'none',
|
||||||
|
// data: seriesList,
|
||||||
|
data: timeControl.value ? completeTimeSeries(seriesList) : seriesList,
|
||||||
|
lineStyle: lineStyle[lineS],
|
||||||
|
yAxisIndex: setList.indexOf(kk[0].unit)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
yData.forEach((item: any, index: any) => {
|
||||||
|
let [min, max] = yMethod(item)
|
||||||
|
echartsData.value.yAxis[index].min = min
|
||||||
|
echartsData.value.yAxis[index].max = max
|
||||||
|
})
|
||||||
|
// console.log("🚀 ~ result.forEach ~ echartsData.value:", echartsData.value)
|
||||||
|
}
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
const setTimeControl = () => {
|
||||||
|
timeControl.value = !timeControl.value
|
||||||
|
setEchart()
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectChange = (flag: boolean, height: any) => {
|
||||||
|
pageHeight.value = mainHeight(height * 1.6, 1.6)
|
||||||
|
}
|
||||||
|
//导出
|
||||||
|
const historyChart = ref()
|
||||||
|
|
||||||
|
const countData: any = ref([])
|
||||||
|
const countDataCopy: any = ref([])
|
||||||
|
|
||||||
|
//根据选择的指标处理谐波次数
|
||||||
|
const formatCountOptions = () => {
|
||||||
|
countData.value = []
|
||||||
|
if (searchForm.value.index.length != 0) {
|
||||||
|
searchForm.value.index.forEach((item: any, index: any) => {
|
||||||
|
countDataCopy.value.forEach((vv: any, vvs: any) => {
|
||||||
|
if (vv.index == item) {
|
||||||
|
countData.value.push(vv)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
countData.value.map((item: any, key: any) => {
|
||||||
|
if (item.name == '谐波电流有效值') {
|
||||||
|
item.name = '谐波电流次数'
|
||||||
|
} else if (item.name == '谐波电压含有率') {
|
||||||
|
item.name = '谐波电压次数'
|
||||||
|
} else if (item.name == '间谐波电压含有率') {
|
||||||
|
item.name = '间谐波电压次数'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// setTimeout(() => {
|
||||||
|
// tableHeaderRef.value.computedSearchRow()
|
||||||
|
// }, 500)
|
||||||
|
}
|
||||||
|
// 判断下拉框是否存在
|
||||||
|
const onCountChange = (val: any, index: any) => {
|
||||||
|
if (val.length == 0) {
|
||||||
|
countData.value[index].count = countData.value[index].countOptions[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const flag = ref(true)
|
||||||
|
const onIndexChange = (val: any) => {
|
||||||
|
num.value += 1
|
||||||
|
let pp: any = []
|
||||||
|
indexOptions.value.forEach((item: any) => {
|
||||||
|
const filteredResult = val.filter(vv => item.id == vv)
|
||||||
|
if (filteredResult.length > 0) {
|
||||||
|
pp.push(filteredResult[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
searchForm.value.index = pp
|
||||||
|
flag.value = true
|
||||||
|
formatCountOptions()
|
||||||
|
}
|
||||||
|
watch(
|
||||||
|
() => searchForm.value.index,
|
||||||
|
(val: any, oldval: any) => {},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const openDialog = async (row: any, field: any, title: any) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
trendRequestData.value = row
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
// 默认当天
|
||||||
|
datePickerRef.value.setInterval(5)
|
||||||
|
datePickerRef.value.timeValue = [row.time, row.time]
|
||||||
|
initCode(field, title)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ getTrendRequest, openDialog })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.history_header {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
// flex-wrap: wrap;
|
||||||
|
#history_select {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
// justify-content: flex-start;
|
||||||
|
// overflow-x: auto;
|
||||||
|
height: auto;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
.el-form-item {
|
||||||
|
flex: none !important;
|
||||||
|
// max-width: 380px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-select {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #history_select::-webkit-scrollbar {
|
||||||
|
// width: 0 !important;
|
||||||
|
// display: none !important;
|
||||||
|
// }
|
||||||
|
|
||||||
|
.history_searchBtn {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.history_chart {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
// flex: 1;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history_count {
|
||||||
|
.el-select {
|
||||||
|
min-width: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,186 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<!-- 指标越限详情 -->
|
||||||
|
<el-dialog draggable title="指标越限详情" v-model="dialogVisible" append-to-body width="70%">
|
||||||
|
<TableHeader datePicker showExport :showReset="false" ref="tableHeaderRef">
|
||||||
|
<template v-slot:select>
|
||||||
|
<el-form-item label="监测点">
|
||||||
|
<el-select
|
||||||
|
v-model="tableStore.table.params.lineId"
|
||||||
|
placeholder="请选择监测点"
|
||||||
|
style="width: 150px"
|
||||||
|
filterable
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in options"
|
||||||
|
:key="item.lineId"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.lineId"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</TableHeader>
|
||||||
|
<Table ref="tableRef" @cell-click="cellClickEvent" isGroup :height="height"></Table>
|
||||||
|
</el-dialog>
|
||||||
|
<!-- 谐波电流、谐波电压占有率 -->
|
||||||
|
<HarmonicRatio ref="harmonicRatioRef" v-if="dialogFlag" @close="onHarmonicRatioClose" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, provide,nextTick } from 'vue'
|
||||||
|
import Table from '@/components/table/index.vue'
|
||||||
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
|
import TableStore from '@/utils/tableStore'
|
||||||
|
import { mainHeight } from '@/utils/layout'
|
||||||
|
import HarmonicRatio from '@/components/cockpit/gridSideStatistics/components/harmonicRatio.vue'
|
||||||
|
import { cslineList } from '@/api/harmonic-boot/cockpit/cockpit'
|
||||||
|
|
||||||
|
const dialogVisible: any = ref(false)
|
||||||
|
const harmonicRatioRef: any = ref(null)
|
||||||
|
|
||||||
|
const options = ref()
|
||||||
|
const height = mainHeight(0, 2).height as any
|
||||||
|
const tableHeaderRef = ref()
|
||||||
|
const dialogFlag = ref(false)
|
||||||
|
const loop50 = (key: string) => {
|
||||||
|
let list: any[] = []
|
||||||
|
for (let i = 2; i < 26; i++) {
|
||||||
|
list.push({
|
||||||
|
title: i + '次',
|
||||||
|
field: key + i + 'Overtime',
|
||||||
|
width: '60',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row[key + i + 'Overtime']}</span>`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
const tableStore: any = new TableStore({
|
||||||
|
url: '/cs-harmonic-boot/totalLimitStatistics/details',
|
||||||
|
method: 'POST',
|
||||||
|
publicHeight: 30,
|
||||||
|
showPage: false,
|
||||||
|
exportName: '每日越限占比统计',
|
||||||
|
column: [
|
||||||
|
{
|
||||||
|
field: 'index',
|
||||||
|
title: '序号',
|
||||||
|
width: '80',
|
||||||
|
formatter: (row: any) => {
|
||||||
|
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '日期',
|
||||||
|
field: 'time',
|
||||||
|
width: '150',
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '名称',
|
||||||
|
field: 'lineName',
|
||||||
|
width: '150'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '闪变越限(%)',
|
||||||
|
field: 'flickerOvertime',
|
||||||
|
width: '90',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.flickerOvertime}</span>`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '谐波电压越限(%)',
|
||||||
|
children: loop50('uharm')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '谐波电流越限(%)',
|
||||||
|
children: loop50('iharm')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '三相不平衡度越限(%)',
|
||||||
|
field: 'ubalanceOvertime',
|
||||||
|
width: '100',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.ubalanceOvertime}</span>`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '电压偏差越限(%)',
|
||||||
|
field: 'voltageDevOvertime',
|
||||||
|
width: '100',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.uaberranceOvertime}</span>`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '频率偏差越限(%)',
|
||||||
|
field: 'freqDevOvertime',
|
||||||
|
width: '100',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.freqDevOvertime}</span>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
beforeSearchFun: () => {
|
||||||
|
},
|
||||||
|
loadCallback: () => {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
provide('tableStore', tableStore)
|
||||||
|
tableStore.table.params.sortBy = ''
|
||||||
|
tableStore.table.params.orderBy = ''
|
||||||
|
const open = async (row: any,searchBeginTime:any,searchEndTime:any) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
initCSlineList()
|
||||||
|
tableStore.table.params.lineId = row.lineId
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
tableHeaderRef.value.setTimeInterval([searchBeginTime, searchEndTime])
|
||||||
|
tableStore.table.params.searchBeginTime =searchBeginTime
|
||||||
|
tableStore.table.params.searchEndTime = searchEndTime
|
||||||
|
tableStore.index()
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 点击行
|
||||||
|
const cellClickEvent = ({ row, column }: any) => {
|
||||||
|
if (column.field != 'name' && column.field != 'time') {
|
||||||
|
dialogFlag.value = true
|
||||||
|
dialogVisible.value = false
|
||||||
|
nextTick(() => {
|
||||||
|
harmonicRatioRef.value.openDialog(row,column.field,column.title.replace(/次/g, ""))
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 谐波弹窗关闭时的回调
|
||||||
|
const onHarmonicRatioClose = () => {
|
||||||
|
dialogFlag.value = false
|
||||||
|
// 重新打开指标越限详情弹窗
|
||||||
|
nextTick(() => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const initCSlineList = async () => {
|
||||||
|
const res = await cslineList({})
|
||||||
|
options.value = res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
defineExpose({ open })
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@@ -1,13 +1,27 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<!--电网侧指标越限统计 -->
|
<!--电网侧指标越限统计 -->
|
||||||
|
<TableHeader
|
||||||
|
:showReset="false"
|
||||||
|
ref="TableHeaderRef"
|
||||||
|
@selectChange="selectChange"
|
||||||
|
datePicker :timeKeyList="prop.timeKey"
|
||||||
|
v-if="fullscreen"
|
||||||
|
></TableHeader>
|
||||||
<my-echart
|
<my-echart
|
||||||
class="tall"
|
class="tall"
|
||||||
:options="echartList"
|
:options="echartList"
|
||||||
:style="{ width: prop.width, height: `calc(${prop.height} / 2 )` }"
|
:style="{
|
||||||
|
width: prop.width,
|
||||||
|
height: `calc(${prop.height} / 2 )`
|
||||||
|
}"
|
||||||
/>
|
/>
|
||||||
<Table ref="tableRef" @cell-click="cellClickEvent" :height="`calc(${prop.height} / 2 )`" isGroup></Table>
|
<Table
|
||||||
|
ref="tableRef"
|
||||||
|
@cell-click="cellClickEvent"
|
||||||
|
:height="`calc(${prop.height} / 2 - ${headerHeight}px + ${fullscreen ? 0 : 56}px )`"
|
||||||
|
isGroup
|
||||||
|
></Table>
|
||||||
<!-- 指标越限详情 -->
|
<!-- 指标越限详情 -->
|
||||||
<OverLimitDetails ref="OverLimitDetailsRef" />
|
<OverLimitDetails ref="OverLimitDetailsRef" />
|
||||||
</div>
|
</div>
|
||||||
@@ -16,60 +30,102 @@
|
|||||||
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
||||||
import TableStore from '@/utils/tableStore'
|
import TableStore from '@/utils/tableStore'
|
||||||
import Table from '@/components/table/index.vue'
|
import Table from '@/components/table/index.vue'
|
||||||
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
import MyEchart from '@/components/echarts/MyEchart.vue'
|
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||||
import { useDictData } from '@/stores/dictData'
|
import OverLimitDetails from '@/components/cockpit/gridSideStatistics/components/overLimitDetails.vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { gridSideLimitStatisticsData } from '@/api/harmonic-boot/cockpit/cockpit'
|
||||||
import { getTimeOfTheMonth } from '@/utils/formatTime'
|
import { getTime } from '@/utils/formatTime'
|
||||||
import OverLimitDetails from '@/components/cockpit/listOfMainMonitoringPoints/components/overLimitDetails.vue'
|
|
||||||
const prop = defineProps({
|
const prop = defineProps({
|
||||||
width: { type: String },
|
w: { type: [String, Number] },
|
||||||
height: { type: String },
|
h: { type: [String, Number] },
|
||||||
timeKey: { type: String },
|
width: { type: [String, Number] },
|
||||||
timeValue: { type: Object }
|
height: { type: [String, Number] },
|
||||||
|
timeKey: { type: Array as () => string[] },
|
||||||
|
timeValue: { type: Object },
|
||||||
|
interval: { type: Number }
|
||||||
})
|
})
|
||||||
const echartList = ref({
|
|
||||||
title: {
|
|
||||||
text: '指标越限占比'
|
|
||||||
},
|
|
||||||
|
|
||||||
xAxis: {
|
const headerHeight = ref(57)
|
||||||
// name: '(区域)',
|
|
||||||
data: ['闪变', '谐波电压', '谐波电流', '电压偏差', '三相不平衡']
|
|
||||||
},
|
|
||||||
|
|
||||||
yAxis: {
|
const echartList = ref({})
|
||||||
name: '%', // 给X轴加单位
|
|
||||||
interval: 20
|
|
||||||
},
|
|
||||||
grid: {
|
|
||||||
left: '10px',
|
|
||||||
right: '20px'
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
// name: '暂降次数',
|
|
||||||
type: 'bar',
|
|
||||||
name: '越限占比',
|
|
||||||
data: [0, 45, 22, 0, 70],
|
|
||||||
barMaxWidth: 30,
|
|
||||||
|
|
||||||
// label: {
|
const TableHeaderRef = ref()
|
||||||
// show: true,
|
|
||||||
// position: 'top',
|
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
|
||||||
// textStyle: {
|
headerHeight.value = height
|
||||||
// //数值样式
|
|
||||||
// color: '#000'
|
if (datePickerValue && datePickerValue.timeValue) {
|
||||||
// },
|
// 更新时间参数
|
||||||
// fontSize: 12
|
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
|
||||||
// }
|
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
|
||||||
|
// 计算是否全屏展示
|
||||||
|
const fullscreen = computed(() => {
|
||||||
|
const w = Number(prop.w)
|
||||||
|
const h = Number(prop.h)
|
||||||
|
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
|
||||||
|
// 执行相应逻辑
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const initEcharts = () => {
|
||||||
|
gridSideLimitStatisticsData({
|
||||||
|
searchBeginTime: tableStore.table.params.searchBeginTime,
|
||||||
|
searchEndTime: tableStore.table.params.searchEndTime
|
||||||
|
}).then((res: any) => {
|
||||||
|
const dataArray = [res.data.flicker, res.data.uharm, res.data.iharm, res.data.voltageDev, res.data.ubalance]
|
||||||
|
echartList.value = {
|
||||||
|
title: {
|
||||||
|
text: '指标越限占比'
|
||||||
|
},
|
||||||
|
|
||||||
|
xAxis: {
|
||||||
|
// name: '(区域)',
|
||||||
|
data: ['闪变', '谐波电压', '谐波电流', '电压偏差', '三相不平衡']
|
||||||
|
},
|
||||||
|
|
||||||
|
yAxis: {
|
||||||
|
name: '%', // 给X轴加单位
|
||||||
|
interval: 20
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '10px',
|
||||||
|
right: '20px'
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
// name: '暂降次数',
|
||||||
|
type: 'bar',
|
||||||
|
name: '越限占比',
|
||||||
|
data: dataArray,
|
||||||
|
barMaxWidth: 30
|
||||||
|
|
||||||
|
// label: {
|
||||||
|
// show: true,
|
||||||
|
// position: 'top',
|
||||||
|
// textStyle: {
|
||||||
|
// //数值样式
|
||||||
|
// color: '#000'
|
||||||
|
// },
|
||||||
|
// fontSize: 12
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const OverLimitDetailsRef = ref()
|
const OverLimitDetailsRef = ref()
|
||||||
const tableStore: any = new TableStore({
|
const tableStore: any = new TableStore({
|
||||||
url: '/user-boot/dept/deptTree',
|
url: '/cs-harmonic-boot/gridSideLimitStatistics/list',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|
||||||
showPage: false,
|
showPage: false,
|
||||||
@@ -85,7 +141,7 @@ const tableStore: any = new TableStore({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '名称',
|
title: '名称',
|
||||||
field: 'name',
|
field: 'lineName',
|
||||||
minWidth: '90'
|
minWidth: '90'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -93,69 +149,58 @@ const tableStore: any = new TableStore({
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
title: '闪变',
|
title: '闪变',
|
||||||
field: 'type',
|
field: 'flicker',
|
||||||
minWidth: '70',
|
minWidth: '70',
|
||||||
render: 'customTemplate',
|
render: 'customTemplate',
|
||||||
customTemplate: (row: any) => {
|
customTemplate: (row: any) => {
|
||||||
return `<span style='cursor: pointer;text-decoration: underline;'>${row.type}</span>`
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.flicker}</span>`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '谐波电压',
|
title: '谐波电压',
|
||||||
field: 'type1',
|
field: 'uharm',
|
||||||
minWidth: '80',
|
minWidth: '80',
|
||||||
render: 'customTemplate',
|
render: 'customTemplate',
|
||||||
customTemplate: (row: any) => {
|
customTemplate: (row: any) => {
|
||||||
return `<span style='cursor: pointer;text-decoration: underline;'>${row.type1}</span>`
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.uharm}</span>`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '谐波电流',
|
title: '谐波电流',
|
||||||
field: 'type2',
|
field: 'iharm',
|
||||||
minWidth: '80',
|
minWidth: '80',
|
||||||
render: 'customTemplate',
|
render: 'customTemplate',
|
||||||
customTemplate: (row: any) => {
|
customTemplate: (row: any) => {
|
||||||
return `<span style='cursor: pointer;text-decoration: underline;'>${row.type2}</span>`
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.iharm}</span>`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '电压偏差',
|
title: '电压偏差',
|
||||||
field: 'type3',
|
field: 'voltageDev',
|
||||||
minWidth: '80',
|
minWidth: '80',
|
||||||
render: 'customTemplate',
|
render: 'customTemplate',
|
||||||
customTemplate: (row: any) => {
|
customTemplate: (row: any) => {
|
||||||
return `<span style='cursor: pointer;text-decoration: underline;'>${row.type3}</span>`
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.voltageDev}</span>`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '三相不平衡',
|
title: '三相不平衡',
|
||||||
field: 'type4',
|
field: 'ubalance',
|
||||||
minWidth: '90',
|
minWidth: '90',
|
||||||
render: 'customTemplate',
|
render: 'customTemplate',
|
||||||
customTemplate: (row: any) => {
|
customTemplate: (row: any) => {
|
||||||
return `<span style='cursor: pointer;text-decoration: underline;'>${row.type4}</span>`
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.ubalance}</span>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
beforeSearchFun: () => {
|
beforeSearchFun: () => {
|
||||||
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
|
setTime()
|
||||||
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
|
|
||||||
},
|
},
|
||||||
loadCallback: () => {
|
loadCallback: () => {
|
||||||
tableStore.table.data = [
|
|
||||||
{
|
|
||||||
name: '1#变压器电网侧',
|
|
||||||
type: '0',
|
|
||||||
type1: '45',
|
|
||||||
type2: '22',
|
|
||||||
type3: '0',
|
|
||||||
type4: '70'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
tableStore.table.height = `calc(${prop.height} - 80px)`
|
tableStore.table.height = `calc(${prop.height} - 80px)`
|
||||||
|
initEcharts()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -167,27 +212,50 @@ provide('tableStore', tableStore)
|
|||||||
// 点击行
|
// 点击行
|
||||||
const cellClickEvent = ({ row, column }: any) => {
|
const cellClickEvent = ({ row, column }: any) => {
|
||||||
if (column.field != 'name') {
|
if (column.field != 'name') {
|
||||||
console.log(row)
|
OverLimitDetailsRef.value.open(
|
||||||
OverLimitDetailsRef.value.open(row)
|
row,
|
||||||
|
tableStore.table.params.searchBeginTime || prop.timeValue?.[0],
|
||||||
|
tableStore.table.params.searchEndTime || prop.timeValue?.[1]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const setTime = () => {
|
||||||
|
const time = getTime(
|
||||||
|
(TableHeaderRef.value?.datePickerRef.interval || prop.interval) ?? 0,
|
||||||
|
prop.timeKey,
|
||||||
|
fullscreen.value
|
||||||
|
? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
|
||||||
|
: prop.timeValue
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(time)) {
|
||||||
|
tableStore.table.params.searchBeginTime = time[0]
|
||||||
|
tableStore.table.params.searchEndTime = time[1]
|
||||||
|
TableHeaderRef.value?.setInterval(time[2] - 0)
|
||||||
|
TableHeaderRef.value?.setTimeInterval([time[0], time[1]])
|
||||||
|
} else {
|
||||||
|
console.warn('获取时间失败,time 不是一个有效数组')
|
||||||
|
}
|
||||||
|
}
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeKey,
|
() => prop.timeKey,
|
||||||
val => {
|
val => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
|
initEcharts()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeValue, // 监听的目标(函数形式避免直接传递 props 导致的警告)
|
() => prop.timeValue,
|
||||||
(newVal, oldVal) => {
|
(newVal, oldVal) => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
deep: true // 若 timeValue 是对象/数组,需开启深度监听
|
deep: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
463
src/components/cockpit/indicatorCrossingTime/index.vue
Normal file
463
src/components/cockpit/indicatorCrossingTime/index.vue
Normal file
@@ -0,0 +1,463 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<!--指标越限时间分布
|
||||||
|
-->
|
||||||
|
<TableHeader :showReset="false" :timeKeyList="prop.timeKey" ref="TableHeaderRef" @selectChange="selectChange" datePicker v-if="fullscreen">
|
||||||
|
<template v-slot:select>
|
||||||
|
<el-form-item label="监测点">
|
||||||
|
<el-select size="small" filterable v-model="tableStore.table.params.lineId">
|
||||||
|
<el-option
|
||||||
|
v-for="item in lineList"
|
||||||
|
:key="item.lineId"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.lineId"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</TableHeader>
|
||||||
|
<div v-loading="tableStore.table.loading">
|
||||||
|
<my-echart
|
||||||
|
class="tall"
|
||||||
|
:options="echartList1"
|
||||||
|
:style="{
|
||||||
|
width: prop.width,
|
||||||
|
height: `calc(${prop.height} - ${headerHeight}px + ${fullscreen ? 0 : 56}px)`
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<!-- <my-echart
|
||||||
|
class="mt10"
|
||||||
|
:options="echartList1"
|
||||||
|
:style="{
|
||||||
|
width: prop.width,
|
||||||
|
height: `calc(${prop.height} / 2 - ${headerHeight / 2}px + ${fullscreen ? 0 : 28}px )`
|
||||||
|
}"
|
||||||
|
/> -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
||||||
|
import TableStore from '@/utils/tableStore'
|
||||||
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
|
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||||
|
import { limitProbabilityData, cslineList } from '@/api/harmonic-boot/cockpit/cockpit'
|
||||||
|
import { getTime } from '@/utils/formatTime'
|
||||||
|
|
||||||
|
const prop = defineProps({
|
||||||
|
w: { type: [String, Number] },
|
||||||
|
h: { type: [String, Number] },
|
||||||
|
width: { type: [String, Number] },
|
||||||
|
height: { type: [String, Number] },
|
||||||
|
timeKey: { type: Array as () => string[] },
|
||||||
|
timeValue: { type: Object },
|
||||||
|
interval: { type: Number }
|
||||||
|
})
|
||||||
|
|
||||||
|
// const options = ref(JSON.parse(window.localStorage.getItem('lineIdList') || '[]'))
|
||||||
|
|
||||||
|
const lineList = ref()
|
||||||
|
|
||||||
|
const headerHeight = ref(57)
|
||||||
|
|
||||||
|
const TableHeaderRef = ref()
|
||||||
|
|
||||||
|
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
|
||||||
|
headerHeight.value = height
|
||||||
|
|
||||||
|
if (datePickerValue && datePickerValue.timeValue) {
|
||||||
|
// 更新时间参数
|
||||||
|
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
|
||||||
|
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算是否全屏展示
|
||||||
|
const fullscreen = computed(() => {
|
||||||
|
const w = Number(prop.w)
|
||||||
|
const h = Number(prop.h)
|
||||||
|
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
|
||||||
|
// 执行相应逻辑
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const echartList = ref()
|
||||||
|
|
||||||
|
const echartList1 = ref()
|
||||||
|
|
||||||
|
const probabilityData = ref()
|
||||||
|
|
||||||
|
const initLineList = async () => {
|
||||||
|
cslineList({}).then(res => {
|
||||||
|
lineList.value = res.data
|
||||||
|
tableStore.table.params.lineId = lineList.value[0].lineId
|
||||||
|
tableStore.index()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 越限程度概率分布
|
||||||
|
const initProbabilityData = () => {
|
||||||
|
// 只有当 lineList 已加载且有数据时才设置默认 lineId
|
||||||
|
if (!tableStore.table.params.lineId && lineList.value && lineList.value.length > 0) {
|
||||||
|
tableStore.table.params.lineId = lineList.value[0].lineId
|
||||||
|
}
|
||||||
|
const params = {
|
||||||
|
searchBeginTime: tableStore.table.params.searchBeginTime || prop.timeValue?.[0],
|
||||||
|
searchEndTime: tableStore.table.params.searchEndTime || prop.timeValue?.[1],
|
||||||
|
lineId: tableStore.table.params.lineId
|
||||||
|
}
|
||||||
|
limitProbabilityData(params).then((res: any) => {
|
||||||
|
probabilityData.value = res.data
|
||||||
|
|
||||||
|
// 处理接口返回的数据,转换为图表所需格式
|
||||||
|
if (res.data && Array.isArray(res.data)) {
|
||||||
|
// 定义指标类型顺序
|
||||||
|
const indicatorOrder = ['闪变', '谐波电压', '谐波电流', '电压偏差', '三相电压不平衡度', '频率偏差']
|
||||||
|
// 按照指定顺序排序数据
|
||||||
|
const sortedData = [...res.data].sort((a, b) => {
|
||||||
|
return indicatorOrder.indexOf(a.indexName) - indicatorOrder.indexOf(b.indexName)
|
||||||
|
})
|
||||||
|
|
||||||
|
// 构造 series 数据
|
||||||
|
const seriesData: any = []
|
||||||
|
let maxValue: any = 0 // 用于存储数据中的最大值
|
||||||
|
// 遍历每个越限程度区间(0-20%, 20-40%, 40-60%, 60-80%, 80-100%)
|
||||||
|
for (let xIndex = 0; xIndex < 5; xIndex++) {
|
||||||
|
// 遍历每个指标类型
|
||||||
|
sortedData.forEach((item, yIndex) => {
|
||||||
|
// 从 extentGrades 中获取对应区间的值
|
||||||
|
const extentGrade = item.extentGrades[xIndex]
|
||||||
|
const value = extentGrade ? (Object.values(extentGrade)[0] as number) : 0
|
||||||
|
seriesData.push([xIndex, yIndex, value])
|
||||||
|
|
||||||
|
// 更新最大值
|
||||||
|
if (value > maxValue) {
|
||||||
|
maxValue = value
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算 z 轴最大值(最大值加 5)
|
||||||
|
const zAxisMax = Math.ceil(maxValue) + 5
|
||||||
|
// 构造 yAxis 数据(指标类型名称)
|
||||||
|
const yAxisData = sortedData.map(item => item.indexName)
|
||||||
|
|
||||||
|
echartList.value = {
|
||||||
|
options: {
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
tooltip: {
|
||||||
|
textStyle: {
|
||||||
|
color: '#fff',
|
||||||
|
fontStyle: 'normal',
|
||||||
|
opacity: 0.35,
|
||||||
|
fontSize: 14
|
||||||
|
},
|
||||||
|
backgroundColor: 'rgba(0,0,0,0.55)',
|
||||||
|
borderWidth: 0,
|
||||||
|
formatter: function (params: any) {
|
||||||
|
var yIndex = params.value[1] //获取y轴索引
|
||||||
|
var tips = ''
|
||||||
|
tips += '指标类型: ' + yAxisData[yIndex] + '</br>'
|
||||||
|
tips += '越限程度: ' + params.seriesName + '</br>'
|
||||||
|
tips += '越限次数: ' + params.value[2] + '</br>'
|
||||||
|
return tips
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: '指标越限概率分布',
|
||||||
|
x: 'center',
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: 'normal'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 移除或隐藏 visualMap 组件
|
||||||
|
visualMap: {
|
||||||
|
show: false, // 设置为 false 隐藏右侧颜色条
|
||||||
|
min: 0,
|
||||||
|
// max: 100,
|
||||||
|
max: zAxisMax, // 使用计算出的最大值加5
|
||||||
|
inRange: {
|
||||||
|
color: ['#313695', '#00BB00', '#ff8000', '#d73027', '#a50026']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 添加 legend 配置并设置为不显示
|
||||||
|
legend: {
|
||||||
|
show: false // 隐藏图例
|
||||||
|
},
|
||||||
|
xAxis3D: {
|
||||||
|
type: 'category',
|
||||||
|
name: '越限程度',
|
||||||
|
nameLocation: 'middle',
|
||||||
|
nameGap: 50,
|
||||||
|
data: ['0-20%', '20-40%', '40-60%', '60-80%', '80-100%']
|
||||||
|
},
|
||||||
|
yAxis3D: {
|
||||||
|
type: 'category',
|
||||||
|
name: '指标类型',
|
||||||
|
nameLocation: 'middle',
|
||||||
|
nameGap: 50,
|
||||||
|
data: yAxisData,
|
||||||
|
|
||||||
|
splitLine: {
|
||||||
|
lineStyle: {
|
||||||
|
type: 'dashed',
|
||||||
|
opacity: 0.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
zAxis3D: {
|
||||||
|
type: 'value',
|
||||||
|
name: '越限次数',
|
||||||
|
nameLocation: 'middle',
|
||||||
|
nameGap: 30,
|
||||||
|
minInterval: 10
|
||||||
|
|
||||||
|
// max: 100
|
||||||
|
},
|
||||||
|
grid3D: {
|
||||||
|
viewControl: {
|
||||||
|
projection: 'perspective',
|
||||||
|
distance: 260,
|
||||||
|
rotateSensitivity: 10,
|
||||||
|
zoomSensitivity: 2
|
||||||
|
},
|
||||||
|
boxWidth: 150,
|
||||||
|
boxDepth: 100,
|
||||||
|
boxHeight: 100,
|
||||||
|
light: {
|
||||||
|
main: {
|
||||||
|
intensity: 1.2
|
||||||
|
},
|
||||||
|
ambient: {
|
||||||
|
intensity: 0.4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'bar3D',
|
||||||
|
name: '0-20%',
|
||||||
|
data: seriesData.filter((item: any) => item[0] === 0),
|
||||||
|
shading: 'realistic',
|
||||||
|
label: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
opacity: 0.9
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#000'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
color: '#ff8000'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'bar3D',
|
||||||
|
name: '20-40%',
|
||||||
|
data: seriesData.filter((item: any) => item[0] === 1),
|
||||||
|
shading: 'realistic',
|
||||||
|
label: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
opacity: 0.9
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#000'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
color: '#ff8000'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'bar3D',
|
||||||
|
name: '40-60%',
|
||||||
|
data: seriesData.filter((item: any) => item[0] === 2),
|
||||||
|
shading: 'realistic',
|
||||||
|
label: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
opacity: 0.9
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#000'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
color: '#ff8000'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'bar3D',
|
||||||
|
name: '60-80%',
|
||||||
|
data: seriesData.filter((item: any) => item[0] === 3),
|
||||||
|
shading: 'realistic',
|
||||||
|
label: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
opacity: 0.9
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#000'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
color: '#ff8000'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'bar3D',
|
||||||
|
name: '80-100%',
|
||||||
|
data: seriesData.filter((item: any) => item[0] === 4),
|
||||||
|
shading: 'realistic',
|
||||||
|
label: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
opacity: 0.9
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#000'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
color: '#ff8000'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableStore: any = new TableStore({
|
||||||
|
url: '/cs-harmonic-boot/limitRateDetailD/limitTimeProbabilityData',
|
||||||
|
method: 'POST',
|
||||||
|
showPage: false,
|
||||||
|
column: [],
|
||||||
|
beforeSearchFun: () => {
|
||||||
|
setTime()
|
||||||
|
// 只有当 lineList 已加载且有数据时才设置默认 lineId
|
||||||
|
if (!tableStore.table.params.lineId && lineList.value && lineList.value.length > 0) {
|
||||||
|
tableStore.table.params.lineId = lineList.value[0].lineId
|
||||||
|
}
|
||||||
|
},
|
||||||
|
loadCallback: () => {
|
||||||
|
// 处理返回的数据,将其转换为图表所需格式
|
||||||
|
const indexNames: any = [...new Set(tableStore.table.data.map((item: any) => item.indexName))]
|
||||||
|
const timePeriods = [...new Set(tableStore.table.data.map((item: any) => item.timePeriod))]
|
||||||
|
|
||||||
|
// 构建系列数据
|
||||||
|
const seriesData = indexNames.map((indexName: string) => {
|
||||||
|
const dataIndex = tableStore.table.data.filter((item: any) => item.indexName === indexName)
|
||||||
|
return {
|
||||||
|
name: indexName,
|
||||||
|
type: 'line',
|
||||||
|
symbol: 'none',
|
||||||
|
data: dataIndex.map((item: any) => [item.timePeriod, item.times])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
echartList1.value = {
|
||||||
|
title: {
|
||||||
|
text: '指标越限时间概率分布'
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis'
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: indexNames
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
name: '时间段',
|
||||||
|
data: timePeriods
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value'
|
||||||
|
// name: '次数'
|
||||||
|
},
|
||||||
|
series: seriesData
|
||||||
|
}
|
||||||
|
initProbabilityData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
provide('tableStore', tableStore)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initLineList()
|
||||||
|
})
|
||||||
|
|
||||||
|
const setTime = () => {
|
||||||
|
const time = getTime(
|
||||||
|
(TableHeaderRef.value?.datePickerRef.interval || prop.interval) ?? 0,
|
||||||
|
prop.timeKey,
|
||||||
|
fullscreen.value
|
||||||
|
? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
|
||||||
|
: prop.timeValue
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(time)) {
|
||||||
|
tableStore.table.params.searchBeginTime = time[0]
|
||||||
|
tableStore.table.params.searchEndTime = time[1]
|
||||||
|
TableHeaderRef.value?.setInterval(time[2] - 0)
|
||||||
|
TableHeaderRef.value?.setTimeInterval([time[0], time[1]])
|
||||||
|
} else {
|
||||||
|
console.warn('获取时间失败,time 不是一个有效数组')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
watch(
|
||||||
|
() => prop.timeKey,
|
||||||
|
val => {
|
||||||
|
tableStore.index()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
watch(
|
||||||
|
() => prop.timeValue,
|
||||||
|
(newVal, oldVal) => {
|
||||||
|
tableStore.index()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const addMenu = () => {}
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@@ -1,26 +1,38 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!--指标越限明细 -->
|
<!--指标越限明细 -->
|
||||||
|
<TableHeader
|
||||||
<el-calendar v-model="value" :style="{ height: prop.height, overflow: 'auto' }">
|
:showReset="false"
|
||||||
|
ref="TableHeaderRef"
|
||||||
|
@selectChange="selectChange"
|
||||||
|
datePicker
|
||||||
|
v-if="fullscreen"
|
||||||
|
:timeKeyList="prop.timeKey"
|
||||||
|
></TableHeader>
|
||||||
|
<el-calendar
|
||||||
|
v-model="value"
|
||||||
|
:style="{
|
||||||
|
height: `calc(${prop.height} - ${headerHeight}px + ${fullscreen ? 0 : 56}px )`,
|
||||||
|
overflow: 'auto'
|
||||||
|
}"
|
||||||
|
v-loading="tableStore.table.loading"
|
||||||
|
>
|
||||||
<template #date-cell="{ data }">
|
<template #date-cell="{ data }">
|
||||||
<div style="height: 100%; padding: 8px" :style="{ background: setBackground(data.day) }">
|
<div
|
||||||
|
style="padding: 8px"
|
||||||
|
:style="{
|
||||||
|
background: setBackground(data.day),
|
||||||
|
height: `calc((${prop.height} - 100px - ${headerHeight}px + ${fullscreen ? 0 : 56}px) / 5 )`
|
||||||
|
}"
|
||||||
|
>
|
||||||
<p :class="data.isSelected ? 'is-selected' : ''">
|
<p :class="data.isSelected ? 'is-selected' : ''">
|
||||||
{{ data.day.split('-').slice(2).join('-') }}
|
{{ data.day.split('-').slice(2).join('-') }}
|
||||||
</p>
|
</p>
|
||||||
<el-tooltip
|
<el-tooltip effect="dark" placement="top" :hide-after="0" v-if="getTextForDate(data.day)">
|
||||||
effect="dark"
|
|
||||||
placement="top"
|
|
||||||
:hide-after="0"
|
|
||||||
v-if="list?.filter(item => item.time == data.day)[0]?.text || false"
|
|
||||||
>
|
|
||||||
<template #content>
|
<template #content>
|
||||||
<span v-html="list?.filter(item => item.time == data.day)[0]?.text || ''"></span>
|
<span v-html="getTextForDate(data.day)"></span>
|
||||||
</template>
|
</template>
|
||||||
<div
|
<div class="details" v-html="fullscreen ? getTextForDate(data.day) : '有越限'"></div>
|
||||||
:style="{ height: `calc(${prop.height} / 5 - 47px)`, overflow: 'auto' }"
|
|
||||||
v-html="list?.filter(item => item.time == data.day)[0]?.text || ''"
|
|
||||||
></div>
|
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -30,135 +42,161 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
||||||
import TableStore from '@/utils/tableStore'
|
import TableStore from '@/utils/tableStore'
|
||||||
import Table from '@/components/table/index.vue'
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
import { useDictData } from '@/stores/dictData'
|
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
||||||
import { getTimeOfTheMonth } from '@/utils/formatTime'
|
|
||||||
import { overflow } from 'html2canvas/dist/types/css/property-descriptors/overflow'
|
|
||||||
import { dayjs } from 'element-plus'
|
import { dayjs } from 'element-plus'
|
||||||
|
import { getTime } from '@/utils/formatTime'
|
||||||
|
|
||||||
|
const prop = defineProps({
|
||||||
|
w: { type: [String, Number] },
|
||||||
|
h: { type: [String, Number] },
|
||||||
|
width: { type: [String, Number] },
|
||||||
|
height: { type: [String, Number] },
|
||||||
|
timeKey: { type: Array as () => string[] },
|
||||||
|
timeValue: { type: Object },
|
||||||
|
interval: { type: Number }
|
||||||
|
})
|
||||||
|
|
||||||
|
const headerHeight = ref(57)
|
||||||
|
|
||||||
|
const list = ref()
|
||||||
|
|
||||||
|
const TableHeaderRef = ref()
|
||||||
|
|
||||||
dayjs.en.weekStart = 1 //设置日历的周起始日为星期一
|
dayjs.en.weekStart = 1 //设置日历的周起始日为星期一
|
||||||
const value = ref(new Date())
|
const value = ref(new Date())
|
||||||
const prop = defineProps({
|
|
||||||
width: { type: String },
|
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
|
||||||
height: { type: String },
|
headerHeight.value = height
|
||||||
timeKey: { type: String },
|
|
||||||
timeValue: { type: Object }
|
if (datePickerValue && datePickerValue.timeValue) {
|
||||||
})
|
// 更新时间参数
|
||||||
const list = ref([
|
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
|
||||||
{
|
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
|
||||||
time: '2025-10-01',
|
|
||||||
key: 81,
|
|
||||||
text: '3次谐波越限<br/>5次谐波越限<br/>三相不平衡越限'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
time: '2025-10-31',
|
|
||||||
key: 81,
|
|
||||||
text: '3次谐波越限<br/>5次谐波越限<br/>三相不平衡越限'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
time: '2025-10-08',
|
|
||||||
key: 20,
|
|
||||||
text: '3次谐波越限<br/>5次谐波越限<br/>三相不平衡越限'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
time: '2025-10-16',
|
|
||||||
key: 20,
|
|
||||||
text: '3次谐波越限<br/>5次谐波越限<br/>三相不平衡越限'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
time: '2025-10-23',
|
|
||||||
key: 20,
|
|
||||||
text: '3次谐波越限<br/>5次谐波越限<br/>三相不平衡越限'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
time: '2025-10-04',
|
|
||||||
key: 0,
|
|
||||||
text: ''
|
|
||||||
},
|
|
||||||
{
|
|
||||||
time: '2025-10-05',
|
|
||||||
key: 0,
|
|
||||||
text: ''
|
|
||||||
}
|
}
|
||||||
])
|
}
|
||||||
|
|
||||||
|
// 计算是否全屏展示
|
||||||
|
const fullscreen = computed(() => {
|
||||||
|
const w = Number(prop.w)
|
||||||
|
const h = Number(prop.h)
|
||||||
|
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
|
||||||
|
// 执行相应逻辑
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const getTextForDate = (date: string) => {
|
||||||
|
const item = list.value?.find((item: any) => item.time === date)
|
||||||
|
return item ? item.text : ''
|
||||||
|
}
|
||||||
|
|
||||||
const tableStore: any = new TableStore({
|
const tableStore: any = new TableStore({
|
||||||
url: '/user-boot/dept/deptTree',
|
url: '/cs-harmonic-boot/limitRateDetailD/limitCalendarData',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|
||||||
showPage: false,
|
showPage: false,
|
||||||
|
|
||||||
column: [],
|
column: [],
|
||||||
beforeSearchFun: () => {
|
beforeSearchFun: () => {
|
||||||
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
|
setTime()
|
||||||
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
|
|
||||||
// value.value = new Date(prop.timeValue?.[0])
|
|
||||||
},
|
},
|
||||||
loadCallback: () => {
|
loadCallback: () => {
|
||||||
tableStore.table.data = []
|
value.value = tableStore.table.params.searchBeginTime
|
||||||
|
if (tableStore.table.data && tableStore.table.data.length > 0) {
|
||||||
|
list.value = tableStore.table.data.map((item: any) => {
|
||||||
|
// 将 items 数组转换为带换行的文本
|
||||||
|
const text = item.items && item.items.length > 0 ? item.items.join('<br/>') : ''
|
||||||
|
|
||||||
|
return {
|
||||||
|
time: item.time,
|
||||||
|
key: item.status || 0,
|
||||||
|
text: text
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
list.value = []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const tableRef = ref([])
|
|
||||||
|
|
||||||
const setBackground = (value: string) => {
|
const setBackground = (value: string) => {
|
||||||
let data = []
|
const data = list.value?.find((item: any) => item.time === value)
|
||||||
data = list.value?.filter(item => item.time == value)
|
|
||||||
|
|
||||||
if (data && data?.length > 0) {
|
if (data) {
|
||||||
if (data[0].key < 10) {
|
// 根据 status 值返回对应的颜色
|
||||||
return '#33996690'
|
switch (data.key) {
|
||||||
} else if (data[0].key < 80) {
|
case 0: // 无越限
|
||||||
return '#FFCC3390'
|
return '#33996690'
|
||||||
} else if (data[0].key <= 100) {
|
case 1: // 一般越限
|
||||||
return '#Ff660090'
|
return '#FFCC3390'
|
||||||
|
case 2: // 严重越限
|
||||||
|
return '#Ff660090'
|
||||||
|
default:
|
||||||
|
return '#fff' // 默认白色背景
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return '#fff'
|
return '#fff' // 默认白色背景
|
||||||
}
|
}
|
||||||
|
|
||||||
provide('tableRef', tableRef)
|
|
||||||
|
|
||||||
provide('tableStore', tableStore)
|
provide('tableStore', tableStore)
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
tableStore.index()
|
nextTick(() => {
|
||||||
})
|
|
||||||
watch(
|
|
||||||
() => prop.timeKey,
|
|
||||||
val => {
|
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const setTime = () => {
|
||||||
|
const time = getTime(
|
||||||
|
(TableHeaderRef.value?.datePickerRef.interval || prop.interval) ?? 0,
|
||||||
|
prop.timeKey,
|
||||||
|
fullscreen.value
|
||||||
|
? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
|
||||||
|
: prop.timeValue
|
||||||
|
)
|
||||||
|
if (Array.isArray(time)) {
|
||||||
|
tableStore.table.params.searchBeginTime = time[0]
|
||||||
|
tableStore.table.params.searchEndTime = time[1]
|
||||||
|
TableHeaderRef.value?.setInterval(time[2] - 0)
|
||||||
|
TableHeaderRef.value?.setTimeInterval([time[0], time[1]])
|
||||||
|
} else {
|
||||||
|
console.warn('获取时间失败,time 不是一个有效数组')
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeValue, // 监听的目标(函数形式避免直接传递 props 导致的警告)
|
() => prop.timeValue,
|
||||||
(newVal, oldVal) => {
|
(newVal, oldVal) => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
deep: true // 若 timeValue 是对象/数组,需开启深度监听
|
deep: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const addMenu = () => {}
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
:deep(.el-calendar) {
|
:deep(.el-calendar) {
|
||||||
.el-calendar__header {
|
.el-calendar__button-group {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.el-calendar__body {
|
.el-calendar__body {
|
||||||
padding: 0px !important;
|
padding: 0px !important;
|
||||||
height: 100%;
|
height: calc(100% - 46px);
|
||||||
.el-calendar-table {
|
.el-calendar-table {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.el-calendar-day {
|
.el-calendar-day {
|
||||||
|
// height: calc(912px / 5 );
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
.details {
|
||||||
|
height: calc(100% - 20px);
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.el-calendar-table__row {
|
.el-calendar-table__row {
|
||||||
.next {
|
.next {
|
||||||
|
|||||||
@@ -1,377 +1,446 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!--指标越限概率分布 -->
|
<!--指标越限概率分布 -->
|
||||||
<my-echart
|
<TableHeader :showReset="false" :timeKeyList="prop.timeKey" ref="TableHeaderRef" @selectChange="selectChange" datePicker v-if="fullscreen">
|
||||||
class="tall"
|
<template v-slot:select>
|
||||||
:options="echartList"
|
<el-form-item label="监测点">
|
||||||
:style="{ width: prop.width, height: `calc(${prop.height} / 2 )` }"
|
<el-select size="small" filterable v-model="tableStore.table.params.lineId">
|
||||||
/>
|
<el-option
|
||||||
<my-echart
|
v-for="item in lineList"
|
||||||
class="mt10"
|
:key="item.lineId"
|
||||||
:options="echartList1"
|
:label="item.name"
|
||||||
:style="{ width: prop.width, height: `calc(${prop.height} / 2 - 10px)` }"
|
:value="item.lineId"
|
||||||
/>
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</TableHeader>
|
||||||
|
<div v-loading="tableStore.table.loading">
|
||||||
|
<my-echart
|
||||||
|
class="tall"
|
||||||
|
:options="echartList"
|
||||||
|
:style="{
|
||||||
|
width: prop.width,
|
||||||
|
height: `calc(${prop.height} - ${headerHeight}px + ${fullscreen ? 0 : 56}px)`
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
<!-- <my-echart
|
||||||
|
class="mt10"
|
||||||
|
:options="echartList1"
|
||||||
|
:style="{
|
||||||
|
width: prop.width,
|
||||||
|
height: `calc(${prop.height} / 2 - ${headerHeight / 2}px + ${fullscreen ? 0 : 28}px )`
|
||||||
|
}"
|
||||||
|
/> -->
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
||||||
import TableStore from '@/utils/tableStore'
|
import TableStore from '@/utils/tableStore'
|
||||||
import Table from '@/components/table/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 { useDictData } from '@/stores/dictData'
|
import { limitProbabilityData, cslineList } from '@/api/harmonic-boot/cockpit/cockpit'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { getTime } from '@/utils/formatTime'
|
||||||
import { getTimeOfTheMonth } from '@/utils/formatTime'
|
|
||||||
const prop = defineProps({
|
const prop = defineProps({
|
||||||
width: { type: String },
|
w: { type: [String, Number] },
|
||||||
height: { type: String },
|
h: { type: [String, Number] },
|
||||||
timeKey: { type: String },
|
width: { type: [String, Number] },
|
||||||
timeValue: { type: Object }
|
height: { type: [String, Number] },
|
||||||
|
timeKey: { type: Array as () => string[] },
|
||||||
|
timeValue: { type: Object },
|
||||||
|
interval: { type: Number }
|
||||||
})
|
})
|
||||||
const echartList = ref({
|
|
||||||
options: {
|
|
||||||
xAxis: null,
|
|
||||||
yAxis: null,
|
|
||||||
dataZoom: null,
|
|
||||||
backgroundColor: '#fff',
|
|
||||||
tooltip: {
|
|
||||||
// trigger: 'axis'
|
|
||||||
textStyle: {
|
|
||||||
color: '#fff',
|
|
||||||
fontStyle: 'normal',
|
|
||||||
opacity: 0.35,
|
|
||||||
fontSize: 14
|
|
||||||
},
|
|
||||||
backgroundColor: 'rgba(0,0,0,0.55)',
|
|
||||||
borderWidth: 0,
|
|
||||||
formatter: function (params: any) {
|
|
||||||
console.log(params)
|
|
||||||
var tips = ''
|
|
||||||
for (var i = 0; i < params.length; i++) {
|
|
||||||
tips += params[i].name + '</br/>'
|
|
||||||
tips += '监测点数' + ':' + ' ' + ' ' + params[i].value + '</br/>'
|
|
||||||
}
|
|
||||||
return tips
|
|
||||||
}
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
text: '指标越限概率分布',
|
|
||||||
x: 'center'
|
|
||||||
},
|
|
||||||
|
|
||||||
visualMap: {
|
// const options = ref(JSON.parse(window.localStorage.getItem('lineIdList') || '[]'))
|
||||||
max: 20,
|
|
||||||
show: false,
|
const lineList = ref()
|
||||||
inRange: {
|
|
||||||
color: ['#313695', '#00BB00', '#ff8000', '#a50026']
|
const headerHeight = ref(57)
|
||||||
}
|
|
||||||
},
|
const TableHeaderRef = ref()
|
||||||
xAxis3D: {
|
|
||||||
type: 'category',
|
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
|
||||||
name: '指标越限',
|
headerHeight.value = height
|
||||||
data: ['0-10', '10-20', '20-30', '30-40', '40-50'],
|
|
||||||
axisLine: {
|
if (datePickerValue && datePickerValue.timeValue) {
|
||||||
lineStyle: {
|
// 更新时间参数
|
||||||
color: '#111'
|
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
|
||||||
}
|
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
|
||||||
},
|
}
|
||||||
axisLabel: {
|
}
|
||||||
color: '#111'
|
|
||||||
}
|
// 计算是否全屏展示
|
||||||
},
|
const fullscreen = computed(() => {
|
||||||
yAxis3D: {
|
const w = Number(prop.w)
|
||||||
type: 'category',
|
const h = Number(prop.h)
|
||||||
name: '指标类型',
|
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
|
||||||
data: ['闪变', '谐波电压', '谐波电流', '电压偏差', '三相不平衡'],
|
// 执行相应逻辑
|
||||||
nameTextStyle: {
|
return true
|
||||||
color: '#111'
|
} else {
|
||||||
},
|
return false
|
||||||
axisLine: {
|
}
|
||||||
show: true,
|
})
|
||||||
lineStyle: {
|
|
||||||
color: '#111'
|
const echartList = ref()
|
||||||
}
|
|
||||||
},
|
const echartList1 = ref()
|
||||||
axisLabel: {
|
|
||||||
color: '#111'
|
const probabilityData = ref()
|
||||||
},
|
|
||||||
splitLine: {
|
const initLineList = async () => {
|
||||||
lineStyle: {
|
cslineList({}).then(res => {
|
||||||
// 使用深浅的间隔色
|
lineList.value = res.data
|
||||||
color: ['#111'],
|
tableStore.table.params.lineId = lineList.value[0].lineId
|
||||||
type: 'dashed',
|
tableStore.index()
|
||||||
opacity: 0.5
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
},
|
// 越限程度概率分布
|
||||||
zAxis3D: {
|
const initProbabilityData = () => {
|
||||||
type: 'value',
|
// 只有当 lineList 已加载且有数据时才设置默认 lineId
|
||||||
splitNumber: 10,
|
if (!tableStore.table.params.lineId && lineList.value && lineList.value.length > 0) {
|
||||||
minInterval: 10,
|
tableStore.table.params.lineId = lineList.value[0].lineId
|
||||||
name: '越限占比'
|
}
|
||||||
},
|
const params = {
|
||||||
grid3D: {
|
searchBeginTime: tableStore.table.params.searchBeginTime || prop.timeValue?.[0],
|
||||||
viewControl: {
|
searchEndTime: tableStore.table.params.searchEndTime || prop.timeValue?.[1],
|
||||||
projection: 'perspective',
|
lineId: tableStore.table.params.lineId
|
||||||
distance: 250
|
}
|
||||||
},
|
limitProbabilityData(params).then((res: any) => {
|
||||||
boxWidth: 200,
|
probabilityData.value = res.data
|
||||||
boxDepth: 80,
|
|
||||||
light: {
|
// 处理接口返回的数据,转换为图表所需格式
|
||||||
main: {
|
if (res.data && Array.isArray(res.data)) {
|
||||||
intensity: 1.2
|
// 定义指标类型顺序
|
||||||
},
|
const indicatorOrder = ['闪变', '谐波电压', '谐波电流', '电压偏差', '三相电压不平衡度', '频率偏差']
|
||||||
ambient: {
|
// 按照指定顺序排序数据
|
||||||
intensity: 0.3
|
const sortedData = [...res.data].sort((a, b) => {
|
||||||
}
|
return indicatorOrder.indexOf(a.indexName) - indicatorOrder.indexOf(b.indexName)
|
||||||
}
|
})
|
||||||
},
|
|
||||||
series: [
|
// 构造 series 数据
|
||||||
{
|
const seriesData: any = []
|
||||||
type: 'bar3D',
|
let maxValue: any = 0 // 用于存储数据中的最大值
|
||||||
data: [
|
// 遍历每个越限程度区间(0-20%, 20-40%, 40-60%, 60-80%, 80-100%)
|
||||||
[0, 0, 1],
|
for (let xIndex = 0; xIndex < 5; xIndex++) {
|
||||||
[0, 1, 1],
|
// 遍历每个指标类型
|
||||||
[0.2, 1]
|
sortedData.forEach((item, yIndex) => {
|
||||||
],
|
// 从 extentGrades 中获取对应区间的值
|
||||||
shading: 'realistic',
|
const extentGrade = item.extentGrades[xIndex]
|
||||||
label: {
|
const value = extentGrade ? (Object.values(extentGrade)[0] as number) : 0
|
||||||
show: false,
|
seriesData.push([xIndex, yIndex, value])
|
||||||
textStyle: {
|
|
||||||
fontSize: 16,
|
// 更新最大值
|
||||||
borderWidth: 1
|
if (value > maxValue) {
|
||||||
|
maxValue = value
|
||||||
}
|
}
|
||||||
},
|
})
|
||||||
|
}
|
||||||
|
|
||||||
itemStyle: {
|
// 计算 z 轴最大值(最大值加 5)
|
||||||
opacity: 1
|
const zAxisMax = Math.ceil(maxValue) + 5
|
||||||
},
|
// 构造 yAxis 数据(指标类型名称)
|
||||||
emphasis: {
|
const yAxisData = sortedData.map(item => item.indexName)
|
||||||
label: {
|
|
||||||
|
echartList.value = {
|
||||||
|
options: {
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
tooltip: {
|
||||||
textStyle: {
|
textStyle: {
|
||||||
fontSize: 20,
|
color: '#fff',
|
||||||
color: '#900'
|
fontStyle: 'normal',
|
||||||
|
opacity: 0.35,
|
||||||
|
fontSize: 14
|
||||||
|
},
|
||||||
|
backgroundColor: 'rgba(0,0,0,0.55)',
|
||||||
|
borderWidth: 0,
|
||||||
|
formatter: function (params: any) {
|
||||||
|
var yIndex = params.value[1] //获取y轴索引
|
||||||
|
var tips = ''
|
||||||
|
tips += '指标类型: ' + yAxisData[yIndex] + '</br>'
|
||||||
|
tips += '越限程度: ' + params.seriesName + '</br>'
|
||||||
|
tips += '越限次数: ' + params.value[2] + '</br>'
|
||||||
|
return tips
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
itemStyle: {
|
title: {
|
||||||
color: '#900'
|
text: '指标越限概率分布',
|
||||||
}
|
x: 'center',
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: 'normal'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 移除或隐藏 visualMap 组件
|
||||||
|
visualMap: {
|
||||||
|
show: false, // 设置为 false 隐藏右侧颜色条
|
||||||
|
min: 0,
|
||||||
|
// max: 100,
|
||||||
|
max: zAxisMax, // 使用计算出的最大值加5
|
||||||
|
inRange: {
|
||||||
|
color: ['#313695', '#00BB00', '#ff8000', '#d73027', '#a50026']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
// 添加 legend 配置并设置为不显示
|
||||||
|
legend: {
|
||||||
|
show: false // 隐藏图例
|
||||||
|
},
|
||||||
|
xAxis3D: {
|
||||||
|
type: 'category',
|
||||||
|
name: '越限程度',
|
||||||
|
nameLocation: 'middle',
|
||||||
|
nameGap: 50,
|
||||||
|
data: ['0-20%', '20-40%', '40-60%', '60-80%', '80-100%']
|
||||||
|
},
|
||||||
|
yAxis3D: {
|
||||||
|
type: 'category',
|
||||||
|
name: '指标类型',
|
||||||
|
nameLocation: 'middle',
|
||||||
|
nameGap: 50,
|
||||||
|
data: yAxisData,
|
||||||
|
|
||||||
|
splitLine: {
|
||||||
|
lineStyle: {
|
||||||
|
type: 'dashed',
|
||||||
|
opacity: 0.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
zAxis3D: {
|
||||||
|
type: 'value',
|
||||||
|
name: '越限次数',
|
||||||
|
nameLocation: 'middle',
|
||||||
|
nameGap: 30,
|
||||||
|
minInterval: 10
|
||||||
|
|
||||||
|
// max: 100
|
||||||
|
},
|
||||||
|
grid3D: {
|
||||||
|
viewControl: {
|
||||||
|
projection: 'perspective',
|
||||||
|
distance: 260,
|
||||||
|
rotateSensitivity: 10,
|
||||||
|
zoomSensitivity: 2
|
||||||
|
},
|
||||||
|
boxWidth: 150,
|
||||||
|
boxDepth: 100,
|
||||||
|
boxHeight: 100,
|
||||||
|
light: {
|
||||||
|
main: {
|
||||||
|
intensity: 1.2
|
||||||
|
},
|
||||||
|
ambient: {
|
||||||
|
intensity: 0.4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'bar3D',
|
||||||
|
name: '0-20%',
|
||||||
|
data: seriesData.filter((item: any) => item[0] === 0),
|
||||||
|
shading: 'realistic',
|
||||||
|
label: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
opacity: 0.9
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#000'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
color: '#ff8000'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'bar3D',
|
||||||
|
name: '20-40%',
|
||||||
|
data: seriesData.filter((item: any) => item[0] === 1),
|
||||||
|
shading: 'realistic',
|
||||||
|
label: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
opacity: 0.9
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#000'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
color: '#ff8000'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'bar3D',
|
||||||
|
name: '40-60%',
|
||||||
|
data: seriesData.filter((item: any) => item[0] === 2),
|
||||||
|
shading: 'realistic',
|
||||||
|
label: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
opacity: 0.9
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#000'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
color: '#ff8000'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'bar3D',
|
||||||
|
name: '60-80%',
|
||||||
|
data: seriesData.filter((item: any) => item[0] === 3),
|
||||||
|
shading: 'realistic',
|
||||||
|
label: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
opacity: 0.9
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#000'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
color: '#ff8000'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'bar3D',
|
||||||
|
name: '80-100%',
|
||||||
|
data: seriesData.filter((item: any) => item[0] === 4),
|
||||||
|
shading: 'realistic',
|
||||||
|
label: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
opacity: 0.9
|
||||||
|
},
|
||||||
|
emphasis: {
|
||||||
|
label: {
|
||||||
|
show: true,
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 14,
|
||||||
|
color: '#000'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
color: '#ff8000'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const echartList1 = ref({
|
|
||||||
title: {
|
|
||||||
text: '越限时间概率分布'
|
|
||||||
},
|
|
||||||
|
|
||||||
xAxis: {
|
|
||||||
// name: '时间',
|
|
||||||
// data: ['闪变', '谐波电压', '谐波电流', '电压偏差', '三相不平衡']
|
|
||||||
type: 'time',
|
|
||||||
axisLabel: {
|
|
||||||
formatter: {
|
|
||||||
day: '{MM}-{dd}',
|
|
||||||
month: '{MM}',
|
|
||||||
year: '{yyyy}'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
})
|
||||||
|
}
|
||||||
|
|
||||||
yAxis: {
|
|
||||||
name: '次' // 给X轴加单位
|
|
||||||
},
|
|
||||||
grid: {
|
|
||||||
left: '10px',
|
|
||||||
right: '20px'
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
type: 'line',
|
|
||||||
showSymbol: false,
|
|
||||||
// smooth: true,
|
|
||||||
name: '闪变',
|
|
||||||
data: [
|
|
||||||
['2025-10-16 07:00:00', 10],
|
|
||||||
['2025-10-16 07:15:00', 10],
|
|
||||||
['2025-10-16 07:30:00', 10],
|
|
||||||
['2025-10-16 07:45:00', 10],
|
|
||||||
['2025-10-16 08:00:00', 30],
|
|
||||||
['2025-10-16 08:15:00', 50],
|
|
||||||
['2025-10-16 08:30:00', 60],
|
|
||||||
['2025-10-16 08:45:00', 70],
|
|
||||||
['2025-10-16 09:00:00', 100],
|
|
||||||
['2025-10-16 09:15:00', 120],
|
|
||||||
['2025-10-16 09:30:00', 130],
|
|
||||||
['2025-10-16 09:45:00', 140],
|
|
||||||
['2025-10-16 10:00:00', 160],
|
|
||||||
['2025-10-16 10:15:00', 160],
|
|
||||||
['2025-10-16 10:30:00', 130],
|
|
||||||
['2025-10-16 10:45:00', 120],
|
|
||||||
['2025-10-16 11:00:00', 140],
|
|
||||||
['2025-10-16 11:15:00', 80],
|
|
||||||
['2025-10-16 11:30:00', 70],
|
|
||||||
['2025-10-16 11:45:00', 90],
|
|
||||||
['2025-10-16 12:00:00', 60],
|
|
||||||
['2025-10-16 12:15:00', 60],
|
|
||||||
['2025-10-16 12:30:00', 60],
|
|
||||||
['2025-10-16 12:45:00', 60]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'line',
|
|
||||||
showSymbol: false,
|
|
||||||
// smooth: true,
|
|
||||||
name: '谐波电压',
|
|
||||||
data: [
|
|
||||||
['2025-10-16 07:00:00', 1],
|
|
||||||
['2025-10-16 07:15:00', 1],
|
|
||||||
['2025-10-16 07:30:00', 1],
|
|
||||||
['2025-10-16 07:45:00', 1],
|
|
||||||
['2025-10-16 08:00:00', 3],
|
|
||||||
['2025-10-16 08:15:00', 5],
|
|
||||||
['2025-10-16 08:30:00', 6],
|
|
||||||
['2025-10-16 08:45:00', 7],
|
|
||||||
['2025-10-16 09:00:00', 10],
|
|
||||||
['2025-10-16 09:15:00', 12],
|
|
||||||
['2025-10-16 09:30:00', 13],
|
|
||||||
['2025-10-16 09:45:00', 14],
|
|
||||||
['2025-10-16 10:00:00', 16],
|
|
||||||
['2025-10-16 10:15:00', 16],
|
|
||||||
['2025-10-16 10:30:00', 13],
|
|
||||||
['2025-10-16 10:45:00', 12],
|
|
||||||
['2025-10-16 11:00:00', 14],
|
|
||||||
['2025-10-16 11:15:00', 8],
|
|
||||||
['2025-10-16 11:30:00', 7],
|
|
||||||
['2025-10-16 11:45:00', 9],
|
|
||||||
['2025-10-16 12:00:00', 6],
|
|
||||||
['2025-10-16 12:15:00', 6],
|
|
||||||
['2025-10-16 12:30:00', 6],
|
|
||||||
['2025-10-16 12:45:00', 6]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'line',
|
|
||||||
showSymbol: false,
|
|
||||||
// smooth: true,
|
|
||||||
name: '谐波电流',
|
|
||||||
data: [
|
|
||||||
['2025-10-16 07:00:00', 19],
|
|
||||||
['2025-10-16 07:15:00', 19],
|
|
||||||
['2025-10-16 07:30:00', 19],
|
|
||||||
['2025-10-16 07:45:00', 19],
|
|
||||||
['2025-10-16 08:00:00', 39],
|
|
||||||
['2025-10-16 08:15:00', 59],
|
|
||||||
['2025-10-16 08:30:00', 69],
|
|
||||||
['2025-10-16 08:45:00', 79],
|
|
||||||
['2025-10-16 09:00:00', 109],
|
|
||||||
['2025-10-16 09:15:00', 129],
|
|
||||||
['2025-10-16 09:30:00', 139],
|
|
||||||
['2025-10-16 09:45:00', 149],
|
|
||||||
['2025-10-16 10:00:00', 169],
|
|
||||||
['2025-10-16 10:15:00', 169],
|
|
||||||
['2025-10-16 10:30:00', 139],
|
|
||||||
['2025-10-16 10:45:00', 129],
|
|
||||||
['2025-10-16 11:00:00', 149],
|
|
||||||
['2025-10-16 11:15:00', 89],
|
|
||||||
['2025-10-16 11:30:00', 79],
|
|
||||||
['2025-10-16 11:45:00', 99],
|
|
||||||
['2025-10-16 12:00:00', 69],
|
|
||||||
['2025-10-16 12:15:00', 69],
|
|
||||||
['2025-10-16 12:30:00', 69],
|
|
||||||
['2025-10-16 12:45:00', 69]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'line',
|
|
||||||
showSymbol: false,
|
|
||||||
// smooth: true,
|
|
||||||
name: '电压偏差',
|
|
||||||
data: [
|
|
||||||
['2025-10-16 07:00:00', 12],
|
|
||||||
['2025-10-16 07:15:00', 12],
|
|
||||||
['2025-10-16 07:30:00', 12],
|
|
||||||
['2025-10-16 07:45:00', 12],
|
|
||||||
['2025-10-16 08:00:00', 32],
|
|
||||||
['2025-10-16 08:15:00', 52],
|
|
||||||
['2025-10-16 08:30:00', 62],
|
|
||||||
['2025-10-16 08:45:00', 72],
|
|
||||||
['2025-10-16 09:00:00', 112],
|
|
||||||
['2025-10-16 09:15:00', 122],
|
|
||||||
['2025-10-16 09:30:00', 122],
|
|
||||||
['2025-10-16 09:45:00', 152],
|
|
||||||
['2025-10-16 10:00:00', 122],
|
|
||||||
['2025-10-16 10:15:00', 112],
|
|
||||||
['2025-10-16 10:30:00', 132],
|
|
||||||
['2025-10-16 10:45:00', 122],
|
|
||||||
['2025-10-16 11:00:00', 142],
|
|
||||||
['2025-10-16 11:15:00', 82],
|
|
||||||
['2025-10-16 11:30:00', 72],
|
|
||||||
['2025-10-16 11:45:00', 92],
|
|
||||||
['2025-10-16 12:00:00', 62],
|
|
||||||
['2025-10-16 12:15:00', 62],
|
|
||||||
['2025-10-16 12:30:00', 62],
|
|
||||||
['2025-10-16 12:45:00', 62]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'line',
|
|
||||||
showSymbol: false,
|
|
||||||
// smooth: true,
|
|
||||||
name: '三相不平衡',
|
|
||||||
data: [
|
|
||||||
['2025-10-16 07:00:00', 10],
|
|
||||||
['2025-10-16 07:15:00', 10],
|
|
||||||
['2025-10-16 07:30:00', 10],
|
|
||||||
['2025-10-16 07:45:00', 10],
|
|
||||||
['2025-10-16 08:00:00', 30],
|
|
||||||
['2025-10-16 08:15:00', 50],
|
|
||||||
['2025-10-16 08:30:00', 60],
|
|
||||||
['2025-10-16 08:45:00', 70],
|
|
||||||
['2025-10-16 09:00:00', 100],
|
|
||||||
['2025-10-16 09:15:00', 120],
|
|
||||||
['2025-10-16 09:30:00', 130],
|
|
||||||
['2025-10-16 09:45:00', 140],
|
|
||||||
['2025-10-16 10:00:00', 160],
|
|
||||||
['2025-10-16 10:15:00', 160],
|
|
||||||
['2025-10-16 10:30:00', 130],
|
|
||||||
['2025-10-16 10:45:00', 120],
|
|
||||||
['2025-10-16 11:00:00', 140],
|
|
||||||
['2025-10-16 11:15:00', 80],
|
|
||||||
['2025-10-16 11:30:00', 70],
|
|
||||||
['2025-10-16 11:45:00', 90],
|
|
||||||
['2025-10-16 12:00:00', 60],
|
|
||||||
['2025-10-16 12:15:00', 60],
|
|
||||||
['2025-10-16 12:30:00', 60],
|
|
||||||
['2025-10-16 12:45:00', 60]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const tableStore: any = new TableStore({
|
const tableStore: any = new TableStore({
|
||||||
url: '/user-boot/dept/deptTree',
|
url: '/cs-harmonic-boot/limitRateDetailD/limitTimeProbabilityData',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
showPage: false,
|
showPage: false,
|
||||||
column: [],
|
column: [],
|
||||||
beforeSearchFun: () => {
|
beforeSearchFun: () => {
|
||||||
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
|
setTime()
|
||||||
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
|
// 只有当 lineList 已加载且有数据时才设置默认 lineId
|
||||||
|
if (!tableStore.table.params.lineId && lineList.value && lineList.value.length > 0) {
|
||||||
|
tableStore.table.params.lineId = lineList.value[0].lineId
|
||||||
|
}
|
||||||
},
|
},
|
||||||
loadCallback: () => {
|
loadCallback: () => {
|
||||||
tableStore.table.data = []
|
// 处理返回的数据,将其转换为图表所需格式
|
||||||
|
const indexNames: any = [...new Set(tableStore.table.data.map((item: any) => item.indexName))]
|
||||||
|
const timePeriods = [...new Set(tableStore.table.data.map((item: any) => item.timePeriod))]
|
||||||
|
|
||||||
|
// 构建系列数据
|
||||||
|
const seriesData = indexNames.map((indexName: string) => {
|
||||||
|
const dataIndex = tableStore.table.data.filter((item: any) => item.indexName === indexName)
|
||||||
|
return {
|
||||||
|
name: indexName,
|
||||||
|
type: 'line',
|
||||||
|
symbol: 'none',
|
||||||
|
data: dataIndex.map((item: any) => [item.timePeriod, item.times])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
echartList1.value = {
|
||||||
|
title: {
|
||||||
|
text: '指标越限时间概率分布'
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis'
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
data: indexNames
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
name: '时间段',
|
||||||
|
data: timePeriods
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
type: 'value'
|
||||||
|
// name: '次数'
|
||||||
|
},
|
||||||
|
series: seriesData
|
||||||
|
}
|
||||||
|
initProbabilityData()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const tableRef = ref()
|
|
||||||
provide('tableRef', tableRef)
|
|
||||||
|
|
||||||
provide('tableStore', tableStore)
|
provide('tableStore', tableStore)
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
tableStore.index()
|
initLineList()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const setTime = () => {
|
||||||
|
const time = getTime(
|
||||||
|
(TableHeaderRef.value?.datePickerRef.interval || prop.interval) ?? 0,
|
||||||
|
prop.timeKey,
|
||||||
|
fullscreen.value
|
||||||
|
? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
|
||||||
|
: prop.timeValue
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(time)) {
|
||||||
|
tableStore.table.params.searchBeginTime = time[0]
|
||||||
|
tableStore.table.params.searchEndTime = time[1]
|
||||||
|
TableHeaderRef.value?.setInterval(time[2] - 0)
|
||||||
|
TableHeaderRef.value?.setTimeInterval([time[0], time[1]])
|
||||||
|
} else {
|
||||||
|
console.warn('获取时间失败,time 不是一个有效数组')
|
||||||
|
}
|
||||||
|
}
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeKey,
|
() => prop.timeKey,
|
||||||
val => {
|
val => {
|
||||||
@@ -379,12 +448,12 @@ watch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeValue, // 监听的目标(函数形式避免直接传递 props 导致的警告)
|
() => prop.timeValue,
|
||||||
(newVal, oldVal) => {
|
(newVal, oldVal) => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
deep: true // 若 timeValue 是对象/数组,需开启深度监听
|
deep: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,709 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog draggable title="趋势图" v-model="dialogVisible" append-to-body width="70%">
|
||||||
|
<!-- 总体指标占比详情谐波含有率 -->
|
||||||
|
<div>
|
||||||
|
<TableHeader ref="tableHeaderRef" :showSearch="false" @selectChange="selectChange">
|
||||||
|
<template v-slot:select>
|
||||||
|
<el-form-item>
|
||||||
|
<DatePicker ref="datePickerRef"></DatePicker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="统计指标" label-width="80px">
|
||||||
|
<el-select
|
||||||
|
multiple
|
||||||
|
:multiple-limit="2"
|
||||||
|
collapse-tags
|
||||||
|
collapse-tags-tooltip
|
||||||
|
v-model="searchForm.index"
|
||||||
|
placeholder="请选择统计指标"
|
||||||
|
@change="onIndexChange($event)"
|
||||||
|
filterable
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in indexOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-radio-group v-model="searchForm.dataLevel" @change="init()">
|
||||||
|
<el-radio-button label="一次值" value="Primary" />
|
||||||
|
<el-radio-button label="二次值" value="Secondary" />
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="统计类型">
|
||||||
|
<el-select
|
||||||
|
style="min-width: 120px !important"
|
||||||
|
placeholder="请选择"
|
||||||
|
v-model="searchForm.valueType"
|
||||||
|
filterable
|
||||||
|
>
|
||||||
|
<el-option value="max" label="最大值"></el-option>
|
||||||
|
<el-option value="min" label="最小值"></el-option>
|
||||||
|
<el-option value="avg" label="平均值"></el-option>
|
||||||
|
<el-option value="cp95" label="cp95"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<div
|
||||||
|
class="history_count"
|
||||||
|
v-for="(item, index) in countData"
|
||||||
|
:key="index"
|
||||||
|
v-show="item.countOptions.length != 0"
|
||||||
|
>
|
||||||
|
<span class="mr12">
|
||||||
|
{{ item.name.includes('次数') ? item.name : item.name + '谐波次数' }}
|
||||||
|
</span>
|
||||||
|
<el-select
|
||||||
|
v-model="item.count"
|
||||||
|
@change="onCountChange($event, index)"
|
||||||
|
placeholder="请选择谐波次数"
|
||||||
|
style="width: 100px"
|
||||||
|
class="mr20"
|
||||||
|
filterable
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="vv in item.countOptions"
|
||||||
|
:key="vv"
|
||||||
|
:label="vv"
|
||||||
|
:value="vv"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
<template #operation>
|
||||||
|
<el-button type="primary" icon="el-icon-Search" @click="init()">查询</el-button>
|
||||||
|
<el-button :type="timeControl ? 'primary' : ''" icon="el-icon-Sort" @click="setTimeControl">
|
||||||
|
缺失数据
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</TableHeader>
|
||||||
|
</div>
|
||||||
|
<div class="history_chart" :style="pageHeight" v-loading="loading">
|
||||||
|
<MyEchart
|
||||||
|
ref="historyChart"
|
||||||
|
:options="echartsData"
|
||||||
|
v-if="showEchart"
|
||||||
|
/>
|
||||||
|
<el-empty :style="pageHeight" v-else description="暂无数据" />
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { mainHeight } from '@/utils/layout'
|
||||||
|
import { queryByCode, queryCsDictTree } from '@/api/system-boot/dictTree'
|
||||||
|
import { ref, onMounted, watch } from 'vue'
|
||||||
|
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||||
|
import { useDictData } from '@/stores/dictData'
|
||||||
|
import { queryStatistical } from '@/api/system-boot/csstatisticalset'
|
||||||
|
import { yMethod, exportCSV, completeTimeSeries } from '@/utils/echartMethod'
|
||||||
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
|
import { trendData } from '@/api/harmonic-boot/cockpit/cockpit'
|
||||||
|
import DatePicker from '@/components/form/datePicker/index.vue'
|
||||||
|
import { color } from '@/components/echarts/color'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
const dictData = useDictData()
|
||||||
|
defineOptions({
|
||||||
|
// name: 'govern/device/control'
|
||||||
|
})
|
||||||
|
const props = defineProps({
|
||||||
|
TrendList: {
|
||||||
|
type: Array
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const dialogVisible: any = ref(false)
|
||||||
|
// console.log("🚀 ~ props:", props.TrendList)
|
||||||
|
const showEchart = ref(true)
|
||||||
|
const num = ref(0)
|
||||||
|
const timeControl = ref(false)
|
||||||
|
//值类型
|
||||||
|
const pageHeight = ref(mainHeight(57 * 1.6, 1.6))
|
||||||
|
const loading = ref(true)
|
||||||
|
const searchForm: any = ref({})
|
||||||
|
const tableHeaderRef = ref()
|
||||||
|
const typeOptions = [
|
||||||
|
{
|
||||||
|
name: '平均值',
|
||||||
|
id: 'avg'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '最大值',
|
||||||
|
id: 'max'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '最小值',
|
||||||
|
id: 'min'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'CP95值',
|
||||||
|
id: 'cp95'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
searchForm.value = {
|
||||||
|
index: [],
|
||||||
|
type: typeOptions[0].id,
|
||||||
|
count: '',
|
||||||
|
searchBeginTime: '',
|
||||||
|
searchEndTime: '',
|
||||||
|
dataLevel: 'Primary',
|
||||||
|
valueType: 'avg'
|
||||||
|
}
|
||||||
|
//统计指标
|
||||||
|
const indexOptions: any = ref([])
|
||||||
|
//谐波次数
|
||||||
|
const countOptions: any = ref([])
|
||||||
|
// Harmonic_Type
|
||||||
|
// portable-harmonic
|
||||||
|
const legendDictList: any = ref([])
|
||||||
|
|
||||||
|
const initCode = (field: string, title: string) => {
|
||||||
|
queryByCode('steady_state_limit_trend').then(res => {
|
||||||
|
queryCsDictTree(res.data.id).then(item => {
|
||||||
|
//排序
|
||||||
|
indexOptions.value = item.data.sort((a: any, b: any) => {
|
||||||
|
return a.sort - b.sort
|
||||||
|
})
|
||||||
|
const titleMap: Record<string, number> = {
|
||||||
|
flickerOvertime: 0,
|
||||||
|
uaberranceOvertime: 3,
|
||||||
|
ubalanceOvertime: 4,
|
||||||
|
freqDevOvertime: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
let defaultIndex = 0 // 默认值
|
||||||
|
|
||||||
|
if (field in titleMap) {
|
||||||
|
defaultIndex = titleMap[field]
|
||||||
|
} else if (field.includes('uharm')) {
|
||||||
|
defaultIndex = 1
|
||||||
|
} else if (field.includes('iharm')) {
|
||||||
|
defaultIndex = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
searchForm.value.index[0] = indexOptions.value[defaultIndex].id
|
||||||
|
})
|
||||||
|
queryStatistical(res.data.id).then(vv => {
|
||||||
|
legendDictList.value = vv.data
|
||||||
|
indexOptions.value.map((item: any, index: any) => {
|
||||||
|
if (!countDataCopy.value[index]) {
|
||||||
|
countDataCopy.value[index] = {
|
||||||
|
index: item.id,
|
||||||
|
countOptions: [],
|
||||||
|
count: [],
|
||||||
|
name: indexOptions.value.find((vv: any) => {
|
||||||
|
return vv.id == item.id
|
||||||
|
})?.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
legendDictList.value?.selectedList?.map((vv: any, vvs: any) => {
|
||||||
|
//查找相等的指标
|
||||||
|
if (item.id == vv.dataType) {
|
||||||
|
vv.eleEpdPqdVOS.map((kk: any, kks: any) => {
|
||||||
|
if (kk.harmStart && kk.harmEnd) {
|
||||||
|
range(0, 0, 0)
|
||||||
|
|
||||||
|
if (kk.showName == '间谐波电压含有率') {
|
||||||
|
countDataCopy.value[index].countOptions = range(kk.harmStart, kk.harmEnd, 1).map(
|
||||||
|
(item: any) => {
|
||||||
|
return item - 0.5
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
countDataCopy.value[index].countOptions = range(kk.harmStart, kk.harmEnd, 1)
|
||||||
|
}
|
||||||
|
if (title && countDataCopy.value[index].countOptions.includes(Number(title))) {
|
||||||
|
countDataCopy.value[index].count = Number(title)
|
||||||
|
} else if (title && countDataCopy.value[index].countOptions.includes(title)) {
|
||||||
|
countDataCopy.value[index].count = title
|
||||||
|
} else if (
|
||||||
|
!countDataCopy.value[index].count ||
|
||||||
|
countDataCopy.value[index].count.length == 0
|
||||||
|
) {
|
||||||
|
// 只有当count为空时才设置默认值
|
||||||
|
countDataCopy.value[index].count = countDataCopy.value[index].countOptions[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
nextTick(() => {
|
||||||
|
formatCountOptions()
|
||||||
|
})
|
||||||
|
init()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const chartsList = ref<any>([])
|
||||||
|
const chartTitle: any = ref('')
|
||||||
|
const echartsData = ref<any>(null)
|
||||||
|
//加载echarts图表
|
||||||
|
//历史趋势数据
|
||||||
|
const historyDataList: any = ref([])
|
||||||
|
const range = (start: any, end: any, step: any) => {
|
||||||
|
return Array.from({ length: (end - start) / step + 1 }, (_, i) => start + i * step)
|
||||||
|
}
|
||||||
|
//获取请求趋势数据参数
|
||||||
|
const trendRequestData = ref()
|
||||||
|
const getTrendRequest = (val: any) => {
|
||||||
|
trendRequestData.value = val
|
||||||
|
// init()
|
||||||
|
}
|
||||||
|
//初始化趋势图
|
||||||
|
const headerRef = ref()
|
||||||
|
const datePickerRef = ref()
|
||||||
|
const lineStyle = [{ type: 'solid' }, { type: 'dashed' }, { type: 'dotted' }]
|
||||||
|
const init = async () => {
|
||||||
|
loading.value = true
|
||||||
|
// 选择指标的时候切换legend内容和data数据
|
||||||
|
let list: any = []
|
||||||
|
legendDictList.value?.selectedList?.map((item: any) => {
|
||||||
|
searchForm.value.index.map((vv: any) => {
|
||||||
|
if (item.dataType == vv) {
|
||||||
|
list.push(item.eleEpdPqdVOS)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
//颜色数组
|
||||||
|
const colorList = color
|
||||||
|
//选择的指标使用方法处理
|
||||||
|
formatCountOptions()
|
||||||
|
//查询历史趋势
|
||||||
|
historyDataList.value = []
|
||||||
|
chartTitle.value = ''
|
||||||
|
|
||||||
|
searchForm.value.index.map((item: any, indexs: any) => {
|
||||||
|
indexOptions.value.map((vv: any) => {
|
||||||
|
if (vv.id == item) {
|
||||||
|
chartTitle.value += indexs == searchForm.value.index.length - 1 ? vv.name : vv.name + '/'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
let lists: any = []
|
||||||
|
let frequencys: any = null
|
||||||
|
countData.value.map((item: any, index: any) => {
|
||||||
|
if (item.name.includes('谐波含有率')) {
|
||||||
|
frequencys = item.count
|
||||||
|
} else {
|
||||||
|
frequencys = ''
|
||||||
|
}
|
||||||
|
lists[index] = {
|
||||||
|
statisticalId: item.index,
|
||||||
|
frequency: frequencys !== null && frequencys !== undefined ? String(frequencys) : ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
let obj = {
|
||||||
|
//...trendRequestData.value,
|
||||||
|
lineId: trendRequestData.value.lineId,
|
||||||
|
list: lists,
|
||||||
|
dataLevel: searchForm.value.dataLevel,
|
||||||
|
valueType: searchForm.value.valueType,
|
||||||
|
searchBeginTime: datePickerRef.value && datePickerRef.value.timeValue[0],
|
||||||
|
searchEndTime: datePickerRef.value && datePickerRef.value.timeValue[1]
|
||||||
|
}
|
||||||
|
if (searchForm.value.index.length == 0) {
|
||||||
|
ElMessage.warning('请选择统计指标')
|
||||||
|
loading.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (obj.list.length != 0) {
|
||||||
|
try {
|
||||||
|
showEchart.value = true
|
||||||
|
await trendData(obj)
|
||||||
|
.then((res: any) => {
|
||||||
|
if (res.code == 'A0000') {
|
||||||
|
if (res.data.length == 0) {
|
||||||
|
loading.value = false
|
||||||
|
showEchart.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
historyDataList.value = res.data
|
||||||
|
chartsList.value = JSON.parse(JSON.stringify(res.data))
|
||||||
|
loading.value = false
|
||||||
|
setEchart()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const setEchart = () => {
|
||||||
|
loading.value = true
|
||||||
|
echartsData.value = {}
|
||||||
|
//icon图标替换legend图例
|
||||||
|
|
||||||
|
// y轴单位数组
|
||||||
|
let unitList: any = []
|
||||||
|
|
||||||
|
let groupedData = chartsList.value.reduce((acc: any, item: any) => {
|
||||||
|
let key = ''
|
||||||
|
if (item.phase == null) {
|
||||||
|
key = item.unit
|
||||||
|
} else {
|
||||||
|
key = item.anotherName
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!acc[key]) {
|
||||||
|
acc[key] = []
|
||||||
|
}
|
||||||
|
acc[key].push(item)
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
let result = Object.values(groupedData)
|
||||||
|
if (chartsList.value.length > 0) {
|
||||||
|
unitList = result.map((item: any) => {
|
||||||
|
return item[0].unit
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
echartsData.value = {
|
||||||
|
legend: {
|
||||||
|
itemWidth: 20,
|
||||||
|
itemHeight: 20,
|
||||||
|
itemStyle: { opacity: 0 }, //去圆点
|
||||||
|
type: 'scroll', // 开启滚动分页
|
||||||
|
// orient: 'vertical', // 垂直排列
|
||||||
|
top: 5,
|
||||||
|
right: 70
|
||||||
|
// width: 550,
|
||||||
|
// height: 50
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
top: '80px'
|
||||||
|
},
|
||||||
|
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,
|
||||||
|
formatter(params: any) {
|
||||||
|
const xname = params[0].value[0]
|
||||||
|
let str = `${xname}<br>`
|
||||||
|
params.forEach((el: any, index: any) => {
|
||||||
|
let marker = ''
|
||||||
|
|
||||||
|
if (el.value[3] == 'dashed') {
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
marker += `<span style="display:inline-block;border: 2px ${el.color} solid;margin-right:5px;width:10px;height:0px;background-color:#ffffff00;"></span>`
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
marker = `<span style="display:inline-block;border: 2px ${el.color} ${el.value[3]};margin-right:5px;width:40px;height:0px;background-color:#ffffff00;"></span>`
|
||||||
|
}
|
||||||
|
let unit = el.value[2] ? el.value[2] : ''
|
||||||
|
str += `${marker}${el.seriesName.split('(')[0]}:${el.value[1]}${unit}
|
||||||
|
<br>`
|
||||||
|
})
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
},
|
||||||
|
color: ['#DAA520', '#2E8B57', '#A52a2a', ...color],
|
||||||
|
xAxis: {
|
||||||
|
type: 'time',
|
||||||
|
axisLabel: {
|
||||||
|
formatter: {
|
||||||
|
day: '{MM}-{dd}',
|
||||||
|
month: '{MM}',
|
||||||
|
year: '{yyyy}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: [{}],
|
||||||
|
toolbox: {
|
||||||
|
featureProps: {
|
||||||
|
myTool1: {
|
||||||
|
show: true,
|
||||||
|
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',
|
||||||
|
onclick: e => {
|
||||||
|
// console.log("🚀 ~ init ~ echartsData.value:", echartsData.value.options.series.map(item => item.data))
|
||||||
|
|
||||||
|
let list = echartsData.value.options.series?.map((item: any) => item.data)
|
||||||
|
let dataList = list[0]?.map((item: any, index: any) => {
|
||||||
|
let value = [item[0], item[1]]
|
||||||
|
list.forEach((item1: any, index1: any) => {
|
||||||
|
if (index1 > 0) {
|
||||||
|
value.push(item1 && item1[index] ? item1[index][1] : null)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return value
|
||||||
|
})
|
||||||
|
exportCSV(
|
||||||
|
echartsData.value.options.series.map((item: any) => item.name),
|
||||||
|
dataList,
|
||||||
|
'历史趋势.csv'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
series: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// console.log("🚀 ~ unitList.forEach ~ unitList:", unitList)
|
||||||
|
|
||||||
|
if (chartsList.value.length > 0) {
|
||||||
|
let yData: any = []
|
||||||
|
echartsData.value.yAxis = []
|
||||||
|
let setList = [...new Set(unitList)]
|
||||||
|
|
||||||
|
setList.forEach((item: any, index: any) => {
|
||||||
|
if (index > 2) {
|
||||||
|
echartsData.value.grid.right = (index - 1) * 80
|
||||||
|
}
|
||||||
|
yData.push([])
|
||||||
|
let right = {
|
||||||
|
position: 'right',
|
||||||
|
offset: (index - 1) * 80
|
||||||
|
}
|
||||||
|
// console.log("🚀 ~ unitList.forEach ~ right.index:", index)
|
||||||
|
echartsData.value.yAxis.push({
|
||||||
|
name: item,
|
||||||
|
yAxisIndex: index,
|
||||||
|
splitNumber: 5,
|
||||||
|
minInterval: 1,
|
||||||
|
splitLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
...(index > 0 ? right : null)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// console.log("🚀 ~ result.forEach ~ result:", result)
|
||||||
|
// '电压负序分量', '电压正序分量', '电压零序分量'
|
||||||
|
let ABCName = [
|
||||||
|
...new Set(
|
||||||
|
chartsList.value.map((item: any) => {
|
||||||
|
return item.anotherName == '电压负序分量'
|
||||||
|
? '电压不平衡'
|
||||||
|
: item.anotherName == '电压正序分量'
|
||||||
|
? '电压不平衡'
|
||||||
|
: item.anotherName == '电压零序分量'
|
||||||
|
? '电压不平衡'
|
||||||
|
: item.anotherName
|
||||||
|
})
|
||||||
|
)
|
||||||
|
]
|
||||||
|
// console.log("🚀 ~ .then ~ ABCName:", ABCName)
|
||||||
|
result.forEach((item: any, index: any) => {
|
||||||
|
let yMethodList: any = []
|
||||||
|
|
||||||
|
let ABCList = Object.values(
|
||||||
|
item.reduce((acc, item) => {
|
||||||
|
let key = ''
|
||||||
|
if (item.phase == null) {
|
||||||
|
key = item.anotherName
|
||||||
|
} else {
|
||||||
|
key = item.phase
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!acc[key]) {
|
||||||
|
acc[key] = []
|
||||||
|
}
|
||||||
|
acc[key].push(item)
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
)
|
||||||
|
// console.log("🚀 ~ ABCList.forEach ~ ABCList:", ABCList)
|
||||||
|
|
||||||
|
ABCList.forEach((kk: any) => {
|
||||||
|
let colorName = kk[0].phase?.charAt(0).toUpperCase()
|
||||||
|
let lineS = ABCName.findIndex(
|
||||||
|
item =>
|
||||||
|
item ===
|
||||||
|
(kk[0].anotherName == '电压负序分量'
|
||||||
|
? '电压不平衡'
|
||||||
|
: kk[0].anotherName == '电压正序分量'
|
||||||
|
? '电压不平衡'
|
||||||
|
: kk[0].anotherName == '电压零序分量'
|
||||||
|
? '电压不平衡'
|
||||||
|
: kk[0].anotherName)
|
||||||
|
)
|
||||||
|
|
||||||
|
let seriesList: any = []
|
||||||
|
kk.forEach((cc: any) => {
|
||||||
|
if (cc.statisticalData !== null) {
|
||||||
|
yData[setList.indexOf(kk[0].unit)].push(cc.statisticalData?.toFixed(2))
|
||||||
|
}
|
||||||
|
|
||||||
|
seriesList.push([cc.time, cc.statisticalData?.toFixed(2), cc.unit, lineStyle[lineS].type])
|
||||||
|
})
|
||||||
|
// console.log(kk);
|
||||||
|
|
||||||
|
echartsData.value.options.series.push({
|
||||||
|
name: kk[0].phase ? kk[0].phase + '相' + kk[0].anotherName : kk[0].anotherName,
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
color:
|
||||||
|
colorName == 'A' ? '#DAA520' : colorName == 'B' ? '#2E8B57' : colorName == 'C' ? '#A52a2a' : '',
|
||||||
|
symbol: 'none',
|
||||||
|
// data: seriesList,
|
||||||
|
data: timeControl.value ? completeTimeSeries(seriesList) : seriesList,
|
||||||
|
lineStyle: lineStyle[lineS],
|
||||||
|
yAxisIndex: setList.indexOf(kk[0].unit)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
yData.forEach((item: any, index: any) => {
|
||||||
|
let [min, max] = yMethod(item)
|
||||||
|
echartsData.value.yAxis[index].min = min
|
||||||
|
echartsData.value.yAxis[index].max = max
|
||||||
|
})
|
||||||
|
// console.log("🚀 ~ result.forEach ~ echartsData.value:", echartsData.value)
|
||||||
|
}
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
const setTimeControl = () => {
|
||||||
|
timeControl.value = !timeControl.value
|
||||||
|
setEchart()
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectChange = (flag: boolean, height: any) => {
|
||||||
|
|
||||||
|
pageHeight.value = mainHeight(height * 1.6, 1.6)
|
||||||
|
}
|
||||||
|
//导出
|
||||||
|
const historyChart = ref()
|
||||||
|
|
||||||
|
const countData: any = ref([])
|
||||||
|
const countDataCopy: any = ref([])
|
||||||
|
|
||||||
|
//根据选择的指标处理谐波次数
|
||||||
|
const formatCountOptions = () => {
|
||||||
|
countData.value = []
|
||||||
|
if (searchForm.value.index.length != 0) {
|
||||||
|
searchForm.value.index.forEach((item: any, index: any) => {
|
||||||
|
countDataCopy.value.forEach((vv: any, vvs: any) => {
|
||||||
|
if (vv.index == item) {
|
||||||
|
countData.value.push(vv)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
countData.value.map((item: any, key: any) => {
|
||||||
|
if (item.name == '谐波电流有效值') {
|
||||||
|
item.name = '谐波电流次数'
|
||||||
|
} else if (item.name == '谐波电压含有率') {
|
||||||
|
item.name = '谐波电压次数'
|
||||||
|
} else if (item.name == '间谐波电压含有率') {
|
||||||
|
item.name = '间谐波电压次数'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// setTimeout(() => {
|
||||||
|
// tableHeaderRef.value.computedSearchRow()
|
||||||
|
// }, 500)
|
||||||
|
}
|
||||||
|
// 判断下拉框是否存在
|
||||||
|
const onCountChange = (val: any, index: any) => {
|
||||||
|
if (val.length == 0) {
|
||||||
|
countData.value[index].count = countData.value[index].countOptions[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const flag = ref(true)
|
||||||
|
const onIndexChange = (val: any) => {
|
||||||
|
num.value += 1
|
||||||
|
let pp: any = []
|
||||||
|
indexOptions.value.forEach((item: any) => {
|
||||||
|
const filteredResult = val.filter(vv => item.id == vv)
|
||||||
|
if (filteredResult.length > 0) {
|
||||||
|
pp.push(filteredResult[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
searchForm.value.index = pp
|
||||||
|
flag.value = true
|
||||||
|
formatCountOptions()
|
||||||
|
}
|
||||||
|
watch(
|
||||||
|
() => searchForm.value.index,
|
||||||
|
(val: any, oldval: any) => {},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const openDialog = async (row: any, field: any, title: any) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
trendRequestData.value = row
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
// 默认当天
|
||||||
|
datePickerRef.value.setInterval(5)
|
||||||
|
datePickerRef.value.timeValue = [row.time, row.time]
|
||||||
|
initCode(field, title)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ getTrendRequest, openDialog })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.history_header {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
// flex-wrap: wrap;
|
||||||
|
#history_select {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
// justify-content: flex-start;
|
||||||
|
// overflow-x: auto;
|
||||||
|
height: auto;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
.el-form-item {
|
||||||
|
flex: none !important;
|
||||||
|
// max-width: 380px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-select {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #history_select::-webkit-scrollbar {
|
||||||
|
// width: 0 !important;
|
||||||
|
// display: none !important;
|
||||||
|
// }
|
||||||
|
|
||||||
|
.history_searchBtn {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.history_chart {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
// flex: 1;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history_count {
|
||||||
|
.el-select {
|
||||||
|
min-width: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,191 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<!-- 指标越限详情 -->
|
||||||
|
<el-dialog draggable title="指标越限详情" v-model="dialogVisible" append-to-body width="70%">
|
||||||
|
<TableHeader datePicker showExport :showReset="false" ref="tableHeaderRef">
|
||||||
|
<template v-slot:select>
|
||||||
|
<el-form-item label="监测点">
|
||||||
|
<el-select
|
||||||
|
v-model="tableStore.table.params.lineId"
|
||||||
|
placeholder="请选择监测点"
|
||||||
|
style="width: 150px"
|
||||||
|
filterable
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in options"
|
||||||
|
:key="item.lineId"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.lineId"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</TableHeader>
|
||||||
|
<Table ref="tableRef" @cell-click="cellClickEvent" isGroup :height="height"></Table>
|
||||||
|
</el-dialog>
|
||||||
|
<!-- 谐波电流、谐波电压占有率 -->
|
||||||
|
<HarmonicRatio
|
||||||
|
ref="harmonicRatioRef"
|
||||||
|
@close="onHarmonicRatioClose"
|
||||||
|
v-if="dialogFlag"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, provide,nextTick } from 'vue'
|
||||||
|
import Table from '@/components/table/index.vue'
|
||||||
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
|
import TableStore from '@/utils/tableStore'
|
||||||
|
import { mainHeight } from '@/utils/layout'
|
||||||
|
import HarmonicRatio from '@/components/cockpit/indicatorFittingChart/components/harmonicRatio.vue'
|
||||||
|
import { cslineList } from '@/api/harmonic-boot/cockpit/cockpit'
|
||||||
|
|
||||||
|
const dialogVisible: any = ref(false)
|
||||||
|
const harmonicRatioRef: any = ref(null)
|
||||||
|
|
||||||
|
const dialogFlag = ref(false)
|
||||||
|
|
||||||
|
const options = ref()
|
||||||
|
const height = mainHeight(0, 2).height as any
|
||||||
|
const tableHeaderRef = ref()
|
||||||
|
const loop50 = (key: string) => {
|
||||||
|
let list: any[] = []
|
||||||
|
for (let i = 2; i < 26; i++) {
|
||||||
|
list.push({
|
||||||
|
title: i + '次',
|
||||||
|
field: key + i + 'Overtime',
|
||||||
|
width: '60',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row[key + i + 'Overtime']}</span>`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
const tableStore: any = new TableStore({
|
||||||
|
url: '/cs-harmonic-boot/mainLine/statLimitRateDetails',
|
||||||
|
method: 'POST',
|
||||||
|
publicHeight: 30,
|
||||||
|
showPage: false,
|
||||||
|
exportName: '主要监测点列表',
|
||||||
|
column: [
|
||||||
|
{
|
||||||
|
field: 'index',
|
||||||
|
title: '序号',
|
||||||
|
width: '80',
|
||||||
|
formatter: (row: any) => {
|
||||||
|
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '日期',
|
||||||
|
field: 'time',
|
||||||
|
width: '150',
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '名称',
|
||||||
|
field: 'lineName',
|
||||||
|
width: '150'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '闪变越限(分钟)',
|
||||||
|
field: 'flickerOvertime',
|
||||||
|
width: '90',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.flickerOvertime}</span>`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '谐波电压越限(分钟)',
|
||||||
|
children: loop50('uharm')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '谐波电流越限(分钟)',
|
||||||
|
children: loop50('iharm')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '三相不平衡度越限(分钟)',
|
||||||
|
field: 'ubalanceOvertime',
|
||||||
|
width: '100',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.ubalanceOvertime}</span>`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '电压偏差越限(分钟)',
|
||||||
|
field: 'uaberranceOvertime',
|
||||||
|
width: '100',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.uaberranceOvertime}</span>`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '频率偏差越限(分钟)',
|
||||||
|
field: 'freqDevOvertime',
|
||||||
|
width: '100',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.freqDevOvertime}</span>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
beforeSearchFun: () => {
|
||||||
|
},
|
||||||
|
loadCallback: () => {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
provide('tableStore', tableStore)
|
||||||
|
tableStore.table.params.sortBy = ''
|
||||||
|
tableStore.table.params.orderBy = ''
|
||||||
|
const open = async (row: any,searchBeginTime:any,searchEndTime:any) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
initCSlineList()
|
||||||
|
tableStore.table.params.lineId = row.lineId
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
tableHeaderRef.value.setTimeInterval([searchBeginTime, searchEndTime])
|
||||||
|
tableStore.table.params.searchBeginTime =searchBeginTime
|
||||||
|
tableStore.table.params.searchEndTime = searchEndTime
|
||||||
|
tableStore.index()
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 点击行
|
||||||
|
const cellClickEvent = ({ row, column }: any) => {
|
||||||
|
if (column.field != 'name' && column.field != 'time') {
|
||||||
|
dialogFlag.value = true
|
||||||
|
dialogVisible.value = false
|
||||||
|
nextTick(() => {
|
||||||
|
harmonicRatioRef.value.openDialog(row,column.field,column.title.replace(/次/g, ""))
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 谐波弹窗关闭时的回调
|
||||||
|
const onHarmonicRatioClose = () => {
|
||||||
|
dialogFlag.value = false
|
||||||
|
// 重新打开指标越限详情弹窗
|
||||||
|
nextTick(() => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const initCSlineList = async () => {
|
||||||
|
const res = await cslineList({})
|
||||||
|
options.value = res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
defineExpose({ open })
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@@ -1,41 +1,75 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!--主要监测点列表 -->
|
<!--主要监测点列表 -->
|
||||||
<TableHeader :showReset="false" >
|
<TableHeader :showReset="false" :timeKeyList="prop.timeKey" @selectChange="selectChange" v-if="fullscreen" datePicker ref="TableHeaderRef">
|
||||||
<template v-slot:select>
|
<template v-slot:select>
|
||||||
<el-form-item label="关键词">
|
<el-form-item label="关键词">
|
||||||
<el-input v-model="tableStore.table.params.searchValue" clearable placeholder="请输关键字" />
|
<el-input v-model="tableStore.table.params.keywords" clearable placeholder="请输关键字" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<Table ref="tableRef" @cell-click="cellClickEvent" :height="`calc(${prop.height} - 58px)`"></Table>
|
<Table
|
||||||
|
ref="tableRef"
|
||||||
|
@cell-click="cellClickEvent"
|
||||||
|
:height="`calc(${prop.height} - ${headerHeight}px + ${fullscreen ? -58 : 56}px )`"
|
||||||
|
></Table>
|
||||||
<!-- 指标越限详情 -->
|
<!-- 指标越限详情 -->
|
||||||
<OverLimitDetails ref="OverLimitDetailsRef" />
|
<OverLimitDetails ref="OverLimitDetailsRef" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
import { ref, onMounted, provide, reactive, watch, nextTick } from 'vue'
|
||||||
import TableStore from '@/utils/tableStore'
|
import TableStore from '@/utils/tableStore'
|
||||||
import Table from '@/components/table/index.vue'
|
import Table from '@/components/table/index.vue'
|
||||||
import TableHeader from '@/components/table/header/index.vue'
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
import { useDictData } from '@/stores/dictData'
|
import { getTime } from '@/utils/formatTime'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import OverLimitDetails from '@/components/cockpit/indicatorFittingChart/components/overLimitDetails.vue'
|
||||||
import { getTimeOfTheMonth } from '@/utils/formatTime'
|
import { useRoute } from 'vue-router'
|
||||||
import { ElTag } from 'element-plus'
|
import { useTimeCacheStore } from '@/stores/timeCache'
|
||||||
import OverLimitDetails from '@/components/cockpit/listOfMainMonitoringPoints/components/overLimitDetails.vue'
|
|
||||||
const prop = defineProps({
|
|
||||||
width: { type: String },
|
|
||||||
height: { type: String },
|
|
||||||
timeKey: { type: String },
|
|
||||||
timeValue: { type: Object }
|
|
||||||
})
|
|
||||||
const dictData = useDictData()
|
|
||||||
const OverLimitDetailsRef = ref()
|
|
||||||
const tableStore: any = new TableStore({
|
|
||||||
url: '/user-boot/role/selectRoleDetail?id=0',
|
|
||||||
method: 'POST',
|
|
||||||
|
|
||||||
showPage: false,
|
const prop = defineProps({
|
||||||
|
w: { type: [String, Number] },
|
||||||
|
h: { type: [String, Number] },
|
||||||
|
width: { type: [String, Number] },
|
||||||
|
height: { type: [String, Number] },
|
||||||
|
timeKey: { type: Array as () => string[] },
|
||||||
|
timeValue: { type: Object },
|
||||||
|
interval: { type: Number }
|
||||||
|
})
|
||||||
|
const OverLimitDetailsRef = ref()
|
||||||
|
const headerHeight = ref(57)
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
const timeCacheStore = useTimeCacheStore()
|
||||||
|
|
||||||
|
const TableHeaderRef = ref()
|
||||||
|
|
||||||
|
// 计算是否全屏展示
|
||||||
|
const fullscreen = computed(() => {
|
||||||
|
const w = Number(prop.w)
|
||||||
|
const h = Number(prop.h)
|
||||||
|
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
|
||||||
|
// 执行相应逻辑
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
|
||||||
|
headerHeight.value = height
|
||||||
|
|
||||||
|
if (datePickerValue && datePickerValue.timeValue) {
|
||||||
|
// 更新时间参数
|
||||||
|
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
|
||||||
|
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableStore: any = new TableStore({
|
||||||
|
url: '/cs-harmonic-boot/mainLine/list',
|
||||||
|
method: 'POST',
|
||||||
|
showPage: fullscreen.value ? true : false,
|
||||||
exportName: '主要监测点列表',
|
exportName: '主要监测点列表',
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
@@ -48,95 +82,82 @@ const tableStore: any = new TableStore({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '监测点名称',
|
title: '监测点名称',
|
||||||
field: 'name',
|
field: 'lineName',
|
||||||
minWidth: '90',
|
minWidth: '90',
|
||||||
|
|
||||||
render: 'customTemplate',
|
render: 'customTemplate',
|
||||||
customTemplate: (row: any) => {
|
customTemplate: (row: any) => {
|
||||||
return `<span style='cursor: pointer;text-decoration: underline;'>${row.name}</span>`
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.lineName}</span>`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
title: '监测对象类型',
|
title: '监测对象类型',
|
||||||
field: 'type',
|
field: 'objType',
|
||||||
minWidth: '90'
|
minWidth: '90'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '是否治理',
|
title: '是否治理',
|
||||||
field: 'whetherToGovern',
|
field: 'govern',
|
||||||
minWidth: '70'
|
minWidth: '70'
|
||||||
},
|
},
|
||||||
|
|
||||||
{ title: '主要存在的电能质量问题', field: 'question', minWidth: '150' }
|
{ title: '主要存在的电能质量问题', field: 'problems', minWidth: '150', showOverflow: true }
|
||||||
],
|
],
|
||||||
beforeSearchFun: () => {
|
beforeSearchFun: () => {
|
||||||
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
|
setTime()
|
||||||
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
|
|
||||||
},
|
},
|
||||||
loadCallback: () => {
|
loadCallback: () => {
|
||||||
|
|
||||||
tableStore.table.data = [
|
|
||||||
{
|
|
||||||
name: '10kV1#电动机',
|
|
||||||
type: '电动机',
|
|
||||||
whetherToGovern: '否',
|
|
||||||
question: '3次谐波电压、5次谐波电流、电压不平衡度超标'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '10kV2#(治理后)',
|
|
||||||
type: '电焊机',
|
|
||||||
whetherToGovern: '100A APF',
|
|
||||||
question: '所有指标均合格'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '380V电焊机(治理前)',
|
|
||||||
type: '电焊机',
|
|
||||||
whetherToGovern: '100A APF',
|
|
||||||
question: '5次谐波电流、电压不平衡度超标'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '380V水泵机',
|
|
||||||
type: '电动机',
|
|
||||||
whetherToGovern: '否',
|
|
||||||
question: '所有指标均合格'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
tableStore.table.height = `calc(${prop.height} - 80px)`
|
tableStore.table.height = `calc(${prop.height} - 80px)`
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const tableRef = ref()
|
const tableRef = ref()
|
||||||
provide('tableRef', tableRef)
|
provide('tableRef', tableRef)
|
||||||
tableStore.table.params.type = ''
|
tableStore.table.params.keywords = ''
|
||||||
tableStore.table.params.searchValue = ''
|
|
||||||
provide('tableStore', tableStore)
|
provide('tableStore', tableStore)
|
||||||
|
|
||||||
// 点击行
|
// 点击行
|
||||||
const cellClickEvent = ({ row, column }: any) => {
|
const cellClickEvent = ({ row, column }: any) => {
|
||||||
if (column.field == 'name') {
|
if (column.field == 'lineName') {
|
||||||
console.log(row)
|
OverLimitDetailsRef.value.open(
|
||||||
OverLimitDetailsRef.value.open(row)
|
row,
|
||||||
|
tableStore.table.params.searchBeginTime || prop.timeValue?.[0],
|
||||||
|
tableStore.table.params.searchEndTime || prop.timeValue?.[1]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setTime = () => {
|
||||||
|
const time = getTime(
|
||||||
|
(TableHeaderRef.value?.datePickerRef.interval || prop.interval) ?? 0,
|
||||||
|
prop.timeKey,
|
||||||
|
fullscreen.value
|
||||||
|
? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
|
||||||
|
: prop.timeValue
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(time)) {
|
||||||
|
tableStore.table.params.searchBeginTime = time[0]
|
||||||
|
tableStore.table.params.searchEndTime = time[1]
|
||||||
|
// TableHeaderRef.value?.setInterval(time[2] - 0)
|
||||||
|
// TableHeaderRef.value?.setTimeInterval([time[0], time[1]])
|
||||||
|
} else {
|
||||||
|
console.warn('获取时间失败,time 不是一个有效数组')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 在组件挂载时设置缓存值到 DatePicker
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeKey,
|
() => prop.timeValue,
|
||||||
val => {
|
|
||||||
tableStore.index()
|
|
||||||
}
|
|
||||||
)
|
|
||||||
watch(
|
|
||||||
() => prop.timeValue, // 监听的目标(函数形式避免直接传递 props 导致的警告)
|
|
||||||
(newVal, oldVal) => {
|
(newVal, oldVal) => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
deep: true // 若 timeValue 是对象/数组,需开启深度监听
|
deep: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,449 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 总体指标占比详情谐波含有率 -->
|
||||||
|
<el-dialog draggable title="谐波电压/电流含有率" v-model="dialogVisible" append-to-body width="70%">
|
||||||
|
<TableHeader datePicker showExport :showReset="false" @selectChange="selectChange">
|
||||||
|
<template v-slot:select>
|
||||||
|
<el-form-item label="谐波次数">
|
||||||
|
<el-select
|
||||||
|
v-model="tableStore.table.params.searchValue"
|
||||||
|
placeholder="请选择谐波次数"
|
||||||
|
style="width: 150px"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in harmonicOptions"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="指标类型" v-show="!tableStore.table.params.checked">
|
||||||
|
<el-select
|
||||||
|
v-model="tableStore.table.params.indicatorType"
|
||||||
|
placeholder="请选择指标类型"
|
||||||
|
style="width: 150px"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in indicatorList"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="指标类型1" v-show="tableStore.table.params.checked == true">
|
||||||
|
<el-select
|
||||||
|
v-model="tableStore.table.params.indicatorType1"
|
||||||
|
placeholder="请选择指标类型1"
|
||||||
|
style="width: 150px"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in indicatorList"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="指标类型2" v-show="tableStore.table.params.checked == true">
|
||||||
|
<el-select
|
||||||
|
v-model="tableStore.table.params.indicatorType2"
|
||||||
|
placeholder="请选择指标类型2"
|
||||||
|
style="width: 150px"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in indicatorList"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-checkbox v-model="tableStore.table.params.checked">指标对比分析</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</TableHeader>
|
||||||
|
<my-echart
|
||||||
|
class="tall"
|
||||||
|
v-if="!tableStore.table.params.checked"
|
||||||
|
:options="echartList"
|
||||||
|
style="width: 98%; height: 320px"
|
||||||
|
/>
|
||||||
|
<my-echart class="tall" v-else :options="echartContrastList" style="width: 98%; height: 320px" />
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
||||||
|
import TableStore from '@/utils/tableStore'
|
||||||
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
|
import { getTimeOfTheMonth } from '@/utils/formatTime'
|
||||||
|
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||||
|
import { useConfig } from '@/stores/config'
|
||||||
|
const prop = defineProps({
|
||||||
|
width: { type: [String, Number]},
|
||||||
|
height: { type: [String, Number]},
|
||||||
|
timeKey: { type: [String, Number]},
|
||||||
|
timeValue: { type: Object }
|
||||||
|
})
|
||||||
|
|
||||||
|
const dialogVisible: any = ref(false)
|
||||||
|
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
value: '35kV进线',
|
||||||
|
label: '35kV进线'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const config = useConfig()
|
||||||
|
|
||||||
|
const harmonicOptions = Array.from({ length: 50 }, (_, i) => ({
|
||||||
|
value: String(i + 1),
|
||||||
|
label: `${i + 1}次谐波`
|
||||||
|
}))
|
||||||
|
|
||||||
|
const exceedingTheLimitList: any = ref([
|
||||||
|
{
|
||||||
|
label: '越限',
|
||||||
|
value: '1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '不越限',
|
||||||
|
value: '0'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
const indicatorList: any = ref([
|
||||||
|
{
|
||||||
|
label: '谐波电压总畸变率',
|
||||||
|
value: '1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '各次谐波电压',
|
||||||
|
value: '2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '各次谐波电压',
|
||||||
|
value: '3'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '三相电压不平衡',
|
||||||
|
value: '4'
|
||||||
|
}
|
||||||
|
])
|
||||||
|
const echartList = ref({
|
||||||
|
title: {
|
||||||
|
text: '谐波电压含有率'
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'time',
|
||||||
|
axisLabel: {
|
||||||
|
formatter: {
|
||||||
|
day: '{MM}-{dd}',
|
||||||
|
month: '{MM}',
|
||||||
|
year: '{yyyy}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: [{}, {}],
|
||||||
|
grid: {
|
||||||
|
left: '10px',
|
||||||
|
right: '20px'
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'A相',
|
||||||
|
type: 'line',
|
||||||
|
showSymbol: false,
|
||||||
|
smooth: true,
|
||||||
|
data: [
|
||||||
|
['2025-10-16 07:00:00', 0.5],
|
||||||
|
['2025-10-16 07:15:00', 0.6],
|
||||||
|
['2025-10-16 07:30:00', 0.4],
|
||||||
|
['2025-10-16 07:45:00', 0.7],
|
||||||
|
['2025-10-16 08:00:00', 1.2],
|
||||||
|
['2025-10-16 08:15:00', 1.5],
|
||||||
|
['2025-10-16 08:30:00', 1.8],
|
||||||
|
['2025-10-16 08:45:00', 2.1],
|
||||||
|
['2025-10-16 09:00:00', 2.5],
|
||||||
|
['2025-10-16 09:15:00', 2.8],
|
||||||
|
['2025-10-16 09:30:00', 3.0],
|
||||||
|
['2025-10-16 09:45:00', 2.7],
|
||||||
|
['2025-10-16 10:00:00', 2.2],
|
||||||
|
['2025-10-16 10:15:00', 1.9],
|
||||||
|
['2025-10-16 10:30:00', 1.6],
|
||||||
|
['2025-10-16 10:45:00', 1.3],
|
||||||
|
['2025-10-16 11:00:00', 1.1],
|
||||||
|
['2025-10-16 11:15:00', 0.8],
|
||||||
|
['2025-10-16 11:30:00', 0.6],
|
||||||
|
['2025-10-16 11:45:00', 0.4],
|
||||||
|
['2025-10-16 12:00:00', 0.3],
|
||||||
|
['2025-10-16 12:15:00', 0.2],
|
||||||
|
['2025-10-16 12:30:00', 0.3],
|
||||||
|
['2025-10-16 12:45:00', 0.4]
|
||||||
|
],
|
||||||
|
yAxisIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'B相',
|
||||||
|
type: 'line',
|
||||||
|
showSymbol: false,
|
||||||
|
smooth: true,
|
||||||
|
data: [
|
||||||
|
['2025-10-16 07:00:00', 0.4],
|
||||||
|
['2025-10-16 07:15:00', 0.5],
|
||||||
|
['2025-10-16 07:30:00', 0.3],
|
||||||
|
['2025-10-16 07:45:00', 0.6],
|
||||||
|
['2025-10-16 08:00:00', 1.0],
|
||||||
|
['2025-10-16 08:15:00', 1.3],
|
||||||
|
['2025-10-16 08:30:00', 1.6],
|
||||||
|
['2025-10-16 08:45:00', 1.9],
|
||||||
|
['2025-10-16 09:00:00', 2.2],
|
||||||
|
['2025-10-16 09:15:00', 2.5],
|
||||||
|
['2025-10-16 09:30:00', 2.7],
|
||||||
|
['2025-10-16 09:45:00', 2.4],
|
||||||
|
['2025-10-16 10:00:00', 2.0],
|
||||||
|
['2025-10-16 10:15:00', 1.7],
|
||||||
|
['2025-10-16 10:30:00', 1.4],
|
||||||
|
['2025-10-16 10:45:00', 1.1],
|
||||||
|
['2025-10-16 11:00:00', 0.9],
|
||||||
|
['2025-10-16 11:15:00', 0.7],
|
||||||
|
['2025-10-16 11:30:00', 0.5],
|
||||||
|
['2025-10-16 11:45:00', 0.3],
|
||||||
|
['2025-10-16 12:00:00', 0.2],
|
||||||
|
['2025-10-16 12:15:00', 0.1],
|
||||||
|
['2025-10-16 12:30:00', 0.2],
|
||||||
|
['2025-10-16 12:45:00', 0.3]
|
||||||
|
],
|
||||||
|
yAxisIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'C相',
|
||||||
|
type: 'line',
|
||||||
|
showSymbol: false,
|
||||||
|
smooth: true,
|
||||||
|
data: [
|
||||||
|
['2025-10-16 07:00:00', 0.6],
|
||||||
|
['2025-10-16 07:15:00', 0.7],
|
||||||
|
['2025-10-16 07:30:00', 0.5],
|
||||||
|
['2025-10-16 07:45:00', 0.8],
|
||||||
|
['2025-10-16 08:00:00', 1.4],
|
||||||
|
['2025-10-16 08:15:00', 1.7],
|
||||||
|
['2025-10-16 08:30:00', 2.0],
|
||||||
|
['2025-10-16 08:45:00', 2.3],
|
||||||
|
['2025-10-16 09:00:00', 2.8],
|
||||||
|
['2025-10-16 09:15:00', 3.1],
|
||||||
|
['2025-10-16 09:30:00', 3.3],
|
||||||
|
['2025-10-16 09:45:00', 3.0],
|
||||||
|
['2025-10-16 10:00:00', 2.5],
|
||||||
|
['2025-10-16 10:15:00', 2.1],
|
||||||
|
['2025-10-16 10:30:00', 1.8],
|
||||||
|
['2025-10-16 10:45:00', 1.5],
|
||||||
|
['2025-10-16 11:00:00', 1.3],
|
||||||
|
['2025-10-16 11:15:00', 1.0],
|
||||||
|
['2025-10-16 11:30:00', 0.8],
|
||||||
|
['2025-10-16 11:45:00', 0.6],
|
||||||
|
['2025-10-16 12:00:00', 0.5],
|
||||||
|
['2025-10-16 12:15:00', 0.4],
|
||||||
|
['2025-10-16 12:30:00', 0.5],
|
||||||
|
['2025-10-16 12:45:00', 0.6]
|
||||||
|
],
|
||||||
|
yAxisIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '暂降触发点',
|
||||||
|
type: 'line',
|
||||||
|
showSymbol: false,
|
||||||
|
smooth: true,
|
||||||
|
data: [
|
||||||
|
['2025-10-16 07:00:00', 3.14159],
|
||||||
|
['2025-10-16 07:15:00', 3.14159],
|
||||||
|
['2025-10-16 07:30:00', 3.14159],
|
||||||
|
['2025-10-16 07:45:00', 3.14159],
|
||||||
|
['2025-10-16 08:00:00', 3.14159],
|
||||||
|
['2025-10-16 08:15:00', 3.14159],
|
||||||
|
['2025-10-16 08:30:00', 3.14159],
|
||||||
|
['2025-10-16 08:45:00', 3.14159],
|
||||||
|
['2025-10-16 09:00:00', 3.14159],
|
||||||
|
['2025-10-16 09:15:00', 3.14159],
|
||||||
|
['2025-10-16 09:30:00', 3.14159],
|
||||||
|
['2025-10-16 09:45:00', 3.14159],
|
||||||
|
['2025-10-16 10:00:00', 3.14159],
|
||||||
|
['2025-10-16 10:15:00', 3.14159],
|
||||||
|
['2025-10-16 10:30:00', 3.14159],
|
||||||
|
['2025-10-16 10:45:00', 3.14159],
|
||||||
|
['2025-10-16 11:00:00', 3.14159],
|
||||||
|
['2025-10-16 11:15:00', 3.14159],
|
||||||
|
['2025-10-16 11:30:00', 3.14159],
|
||||||
|
['2025-10-16 11:45:00', 3.14159],
|
||||||
|
['2025-10-16 12:00:00', 3.14159],
|
||||||
|
['2025-10-16 12:15:00', 3.14159],
|
||||||
|
['2025-10-16 12:30:00', 3.14159],
|
||||||
|
['2025-10-16 12:45:00', 3.14159]
|
||||||
|
],
|
||||||
|
lineStyle: {
|
||||||
|
type: 'dashed',
|
||||||
|
color: '#ff0000' // 红色
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
color: '#ff0000' // 红色
|
||||||
|
},
|
||||||
|
yAxisIndex: 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const echartContrastList = ref({
|
||||||
|
title: {
|
||||||
|
text: 'A相谐波电压和A相谐波电流对比趋势图'
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'time',
|
||||||
|
axisLabel: {
|
||||||
|
formatter: {
|
||||||
|
day: '{MM}-{dd}',
|
||||||
|
month: '{MM}',
|
||||||
|
year: '{yyyy}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: [{}, {}],
|
||||||
|
grid: {
|
||||||
|
left: '10px',
|
||||||
|
right: '20px'
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: 'A相谐波电压',
|
||||||
|
type: 'line',
|
||||||
|
showSymbol: false,
|
||||||
|
smooth: true,
|
||||||
|
data: [
|
||||||
|
['2025-10-16 07:00:00', 0],
|
||||||
|
['2025-10-16 07:15:00', 0],
|
||||||
|
['2025-10-16 07:30:00', 0],
|
||||||
|
['2025-10-16 07:45:00', 0],
|
||||||
|
['2025-10-16 08:00:00', 0],
|
||||||
|
['2025-10-16 08:15:00', 0.1],
|
||||||
|
['2025-10-16 08:30:00', 0.1],
|
||||||
|
['2025-10-16 08:45:00', 0.1],
|
||||||
|
['2025-10-16 09:00:00', 1],
|
||||||
|
['2025-10-16 09:15:00', 1],
|
||||||
|
['2025-10-16 09:30:00', 1],
|
||||||
|
['2025-10-16 09:45:00', 1],
|
||||||
|
['2025-10-16 10:00:00', 0.8],
|
||||||
|
['2025-10-16 10:15:00', 0.8],
|
||||||
|
['2025-10-16 10:30:00', 0.8],
|
||||||
|
['2025-10-16 10:45:00', 0.8],
|
||||||
|
['2025-10-16 11:00:00', 0.8],
|
||||||
|
['2025-10-16 11:15:00', 0.1],
|
||||||
|
['2025-10-16 11:30:00', 0.1],
|
||||||
|
['2025-10-16 11:45:00', 0.1],
|
||||||
|
['2025-10-16 12:00:00', 0],
|
||||||
|
['2025-10-16 12:15:00', 0],
|
||||||
|
['2025-10-16 12:30:00', 0],
|
||||||
|
['2025-10-16 12:45:00', 0]
|
||||||
|
],
|
||||||
|
yAxisIndex: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'A相谐波电流',
|
||||||
|
type: 'line',
|
||||||
|
showSymbol: false,
|
||||||
|
smooth: true,
|
||||||
|
data: [
|
||||||
|
['2025-10-16 07:00:00', 0],
|
||||||
|
['2025-10-16 07:15:00', 0],
|
||||||
|
['2025-10-16 07:30:00', 0],
|
||||||
|
['2025-10-16 07:45:00', 0],
|
||||||
|
['2025-10-16 08:00:00', 0],
|
||||||
|
['2025-10-16 08:15:00', 0.05],
|
||||||
|
['2025-10-16 08:30:00', 0.05],
|
||||||
|
['2025-10-16 08:45:00', 0.05],
|
||||||
|
['2025-10-16 09:00:00', 0.5],
|
||||||
|
['2025-10-16 09:15:00', 0.5],
|
||||||
|
['2025-10-16 09:30:00', 0.5],
|
||||||
|
['2025-10-16 09:45:00', 0.5],
|
||||||
|
['2025-10-16 10:00:00', 0.4],
|
||||||
|
['2025-10-16 10:15:00', 0.4],
|
||||||
|
['2025-10-16 10:30:00', 0.4],
|
||||||
|
['2025-10-16 10:45:00', 0.4],
|
||||||
|
['2025-10-16 11:00:00', 0.4],
|
||||||
|
['2025-10-16 11:15:00', 0.05],
|
||||||
|
['2025-10-16 11:30:00', 0.05],
|
||||||
|
['2025-10-16 11:45:00', 0.05],
|
||||||
|
['2025-10-16 12:00:00', 0],
|
||||||
|
['2025-10-16 12:15:00', 0],
|
||||||
|
['2025-10-16 12:30:00', 0],
|
||||||
|
['2025-10-16 12:45:00', 0]
|
||||||
|
],
|
||||||
|
yAxisIndex: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const headerHeight = ref(57)
|
||||||
|
const selectChange = (showSelect: any, height: any) => {
|
||||||
|
headerHeight.value = height
|
||||||
|
}
|
||||||
|
const tableStore: any = new TableStore({
|
||||||
|
url: '/user-boot/role/selectRoleDetail?id=0',
|
||||||
|
method: 'POST',
|
||||||
|
|
||||||
|
showPage: false,
|
||||||
|
exportName: '主要监测点列表',
|
||||||
|
column: [],
|
||||||
|
beforeSearchFun: () => {},
|
||||||
|
loadCallback: () => {
|
||||||
|
tableStore.table.height = `calc(${prop.height} - 80px)`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const tableRef = ref()
|
||||||
|
provide('tableRef', tableRef)
|
||||||
|
tableStore.table.params.power = '1'
|
||||||
|
tableStore.table.params.indicator = '1'
|
||||||
|
tableStore.table.params.exceedingTheLimit = '1'
|
||||||
|
tableStore.table.params.searchValue = ''
|
||||||
|
tableStore.table.params.checked = false
|
||||||
|
tableStore.table.params.indicatorType = '' // 指标类型
|
||||||
|
tableStore.table.params.indicatorType1 = '' // 指标类型1
|
||||||
|
tableStore.table.params.indicatorType2 = '' // 指标类型2
|
||||||
|
provide('tableStore', tableStore)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
tableStore.index()
|
||||||
|
})
|
||||||
|
watch(
|
||||||
|
() => prop.timeKey,
|
||||||
|
val => {
|
||||||
|
tableStore.index()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
watch(
|
||||||
|
() => prop.timeValue, // 监听的目标(函数形式避免直接传递 props 导致的警告)
|
||||||
|
(newVal, oldVal) => {
|
||||||
|
tableStore.index()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
deep: true // 若 timeValue 是对象/数组,需开启深度监听
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const openDialog = async (row: any) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
tableStore.index()
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ openDialog })
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
:deep(.el-select) {
|
||||||
|
min-width: 80px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,134 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 综合评估详情 -->
|
||||||
|
<el-dialog draggable title="指标合格率统计" v-model="dialogVisible" append-to-body width="70%">
|
||||||
|
<TableHeader datePicker showExport :showReset="false">
|
||||||
|
<template v-slot:select>
|
||||||
|
<el-form-item label="监测点名称">
|
||||||
|
<el-select
|
||||||
|
v-model="tableStore.table.params.searchValue"
|
||||||
|
placeholder="请选择监测点名称"
|
||||||
|
style="width: 240px"
|
||||||
|
>
|
||||||
|
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</TableHeader>
|
||||||
|
<Table ref="tableRef" isGroup :height="height"></Table>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, provide } from 'vue'
|
||||||
|
import Table from '@/components/table/index.vue'
|
||||||
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
|
import TableStore from '@/utils/tableStore'
|
||||||
|
import { mainHeight } from '@/utils/layout'
|
||||||
|
const dialogVisible: any = ref(false)
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
value: '35kV进线',
|
||||||
|
label: '35kV进线'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
const height = mainHeight(0, 2).height as any
|
||||||
|
const loop50 = (key: string) => {
|
||||||
|
let list: any[] = []
|
||||||
|
for (let i = 2; i < 51; i++) {
|
||||||
|
list.push({
|
||||||
|
title: i + '次',
|
||||||
|
// field: key + i,
|
||||||
|
field: 'flicker',
|
||||||
|
width: '80'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
const tableStore: any = new TableStore({
|
||||||
|
url: '/user-boot/role/selectRoleDetail?id=0',
|
||||||
|
method: 'POST',
|
||||||
|
publicHeight: 30,
|
||||||
|
showPage: false,
|
||||||
|
exportName: '主要监测点列表',
|
||||||
|
column: [
|
||||||
|
{
|
||||||
|
field: 'index',
|
||||||
|
title: '序号',
|
||||||
|
width: '80',
|
||||||
|
formatter: (row: any) => {
|
||||||
|
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '日期',
|
||||||
|
field: 'time',
|
||||||
|
width: '150'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '名称',
|
||||||
|
field: 'name',
|
||||||
|
width: '150'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '闪变越限(分钟)',
|
||||||
|
field: 'flicker',
|
||||||
|
width: '80'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '谐波电压越限(分钟)',
|
||||||
|
children: loop50('voltage')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '谐波电流越限(分钟)',
|
||||||
|
children: loop50('harmonicCurrent')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '三相不平衡度越限(分钟)',
|
||||||
|
field: 'flicker',
|
||||||
|
width: '100'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '电压偏差越限(分钟)',
|
||||||
|
field: 'flicker',
|
||||||
|
width: '100'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '频率偏差越限(分钟)',
|
||||||
|
field: 'flicker',
|
||||||
|
width: '100'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
beforeSearchFun: () => {},
|
||||||
|
loadCallback: () => {
|
||||||
|
tableStore.table.data = [
|
||||||
|
{
|
||||||
|
time: '2024-01-01 00:00:00',
|
||||||
|
name: '35kV进线',
|
||||||
|
flicker: '0',
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
time: '2024-01-01 00:00:00',
|
||||||
|
name: '35kV进线',
|
||||||
|
flicker: '0',
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
time: '2024-01-01 00:00:00',
|
||||||
|
name: '35kV进线',
|
||||||
|
flicker: '0',
|
||||||
|
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
tableStore.table.params.searchValue = ''
|
||||||
|
provide('tableStore', tableStore)
|
||||||
|
const open = async (row: any) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
tableStore.index()
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ open })
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@@ -1,21 +1,30 @@
|
|||||||
<template>
|
<template>
|
||||||
<!-- 综合评估详情 -->
|
<div>
|
||||||
<el-dialog draggable title="指标合格率统计" v-model="dialogVisible" append-to-body width="70%">
|
<!-- 综合评估详情 -->
|
||||||
<TableHeader datePicker showExport :showReset="false">
|
<el-dialog draggable title="指标合格率统计" v-model="dialogVisible" append-to-body width="70%">
|
||||||
<template v-slot:select>
|
<TableHeader datePicker showExport :showReset="false">
|
||||||
<el-form-item label="监测点名称">
|
<template v-slot:select>
|
||||||
<el-select
|
<el-form-item label="监测点名称">
|
||||||
v-model="tableStore.table.params.searchValue"
|
<el-select
|
||||||
placeholder="请选择监测点名称"
|
v-model="tableStore.table.params.searchValue"
|
||||||
style="width: 240px"
|
placeholder="请选择监测点名称"
|
||||||
>
|
style="width: 150px"
|
||||||
<el-option v-for="item in options" :key="item.value" :label="item.label" :value="item.value" />
|
>
|
||||||
</el-select>
|
<el-option
|
||||||
</el-form-item>
|
v-for="item in options"
|
||||||
</template>
|
:key="item.value"
|
||||||
</TableHeader>
|
:label="item.label"
|
||||||
<Table ref="tableRef" isGroup :height="height"></Table>
|
:value="item.value"
|
||||||
</el-dialog>
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</TableHeader>
|
||||||
|
<Table ref="tableRef" @cell-click="cellClickEvent" isGroup :height="height"></Table>
|
||||||
|
</el-dialog>
|
||||||
|
<!-- 谐波电流、谐波电压占有率 -->
|
||||||
|
<HarmonicRatio ref="harmonicRatioRef" />
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, provide } from 'vue'
|
import { ref, provide } from 'vue'
|
||||||
@@ -23,7 +32,9 @@ import Table from '@/components/table/index.vue'
|
|||||||
import TableHeader from '@/components/table/header/index.vue'
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
import TableStore from '@/utils/tableStore'
|
import TableStore from '@/utils/tableStore'
|
||||||
import { mainHeight } from '@/utils/layout'
|
import { mainHeight } from '@/utils/layout'
|
||||||
|
import HarmonicRatio from '@/components/cockpit/listOfMainMonitoringPoints/components/harmonicRatio.vue'
|
||||||
const dialogVisible: any = ref(false)
|
const dialogVisible: any = ref(false)
|
||||||
|
const harmonicRatioRef: any = ref(null)
|
||||||
const options = [
|
const options = [
|
||||||
{
|
{
|
||||||
value: '35kV进线',
|
value: '35kV进线',
|
||||||
@@ -38,7 +49,11 @@ const loop50 = (key: string) => {
|
|||||||
title: i + '次',
|
title: i + '次',
|
||||||
// field: key + i,
|
// field: key + i,
|
||||||
field: 'flicker',
|
field: 'flicker',
|
||||||
width: '80'
|
width: '80',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.flicker}</span>`
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return list
|
return list
|
||||||
@@ -71,7 +86,11 @@ const tableStore: any = new TableStore({
|
|||||||
{
|
{
|
||||||
title: '闪变越限(分钟)',
|
title: '闪变越限(分钟)',
|
||||||
field: 'flicker',
|
field: 'flicker',
|
||||||
width: '80'
|
width: '80',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.flicker}</span>`
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '谐波电压越限(分钟)',
|
title: '谐波电压越限(分钟)',
|
||||||
@@ -103,21 +122,18 @@ const tableStore: any = new TableStore({
|
|||||||
{
|
{
|
||||||
time: '2024-01-01 00:00:00',
|
time: '2024-01-01 00:00:00',
|
||||||
name: '35kV进线',
|
name: '35kV进线',
|
||||||
flicker: '0',
|
flicker: '0'
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
time: '2024-01-01 00:00:00',
|
time: '2024-01-01 00:00:00',
|
||||||
name: '35kV进线',
|
name: '35kV进线',
|
||||||
flicker: '0',
|
flicker: '0'
|
||||||
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
time: '2024-01-01 00:00:00',
|
time: '2024-01-01 00:00:00',
|
||||||
name: '35kV进线',
|
name: '35kV进线',
|
||||||
flicker: '0',
|
flicker: '0'
|
||||||
|
}
|
||||||
},
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -129,6 +145,15 @@ const open = async (row: any) => {
|
|||||||
tableStore.index()
|
tableStore.index()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 点击行
|
||||||
|
const cellClickEvent = ({ row, column }: any) => {
|
||||||
|
console.log(row, '1111')
|
||||||
|
if (column.field != 'name' && column.field != 'time') {
|
||||||
|
harmonicRatioRef.value.openDialog(row)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
defineExpose({ open })
|
defineExpose({ open })
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped></style>
|
||||||
|
|||||||
@@ -1,89 +1,131 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!--指标拟合图 -->
|
<!--指标拟合图 -->
|
||||||
<TableHeader :showReset="false" @selectChange="selectChange">
|
<TableHeader
|
||||||
|
datePicker
|
||||||
|
@selectChange="selectChange"
|
||||||
|
v-if="fullscreen"
|
||||||
|
ref="TableHeaderRef"
|
||||||
|
:timeKeyList="prop.timeKey"
|
||||||
|
>
|
||||||
<template v-slot:select>
|
<template v-slot:select>
|
||||||
|
<el-form-item label="监测点">
|
||||||
|
<el-select filterable v-model="tableStore.table.params.lineId" placeholder="请选择监测点" clearable>
|
||||||
|
<el-option
|
||||||
|
v-for="item in lineList"
|
||||||
|
:key="item.lineId"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.lineId"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="用户功率">
|
<el-form-item label="用户功率">
|
||||||
<el-select
|
<el-select
|
||||||
|
filterable
|
||||||
v-model="tableStore.table.params.power"
|
v-model="tableStore.table.params.power"
|
||||||
placeholder="请选择用户功率"
|
placeholder="请选择用户功率"
|
||||||
clearable
|
clearable
|
||||||
style="width: 130px"
|
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option v-for="item in powerList" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
v-for="item in powerList"
|
</el-select>
|
||||||
:key="item.value"
|
</el-form-item>
|
||||||
:label="item.label"
|
<el-form-item label="统计类型">
|
||||||
:value="item.value"
|
<el-select
|
||||||
/>
|
style="min-width: 120px !important"
|
||||||
|
placeholder="请选择"
|
||||||
|
v-model="tableStore.table.params.valueType"
|
||||||
|
filterable
|
||||||
|
>
|
||||||
|
<el-option value="max" label="最大值"></el-option>
|
||||||
|
<el-option value="min" label="最小值"></el-option>
|
||||||
|
<el-option value="avg" label="平均值"></el-option>
|
||||||
|
<el-option value="cp95" label="cp95"></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="电能质量指标">
|
<el-form-item label="电能质量指标">
|
||||||
<el-select
|
<el-select
|
||||||
|
filterable
|
||||||
v-model="tableStore.table.params.indicator"
|
v-model="tableStore.table.params.indicator"
|
||||||
placeholder="请选择电能质量指标"
|
placeholder="请选择电能质量指标"
|
||||||
clearable
|
clearable
|
||||||
style="width: 130px"
|
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option v-for="item in indicatorList" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
v-for="item in indicatorList"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value"
|
|
||||||
/>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="越限情况">
|
<el-form-item>
|
||||||
<el-select
|
<div v-if="shouldShowHarmonicCount()" style="display: flex; color: var(--el-text-color-regular)">
|
||||||
v-model="tableStore.table.params.exceedingTheLimit"
|
<span style="width: 160px">{{ getHarmonicTypeName() }}谐波次数</span>
|
||||||
placeholder="请选择越限情况"
|
<el-select
|
||||||
clearable
|
v-model="tableStore.table.params.harmonicCount"
|
||||||
style="width: 90px"
|
placeholder="请选择谐波次数"
|
||||||
>
|
style="min-width: 80px !important"
|
||||||
<el-option
|
filterable
|
||||||
v-for="item in exceedingTheLimitList"
|
>
|
||||||
:key="item.value"
|
<el-option
|
||||||
:label="item.label"
|
v-for="num in harmonicCountOptions"
|
||||||
:value="item.value"
|
:key="num"
|
||||||
/>
|
:label="num"
|
||||||
</el-select>
|
:value="num"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<my-echart
|
<div v-loading="tableStore.table.loading">
|
||||||
class="tall"
|
<my-echart
|
||||||
:options="echartList"
|
class="tall"
|
||||||
:style="{ width: prop.width, height: `calc(${prop.height} - ${headerHeight}px )` }"
|
:options="echartList"
|
||||||
/>
|
:style="{
|
||||||
|
width: prop.width,
|
||||||
|
height: `calc(${prop.height} - ${headerHeight}px + ${fullscreen ? 0 : 56}px )`
|
||||||
|
}"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
import { ref, onMounted, provide, reactive, watch, h, computed, nextTick } from 'vue'
|
||||||
import TableStore from '@/utils/tableStore'
|
import TableStore from '@/utils/tableStore'
|
||||||
import Table from '@/components/table/index.vue'
|
|
||||||
import TableHeader from '@/components/table/header/index.vue'
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
import { useDictData } from '@/stores/dictData'
|
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
||||||
import { getTimeOfTheMonth } from '@/utils/formatTime'
|
|
||||||
import MyEchart from '@/components/echarts/MyEchart.vue'
|
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||||
import { useConfig } from '@/stores/config'
|
import { useConfig } from '@/stores/config'
|
||||||
|
import { cslineList, fittingData } from '@/api/harmonic-boot/cockpit/cockpit'
|
||||||
|
import { queryByCode, queryCsDictTree } from '@/api/system-boot/dictTree'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
import { getTime } from '@/utils/formatTime'
|
||||||
|
|
||||||
const prop = defineProps({
|
const prop = defineProps({
|
||||||
width: { type: String },
|
w: { type: [String, Number] },
|
||||||
height: { type: String },
|
h: { type: [String, Number] },
|
||||||
timeKey: { type: String },
|
width: { type: [String, Number] },
|
||||||
timeValue: { type: Object }
|
height: { type: [String, Number] },
|
||||||
|
timeKey: { type: Array as () => string[] },
|
||||||
|
timeValue: { type: Object },
|
||||||
|
interval: { type: Number }
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const TableHeaderRef = ref()
|
||||||
|
|
||||||
const config = useConfig()
|
const config = useConfig()
|
||||||
const powerList: any = ref([
|
|
||||||
{
|
const lineList: any = ref()
|
||||||
label: '三相总有功功率',
|
|
||||||
value: '1'
|
const powerList: any = ref()
|
||||||
},
|
|
||||||
{
|
const chartsList = ref<any>([])
|
||||||
label: '三相总无功功率',
|
|
||||||
value: '2'
|
// 计算是否全屏展示
|
||||||
|
const fullscreen = computed(() => {
|
||||||
|
const w = Number(prop.w)
|
||||||
|
const h = Number(prop.h)
|
||||||
|
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
|
||||||
|
// 执行相应逻辑
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
])
|
})
|
||||||
const exceedingTheLimitList: any = ref([
|
const exceedingTheLimitList: any = ref([
|
||||||
{
|
{
|
||||||
label: '越限',
|
label: '越限',
|
||||||
@@ -94,178 +136,345 @@ const exceedingTheLimitList: any = ref([
|
|||||||
value: '0'
|
value: '0'
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
const indicatorList: any = ref([
|
|
||||||
{
|
const indicatorList = ref()
|
||||||
label: '谐波电压总畸变率',
|
|
||||||
value: '1'
|
const initLineList = async () => {
|
||||||
},
|
cslineList({}).then(res => {
|
||||||
{
|
lineList.value = res.data
|
||||||
label: '各次谐波电压',
|
tableStore.table.params.lineId = lineList.value[0].lineId
|
||||||
value: '2'
|
})
|
||||||
},
|
}
|
||||||
{
|
|
||||||
label: '各次谐波电压',
|
const echartList = ref()
|
||||||
value: '3'
|
|
||||||
},
|
const headerHeight = ref(57)
|
||||||
{
|
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
|
||||||
label: '三相电压不平衡',
|
headerHeight.value = height
|
||||||
value: '4'
|
if (datePickerValue && datePickerValue.timeValue) {
|
||||||
|
// 更新时间参数
|
||||||
|
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
|
||||||
|
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
|
||||||
}
|
}
|
||||||
])
|
}
|
||||||
const echartList = ref({
|
|
||||||
title: {
|
|
||||||
text: '谐波电压总畸变率越限与功率负荷曲线拟合图'
|
|
||||||
},
|
|
||||||
|
|
||||||
xAxis: {
|
const setEchart = () => {
|
||||||
type: 'time',
|
// 获取当前选择的功率和指标名称
|
||||||
axisLabel: {
|
const powerName = powerList.value?.find((item: any) => item.id === tableStore.table.params.power)?.name || '功率'
|
||||||
formatter: {
|
const indicatorName =
|
||||||
day: '{MM}-{dd}',
|
indicatorList.value?.find((item: any) => item.id === tableStore.table.params.indicator)?.name || '电能质量指标'
|
||||||
month: '{MM}',
|
|
||||||
year: '{yyyy}'
|
echartList.value = {
|
||||||
|
title: {
|
||||||
|
text: `${indicatorName}与${powerName}负荷曲线拟合图`
|
||||||
|
},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
formatter: function (params: any) {
|
||||||
|
let result = params[0].name
|
||||||
|
params.forEach((item: any) => {
|
||||||
|
if (item.seriesName === indicatorName) {
|
||||||
|
// 对于电能质量指标,格式化Y轴值显示
|
||||||
|
let valueText = ''
|
||||||
|
if (item.value[1] == 0) {
|
||||||
|
valueText = '不越限'
|
||||||
|
} else if (item.value[1] == 1) {
|
||||||
|
valueText = '越限'
|
||||||
|
} else {
|
||||||
|
valueText = item.value[1]
|
||||||
|
}
|
||||||
|
result += `<br/>${item.marker}${item.seriesName}: ${valueText}`
|
||||||
|
} else {
|
||||||
|
// 对于功率数据,正常显示数值
|
||||||
|
result += `<br/>${item.marker}${item.seriesName}: ${item.value[1]}`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
xAxis: {
|
||||||
|
type: 'time',
|
||||||
yAxis: [{}, {}],
|
axisLabel: {
|
||||||
grid: {
|
formatter: {
|
||||||
left: '10px',
|
day: '{MM}-{dd}',
|
||||||
right: '20px'
|
month: '{MM}',
|
||||||
},
|
year: '{yyyy}'
|
||||||
options: {
|
}
|
||||||
series: [
|
}
|
||||||
{
|
},
|
||||||
// name: '暂降次数',
|
yAxis: [
|
||||||
type: 'bar',
|
{},
|
||||||
name: '有功功率',
|
indicatorName
|
||||||
data: [
|
? {
|
||||||
['2025-10-16 07:00:00', 10],
|
min: 0,
|
||||||
['2025-10-16 07:15:00', 10],
|
max: 1,
|
||||||
['2025-10-16 07:30:00', 10],
|
axisLabel: {
|
||||||
['2025-10-16 07:45:00', 10],
|
formatter: function (value: number) {
|
||||||
['2025-10-16 08:00:00', 30],
|
if (value === 0) {
|
||||||
['2025-10-16 08:15:00', 50],
|
return '不越限'
|
||||||
['2025-10-16 08:30:00', 60],
|
} else if (value === 1) {
|
||||||
['2025-10-16 08:45:00', 70],
|
return '越限'
|
||||||
['2025-10-16 09:00:00', 100],
|
}
|
||||||
['2025-10-16 09:15:00', 120],
|
return value
|
||||||
['2025-10-16 09:30:00', 130],
|
}
|
||||||
['2025-10-16 09:45:00', 140],
|
}
|
||||||
['2025-10-16 10:00:00', 160],
|
}
|
||||||
['2025-10-16 10:15:00', 160],
|
: {}
|
||||||
['2025-10-16 10:30:00', 130],
|
],
|
||||||
['2025-10-16 10:45:00', 120],
|
grid: {
|
||||||
['2025-10-16 11:00:00', 140],
|
left: '10px',
|
||||||
['2025-10-16 11:15:00', 80],
|
right: '20px'
|
||||||
['2025-10-16 11:30:00', 70],
|
},
|
||||||
['2025-10-16 11:45:00', 90],
|
options: {
|
||||||
['2025-10-16 12:00:00', 60],
|
series: [
|
||||||
['2025-10-16 12:15:00', 60],
|
{
|
||||||
['2025-10-16 12:30:00', 60],
|
type: 'bar',
|
||||||
['2025-10-16 12:45:00', 60]
|
name: powerName, // 动态设置功率名称
|
||||||
],
|
data: [],
|
||||||
itemStyle: {
|
itemStyle: {
|
||||||
normal: {
|
normal: {
|
||||||
//这里是颜色
|
color: function (params: any) {
|
||||||
color: function (params: any) {
|
if (params.value[1] == 0 || params.value[1] == 3.14159) {
|
||||||
if (params.value[1] == 0 || params.value[1] == 3.14159) {
|
return '#ccc'
|
||||||
return '#ccc'
|
} else {
|
||||||
} else {
|
return config.layout.elementUiPrimary[0]
|
||||||
return config.layout.elementUiPrimary[0]
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
yAxisIndex: 0
|
||||||
},
|
},
|
||||||
yAxisIndex: 0
|
{
|
||||||
},
|
name: indicatorName, // 动态设置指标名称
|
||||||
{
|
type: 'line',
|
||||||
name: '谐波总畸变率',
|
step: 'end',
|
||||||
type: 'line',
|
showSymbol: false,
|
||||||
showSymbol: false,
|
// smooth: true,
|
||||||
smooth: true,
|
data: [],
|
||||||
data: [
|
yAxisIndex: 1
|
||||||
['2025-10-16 07:00:00', 0],
|
}
|
||||||
['2025-10-16 07:15:00', 0],
|
]
|
||||||
['2025-10-16 07:30:00', 0],
|
}
|
||||||
['2025-10-16 07:45:00', 0],
|
|
||||||
['2025-10-16 08:00:00', 0],
|
|
||||||
['2025-10-16 08:15:00', 0.1],
|
|
||||||
['2025-10-16 08:30:00', 0.1],
|
|
||||||
['2025-10-16 08:45:00', 0.1],
|
|
||||||
['2025-10-16 09:00:00', 1],
|
|
||||||
['2025-10-16 09:15:00', 1],
|
|
||||||
['2025-10-16 09:30:00', 1],
|
|
||||||
['2025-10-16 09:45:00', 1],
|
|
||||||
['2025-10-16 10:00:00', 0.8],
|
|
||||||
['2025-10-16 10:15:00', 0.8],
|
|
||||||
['2025-10-16 10:30:00', 0.8],
|
|
||||||
['2025-10-16 10:45:00', 0.8],
|
|
||||||
['2025-10-16 11:00:00', 0.8],
|
|
||||||
['2025-10-16 11:15:00', 0.1],
|
|
||||||
['2025-10-16 11:30:00', 0.1],
|
|
||||||
['2025-10-16 11:45:00', 0.1],
|
|
||||||
['2025-10-16 12:00:00', 0],
|
|
||||||
['2025-10-16 12:15:00', 0],
|
|
||||||
['2025-10-16 12:30:00', 0],
|
|
||||||
['2025-10-16 12:45:00', 0]
|
|
||||||
],
|
|
||||||
yAxisIndex: 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
})
|
|
||||||
const headerHeight = ref(57)
|
|
||||||
const selectChange = (showSelect: any, height: any) => {
|
|
||||||
headerHeight.value = height
|
|
||||||
}
|
|
||||||
const tableStore: any = new TableStore({
|
|
||||||
url: '/user-boot/role/selectRoleDetail?id=0',
|
|
||||||
method: 'POST',
|
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 用户功率数据和电能质量数据
|
||||||
|
let powerData: any[] = []
|
||||||
|
let qualityData: any[] = []
|
||||||
|
|
||||||
|
chartsList.value.forEach((item: any) => {
|
||||||
|
// 根据统计项ID判断是功率数据还是电能质量数据
|
||||||
|
if (item.statisticalIndex === tableStore.table.params.power) {
|
||||||
|
powerData.push(item)
|
||||||
|
} else if (item.statisticalIndex === tableStore.table.params.indicator) {
|
||||||
|
qualityData.push(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 处理功率数据
|
||||||
|
const processedPowerData = powerData.map((item: any) => {
|
||||||
|
return [
|
||||||
|
item.time,
|
||||||
|
item.statisticalData !== null && item.statisticalData !== undefined
|
||||||
|
? parseFloat(item.statisticalData.toFixed(2))
|
||||||
|
: null
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
// 处理电能质量数据
|
||||||
|
const processedQualityData = qualityData.map((item: any) => {
|
||||||
|
return [
|
||||||
|
item.time,
|
||||||
|
item.statisticalData !== null && item.statisticalData !== undefined
|
||||||
|
? parseFloat(item.statisticalData.toFixed(2))
|
||||||
|
: null
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
// 检查是否有有效数据
|
||||||
|
const hasPowerData = processedPowerData.length > 0 && processedPowerData.some(item => item[1] !== null)
|
||||||
|
const hasQualityData = processedQualityData.length > 0 && processedQualityData.some(item => item[1] !== null)
|
||||||
|
|
||||||
|
// 更新图表配置
|
||||||
|
echartList.value.options.series[0].data = processedPowerData
|
||||||
|
echartList.value.options.series[1].data = processedQualityData
|
||||||
|
} catch (error) {
|
||||||
|
console.error('处理图表数据时出错:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const initCode = () => {
|
||||||
|
queryByCode('steady_state_limit_fitting').then(res => {
|
||||||
|
queryCsDictTree(res.data.id).then(item => {
|
||||||
|
powerList.value = item.data.filter((item: any) => {
|
||||||
|
return item.name == '三相总无功功率' || item.name == '三相总有功功率'
|
||||||
|
})
|
||||||
|
|
||||||
|
indicatorList.value = item.data.filter((item: any) => {
|
||||||
|
return item.name != '三相总无功功率' && item.name != '三相总有功功率'
|
||||||
|
})
|
||||||
|
|
||||||
|
tableStore.table.params.power = powerList.value[0].id
|
||||||
|
tableStore.table.params.indicator = indicatorList.value[0].id
|
||||||
|
nextTick(() => {
|
||||||
|
// setTime()
|
||||||
|
tableStore.index()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableStore: any = new TableStore({
|
||||||
|
url: '/cs-device-boot/csGroup/fittingData',
|
||||||
|
method: 'POST',
|
||||||
showPage: false,
|
showPage: false,
|
||||||
exportName: '主要监测点列表',
|
exportName: '主要监测点列表',
|
||||||
column: [],
|
column: [],
|
||||||
beforeSearchFun: () => {
|
beforeSearchFun: () => {
|
||||||
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
|
setTime()
|
||||||
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
|
// 只有当 lineList 已加载且有数据时才设置默认 lineId
|
||||||
|
if (!tableStore.table.params.lineId && lineList.value && lineList.value.length > 0) {
|
||||||
|
tableStore.table.params.lineId = lineList.value[0].lineId
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建请求参数 lists
|
||||||
|
let lists: any = []
|
||||||
|
|
||||||
|
// 处理用户功率指标
|
||||||
|
const selectedPower = powerList.value?.find((item: any) => item.id === tableStore.table.params.power)
|
||||||
|
if (selectedPower) {
|
||||||
|
lists.push({
|
||||||
|
statisticalId: tableStore.table.params.power,
|
||||||
|
valueType: tableStore.table.params.valueType
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理电能质量指标
|
||||||
|
const selectedIndicator = indicatorList.value?.find(
|
||||||
|
(item: any) => item.id === tableStore.table.params.indicator
|
||||||
|
)
|
||||||
|
if (selectedIndicator) {
|
||||||
|
let frequencys = ''
|
||||||
|
if (selectedIndicator.name.includes('谐波含有率')) {
|
||||||
|
frequencys = tableStore.table.params.harmonicCount
|
||||||
|
}
|
||||||
|
|
||||||
|
lists.push({
|
||||||
|
statisticalId: tableStore.table.params.indicator,
|
||||||
|
frequency: frequencys !== null && frequencys !== undefined ? String(frequencys) : ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将 lists 添加到请求参数中
|
||||||
|
tableStore.table.params.list = lists
|
||||||
|
tableStore.table.params.dataLevel = 'Primary'
|
||||||
},
|
},
|
||||||
loadCallback: () => {
|
loadCallback: () => {
|
||||||
tableStore.table.height = `calc(${prop.height} - 80px)`
|
tableStore.table.height = `calc(${prop.height} - 80px)`
|
||||||
|
// 数据加载完成后的处理
|
||||||
|
if (tableStore.table.data) {
|
||||||
|
chartsList.value = JSON.parse(JSON.stringify(tableStore.table.data))
|
||||||
|
setEchart()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const tableRef = ref()
|
const tableRef = ref()
|
||||||
provide('tableRef', tableRef)
|
provide('tableRef', tableRef)
|
||||||
tableStore.table.params.power = '1'
|
|
||||||
tableStore.table.params.indicator = '1'
|
tableStore.table.params.indicator = '1'
|
||||||
tableStore.table.params.exceedingTheLimit = '1'
|
tableStore.table.params.exceedingTheLimit = '1'
|
||||||
|
tableStore.table.params.valueType = 'avg'
|
||||||
tableStore.table.params.searchValue = ''
|
tableStore.table.params.searchValue = ''
|
||||||
provide('tableStore', tableStore)
|
provide('tableStore', tableStore)
|
||||||
|
|
||||||
|
// 添加谐波次数选项(2-50)
|
||||||
|
const harmonicCountOptions = ref(Array.from({ length: 49 }, (_, i) => i + 2))
|
||||||
|
|
||||||
|
// 判断是否应该显示谐波次数选择框
|
||||||
|
const shouldShowHarmonicCount = () => {
|
||||||
|
if (!tableStore.table.params.indicator || !indicatorList.value) return false
|
||||||
|
|
||||||
|
const currentIndicator = indicatorList.value.find((item: any) => item.id === tableStore.table.params.indicator)
|
||||||
|
|
||||||
|
return (
|
||||||
|
currentIndicator &&
|
||||||
|
(currentIndicator.name.includes('电压谐波含有率') || currentIndicator.name.includes('电流谐波含有率'))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取谐波类型名称
|
||||||
|
const getHarmonicTypeName = () => {
|
||||||
|
const currentIndicator = indicatorList.value.find((item: any) => item.id === tableStore.table.params.indicator)
|
||||||
|
|
||||||
|
if (currentIndicator) {
|
||||||
|
if (currentIndicator.name.includes('电压谐波含有率')) {
|
||||||
|
return '电压'
|
||||||
|
} else if (currentIndicator.name.includes('电流谐波含有率')) {
|
||||||
|
return '电流'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听指标变化,当指标变化时重置谐波次数
|
||||||
|
watch(
|
||||||
|
() => tableStore.table.params.indicator,
|
||||||
|
newVal => {
|
||||||
|
if (shouldShowHarmonicCount()) {
|
||||||
|
// 如果之前没有设置过谐波次数,则默认设置为2
|
||||||
|
if (!tableStore.table.params.harmonicCount) {
|
||||||
|
tableStore.table.params.harmonicCount = 2
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果不是谐波含有率指标,则清除谐波次数设置
|
||||||
|
tableStore.table.params.harmonicCount = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
tableStore.index()
|
initLineList().then(() => {
|
||||||
|
initCode()
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeKey,
|
() => prop.timeKey,
|
||||||
val => {
|
val => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
const setTime = () => {
|
||||||
|
const time = getTime(
|
||||||
|
(TableHeaderRef.value?.datePickerRef.interval || prop.interval) ?? 0,
|
||||||
|
prop.timeKey,
|
||||||
|
fullscreen.value
|
||||||
|
? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
|
||||||
|
: prop.timeValue
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(time)) {
|
||||||
|
tableStore.table.params.searchBeginTime = time[0]
|
||||||
|
tableStore.table.params.searchEndTime = time[1]
|
||||||
|
TableHeaderRef.value?.setInterval(time[2] - 0)
|
||||||
|
TableHeaderRef.value?.setTimeInterval([time[0], time[1]])
|
||||||
|
} else {
|
||||||
|
console.warn('获取时间失败,time 不是一个有效数组')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeValue, // 监听的目标(函数形式避免直接传递 props 导致的警告)
|
() => prop.timeValue,
|
||||||
(newVal, oldVal) => {
|
(newVal, oldVal) => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
deep: true // 若 timeValue 是对象/数组,需开启深度监听
|
deep: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const addMenu = () => {}
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
:deep(.el-select) {
|
// :deep(.el-select) {
|
||||||
min-width: 80px;
|
// min-width: 80px;
|
||||||
}
|
// }
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -0,0 +1,186 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<!-- 指标越限详情 -->
|
||||||
|
<el-dialog draggable title="指标越限详情" v-model="dialogVisible" append-to-body width="70%">
|
||||||
|
<TableHeader datePicker showExport :showReset="false" ref="tableHeaderRef">
|
||||||
|
<template v-slot:select>
|
||||||
|
<el-form-item label="监测点">
|
||||||
|
<el-select
|
||||||
|
v-model="tableStore.table.params.lineId"
|
||||||
|
placeholder="请选择监测点"
|
||||||
|
style="width: 150px"
|
||||||
|
filterable
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in options"
|
||||||
|
:key="item.lineId"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.lineId"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</TableHeader>
|
||||||
|
<Table ref="tableRef" @cell-click="cellClickEvent" isGroup :height="height"></Table>
|
||||||
|
</el-dialog>
|
||||||
|
<!-- 谐波电流、谐波电压占有率 -->
|
||||||
|
<HarmonicRatio ref="harmonicRatioRef" v-if="dialogFlag" @close="onHarmonicRatioClose" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, provide,nextTick } from 'vue'
|
||||||
|
import Table from '@/components/table/index.vue'
|
||||||
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
|
import TableStore from '@/utils/tableStore'
|
||||||
|
import { mainHeight } from '@/utils/layout'
|
||||||
|
import HarmonicRatio from '@/components/cockpit/gridSideStatistics/components/harmonicRatio.vue'
|
||||||
|
import { cslineList } from '@/api/harmonic-boot/cockpit/cockpit'
|
||||||
|
|
||||||
|
const dialogVisible: any = ref(false)
|
||||||
|
const harmonicRatioRef: any = ref(null)
|
||||||
|
|
||||||
|
const options = ref()
|
||||||
|
const height = mainHeight(0, 2).height as any
|
||||||
|
const tableHeaderRef = ref()
|
||||||
|
const dialogFlag = ref(false)
|
||||||
|
const loop50 = (key: string) => {
|
||||||
|
let list: any[] = []
|
||||||
|
for (let i = 2; i < 26; i++) {
|
||||||
|
list.push({
|
||||||
|
title: i + '次',
|
||||||
|
field: key + i + 'Overtime',
|
||||||
|
width: '60',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row[key + i + 'Overtime']}</span>`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
const tableStore: any = new TableStore({
|
||||||
|
url: '/cs-harmonic-boot/totalLimitStatistics/details',
|
||||||
|
method: 'POST',
|
||||||
|
publicHeight: 30,
|
||||||
|
showPage: false,
|
||||||
|
exportName: '每日越限占比统计',
|
||||||
|
column: [
|
||||||
|
{
|
||||||
|
field: 'index',
|
||||||
|
title: '序号',
|
||||||
|
width: '80',
|
||||||
|
formatter: (row: any) => {
|
||||||
|
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '日期',
|
||||||
|
field: 'time',
|
||||||
|
width: '150',
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '名称',
|
||||||
|
field: 'lineName',
|
||||||
|
width: '150'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '闪变越限(%)',
|
||||||
|
field: 'flickerOvertime',
|
||||||
|
width: '90',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.flickerOvertime}</span>`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '谐波电压越限(%)',
|
||||||
|
children: loop50('uharm')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '谐波电流越限(%)',
|
||||||
|
children: loop50('iharm')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '三相不平衡度越限(%)',
|
||||||
|
field: 'ubalanceOvertime',
|
||||||
|
width: '100',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.ubalanceOvertime}</span>`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '电压偏差越限(%)',
|
||||||
|
field: 'voltageDevOvertime',
|
||||||
|
width: '100',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.uaberranceOvertime}</span>`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '频率偏差越限(%)',
|
||||||
|
field: 'freqDevOvertime',
|
||||||
|
width: '100',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.freqDevOvertime}</span>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
beforeSearchFun: () => {
|
||||||
|
},
|
||||||
|
loadCallback: () => {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
provide('tableStore', tableStore)
|
||||||
|
tableStore.table.params.sortBy = ''
|
||||||
|
tableStore.table.params.orderBy = ''
|
||||||
|
const open = async (row: any,searchBeginTime:any,searchEndTime:any) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
initCSlineList()
|
||||||
|
tableStore.table.params.lineId = row.lineId
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
tableHeaderRef.value.setTimeInterval([searchBeginTime, searchEndTime])
|
||||||
|
tableStore.table.params.searchBeginTime =searchBeginTime
|
||||||
|
tableStore.table.params.searchEndTime = searchEndTime
|
||||||
|
tableStore.index()
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 点击行
|
||||||
|
const cellClickEvent = ({ row, column }: any) => {
|
||||||
|
if (column.field != 'name' && column.field != 'time') {
|
||||||
|
dialogFlag.value = true
|
||||||
|
dialogVisible.value = false
|
||||||
|
nextTick(() => {
|
||||||
|
harmonicRatioRef.value.openDialog(row,column.field,column.title.replace(/次/g, ""))
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 谐波弹窗关闭时的回调
|
||||||
|
const onHarmonicRatioClose = () => {
|
||||||
|
dialogFlag.value = false
|
||||||
|
// 重新打开指标越限详情弹窗
|
||||||
|
nextTick(() => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const initCSlineList = async () => {
|
||||||
|
const res = await cslineList({})
|
||||||
|
options.value = res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
defineExpose({ open })
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@@ -1,36 +1,107 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!--监测点列表 -->
|
<!-- 监测点列表 -->
|
||||||
|
<TableHeader
|
||||||
<Table ref="tableRef" @cell-click="cellClickEvent" :height="`calc(${prop.height} )`"></Table>
|
ref="TableHeaderRef"
|
||||||
|
:showReset="false"
|
||||||
|
@selectChange="selectChange"
|
||||||
|
datePicker
|
||||||
|
v-if="fullscreen" :timeKeyList="prop.timeKey"
|
||||||
|
></TableHeader>
|
||||||
|
<Table
|
||||||
|
ref="tableRef"
|
||||||
|
@cell-click="cellClickEvent"
|
||||||
|
:height="`calc(${prop.height} - ${headerHeight}px + ${fullscreen ? -58 : 56}px )`"
|
||||||
|
></Table>
|
||||||
<!-- 指标越限详情 -->
|
<!-- 指标越限详情 -->
|
||||||
<OverLimitDetails ref="OverLimitDetailsRef" />
|
<OverLimitDetails ref="OverLimitDetailsRef" />
|
||||||
|
|
||||||
|
<!-- 上传对话框 -->
|
||||||
|
<el-dialog v-model="uploadDialogVisible" title="上传报告" width="500px" @closed="handleDialogClosed">
|
||||||
|
<el-upload
|
||||||
|
ref="uploadRef"
|
||||||
|
class="upload-demo"
|
||||||
|
:auto-upload="true"
|
||||||
|
:on-change="handleChange"
|
||||||
|
:before-upload="beforeUpload"
|
||||||
|
:http-request="handleUpload"
|
||||||
|
:limit="1"
|
||||||
|
:on-exceed="handleExceed"
|
||||||
|
:file-list="fileList"
|
||||||
|
>
|
||||||
|
<el-button type="primary">点击上传</el-button>
|
||||||
|
<template #tip>
|
||||||
|
<div class="el-upload__tip">只能上传Word或PDF文件,且不超过10MB</div>
|
||||||
|
</template>
|
||||||
|
</el-upload>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="uploadDialogVisible = false">取消</el-button>
|
||||||
|
<el-button type="primary" @click="uploadDialogVisible = false">确定</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
||||||
import TableStore from '@/utils/tableStore'
|
import TableStore from '@/utils/tableStore'
|
||||||
import Table from '@/components/table/index.vue'
|
import Table from '@/components/table/index.vue'
|
||||||
import TableHeader from '@/components/table/header/index.vue'
|
|
||||||
import { useDictData } from '@/stores/dictData'
|
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { ElMessage, ElMessageBox } from 'element-plus'
|
||||||
import { getTimeOfTheMonth } from '@/utils/formatTime'
|
import OverLimitDetails from '@/components/cockpit/monitoringPointList/components/overLimitDetails.vue'
|
||||||
import { ElTag } from 'element-plus'
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
import OverLimitDetails from '@/components/cockpit/listOfMainMonitoringPoints/components/overLimitDetails.vue'
|
import { uploadReport, getReportUrl } from '@/api/harmonic-boot/cockpit/cockpit'
|
||||||
|
import { getTime } from '@/utils/formatTime'
|
||||||
|
|
||||||
const prop = defineProps({
|
const prop = defineProps({
|
||||||
width: { type: String },
|
w: { type: [String, Number] },
|
||||||
height: { type: String },
|
h: { type: [String, Number] },
|
||||||
timeKey: { type: String },
|
width: { type: [String, Number] },
|
||||||
timeValue: { type: Object }
|
height: { type: [String, Number] },
|
||||||
|
timeKey: { type: Array as () => string[] },
|
||||||
|
timeValue: { type: Object },
|
||||||
|
interval: { type: Number }
|
||||||
})
|
})
|
||||||
const dictData = useDictData()
|
|
||||||
|
const headerHeight = ref(57)
|
||||||
|
|
||||||
|
const TableHeaderRef = ref()
|
||||||
|
|
||||||
|
// 上传相关
|
||||||
|
const uploadDialogVisible = ref(false)
|
||||||
|
const currentUploadRow = ref<any>(null)
|
||||||
|
const uploadRef = ref()
|
||||||
|
const fileList = ref([])
|
||||||
|
|
||||||
|
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
|
||||||
|
headerHeight.value = height
|
||||||
|
|
||||||
|
if (datePickerValue && datePickerValue.timeValue) {
|
||||||
|
// 更新时间参数
|
||||||
|
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
|
||||||
|
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算是否全屏展示
|
||||||
|
const fullscreen = computed(() => {
|
||||||
|
const w = Number(prop.w)
|
||||||
|
const h = Number(prop.h)
|
||||||
|
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
|
||||||
|
// 执行相应逻辑
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const OverLimitDetailsRef = ref()
|
const OverLimitDetailsRef = ref()
|
||||||
const tableStore: any = new TableStore({
|
const tableStore: any = new TableStore({
|
||||||
url: '/user-boot/role/selectRoleDetail?id=0',
|
url: '/cs-device-boot/csline/getSensitiveUserLineList',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
showPage: fullscreen.value ? true : false,
|
||||||
showPage: false,
|
exportName: '监测点列表',
|
||||||
exportName: '主要监测点列表',
|
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
field: 'index',
|
field: 'index',
|
||||||
@@ -41,107 +112,224 @@ const tableStore: any = new TableStore({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '治理对象名称',
|
title: '监测点名称',
|
||||||
field: 'name',
|
field: 'lineName',
|
||||||
minWidth: '80'
|
minWidth: '120',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.lineName}</span>`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ title: '监测类型', field: 'position', minWidth: '80' },
|
||||||
|
{
|
||||||
|
title: '监测点状态',
|
||||||
|
field: 'runStatus',
|
||||||
|
minWidth: '90',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='color: ${row.runStatus === '中断' ? '#FF0000' : ''}'>${row.runStatus}</span>`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '治理对象',
|
||||||
|
field: 'sensitiveUser',
|
||||||
|
minWidth: '90'
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
title: '电压等级',
|
title: '电压等级',
|
||||||
field: 'type',
|
field: 'volGrade',
|
||||||
minWidth: '70'
|
minWidth: '80'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '治理设备详情',
|
title: '是否治理',
|
||||||
field: 'type1',
|
field: 'govern',
|
||||||
minWidth: '70'
|
minWidth: '80'
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
title: '治理前报告',
|
title: '最新数据时间',
|
||||||
field: 'type2',
|
field: 'latestTime',
|
||||||
minWidth: '80',
|
minWidth: '140',
|
||||||
render: 'customTemplate',
|
render: 'customTemplate',
|
||||||
customTemplate: (row: any) => {
|
customTemplate: (row: any) => {
|
||||||
return `<span style='cursor: pointer;text-decoration: underline;'>${row.type2}</span>`
|
if (row.latestTime) {
|
||||||
|
return `<span>${row.latestTime}</span>`
|
||||||
|
} else {
|
||||||
|
return `<span>/</span>`
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{ title: '监测点名称', field: 'type3', minWidth: '70' },
|
|
||||||
{ title: '监测类型', field: 'type4', minWidth: '60' },
|
|
||||||
{
|
{
|
||||||
title: '监测点状态',
|
title: '操作',
|
||||||
field: 'type5',
|
minWidth: 80,
|
||||||
minWidth: '60',
|
// fixed: 'right',
|
||||||
render: 'customTemplate',
|
render: 'buttons',
|
||||||
customTemplate: (row: any) => {
|
buttons: [
|
||||||
return `<span style='color: ${row.type5 === '中断' ? '#FF0000' : ''}'>${row.type5}</span>`
|
{
|
||||||
}
|
name: 'productSetting',
|
||||||
},
|
title: '上传报告',
|
||||||
{ title: '最新数据时间', field: 'type6', minWidth: '140' }
|
type: 'primary',
|
||||||
|
icon: 'el-icon-upload',
|
||||||
|
render: 'basicButton',
|
||||||
|
click: row => {
|
||||||
|
uploadReportRow(row)
|
||||||
|
},
|
||||||
|
disabled: row => {
|
||||||
|
return row.reportFilePath
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'productSetting',
|
||||||
|
title: '下载报告',
|
||||||
|
type: 'primary',
|
||||||
|
icon: 'el-icon-EditPen',
|
||||||
|
render: 'basicButton',
|
||||||
|
click: row => {
|
||||||
|
downloadTheReport(row.lineId)
|
||||||
|
},
|
||||||
|
disabled: row => {
|
||||||
|
return row.reportFilePath == null || row.reportFilePath.length == 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'productSetting',
|
||||||
|
title: '重新上传',
|
||||||
|
type: 'primary',
|
||||||
|
icon: 'el-icon-upload',
|
||||||
|
render: 'basicButton',
|
||||||
|
click: row => {
|
||||||
|
uploadReportRow(row)
|
||||||
|
},
|
||||||
|
disabled: row => {
|
||||||
|
return row.reportFilePath == null || row.reportFilePath.length == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
],
|
],
|
||||||
beforeSearchFun: () => {
|
beforeSearchFun: () => {
|
||||||
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
|
setTime()
|
||||||
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
|
|
||||||
},
|
},
|
||||||
loadCallback: () => {
|
loadCallback: () => {
|
||||||
tableStore.table.data = [
|
|
||||||
{
|
|
||||||
name: '1#变压器',
|
|
||||||
type: '0.38kV',
|
|
||||||
type1: '250A APF',
|
|
||||||
type2: '报告.doc',
|
|
||||||
type3: '1#变压器 电网侧',
|
|
||||||
type4: '电网侧',
|
|
||||||
type5: '运行',
|
|
||||||
type6: '2025-04-11 18:16:00'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '1#变压器',
|
|
||||||
type: '0.38kV',
|
|
||||||
type1: '250A APF',
|
|
||||||
type2: '报告.doc',
|
|
||||||
type3: '1#变压器 负载侧',
|
|
||||||
type4: '负载侧',
|
|
||||||
type5: '运行',
|
|
||||||
type6: '2025-04-11 18:16:00'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '2#变压器',
|
|
||||||
type: '0.38kV',
|
|
||||||
type1: '100A SVG',
|
|
||||||
type2: '/',
|
|
||||||
type3: '1#变压器 电网侧',
|
|
||||||
type4: '电网侧',
|
|
||||||
type5: '运行',
|
|
||||||
type6: '2025-04-11 18:16:00'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '2#变压器',
|
|
||||||
type: '0.38kV',
|
|
||||||
type1: '100A SVG',
|
|
||||||
type2: '/',
|
|
||||||
type3: '1#变压器 负载侧',
|
|
||||||
type4: '负载侧',
|
|
||||||
type5: '中断',
|
|
||||||
type6: '2025-04-11 18:16:00'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
tableStore.table.height = `calc(${prop.height} - 80px)`
|
tableStore.table.height = `calc(${prop.height} - 80px)`
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const tableRef = ref()
|
const tableRef = ref()
|
||||||
provide('tableRef', tableRef)
|
provide('tableRef', tableRef)
|
||||||
tableStore.table.params.type = ''
|
tableStore.table.params.keywords = ''
|
||||||
tableStore.table.params.searchValue = ''
|
|
||||||
provide('tableStore', tableStore)
|
provide('tableStore', tableStore)
|
||||||
|
|
||||||
|
const setTime = () => {
|
||||||
|
const time = getTime(
|
||||||
|
(TableHeaderRef.value?.datePickerRef.interval || prop.interval) ?? 0,
|
||||||
|
prop.timeKey,
|
||||||
|
fullscreen.value
|
||||||
|
? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
|
||||||
|
: prop.timeValue
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(time)) {
|
||||||
|
tableStore.table.params.searchBeginTime = time[0]
|
||||||
|
tableStore.table.params.searchEndTime = time[1]
|
||||||
|
TableHeaderRef.value?.setInterval(time[2] - 0)
|
||||||
|
TableHeaderRef.value?.setTimeInterval([time[0], time[1]])
|
||||||
|
} else {
|
||||||
|
console.warn('获取时间失败,time 不是一个有效数组')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 点击行
|
// 点击行
|
||||||
const cellClickEvent = ({ row, column }: any) => {
|
const cellClickEvent = ({ row, column }: any) => {
|
||||||
if (column.field == 'name') {
|
if (column.field == 'lineName') {
|
||||||
console.log(row)
|
OverLimitDetailsRef.value.open(
|
||||||
OverLimitDetailsRef.value.open(row)
|
row,
|
||||||
|
tableStore.table.params.searchBeginTime || prop.timeValue?.[0],
|
||||||
|
tableStore.table.params.searchEndTime || prop.timeValue?.[1]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 下载报告
|
||||||
|
const downloadTheReport = (lineId: string) => {
|
||||||
|
getReportUrl({ lineId: lineId }).then((res: any) => {
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = res.data
|
||||||
|
link.download = '治理报告'
|
||||||
|
document.body.appendChild(link)
|
||||||
|
link.click()
|
||||||
|
document.body.removeChild(link)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 上传报告
|
||||||
|
const uploadReportRow = (row: any) => {
|
||||||
|
currentUploadRow.value = row
|
||||||
|
// 打开弹窗前清空文件列表
|
||||||
|
fileList.value = []
|
||||||
|
uploadDialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理弹窗关闭事件
|
||||||
|
const handleDialogClosed = () => {
|
||||||
|
// 清空文件列表
|
||||||
|
fileList.value = []
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理文件超出限制
|
||||||
|
const handleExceed = (files: any, fileList: any) => {
|
||||||
|
ElMessage.warning('只能上传一个文件,请先删除已选择的文件')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 文件变更处理函数
|
||||||
|
const handleChange = (file: any, fileList: any) => {
|
||||||
|
// 在这里直接处理文件上传逻辑
|
||||||
|
beforeUpload(file.raw) // 注意使用 file.raw 获取原始文件对象
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理上传前检查
|
||||||
|
const beforeUpload = (file: any) => {
|
||||||
|
const isWord =
|
||||||
|
file.type === 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' ||
|
||||||
|
file.type === 'application/msword' ||
|
||||||
|
file.name.endsWith('.doc') ||
|
||||||
|
file.name.endsWith('.docx')
|
||||||
|
|
||||||
|
const isPDF = file.type === 'application/pdf' || file.name.endsWith('.pdf')
|
||||||
|
|
||||||
|
const isValidType = isWord || isPDF
|
||||||
|
const isLt10M = file.size / 1024 / 1024 < 10
|
||||||
|
|
||||||
|
if (!isValidType) {
|
||||||
|
ElMessage.error('上传文件只能是 Word 文档(.doc/.docx) 或 PDF 文件(.pdf)!')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if (!isLt10M) {
|
||||||
|
ElMessage.error('上传文件大小不能超过 10MB!')
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 校验通过后允许上传,交由 http-request 处理
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleUpload = async (options: any) => {
|
||||||
|
const { file } = options
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('file', file)
|
||||||
|
formData.append('lineId', currentUploadRow.value?.lineId || currentUploadRow.value?.id || '')
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await uploadReport(formData)
|
||||||
|
ElMessage.success('上传成功')
|
||||||
|
uploadDialogVisible.value = false
|
||||||
|
tableStore.index()
|
||||||
|
return Promise.resolve(result)
|
||||||
|
} catch (error: any) {
|
||||||
|
ElMessage.error('上传失败: ' + (error.message || '未知错误'))
|
||||||
|
return Promise.reject(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,15 +343,13 @@ watch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeValue, // 监听的目标(函数形式避免直接传递 props 导致的警告)
|
() => prop.timeValue,
|
||||||
(newVal, oldVal) => {
|
(newVal, oldVal) => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
deep: true // 若 timeValue 是对象/数组,需开启深度监听
|
deep: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const addMenu = () => {}
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped></style>
|
||||||
|
|||||||
@@ -0,0 +1,708 @@
|
|||||||
|
<template>
|
||||||
|
<el-dialog draggable title="趋势图" v-model="dialogVisible" append-to-body width="70%">
|
||||||
|
<!-- 总体指标占比详情谐波含有率 -->
|
||||||
|
<div>
|
||||||
|
<TableHeader ref="tableHeaderRef" :showSearch="false" @selectChange="selectChange">
|
||||||
|
<template v-slot:select>
|
||||||
|
<el-form-item>
|
||||||
|
<DatePicker ref="datePickerRef"></DatePicker>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="统计指标" label-width="80px">
|
||||||
|
<el-select
|
||||||
|
multiple
|
||||||
|
:multiple-limit="2"
|
||||||
|
collapse-tags
|
||||||
|
collapse-tags-tooltip
|
||||||
|
v-model="searchForm.index"
|
||||||
|
placeholder="请选择统计指标"
|
||||||
|
@change="onIndexChange($event)"
|
||||||
|
filterable
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in indexOptions"
|
||||||
|
:key="item.id"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.id"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-radio-group v-model="searchForm.dataLevel" @change="init()">
|
||||||
|
<el-radio-button label="一次值" value="Primary" />
|
||||||
|
<el-radio-button label="二次值" value="Secondary" />
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="统计类型">
|
||||||
|
<el-select
|
||||||
|
style="min-width: 120px !important"
|
||||||
|
placeholder="请选择"
|
||||||
|
v-model="searchForm.valueType"
|
||||||
|
filterable
|
||||||
|
>
|
||||||
|
<el-option value="max" label="最大值"></el-option>
|
||||||
|
<el-option value="min" label="最小值"></el-option>
|
||||||
|
<el-option value="avg" label="平均值"></el-option>
|
||||||
|
<el-option value="cp95" label="cp95"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<div
|
||||||
|
class="history_count"
|
||||||
|
v-for="(item, index) in countData"
|
||||||
|
:key="index"
|
||||||
|
v-show="item.countOptions.length != 0"
|
||||||
|
>
|
||||||
|
<span class="mr12">
|
||||||
|
{{ item.name.includes('次数') ? item.name : item.name + '谐波次数' }}
|
||||||
|
</span>
|
||||||
|
<el-select
|
||||||
|
v-model="item.count"
|
||||||
|
@change="onCountChange($event, index)"
|
||||||
|
placeholder="请选择谐波次数"
|
||||||
|
style="width: 100px"
|
||||||
|
class="mr20"
|
||||||
|
filterable
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="vv in item.countOptions"
|
||||||
|
:key="vv"
|
||||||
|
:label="vv"
|
||||||
|
:value="vv"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
<template #operation>
|
||||||
|
<el-button type="primary" icon="el-icon-Search" @click="init()">查询</el-button>
|
||||||
|
<el-button :type="timeControl ? 'primary' : ''" icon="el-icon-Sort" @click="setTimeControl">
|
||||||
|
缺失数据
|
||||||
|
</el-button>
|
||||||
|
</template>
|
||||||
|
</TableHeader>
|
||||||
|
</div>
|
||||||
|
<div class="history_chart" :style="pageHeight" v-loading="loading">
|
||||||
|
<MyEchart
|
||||||
|
ref="historyChart"
|
||||||
|
:options="echartsData"
|
||||||
|
v-if="showEchart"
|
||||||
|
/>
|
||||||
|
<el-empty :style="pageHeight" v-else description="暂无数据" />
|
||||||
|
</div>
|
||||||
|
</el-dialog>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { mainHeight } from '@/utils/layout'
|
||||||
|
import { queryByCode, queryCsDictTree } from '@/api/system-boot/dictTree'
|
||||||
|
import { ref, onMounted, watch } from 'vue'
|
||||||
|
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||||
|
import { useDictData } from '@/stores/dictData'
|
||||||
|
import { queryStatistical } from '@/api/system-boot/csstatisticalset'
|
||||||
|
import { yMethod, exportCSV, completeTimeSeries } from '@/utils/echartMethod'
|
||||||
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
|
import { trendData } from '@/api/harmonic-boot/cockpit/cockpit'
|
||||||
|
import DatePicker from '@/components/form/datePicker/index.vue'
|
||||||
|
import { color } from '@/components/echarts/color'
|
||||||
|
import { ElMessage } from 'element-plus'
|
||||||
|
const dictData = useDictData()
|
||||||
|
defineOptions({
|
||||||
|
// name: 'govern/device/control'
|
||||||
|
})
|
||||||
|
const props = defineProps({
|
||||||
|
TrendList: {
|
||||||
|
type: Array
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const dialogVisible: any = ref(false)
|
||||||
|
// console.log("🚀 ~ props:", props.TrendList)
|
||||||
|
const showEchart = ref(true)
|
||||||
|
const num = ref(0)
|
||||||
|
const timeControl = ref(false)
|
||||||
|
//值类型
|
||||||
|
const pageHeight = ref(mainHeight(57 * 1.6, 1.6))
|
||||||
|
const loading = ref(true)
|
||||||
|
const searchForm: any = ref({})
|
||||||
|
const tableHeaderRef = ref()
|
||||||
|
const typeOptions = [
|
||||||
|
{
|
||||||
|
name: '平均值',
|
||||||
|
id: 'avg'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '最大值',
|
||||||
|
id: 'max'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '最小值',
|
||||||
|
id: 'min'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'CP95值',
|
||||||
|
id: 'cp95'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
searchForm.value = {
|
||||||
|
index: [],
|
||||||
|
type: typeOptions[0].id,
|
||||||
|
count: '',
|
||||||
|
searchBeginTime: '',
|
||||||
|
searchEndTime: '',
|
||||||
|
dataLevel: 'Primary',
|
||||||
|
valueType: 'avg'
|
||||||
|
}
|
||||||
|
//统计指标
|
||||||
|
const indexOptions: any = ref([])
|
||||||
|
//谐波次数
|
||||||
|
const countOptions: any = ref([])
|
||||||
|
// Harmonic_Type
|
||||||
|
// portable-harmonic
|
||||||
|
const legendDictList: any = ref([])
|
||||||
|
|
||||||
|
const initCode = (field: string, title: string) => {
|
||||||
|
queryByCode('steady_state_limit_trend').then(res => {
|
||||||
|
queryCsDictTree(res.data.id).then(item => {
|
||||||
|
//排序
|
||||||
|
indexOptions.value = item.data.sort((a: any, b: any) => {
|
||||||
|
return a.sort - b.sort
|
||||||
|
})
|
||||||
|
const titleMap: Record<string, number> = {
|
||||||
|
flickerOvertime: 0,
|
||||||
|
uaberranceOvertime: 3,
|
||||||
|
ubalanceOvertime: 4,
|
||||||
|
freqDevOvertime: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
let defaultIndex = 0 // 默认值
|
||||||
|
|
||||||
|
if (field in titleMap) {
|
||||||
|
defaultIndex = titleMap[field]
|
||||||
|
} else if (field.includes('uharm')) {
|
||||||
|
defaultIndex = 1
|
||||||
|
} else if (field.includes('iharm')) {
|
||||||
|
defaultIndex = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
searchForm.value.index[0] = indexOptions.value[defaultIndex].id
|
||||||
|
})
|
||||||
|
queryStatistical(res.data.id).then(vv => {
|
||||||
|
legendDictList.value = vv.data
|
||||||
|
indexOptions.value.map((item: any, index: any) => {
|
||||||
|
if (!countDataCopy.value[index]) {
|
||||||
|
countDataCopy.value[index] = {
|
||||||
|
index: item.id,
|
||||||
|
countOptions: [],
|
||||||
|
count: [],
|
||||||
|
name: indexOptions.value.find((vv: any) => {
|
||||||
|
return vv.id == item.id
|
||||||
|
})?.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
legendDictList.value?.selectedList?.map((vv: any, vvs: any) => {
|
||||||
|
//查找相等的指标
|
||||||
|
if (item.id == vv.dataType) {
|
||||||
|
vv.eleEpdPqdVOS.map((kk: any, kks: any) => {
|
||||||
|
if (kk.harmStart && kk.harmEnd) {
|
||||||
|
range(0, 0, 0)
|
||||||
|
|
||||||
|
if (kk.showName == '间谐波电压含有率') {
|
||||||
|
countDataCopy.value[index].countOptions = range(kk.harmStart, kk.harmEnd, 1).map(
|
||||||
|
(item: any) => {
|
||||||
|
return item - 0.5
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
countDataCopy.value[index].countOptions = range(kk.harmStart, kk.harmEnd, 1)
|
||||||
|
}
|
||||||
|
if (title && countDataCopy.value[index].countOptions.includes(Number(title))) {
|
||||||
|
countDataCopy.value[index].count = Number(title)
|
||||||
|
} else if (title && countDataCopy.value[index].countOptions.includes(title)) {
|
||||||
|
countDataCopy.value[index].count = title
|
||||||
|
} else if (
|
||||||
|
!countDataCopy.value[index].count ||
|
||||||
|
countDataCopy.value[index].count.length == 0
|
||||||
|
) {
|
||||||
|
// 只有当count为空时才设置默认值
|
||||||
|
countDataCopy.value[index].count = countDataCopy.value[index].countOptions[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
nextTick(() => {
|
||||||
|
formatCountOptions()
|
||||||
|
})
|
||||||
|
init()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const chartsList = ref<any>([])
|
||||||
|
const chartTitle: any = ref('')
|
||||||
|
const echartsData = ref<any>(null)
|
||||||
|
//加载echarts图表
|
||||||
|
//历史趋势数据
|
||||||
|
const historyDataList: any = ref([])
|
||||||
|
const range = (start: any, end: any, step: any) => {
|
||||||
|
return Array.from({ length: (end - start) / step + 1 }, (_, i) => start + i * step)
|
||||||
|
}
|
||||||
|
//获取请求趋势数据参数
|
||||||
|
const trendRequestData = ref()
|
||||||
|
const getTrendRequest = (val: any) => {
|
||||||
|
trendRequestData.value = val
|
||||||
|
// init()
|
||||||
|
}
|
||||||
|
//初始化趋势图
|
||||||
|
const headerRef = ref()
|
||||||
|
const datePickerRef = ref()
|
||||||
|
const lineStyle = [{ type: 'solid' }, { type: 'dashed' }, { type: 'dotted' }]
|
||||||
|
const init = async () => {
|
||||||
|
loading.value = true
|
||||||
|
// 选择指标的时候切换legend内容和data数据
|
||||||
|
let list: any = []
|
||||||
|
legendDictList.value?.selectedList?.map((item: any) => {
|
||||||
|
searchForm.value.index.map((vv: any) => {
|
||||||
|
if (item.dataType == vv) {
|
||||||
|
list.push(item.eleEpdPqdVOS)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
//颜色数组
|
||||||
|
const colorList = color
|
||||||
|
//选择的指标使用方法处理
|
||||||
|
formatCountOptions()
|
||||||
|
//查询历史趋势
|
||||||
|
historyDataList.value = []
|
||||||
|
chartTitle.value = ''
|
||||||
|
|
||||||
|
searchForm.value.index.map((item: any, indexs: any) => {
|
||||||
|
indexOptions.value.map((vv: any) => {
|
||||||
|
if (vv.id == item) {
|
||||||
|
chartTitle.value += indexs == searchForm.value.index.length - 1 ? vv.name : vv.name + '/'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
let lists: any = []
|
||||||
|
let frequencys: any = null
|
||||||
|
countData.value.map((item: any, index: any) => {
|
||||||
|
if (item.name.includes('谐波含有率')) {
|
||||||
|
frequencys = item.count
|
||||||
|
} else {
|
||||||
|
frequencys = ''
|
||||||
|
}
|
||||||
|
lists[index] = {
|
||||||
|
statisticalId: item.index,
|
||||||
|
frequency: frequencys !== null && frequencys !== undefined ? String(frequencys) : ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
let obj = {
|
||||||
|
//...trendRequestData.value,
|
||||||
|
lineId: trendRequestData.value.lineId,
|
||||||
|
list: lists,
|
||||||
|
dataLevel: searchForm.value.dataLevel,
|
||||||
|
valueType: searchForm.value.valueType,
|
||||||
|
searchBeginTime: datePickerRef.value && datePickerRef.value.timeValue[0],
|
||||||
|
searchEndTime: datePickerRef.value && datePickerRef.value.timeValue[1]
|
||||||
|
}
|
||||||
|
if (searchForm.value.index.length == 0) {
|
||||||
|
ElMessage.warning('请选择统计指标')
|
||||||
|
loading.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (obj.list.length != 0) {
|
||||||
|
try {
|
||||||
|
showEchart.value = true
|
||||||
|
await trendData(obj)
|
||||||
|
.then((res: any) => {
|
||||||
|
if (res.code == 'A0000') {
|
||||||
|
if (res.data.length == 0) {
|
||||||
|
loading.value = false
|
||||||
|
showEchart.value = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
historyDataList.value = res.data
|
||||||
|
chartsList.value = JSON.parse(JSON.stringify(res.data))
|
||||||
|
loading.value = false
|
||||||
|
setEchart()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const setEchart = () => {
|
||||||
|
loading.value = true
|
||||||
|
echartsData.value = {}
|
||||||
|
//icon图标替换legend图例
|
||||||
|
|
||||||
|
// y轴单位数组
|
||||||
|
let unitList: any = []
|
||||||
|
|
||||||
|
let groupedData = chartsList.value.reduce((acc: any, item: any) => {
|
||||||
|
let key = ''
|
||||||
|
if (item.phase == null) {
|
||||||
|
key = item.unit
|
||||||
|
} else {
|
||||||
|
key = item.anotherName
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!acc[key]) {
|
||||||
|
acc[key] = []
|
||||||
|
}
|
||||||
|
acc[key].push(item)
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
let result = Object.values(groupedData)
|
||||||
|
if (chartsList.value.length > 0) {
|
||||||
|
unitList = result.map((item: any) => {
|
||||||
|
return item[0].unit
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
echartsData.value = {
|
||||||
|
legend: {
|
||||||
|
itemWidth: 20,
|
||||||
|
itemHeight: 20,
|
||||||
|
itemStyle: { opacity: 0 }, //去圆点
|
||||||
|
type: 'scroll', // 开启滚动分页
|
||||||
|
// orient: 'vertical', // 垂直排列
|
||||||
|
top: 5,
|
||||||
|
right: 70
|
||||||
|
// width: 550,
|
||||||
|
// height: 50
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
top: '80px'
|
||||||
|
},
|
||||||
|
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,
|
||||||
|
formatter(params: any) {
|
||||||
|
const xname = params[0].value[0]
|
||||||
|
let str = `${xname}<br>`
|
||||||
|
params.forEach((el: any, index: any) => {
|
||||||
|
let marker = ''
|
||||||
|
|
||||||
|
if (el.value[3] == 'dashed') {
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
marker += `<span style="display:inline-block;border: 2px ${el.color} solid;margin-right:5px;width:10px;height:0px;background-color:#ffffff00;"></span>`
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
marker = `<span style="display:inline-block;border: 2px ${el.color} ${el.value[3]};margin-right:5px;width:40px;height:0px;background-color:#ffffff00;"></span>`
|
||||||
|
}
|
||||||
|
let unit = el.value[2] ? el.value[2] : ''
|
||||||
|
str += `${marker}${el.seriesName.split('(')[0]}:${el.value[1]}${unit}
|
||||||
|
<br>`
|
||||||
|
})
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
},
|
||||||
|
color: ['#DAA520', '#2E8B57', '#A52a2a', ...color],
|
||||||
|
xAxis: {
|
||||||
|
type: 'time',
|
||||||
|
axisLabel: {
|
||||||
|
formatter: {
|
||||||
|
day: '{MM}-{dd}',
|
||||||
|
month: '{MM}',
|
||||||
|
year: '{yyyy}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: [{}],
|
||||||
|
toolbox: {
|
||||||
|
featureProps: {
|
||||||
|
myTool1: {
|
||||||
|
show: true,
|
||||||
|
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',
|
||||||
|
onclick: e => {
|
||||||
|
// console.log("🚀 ~ init ~ echartsData.value:", echartsData.value.options.series.map(item => item.data))
|
||||||
|
|
||||||
|
let list = echartsData.value.options.series?.map((item: any) => item.data)
|
||||||
|
let dataList = list[0]?.map((item: any, index: any) => {
|
||||||
|
let value = [item[0], item[1]]
|
||||||
|
list.forEach((item1: any, index1: any) => {
|
||||||
|
if (index1 > 0) {
|
||||||
|
value.push(item1 && item1[index] ? item1[index][1] : null)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return value
|
||||||
|
})
|
||||||
|
exportCSV(
|
||||||
|
echartsData.value.options.series.map((item: any) => item.name),
|
||||||
|
dataList,
|
||||||
|
'监测点指标趋势.csv'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
series: []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// console.log("🚀 ~ unitList.forEach ~ unitList:", unitList)
|
||||||
|
|
||||||
|
if (chartsList.value.length > 0) {
|
||||||
|
let yData: any = []
|
||||||
|
echartsData.value.yAxis = []
|
||||||
|
let setList = [...new Set(unitList)]
|
||||||
|
|
||||||
|
setList.forEach((item: any, index: any) => {
|
||||||
|
if (index > 2) {
|
||||||
|
echartsData.value.grid.right = (index - 1) * 80
|
||||||
|
}
|
||||||
|
yData.push([])
|
||||||
|
let right = {
|
||||||
|
position: 'right',
|
||||||
|
offset: (index - 1) * 80
|
||||||
|
}
|
||||||
|
// console.log("🚀 ~ unitList.forEach ~ right.index:", index)
|
||||||
|
echartsData.value.yAxis.push({
|
||||||
|
name: item,
|
||||||
|
yAxisIndex: index,
|
||||||
|
splitNumber: 5,
|
||||||
|
minInterval: 1,
|
||||||
|
splitLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
...(index > 0 ? right : null)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
// console.log("🚀 ~ result.forEach ~ result:", result)
|
||||||
|
// '电压负序分量', '电压正序分量', '电压零序分量'
|
||||||
|
let ABCName = [
|
||||||
|
...new Set(
|
||||||
|
chartsList.value.map((item: any) => {
|
||||||
|
return item.anotherName == '电压负序分量'
|
||||||
|
? '电压不平衡'
|
||||||
|
: item.anotherName == '电压正序分量'
|
||||||
|
? '电压不平衡'
|
||||||
|
: item.anotherName == '电压零序分量'
|
||||||
|
? '电压不平衡'
|
||||||
|
: item.anotherName
|
||||||
|
})
|
||||||
|
)
|
||||||
|
]
|
||||||
|
// console.log("🚀 ~ .then ~ ABCName:", ABCName)
|
||||||
|
result.forEach((item: any, index: any) => {
|
||||||
|
let yMethodList: any = []
|
||||||
|
|
||||||
|
let ABCList = Object.values(
|
||||||
|
item.reduce((acc, item) => {
|
||||||
|
let key = ''
|
||||||
|
if (item.phase == null) {
|
||||||
|
key = item.anotherName
|
||||||
|
} else {
|
||||||
|
key = item.phase
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!acc[key]) {
|
||||||
|
acc[key] = []
|
||||||
|
}
|
||||||
|
acc[key].push(item)
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
)
|
||||||
|
// console.log("🚀 ~ ABCList.forEach ~ ABCList:", ABCList)
|
||||||
|
|
||||||
|
ABCList.forEach((kk: any) => {
|
||||||
|
let colorName = kk[0].phase?.charAt(0).toUpperCase()
|
||||||
|
let lineS = ABCName.findIndex(
|
||||||
|
item =>
|
||||||
|
item ===
|
||||||
|
(kk[0].anotherName == '电压负序分量'
|
||||||
|
? '电压不平衡'
|
||||||
|
: kk[0].anotherName == '电压正序分量'
|
||||||
|
? '电压不平衡'
|
||||||
|
: kk[0].anotherName == '电压零序分量'
|
||||||
|
? '电压不平衡'
|
||||||
|
: kk[0].anotherName)
|
||||||
|
)
|
||||||
|
|
||||||
|
let seriesList: any = []
|
||||||
|
kk.forEach((cc: any) => {
|
||||||
|
if (cc.statisticalData !== null) {
|
||||||
|
yData[setList.indexOf(kk[0].unit)].push(cc.statisticalData?.toFixed(2))
|
||||||
|
}
|
||||||
|
|
||||||
|
seriesList.push([cc.time, cc.statisticalData?.toFixed(2), cc.unit, lineStyle[lineS].type])
|
||||||
|
})
|
||||||
|
// console.log(kk);
|
||||||
|
|
||||||
|
echartsData.value.options.series.push({
|
||||||
|
name: kk[0].phase ? kk[0].phase + '相' + kk[0].anotherName : kk[0].anotherName,
|
||||||
|
type: 'line',
|
||||||
|
smooth: true,
|
||||||
|
color:
|
||||||
|
colorName == 'A' ? '#DAA520' : colorName == 'B' ? '#2E8B57' : colorName == 'C' ? '#A52a2a' : '',
|
||||||
|
symbol: 'none',
|
||||||
|
// data: seriesList,
|
||||||
|
data: timeControl.value ? completeTimeSeries(seriesList) : seriesList,
|
||||||
|
lineStyle: lineStyle[lineS],
|
||||||
|
yAxisIndex: setList.indexOf(kk[0].unit)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
yData.forEach((item: any, index: any) => {
|
||||||
|
let [min, max] = yMethod(item)
|
||||||
|
echartsData.value.yAxis[index].min = min
|
||||||
|
echartsData.value.yAxis[index].max = max
|
||||||
|
})
|
||||||
|
// console.log("🚀 ~ result.forEach ~ echartsData.value:", echartsData.value)
|
||||||
|
}
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
const setTimeControl = () => {
|
||||||
|
timeControl.value = !timeControl.value
|
||||||
|
setEchart()
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectChange = (flag: boolean, height: any) => {
|
||||||
|
pageHeight.value = mainHeight(height * 1.6, 1.6)
|
||||||
|
}
|
||||||
|
//导出
|
||||||
|
const historyChart = ref()
|
||||||
|
|
||||||
|
const countData: any = ref([])
|
||||||
|
const countDataCopy: any = ref([])
|
||||||
|
|
||||||
|
//根据选择的指标处理谐波次数
|
||||||
|
const formatCountOptions = () => {
|
||||||
|
countData.value = []
|
||||||
|
if (searchForm.value.index.length != 0) {
|
||||||
|
searchForm.value.index.forEach((item: any, index: any) => {
|
||||||
|
countDataCopy.value.forEach((vv: any, vvs: any) => {
|
||||||
|
if (vv.index == item) {
|
||||||
|
countData.value.push(vv)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
countData.value.map((item: any, key: any) => {
|
||||||
|
if (item.name == '谐波电流有效值') {
|
||||||
|
item.name = '谐波电流次数'
|
||||||
|
} else if (item.name == '谐波电压含有率') {
|
||||||
|
item.name = '谐波电压次数'
|
||||||
|
} else if (item.name == '间谐波电压含有率') {
|
||||||
|
item.name = '间谐波电压次数'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// setTimeout(() => {
|
||||||
|
// tableHeaderRef.value.computedSearchRow()
|
||||||
|
// }, 500)
|
||||||
|
}
|
||||||
|
// 判断下拉框是否存在
|
||||||
|
const onCountChange = (val: any, index: any) => {
|
||||||
|
if (val.length == 0) {
|
||||||
|
countData.value[index].count = countData.value[index].countOptions[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const flag = ref(true)
|
||||||
|
const onIndexChange = (val: any) => {
|
||||||
|
num.value += 1
|
||||||
|
let pp: any = []
|
||||||
|
indexOptions.value.forEach((item: any) => {
|
||||||
|
const filteredResult = val.filter(vv => item.id == vv)
|
||||||
|
if (filteredResult.length > 0) {
|
||||||
|
pp.push(filteredResult[0])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
searchForm.value.index = pp
|
||||||
|
flag.value = true
|
||||||
|
formatCountOptions()
|
||||||
|
}
|
||||||
|
watch(
|
||||||
|
() => searchForm.value.index,
|
||||||
|
(val: any, oldval: any) => {},
|
||||||
|
{
|
||||||
|
deep: true,
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const openDialog = async (row: any, field: any, title: any) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
trendRequestData.value = row
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
// 默认当天
|
||||||
|
datePickerRef.value.setInterval(5)
|
||||||
|
datePickerRef.value.timeValue = [row.time, row.time]
|
||||||
|
initCode(field, title)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ getTrendRequest, openDialog })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.history_header {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
// flex-wrap: wrap;
|
||||||
|
#history_select {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
// justify-content: flex-start;
|
||||||
|
// overflow-x: auto;
|
||||||
|
height: auto;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
.el-form-item {
|
||||||
|
flex: none !important;
|
||||||
|
// max-width: 380px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.el-select {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// #history_select::-webkit-scrollbar {
|
||||||
|
// width: 0 !important;
|
||||||
|
// display: none !important;
|
||||||
|
// }
|
||||||
|
|
||||||
|
.history_searchBtn {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.history_chart {
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
// flex: 1;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.history_count {
|
||||||
|
.el-select {
|
||||||
|
min-width: 100px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,186 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<!-- 指标越限详情 -->
|
||||||
|
<el-dialog draggable title="指标越限详情" v-model="dialogVisible" append-to-body width="70%">
|
||||||
|
<TableHeader datePicker showExport :showReset="false" ref="tableHeaderRef">
|
||||||
|
<template v-slot:select>
|
||||||
|
<el-form-item label="监测点">
|
||||||
|
<el-select
|
||||||
|
v-model="tableStore.table.params.lineId"
|
||||||
|
placeholder="请选择监测点"
|
||||||
|
style="width: 150px"
|
||||||
|
filterable
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in options"
|
||||||
|
:key="item.lineId"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.lineId"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</TableHeader>
|
||||||
|
<Table ref="tableRef" @cell-click="cellClickEvent" isGroup :height="height"></Table>
|
||||||
|
</el-dialog>
|
||||||
|
<!-- 谐波电流、谐波电压占有率 -->
|
||||||
|
<HarmonicRatio ref="harmonicRatioRef" v-if="dialogFlag" @close="onHarmonicRatioClose" />
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, provide,nextTick } from 'vue'
|
||||||
|
import Table from '@/components/table/index.vue'
|
||||||
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
|
import TableStore from '@/utils/tableStore'
|
||||||
|
import { mainHeight } from '@/utils/layout'
|
||||||
|
import HarmonicRatio from '@/components/cockpit/overLimitStatistics/components/harmonicRatio.vue'
|
||||||
|
import { cslineList } from '@/api/harmonic-boot/cockpit/cockpit'
|
||||||
|
|
||||||
|
const dialogVisible: any = ref(false)
|
||||||
|
const harmonicRatioRef: any = ref(null)
|
||||||
|
|
||||||
|
const options = ref()
|
||||||
|
const height = mainHeight(0, 2).height as any
|
||||||
|
const tableHeaderRef = ref()
|
||||||
|
const dialogFlag = ref(false)
|
||||||
|
const loop50 = (key: string) => {
|
||||||
|
let list: any[] = []
|
||||||
|
for (let i = 2; i < 26; i++) {
|
||||||
|
list.push({
|
||||||
|
title: i + '次',
|
||||||
|
field: key + i + 'Overtime',
|
||||||
|
width: '60',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row[key + i + 'Overtime']}</span>`
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
const tableStore: any = new TableStore({
|
||||||
|
url: '/cs-harmonic-boot/totalLimitStatistics/details',
|
||||||
|
method: 'POST',
|
||||||
|
publicHeight: 30,
|
||||||
|
showPage: false,
|
||||||
|
exportName: '每日越限占比统计',
|
||||||
|
column: [
|
||||||
|
{
|
||||||
|
field: 'index',
|
||||||
|
title: '序号',
|
||||||
|
width: '80',
|
||||||
|
formatter: (row: any) => {
|
||||||
|
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '日期',
|
||||||
|
field: 'time',
|
||||||
|
width: '150',
|
||||||
|
sortable: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '名称',
|
||||||
|
field: 'lineName',
|
||||||
|
width: '150'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '闪变越限(%)',
|
||||||
|
field: 'flickerOvertime',
|
||||||
|
width: '90',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.flickerOvertime}</span>`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '谐波电压越限(%)',
|
||||||
|
children: loop50('uharm')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '谐波电流越限(%)',
|
||||||
|
children: loop50('iharm')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '三相不平衡度越限(%)',
|
||||||
|
field: 'ubalanceOvertime',
|
||||||
|
width: '100',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.ubalanceOvertime}</span>`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '电压偏差越限(%)',
|
||||||
|
field: 'voltageDevOvertime',
|
||||||
|
width: '100',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.uaberranceOvertime}</span>`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '频率偏差越限(%)',
|
||||||
|
field: 'freqDevOvertime',
|
||||||
|
width: '100',
|
||||||
|
render: 'customTemplate',
|
||||||
|
customTemplate: (row: any) => {
|
||||||
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.freqDevOvertime}</span>`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
beforeSearchFun: () => {
|
||||||
|
},
|
||||||
|
loadCallback: () => {
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
provide('tableStore', tableStore)
|
||||||
|
tableStore.table.params.sortBy = ''
|
||||||
|
tableStore.table.params.orderBy = ''
|
||||||
|
const open = async (row: any,searchBeginTime:any,searchEndTime:any) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
initCSlineList()
|
||||||
|
tableStore.table.params.lineId = row.lineId
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
tableHeaderRef.value.setTimeInterval([searchBeginTime, searchEndTime])
|
||||||
|
tableStore.table.params.searchBeginTime =searchBeginTime
|
||||||
|
tableStore.table.params.searchEndTime = searchEndTime
|
||||||
|
tableStore.index()
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 点击行
|
||||||
|
const cellClickEvent = ({ row, column }: any) => {
|
||||||
|
if (column.field != 'name' && column.field != 'time') {
|
||||||
|
dialogFlag.value = true
|
||||||
|
dialogVisible.value = false
|
||||||
|
nextTick(() => {
|
||||||
|
harmonicRatioRef.value.openDialog(row,column.field,column.title.replace(/次/g, ""))
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 谐波弹窗关闭时的回调
|
||||||
|
const onHarmonicRatioClose = () => {
|
||||||
|
dialogFlag.value = false
|
||||||
|
// 重新打开指标越限详情弹窗
|
||||||
|
nextTick(() => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const initCSlineList = async () => {
|
||||||
|
const res = await cslineList({})
|
||||||
|
options.value = res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
defineExpose({ open })
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@@ -1,13 +1,27 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
|
|
||||||
<!--总体指标越限统计 -->
|
<!--总体指标越限统计 -->
|
||||||
|
<TableHeader
|
||||||
|
:showReset="false"
|
||||||
|
ref="TableHeaderRef"
|
||||||
|
@selectChange="selectChange"
|
||||||
|
datePicker
|
||||||
|
v-if="fullscreen" :timeKeyList="prop.timeKey"
|
||||||
|
></TableHeader>
|
||||||
<my-echart
|
<my-echart
|
||||||
class="tall"
|
class="tall"
|
||||||
:options="echartList"
|
:options="echartList"
|
||||||
:style="{ width: prop.width, height: `calc(${prop.height} / 2 )` }"
|
:style="{
|
||||||
|
width: prop.width,
|
||||||
|
height: `calc(${prop.height} / 2 )`
|
||||||
|
}"
|
||||||
/>
|
/>
|
||||||
<Table ref="tableRef" @cell-click="cellClickEvent" :height="`calc(${prop.height} / 2 )`" isGroup></Table>
|
<Table
|
||||||
|
ref="tableRef"
|
||||||
|
@cell-click="cellClickEvent"
|
||||||
|
:height="`calc(${prop.height} / 2 - ${headerHeight}px + ${fullscreen ? 0 : 56}px )`"
|
||||||
|
isGroup
|
||||||
|
></Table>
|
||||||
<!-- 指标越限详情 -->
|
<!-- 指标越限详情 -->
|
||||||
<OverLimitDetails ref="OverLimitDetailsRef" />
|
<OverLimitDetails ref="OverLimitDetailsRef" />
|
||||||
</div>
|
</div>
|
||||||
@@ -16,60 +30,104 @@
|
|||||||
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
||||||
import TableStore from '@/utils/tableStore'
|
import TableStore from '@/utils/tableStore'
|
||||||
import Table from '@/components/table/index.vue'
|
import Table from '@/components/table/index.vue'
|
||||||
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
import MyEchart from '@/components/echarts/MyEchart.vue'
|
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||||
import { useDictData } from '@/stores/dictData'
|
import OverLimitDetails from '@/components/cockpit/overLimitStatistics/components/overLimitDetails.vue'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { useRoute } from 'vue-router'
|
||||||
import { getTimeOfTheMonth } from '@/utils/formatTime'
|
import { useTimeCacheStore } from '@/stores/timeCache'
|
||||||
import OverLimitDetails from '@/components/cockpit/listOfMainMonitoringPoints/components/overLimitDetails.vue'
|
import { totalLimitStatisticsData } from '@/api/harmonic-boot/cockpit/cockpit'
|
||||||
|
import { getTime } from '@/utils/formatTime'
|
||||||
|
|
||||||
const prop = defineProps({
|
const prop = defineProps({
|
||||||
width: { type: String },
|
w: { type: [String, Number] },
|
||||||
height: { type: String },
|
h: { type: [String, Number] },
|
||||||
timeKey: { type: String },
|
width: { type: [String, Number] },
|
||||||
timeValue: { type: Object }
|
height: { type: [String, Number] },
|
||||||
|
timeKey: { type: Array as () => string[] },
|
||||||
|
timeValue: { type: Object },
|
||||||
|
interval: { type: Number }
|
||||||
})
|
})
|
||||||
const echartList = ref({
|
|
||||||
title: {
|
|
||||||
text: '指标越限占比'
|
|
||||||
},
|
|
||||||
|
|
||||||
xAxis: {
|
const headerHeight = ref(57)
|
||||||
// name: '(区域)',
|
|
||||||
data: ['闪变', '谐波电压', '谐波电流', '电压偏差', '三相不平衡']
|
|
||||||
},
|
|
||||||
|
|
||||||
yAxis: {
|
const TableHeaderRef = ref()
|
||||||
name: '%', // 给X轴加单位
|
|
||||||
interval: 20
|
|
||||||
},
|
|
||||||
grid: {
|
|
||||||
left: '10px',
|
|
||||||
right: '20px'
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
// name: '暂降次数',
|
|
||||||
type: 'bar',
|
|
||||||
name: '越限占比',
|
|
||||||
data: [0, 45, 22, 0, 70],
|
|
||||||
barMaxWidth: 30,
|
|
||||||
|
|
||||||
// label: {
|
const echartList = ref({})
|
||||||
// show: true,
|
|
||||||
// position: 'top',
|
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
|
||||||
// textStyle: {
|
headerHeight.value = height
|
||||||
// //数值样式
|
|
||||||
// color: '#000'
|
if (datePickerValue && datePickerValue.timeValue) {
|
||||||
// },
|
// 更新时间参数
|
||||||
// fontSize: 12
|
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
|
||||||
// }
|
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
|
||||||
}
|
}
|
||||||
]
|
}
|
||||||
|
|
||||||
|
// 计算是否全屏展示
|
||||||
|
const fullscreen = computed(() => {
|
||||||
|
const w = Number(prop.w)
|
||||||
|
const h = Number(prop.h)
|
||||||
|
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
|
||||||
|
// 执行相应逻辑
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const initEcharts = () => {
|
||||||
|
totalLimitStatisticsData({
|
||||||
|
searchBeginTime: tableStore.table.params.searchBeginTime,
|
||||||
|
searchEndTime: tableStore.table.params.searchEndTime
|
||||||
|
}).then((res: any) => {
|
||||||
|
const dataArray = [res.data.flicker, res.data.uharm, res.data.iharm, res.data.voltageDev, res.data.ubalance]
|
||||||
|
echartList.value = {
|
||||||
|
title: {
|
||||||
|
text: '指标越限占比'
|
||||||
|
},
|
||||||
|
|
||||||
|
xAxis: {
|
||||||
|
// name: '(区域)',
|
||||||
|
data: ['闪变', '谐波电压', '谐波电流', '电压偏差', '三相不平衡']
|
||||||
|
},
|
||||||
|
|
||||||
|
yAxis: {
|
||||||
|
name: '%', // 给X轴加单位
|
||||||
|
interval: 20
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '10px',
|
||||||
|
right: '20px'
|
||||||
|
},
|
||||||
|
options: {
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
// name: '暂降次数',
|
||||||
|
type: 'bar',
|
||||||
|
name: '越限占比',
|
||||||
|
data: dataArray,
|
||||||
|
barMaxWidth: 30
|
||||||
|
|
||||||
|
// label: {
|
||||||
|
// show: true,
|
||||||
|
// position: 'top',
|
||||||
|
// textStyle: {
|
||||||
|
// //数值样式
|
||||||
|
// color: '#000'
|
||||||
|
// },
|
||||||
|
// fontSize: 12
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const OverLimitDetailsRef = ref()
|
const OverLimitDetailsRef = ref()
|
||||||
const tableStore: any = new TableStore({
|
const tableStore: any = new TableStore({
|
||||||
url: '/user-boot/dept/deptTree',
|
url: '/cs-harmonic-boot/totalLimitStatistics/list',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|
||||||
showPage: false,
|
showPage: false,
|
||||||
@@ -85,7 +143,7 @@ const tableStore: any = new TableStore({
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '名称',
|
title: '名称',
|
||||||
field: 'name',
|
field: 'lineName',
|
||||||
minWidth: '90'
|
minWidth: '90'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -93,69 +151,58 @@ const tableStore: any = new TableStore({
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
title: '闪变',
|
title: '闪变',
|
||||||
field: 'type',
|
field: 'flicker',
|
||||||
minWidth: '70',
|
minWidth: '70',
|
||||||
render: 'customTemplate',
|
render: 'customTemplate',
|
||||||
customTemplate: (row: any) => {
|
customTemplate: (row: any) => {
|
||||||
return `<span style='cursor: pointer;text-decoration: underline;'>${row.type}</span>`
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.flicker}</span>`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '谐波电压',
|
title: '谐波电压',
|
||||||
field: 'type1',
|
field: 'uharm',
|
||||||
minWidth: '80',
|
minWidth: '80',
|
||||||
render: 'customTemplate',
|
render: 'customTemplate',
|
||||||
customTemplate: (row: any) => {
|
customTemplate: (row: any) => {
|
||||||
return `<span style='cursor: pointer;text-decoration: underline;'>${row.type1}</span>`
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.uharm}</span>`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '谐波电流',
|
title: '谐波电流',
|
||||||
field: 'type2',
|
field: 'iharm',
|
||||||
minWidth: '80',
|
minWidth: '80',
|
||||||
render: 'customTemplate',
|
render: 'customTemplate',
|
||||||
customTemplate: (row: any) => {
|
customTemplate: (row: any) => {
|
||||||
return `<span style='cursor: pointer;text-decoration: underline;'>${row.type2}</span>`
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.iharm}</span>`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '电压偏差',
|
title: '电压偏差',
|
||||||
field: 'type3',
|
field: 'voltageDev',
|
||||||
minWidth: '80',
|
minWidth: '80',
|
||||||
render: 'customTemplate',
|
render: 'customTemplate',
|
||||||
customTemplate: (row: any) => {
|
customTemplate: (row: any) => {
|
||||||
return `<span style='cursor: pointer;text-decoration: underline;'>${row.type3}</span>`
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.voltageDev}</span>`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '三相不平衡',
|
title: '三相不平衡',
|
||||||
field: 'type4',
|
field: 'ubalance',
|
||||||
minWidth: '90',
|
minWidth: '90',
|
||||||
render: 'customTemplate',
|
render: 'customTemplate',
|
||||||
customTemplate: (row: any) => {
|
customTemplate: (row: any) => {
|
||||||
return `<span style='cursor: pointer;text-decoration: underline;'>${row.type4}</span>`
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.ubalance}</span>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
beforeSearchFun: () => {
|
beforeSearchFun: () => {
|
||||||
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
|
setTime()
|
||||||
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
|
|
||||||
},
|
},
|
||||||
loadCallback: () => {
|
loadCallback: () => {
|
||||||
tableStore.table.data = [
|
|
||||||
{
|
|
||||||
name: '10kV1#电动机',
|
|
||||||
type: '0',
|
|
||||||
type1: '45',
|
|
||||||
type2: '22',
|
|
||||||
type3: '0',
|
|
||||||
type4: '70'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
tableStore.table.height = `calc(${prop.height} - 80px)`
|
tableStore.table.height = `calc(${prop.height} - 80px)`
|
||||||
|
initEcharts()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -167,27 +214,51 @@ provide('tableStore', tableStore)
|
|||||||
// 点击行
|
// 点击行
|
||||||
const cellClickEvent = ({ row, column }: any) => {
|
const cellClickEvent = ({ row, column }: any) => {
|
||||||
if (column.field != 'name') {
|
if (column.field != 'name') {
|
||||||
console.log(row)
|
OverLimitDetailsRef.value.open(
|
||||||
OverLimitDetailsRef.value.open(row)
|
row,
|
||||||
|
tableStore.table.params.searchBeginTime || prop.timeValue?.[0],
|
||||||
|
tableStore.table.params.searchEndTime || prop.timeValue?.[1]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const setTime = () => {
|
||||||
|
const time = getTime(
|
||||||
|
(TableHeaderRef.value?.datePickerRef.interval || prop.interval) ?? 0,
|
||||||
|
prop.timeKey,
|
||||||
|
fullscreen.value
|
||||||
|
? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
|
||||||
|
: prop.timeValue
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(time)) {
|
||||||
|
tableStore.table.params.searchBeginTime = time[0]
|
||||||
|
tableStore.table.params.searchEndTime = time[1]
|
||||||
|
TableHeaderRef.value?.setInterval(time[2] - 0)
|
||||||
|
TableHeaderRef.value?.setTimeInterval([time[0], time[1]])
|
||||||
|
} else {
|
||||||
|
console.warn('获取时间失败,time 不是一个有效数组')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeKey,
|
() => prop.timeKey,
|
||||||
val => {
|
val => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
|
initEcharts()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeValue, // 监听的目标(函数形式避免直接传递 props 导致的警告)
|
() => prop.timeValue,
|
||||||
(newVal, oldVal) => {
|
(newVal, oldVal) => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
deep: true // 若 timeValue 是对象/数组,需开启深度监听
|
deep: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -1,32 +1,73 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!--敏感负荷列表 -->
|
<!--敏感负荷列表 -->
|
||||||
|
<TableHeader
|
||||||
<Table ref="tableRef" @cell-click="cellClickEvent" :height="`calc(${prop.height})`" isGroup></Table>
|
ref="TableHeaderRef"
|
||||||
|
:showReset="false"
|
||||||
|
@selectChange="selectChange"
|
||||||
|
datePicker
|
||||||
|
v-if="fullscreen" :timeKeyList="prop.timeKey"
|
||||||
|
></TableHeader>
|
||||||
|
<Table
|
||||||
|
ref="tableRef"
|
||||||
|
@cell-click="cellClickEvent"
|
||||||
|
:height="`calc(${prop.height} - ${headerHeight}px + ${fullscreen ? -58 : 56}px )`"
|
||||||
|
isGroup
|
||||||
|
></Table>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
||||||
import TableStore from '@/utils/tableStore'
|
import TableStore from '@/utils/tableStore'
|
||||||
import Table from '@/components/table/index.vue'
|
import Table from '@/components/table/index.vue'
|
||||||
import MyEchart from '@/components/echarts/MyEchart.vue'
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
import { useDictData } from '@/stores/dictData'
|
import { useDictData } from '@/stores/dictData'
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
import { getTime } from '@/utils/formatTime'
|
||||||
import { getTimeOfTheMonth } from '@/utils/formatTime'
|
|
||||||
const prop = defineProps({
|
const prop = defineProps({
|
||||||
width: { type: String },
|
w: { type: [String, Number] },
|
||||||
height: { type: String },
|
h: { type: [String, Number] },
|
||||||
timeKey: { type: String },
|
width: { type: [String, Number] },
|
||||||
timeValue: { type: Object }
|
height: { type: [String, Number] },
|
||||||
|
timeKey: { type: Array as () => string[] },
|
||||||
|
timeValue: { type: Object },
|
||||||
|
interval: { type: Number }
|
||||||
|
})
|
||||||
|
|
||||||
|
const headerHeight = ref(57)
|
||||||
|
|
||||||
|
const TableHeaderRef = ref()
|
||||||
|
|
||||||
|
const dictData = useDictData()
|
||||||
|
const sensitiveUserType = dictData.getBasicData('Interference_Source')
|
||||||
|
|
||||||
|
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
|
||||||
|
headerHeight.value = height
|
||||||
|
|
||||||
|
if (datePickerValue && datePickerValue.timeValue) {
|
||||||
|
// 更新时间参数
|
||||||
|
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
|
||||||
|
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算是否全屏展示
|
||||||
|
const fullscreen = computed(() => {
|
||||||
|
const w = Number(prop.w)
|
||||||
|
const h = Number(prop.h)
|
||||||
|
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
|
||||||
|
// 执行相应逻辑
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const OverLimitDetailsRef = ref()
|
const OverLimitDetailsRef = ref()
|
||||||
const tableStore: any = new TableStore({
|
const tableStore: any = new TableStore({
|
||||||
url: '/user-boot/dept/deptTree',
|
url: '/cs-harmonic-boot/pqSensitiveUser/getList',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
showPage: fullscreen.value ? true : false,
|
||||||
showPage: false,
|
|
||||||
|
|
||||||
column: [
|
column: [
|
||||||
{
|
{
|
||||||
field: 'index',
|
field: 'index',
|
||||||
@@ -44,40 +85,28 @@ const tableStore: any = new TableStore({
|
|||||||
|
|
||||||
{
|
{
|
||||||
title: '敏感负荷类型',
|
title: '敏感负荷类型',
|
||||||
field: 'type',
|
field: 'loadType',
|
||||||
minWidth: '70'
|
minWidth: '70',
|
||||||
|
formatter: row => {
|
||||||
|
return sensitiveUserType.filter(item => item.id == row.cellValue)[0]?.name
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '是否监测',
|
title: '是否监测',
|
||||||
field: 'type1',
|
field: 'isMonitor',
|
||||||
minWidth: '80'
|
minWidth: '80'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '是否治理',
|
title: '是否治理',
|
||||||
field: 'type2',
|
field: 'isGovern',
|
||||||
minWidth: '80'
|
minWidth: '80'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
beforeSearchFun: () => {
|
beforeSearchFun: () => {
|
||||||
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
|
setTime()
|
||||||
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
|
|
||||||
},
|
},
|
||||||
loadCallback: () => {
|
|
||||||
tableStore.table.data = [
|
loadCallback: () => {}
|
||||||
{
|
|
||||||
name: '10kV1#变压器',
|
|
||||||
type: '机房',
|
|
||||||
type1: '是',
|
|
||||||
type2: '100A APF'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '380kV1#母线',
|
|
||||||
type: 'PLC',
|
|
||||||
type1: '是',
|
|
||||||
type2: 'UPS'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const tableRef = ref()
|
const tableRef = ref()
|
||||||
@@ -93,6 +122,25 @@ const cellClickEvent = ({ row, column }: any) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setTime = () => {
|
||||||
|
const time = getTime(
|
||||||
|
(TableHeaderRef.value?.datePickerRef.interval || prop.interval) ?? 0,
|
||||||
|
prop.timeKey,
|
||||||
|
fullscreen.value
|
||||||
|
? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
|
||||||
|
: prop.timeValue
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(time)) {
|
||||||
|
tableStore.table.params.searchBeginTime = time[0]
|
||||||
|
tableStore.table.params.searchEndTime = time[1]
|
||||||
|
TableHeaderRef.value?.setInterval(time[2] - 0)
|
||||||
|
TableHeaderRef.value?.setTimeInterval([time[0], time[1]])
|
||||||
|
} else {
|
||||||
|
console.warn('获取时间失败,time 不是一个有效数组')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
@@ -105,15 +153,13 @@ watch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeValue, // 监听的目标(函数形式避免直接传递 props 导致的警告)
|
() => prop.timeValue,
|
||||||
(newVal, oldVal) => {
|
(newVal, oldVal) => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
deep: true // 若 timeValue 是对象/数组,需开启深度监听
|
deep: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const addMenu = () => {}
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped></style>
|
||||||
|
|||||||
@@ -0,0 +1,225 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<!-- 暂态事件详情 -->
|
||||||
|
<el-dialog draggable title="暂态事件详情 " v-model="dialogVisible" append-to-body width="70%">
|
||||||
|
<TableHeader datePicker showExport :showReset="false" ref="tableHeaderRef" @selectChange="selectChange">
|
||||||
|
<template v-slot:select>
|
||||||
|
<el-form-item label="监测点">
|
||||||
|
<el-select v-model="tableStore.table.params.lineId" placeholder="请选择监测点名称">
|
||||||
|
<el-option
|
||||||
|
v-for="item in options"
|
||||||
|
:key="item.value"
|
||||||
|
:label="item.label"
|
||||||
|
:value="item.value"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</TableHeader>
|
||||||
|
<Table ref="tableRef" isGroup :height="heightRef"></Table>
|
||||||
|
</el-dialog>
|
||||||
|
<!-- 查看波形 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="isWaveCharts"
|
||||||
|
draggable
|
||||||
|
title="波形分析"
|
||||||
|
append-to-body
|
||||||
|
v-if="isWaveCharts"
|
||||||
|
width="70%"
|
||||||
|
@close="handleHideCharts"
|
||||||
|
>
|
||||||
|
<waveFormAnalysis
|
||||||
|
v-loading="loading"
|
||||||
|
ref="waveFormAnalysisRef"
|
||||||
|
@handleHideCharts="handleHideCharts"
|
||||||
|
:wp="wp"
|
||||||
|
/>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, provide } from 'vue'
|
||||||
|
import Table from '@/components/table/index.vue'
|
||||||
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
|
import TableStore from '@/utils/tableStore'
|
||||||
|
import { mainHeight } from '@/utils/layout'
|
||||||
|
import waveFormAnalysis from '@/views/govern/device/control/tabs/components/waveFormAnalysis.vue'
|
||||||
|
import { analyseWave } from '@/api/common'
|
||||||
|
import { getSimpleLine } from '@/api/harmonic-boot/cockpit/cockpit'
|
||||||
|
|
||||||
|
const dialogVisible: any = ref(false)
|
||||||
|
const waveFormAnalysisRef: any = ref(null)
|
||||||
|
// 波形
|
||||||
|
const isWaveCharts = ref(false)
|
||||||
|
const loading = ref(false)
|
||||||
|
const wp = ref({})
|
||||||
|
const boxoList: any = ref({})
|
||||||
|
|
||||||
|
const tableHeaderRef = ref()
|
||||||
|
|
||||||
|
const options = ref()
|
||||||
|
const heightRef = ref(mainHeight(168, 2.1).height)
|
||||||
|
const selectChange = (flag: boolean, h: any) => {
|
||||||
|
heightRef.value = mainHeight(h, 2.1).height
|
||||||
|
}
|
||||||
|
|
||||||
|
const getSimpleLineList = async () => {
|
||||||
|
const res = await getSimpleLine()
|
||||||
|
options.value = res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableStore: any = new TableStore({
|
||||||
|
url: '/cs-harmonic-boot/event/pageEvent',
|
||||||
|
method: 'POST',
|
||||||
|
showPage: true,
|
||||||
|
exportName: '暂态事件详情',
|
||||||
|
column: [
|
||||||
|
{
|
||||||
|
field: 'index',
|
||||||
|
title: '序号',
|
||||||
|
width: '80',
|
||||||
|
formatter: (row: any) => {
|
||||||
|
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '暂态时间',
|
||||||
|
field: 'startTime',
|
||||||
|
minWidth: '180'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '测点名称',
|
||||||
|
field: 'lineName',
|
||||||
|
minWidth: '150'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '暂态类型',
|
||||||
|
field: 'tag',
|
||||||
|
minWidth: '100'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '特征幅值(%)',
|
||||||
|
field: 'amplitude',
|
||||||
|
minWidth: '100'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '暂降深度(%)',
|
||||||
|
field: 'depth',
|
||||||
|
minWidth: '100',
|
||||||
|
formatter: (row: any) => {
|
||||||
|
// 当暂态类型不是电压暂升时,计算暂降深度 = 100 - 特征幅值
|
||||||
|
if (row.row.tag !== '电压暂升') {
|
||||||
|
const amplitude = parseFloat(row.row.amplitude)
|
||||||
|
if (!isNaN(amplitude)) {
|
||||||
|
return 100 - amplitude
|
||||||
|
}
|
||||||
|
return '-'
|
||||||
|
} else {
|
||||||
|
// 电压暂升时不显示暂降深度
|
||||||
|
return '/'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '持续时间(S)',
|
||||||
|
field: 'persistTime',
|
||||||
|
minWidth: '100'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '严重度',
|
||||||
|
field: 'severity',
|
||||||
|
minWidth: '80'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '波形',
|
||||||
|
minWidth: '100',
|
||||||
|
render: 'buttons',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
name: 'edit',
|
||||||
|
text: '波形分析',
|
||||||
|
type: 'primary',
|
||||||
|
icon: 'el-icon-DataLine',
|
||||||
|
render: 'basicButton',
|
||||||
|
disabled: row => {
|
||||||
|
return !row.wavePath
|
||||||
|
},
|
||||||
|
|
||||||
|
click: async row => {
|
||||||
|
row.loading1 = true
|
||||||
|
loading.value = true
|
||||||
|
isWaveCharts.value = true
|
||||||
|
dialogVisible.value = false
|
||||||
|
// 在打开弹窗时立即设置高度
|
||||||
|
nextTick(() => {
|
||||||
|
if (waveFormAnalysisRef.value) {
|
||||||
|
// waveFormAnalysisRef.value.setHeight(false, 360)
|
||||||
|
waveFormAnalysisRef.value.setHeight(999, 130, 1.6666666)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await analyseWave(row.id)
|
||||||
|
.then(res => {
|
||||||
|
row.loading1 = false
|
||||||
|
if (res != undefined) {
|
||||||
|
boxoList.value = row
|
||||||
|
// boxoList.value = {
|
||||||
|
// ...row,
|
||||||
|
// duration: row.persistTime // 将 persistTime 值赋给 duration
|
||||||
|
// }
|
||||||
|
boxoList.value.featureAmplitude =
|
||||||
|
row.evtParamVVaDepth != '-' ? row.evtParamVVaDepth - 0 : null
|
||||||
|
boxoList.value.systemType = 'YPT'
|
||||||
|
wp.value = res.data
|
||||||
|
}
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
row.loading1 = false
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
waveFormAnalysisRef.value &&
|
||||||
|
waveFormAnalysisRef.value.getWpData(wp.value, boxoList.value, true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'edit',
|
||||||
|
text: '暂无波形',
|
||||||
|
type: 'info',
|
||||||
|
icon: 'el-icon-DataLine',
|
||||||
|
render: 'basicButton',
|
||||||
|
disabled: row => {
|
||||||
|
return !!row.wavePath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
beforeSearchFun: () => {},
|
||||||
|
loadCallback: () => {}
|
||||||
|
})
|
||||||
|
|
||||||
|
provide('tableStore', tableStore)
|
||||||
|
const open = async (time: any) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
getSimpleLineList()
|
||||||
|
tableStore.table.params.lineId = ''
|
||||||
|
nextTick(() => {
|
||||||
|
tableHeaderRef.value.setInterval(5)
|
||||||
|
tableHeaderRef.value.setTimeInterval([time, time])
|
||||||
|
tableStore.table.params.searchBeginTime = time
|
||||||
|
tableStore.table.params.searchEndTime = time
|
||||||
|
tableStore.index()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleHideCharts = () => {
|
||||||
|
isWaveCharts.value = false
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ open })
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@@ -1,129 +1,147 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!--暂态事件明细 -->
|
<!--暂态事件明细 -->
|
||||||
|
<TableHeader
|
||||||
<el-calendar v-model="value" :style="{ height: prop.height, overflow: 'auto' }">
|
:showReset="false"
|
||||||
|
ref="TableHeaderRef"
|
||||||
|
@selectChange="selectChange"
|
||||||
|
datePicker
|
||||||
|
v-if="fullscreen"
|
||||||
|
:timeKeyList="prop.timeKey"
|
||||||
|
></TableHeader>
|
||||||
|
<el-calendar
|
||||||
|
v-model="value"
|
||||||
|
:style="{
|
||||||
|
height: `calc(${prop.height} - ${headerHeight}px + ${fullscreen ? 0 : 56}px )`,
|
||||||
|
overflow: 'auto'
|
||||||
|
}"
|
||||||
|
v-loading="tableStore.table.loading"
|
||||||
|
>
|
||||||
<template #date-cell="{ data }">
|
<template #date-cell="{ data }">
|
||||||
<div style="height: 100%; padding: 8px" :style="{ background: setBackground(data.day) }">
|
<div
|
||||||
|
style="padding: 8px"
|
||||||
|
:style="{
|
||||||
|
background: setBackground(data.day),
|
||||||
|
height: `calc((${prop.height} - 100px - ${headerHeight}px + ${fullscreen ? 0 : 56}px) / 5 )`
|
||||||
|
}"
|
||||||
|
>
|
||||||
<p :class="data.isSelected ? 'is-selected' : ''">
|
<p :class="data.isSelected ? 'is-selected' : ''">
|
||||||
{{ data.day.split('-').slice(2).join('-') }}
|
{{ data.day.split('-').slice(2).join('-') }}
|
||||||
</p>
|
</p>
|
||||||
<el-tooltip
|
<el-tooltip effect="dark" placement="top" :hide-after="0" v-if="hasEventData(data.day)">
|
||||||
effect="dark"
|
|
||||||
placement="top"
|
|
||||||
:hide-after="0"
|
|
||||||
v-if="list?.filter(item => item.time == data.day)[0]?.type || false"
|
|
||||||
>
|
|
||||||
<template #content>
|
<template #content>
|
||||||
<!-- <span v-html="list?.filter(item => item.time == data.day)[0]?.type || ''"></span> -->
|
<!-- <span v-html="list?.filter(item => item.time == data.day)[0]?.type || ''"></span> -->
|
||||||
<div v-for="item in list?.filter(item => item.time == data.day)">
|
<div v-for="item in list?.filter((item:any) => item.name == data.day)">
|
||||||
<div>电压暂降:{{ item.type || '' }}</div>
|
<div>电压暂降:{{ item.eventDown || 0 }}</div>
|
||||||
<div>电压中断:{{ item.type1 || '' }}</div>
|
<div>电压中断:{{ item.eventOff || 0 }}</div>
|
||||||
<div>电压暂升:{{ item.type2 || '' }}</div>
|
<div>电压暂升:{{ item.eventUp || 0 }}</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div
|
<div
|
||||||
:style="{ height: `calc(${prop.height} / 5 - 47px)`, overflow: 'auto' }"
|
style="text-decoration: underline"
|
||||||
v-for="item in list?.filter(item => item.time == data.day)"
|
class="details"
|
||||||
|
v-for="item in list?.filter((item:any) => item.name == data.day)"
|
||||||
|
@click="descentClick(item)"
|
||||||
>
|
>
|
||||||
<div>电压暂降:{{ item.type || '' }}</div>
|
<!-- <div>电压暂降:{{ item.eventDown || 0 }}</div>
|
||||||
<div>电压中断:{{ item.type1 || '' }}</div>
|
<div>电压中断:{{ item.eventOff || 0 }}</div>
|
||||||
<div>电压暂升:{{ item.type2 || '' }}</div>
|
<div>电压暂升:{{ item.eventUp || 0 }}</div> -->
|
||||||
|
<template v-if="fullscreen">
|
||||||
|
<div>电压暂降:{{ item.eventDown || 0 }}</div>
|
||||||
|
<div>电压中断:{{ item.eventOff || 0 }}</div>
|
||||||
|
<div>电压暂升:{{ item.eventUp || 0 }}</div>
|
||||||
|
</template>
|
||||||
|
<template v-else>暂态事件</template>
|
||||||
</div>
|
</div>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</el-calendar>
|
</el-calendar>
|
||||||
|
<!-- 暂态事件列表 -->
|
||||||
|
<TransientList ref="transientListRef" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
import { ref, onMounted, provide, reactive, watch, nextTick } from 'vue'
|
||||||
import TableStore from '@/utils/tableStore'
|
import TableStore from '@/utils/tableStore'
|
||||||
import Table from '@/components/table/index.vue'
|
|
||||||
import { useDictData } from '@/stores/dictData'
|
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
||||||
import { getTimeOfTheMonth } from '@/utils/formatTime'
|
|
||||||
import { overflow } from 'html2canvas/dist/types/css/property-descriptors/overflow'
|
|
||||||
import { dayjs } from 'element-plus'
|
import { dayjs } from 'element-plus'
|
||||||
|
import TransientList from './components/transientList.vue'
|
||||||
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
|
import { getTime } from '@/utils/formatTime'
|
||||||
|
|
||||||
|
const prop = defineProps({
|
||||||
|
w: { type: [String, Number] },
|
||||||
|
h: { type: [String, Number] },
|
||||||
|
width: { type: [String, Number] },
|
||||||
|
height: { type: [String, Number] },
|
||||||
|
timeKey: { type: Array as () => string[] },
|
||||||
|
timeValue: { type: Object },
|
||||||
|
interval: { type: Number }
|
||||||
|
})
|
||||||
|
|
||||||
|
const headerHeight = ref(57)
|
||||||
|
|
||||||
|
const TableHeaderRef = ref()
|
||||||
|
|
||||||
|
const hasEventData = (day: string) => {
|
||||||
|
const item = list.value?.find((item: any) => item.name == day)
|
||||||
|
if (!item) return false
|
||||||
|
|
||||||
|
return (item.eventDown || item.eventOff || item.eventUp) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
|
||||||
|
headerHeight.value = height
|
||||||
|
|
||||||
|
if (datePickerValue && datePickerValue.timeValue) {
|
||||||
|
// 更新时间参数
|
||||||
|
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
|
||||||
|
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算是否全屏展示
|
||||||
|
const fullscreen = computed(() => {
|
||||||
|
const w = Number(prop.w)
|
||||||
|
const h = Number(prop.h)
|
||||||
|
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
|
||||||
|
// 执行相应逻辑
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
dayjs.en.weekStart = 1 //设置日历的周起始日为星期一
|
dayjs.en.weekStart = 1 //设置日历的周起始日为星期一
|
||||||
const value = ref(new Date())
|
const value = ref(new Date())
|
||||||
const prop = defineProps({
|
|
||||||
width: { type: String },
|
const transientListRef = ref()
|
||||||
height: { type: String },
|
const list = ref()
|
||||||
timeKey: { type: String },
|
|
||||||
timeValue: { type: Object }
|
|
||||||
})
|
|
||||||
const list = ref([
|
|
||||||
{
|
|
||||||
time: '2025-10-01',
|
|
||||||
key: 81,
|
|
||||||
type: 1,
|
|
||||||
type1: 1,
|
|
||||||
type2: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
time: '2025-10-31',
|
|
||||||
key: 81,
|
|
||||||
type: 1,
|
|
||||||
type1: 1,
|
|
||||||
type2: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
time: '2025-10-08',
|
|
||||||
key: 20,
|
|
||||||
type: 1,
|
|
||||||
type1: 1,
|
|
||||||
type2: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
time: '2025-10-16',
|
|
||||||
key: 20,
|
|
||||||
type: 1,
|
|
||||||
type1: 1,
|
|
||||||
type2: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
time: '2025-10-23',
|
|
||||||
key: 20,
|
|
||||||
type: 1,
|
|
||||||
type1: 1,
|
|
||||||
type2: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
time: '2025-10-04',
|
|
||||||
key: 0
|
|
||||||
},
|
|
||||||
{
|
|
||||||
time: '2025-10-05',
|
|
||||||
key: 0
|
|
||||||
}
|
|
||||||
])
|
|
||||||
const tableStore: any = new TableStore({
|
const tableStore: any = new TableStore({
|
||||||
url: '/user-boot/dept/deptTree',
|
url: '/cs-harmonic-boot/csevent/getEventDate',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|
||||||
showPage: false,
|
showPage: false,
|
||||||
|
|
||||||
column: [],
|
column: [],
|
||||||
|
|
||||||
beforeSearchFun: () => {
|
beforeSearchFun: () => {
|
||||||
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
|
setTime()
|
||||||
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
|
|
||||||
// value.value = new Date(prop.timeValue?.[0])
|
|
||||||
},
|
},
|
||||||
|
|
||||||
loadCallback: () => {
|
loadCallback: () => {
|
||||||
tableStore.table.data = []
|
value.value = tableStore.table.params.searchBeginTime
|
||||||
|
list.value = tableStore.table.data
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const tableRef = ref([])
|
|
||||||
|
|
||||||
const setBackground = (value: string) => {
|
const setBackground = (value: string) => {
|
||||||
let data = []
|
let data = []
|
||||||
data = list.value?.filter(item => item.time == value)
|
data = list.value?.filter((item: any) => item.name == value)
|
||||||
|
|
||||||
if (data && data?.length > 0) {
|
if (data && data?.length > 0) {
|
||||||
if (data[0].key > 0) {
|
if (data[0].eventDown > 0 || data[0].eventOff > 0 || data[0].eventUp > 0) {
|
||||||
return '#Ff660090'
|
return '#Ff660090'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,47 +149,69 @@ const setBackground = (value: string) => {
|
|||||||
return '#fff'
|
return '#fff'
|
||||||
}
|
}
|
||||||
|
|
||||||
provide('tableRef', tableRef)
|
|
||||||
|
|
||||||
provide('tableStore', tableStore)
|
provide('tableStore', tableStore)
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
tableStore.index()
|
nextTick(() => {
|
||||||
})
|
|
||||||
watch(
|
|
||||||
() => prop.timeKey,
|
|
||||||
val => {
|
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const setTime = () => {
|
||||||
|
const time = getTime(
|
||||||
|
(TableHeaderRef.value?.datePickerRef.interval || prop.interval) ?? 0,
|
||||||
|
prop.timeKey,
|
||||||
|
fullscreen.value
|
||||||
|
? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
|
||||||
|
: prop.timeValue
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(time)) {
|
||||||
|
tableStore.table.params.searchBeginTime = time[0]
|
||||||
|
tableStore.table.params.searchEndTime = time[1]
|
||||||
|
TableHeaderRef.value?.setInterval(time[2] - 0)
|
||||||
|
TableHeaderRef.value?.setTimeInterval([time[0], time[1]])
|
||||||
|
} else {
|
||||||
|
console.warn('获取时间失败,time 不是一个有效数组')
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeValue, // 监听的目标(函数形式避免直接传递 props 导致的警告)
|
() => prop.timeValue,
|
||||||
(newVal, oldVal) => {
|
(newVal, oldVal) => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
deep: true // 若 timeValue 是对象/数组,需开启深度监听
|
deep: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const addMenu = () => {}
|
// 电压暂降点击事件
|
||||||
|
const descentClick = (item: any) => {
|
||||||
|
transientListRef.value.open(item.name)
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
:deep(.el-calendar) {
|
:deep(.el-calendar) {
|
||||||
.el-calendar__header {
|
.el-calendar__button-group {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.el-calendar__body {
|
.el-calendar__body {
|
||||||
padding: 0px !important;
|
padding: 0px !important;
|
||||||
height: 100%;
|
height: calc(100% - 46px);
|
||||||
.el-calendar-table {
|
.el-calendar-table {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.el-calendar-day {
|
.el-calendar-day {
|
||||||
|
// height: calc(912px / 5 );
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding: 0px;
|
padding: 0px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
.details {
|
||||||
|
height: calc(100% - 20px);
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.el-calendar-table__row {
|
.el-calendar-table__row {
|
||||||
.next {
|
.next {
|
||||||
|
|||||||
@@ -1,318 +1,265 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!--暂态事件概率分布 -->
|
<!--暂态事件概率分布 -->
|
||||||
|
<TableHeader
|
||||||
|
ref="TableHeaderRef"
|
||||||
|
:timeKeyList="prop.timeKey"
|
||||||
|
:showReset="false"
|
||||||
|
@selectChange="selectChange"
|
||||||
|
datePicker
|
||||||
|
v-if="fullscreen"
|
||||||
|
></TableHeader>
|
||||||
<my-echart
|
<my-echart
|
||||||
class="tall"
|
class="tall"
|
||||||
:options="echartList"
|
:options="echartList"
|
||||||
:style="{ width: prop.width, height: `calc(${prop.height} / 2 )` }"
|
:style="{
|
||||||
|
width: prop.width,
|
||||||
|
height: `calc(${prop.height} - ${headerHeight}px + ${fullscreen ? 0 : 56}px)`
|
||||||
|
}"
|
||||||
/>
|
/>
|
||||||
<my-echart
|
<!-- <my-echart
|
||||||
class="mt10"
|
class="mt10"
|
||||||
:options="echartList1"
|
:options="echartList1"
|
||||||
:style="{ width: prop.width, height: `calc(${prop.height} / 2 - 10px)` }"
|
:style="{
|
||||||
/>
|
width: prop.width,
|
||||||
|
height: `calc(${prop.height} / 2 - ${headerHeight / 2}px + ${fullscreen ? 0 : 28}px )`
|
||||||
|
}"
|
||||||
|
/> -->
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
import { ref, onMounted, provide, reactive, watch } from 'vue'
|
||||||
import TableStore from '@/utils/tableStore'
|
import TableStore from '@/utils/tableStore'
|
||||||
import Table from '@/components/table/index.vue'
|
|
||||||
import MyEchart from '@/components/echarts/MyEchart.vue'
|
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||||
import { useDictData } from '@/stores/dictData'
|
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
||||||
import { getTimeOfTheMonth } from '@/utils/formatTime'
|
|
||||||
import { useConfig } from '@/stores/config'
|
import { useConfig } from '@/stores/config'
|
||||||
const config = useConfig()
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
|
import { getTime } from '@/utils/formatTime'
|
||||||
|
|
||||||
const prop = defineProps({
|
const prop = defineProps({
|
||||||
width: { type: String },
|
w: { type: [String, Number] },
|
||||||
height: { type: String },
|
h: { type: [String, Number] },
|
||||||
timeKey: { type: String },
|
width: { type: [String, Number] },
|
||||||
timeValue: { type: Object }
|
height: { type: [String, Number] },
|
||||||
|
timeKey: { type: Array as () => string[] },
|
||||||
|
timeValue: { type: Object },
|
||||||
|
interval: { type: Number }
|
||||||
})
|
})
|
||||||
const echartList = ref({
|
|
||||||
options: {
|
|
||||||
xAxis: null,
|
|
||||||
yAxis: null,
|
|
||||||
dataZoom: null,
|
|
||||||
backgroundColor: '#fff',
|
|
||||||
tooltip: {
|
|
||||||
// trigger: 'axis'
|
|
||||||
textStyle: {
|
|
||||||
color: '#fff',
|
|
||||||
fontStyle: 'normal',
|
|
||||||
opacity: 0.35,
|
|
||||||
fontSize: 14
|
|
||||||
},
|
|
||||||
backgroundColor: 'rgba(0,0,0,0.55)',
|
|
||||||
borderWidth: 0,
|
|
||||||
formatter: function (params: any) {
|
|
||||||
console.log(params)
|
|
||||||
var tips = ''
|
|
||||||
for (var i = 0; i < params.length; i++) {
|
|
||||||
tips += params[i].name + '</br/>'
|
|
||||||
tips += '监测点数' + ':' + ' ' + ' ' + params[i].value + '</br/>'
|
|
||||||
}
|
|
||||||
return tips
|
|
||||||
}
|
|
||||||
},
|
|
||||||
title: {
|
|
||||||
text: '暂态事件概率分布',
|
|
||||||
x: 'center'
|
|
||||||
},
|
|
||||||
|
|
||||||
visualMap: {
|
const TableHeaderRef = ref()
|
||||||
max: 20,
|
|
||||||
show: false,
|
|
||||||
inRange: {
|
|
||||||
color: ['#313695', '#00BB00', '#ff8000', '#a50026']
|
|
||||||
}
|
|
||||||
},
|
|
||||||
xAxis3D: {
|
|
||||||
type: 'category',
|
|
||||||
name: '特征幅值',
|
|
||||||
data: [
|
|
||||||
'0-10%',
|
|
||||||
'10%-20%',
|
|
||||||
'20%-30%',
|
|
||||||
'30%-40%',
|
|
||||||
'40%-50%',
|
|
||||||
'50%-60%',
|
|
||||||
'60%-70%',
|
|
||||||
'70%-80%',
|
|
||||||
'80%-90%',
|
|
||||||
'90%-100%'
|
|
||||||
],
|
|
||||||
axisLine: {
|
|
||||||
lineStyle: {
|
|
||||||
color: '#111'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
axisLabel: {
|
|
||||||
color: '#111'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
yAxis3D: {
|
|
||||||
type: 'category',
|
|
||||||
name: '持续时间',
|
|
||||||
data: ['0-0.01s', '0.01s-0.1s', '0.1s-1s', '1s-10s', '10s'],
|
|
||||||
nameTextStyle: {
|
|
||||||
color: '#111'
|
|
||||||
},
|
|
||||||
axisLine: {
|
|
||||||
show: true,
|
|
||||||
lineStyle: {
|
|
||||||
color: '#111'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
axisLabel: {
|
|
||||||
color: '#111'
|
|
||||||
},
|
|
||||||
splitLine: {
|
|
||||||
lineStyle: {
|
|
||||||
// 使用深浅的间隔色
|
|
||||||
color: ['#111'],
|
|
||||||
type: 'dashed',
|
|
||||||
opacity: 0.5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
zAxis3D: {
|
|
||||||
type: 'value',
|
|
||||||
splitNumber: 10,
|
|
||||||
minInterval: 10,
|
|
||||||
name: '暂态事件次数'
|
|
||||||
},
|
|
||||||
grid3D: {
|
|
||||||
viewControl: {
|
|
||||||
projection: 'perspective',
|
|
||||||
distance: 250
|
|
||||||
},
|
|
||||||
boxWidth: 200,
|
|
||||||
boxDepth: 80,
|
|
||||||
light: {
|
|
||||||
main: {
|
|
||||||
intensity: 1.2
|
|
||||||
},
|
|
||||||
ambient: {
|
|
||||||
intensity: 0.3
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
type: 'bar3D',
|
|
||||||
data: [
|
|
||||||
[0, 0, 1],
|
|
||||||
[0, 1, 1],
|
|
||||||
[0.2, 1]
|
|
||||||
],
|
|
||||||
shading: 'realistic',
|
|
||||||
label: {
|
|
||||||
show: false,
|
|
||||||
textStyle: {
|
|
||||||
fontSize: 16,
|
|
||||||
borderWidth: 1
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
itemStyle: {
|
const headerHeight = ref(57)
|
||||||
opacity: 1
|
|
||||||
},
|
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
|
||||||
emphasis: {
|
headerHeight.value = height
|
||||||
label: {
|
|
||||||
textStyle: {
|
if (datePickerValue && datePickerValue.timeValue) {
|
||||||
fontSize: 20,
|
// 更新时间参数
|
||||||
color: '#900'
|
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
|
||||||
}
|
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
|
||||||
},
|
}
|
||||||
itemStyle: {
|
}
|
||||||
color: '#900'
|
|
||||||
}
|
// 计算是否全屏展示
|
||||||
}
|
const fullscreen = computed(() => {
|
||||||
}
|
const w = Number(prop.w)
|
||||||
]
|
const h = Number(prop.h)
|
||||||
|
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
|
||||||
|
// 执行相应逻辑
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
const echartList1 = ref({
|
|
||||||
title: {
|
|
||||||
text: '越限时间概率分布'
|
|
||||||
},
|
|
||||||
|
|
||||||
xAxis: {
|
const config = useConfig()
|
||||||
// name: '时间',
|
|
||||||
// data: ['闪变', '谐波电压', '谐波电流', '电压偏差', '三相不平衡']
|
const echartList = ref({})
|
||||||
type: 'time',
|
|
||||||
axisLabel: {
|
const echartList1 = ref({})
|
||||||
formatter: {
|
|
||||||
day: '{MM}-{dd}',
|
const processDataForChart = (rawData: any[]) => {
|
||||||
month: '{MM}',
|
// 将后端返回的扁平数据转换为 ECharts 需要的三维坐标格式 [x, y, z]
|
||||||
year: '{yyyy}'
|
const chartData = rawData.map(item => [item.x, item.y, item.z])
|
||||||
}
|
|
||||||
}
|
return chartData
|
||||||
},
|
}
|
||||||
|
|
||||||
yAxis: {
|
|
||||||
name: '次' // 给X轴加单位
|
|
||||||
},
|
|
||||||
grid: {
|
|
||||||
left: '10px',
|
|
||||||
right: '20px'
|
|
||||||
},
|
|
||||||
options: {
|
|
||||||
series: [
|
|
||||||
{
|
|
||||||
type: 'line',
|
|
||||||
showSymbol: false,
|
|
||||||
// smooth: true,
|
|
||||||
name: '电压中断',
|
|
||||||
color: '#FF9100',
|
|
||||||
data: [
|
|
||||||
['2025-10-16 07:00:00', 10],
|
|
||||||
['2025-10-16 07:15:00', 10],
|
|
||||||
['2025-10-16 07:30:00', 10],
|
|
||||||
['2025-10-16 07:45:00', 10],
|
|
||||||
['2025-10-16 08:00:00', 30],
|
|
||||||
['2025-10-16 08:15:00', 50],
|
|
||||||
['2025-10-16 08:30:00', 60],
|
|
||||||
['2025-10-16 08:45:00', 70],
|
|
||||||
['2025-10-16 09:00:00', 100],
|
|
||||||
['2025-10-16 09:15:00', 120],
|
|
||||||
['2025-10-16 09:30:00', 130],
|
|
||||||
['2025-10-16 09:45:00', 140],
|
|
||||||
['2025-10-16 10:00:00', 160],
|
|
||||||
['2025-10-16 10:15:00', 160],
|
|
||||||
['2025-10-16 10:30:00', 130],
|
|
||||||
['2025-10-16 10:45:00', 120],
|
|
||||||
['2025-10-16 11:00:00', 140],
|
|
||||||
['2025-10-16 11:15:00', 80],
|
|
||||||
['2025-10-16 11:30:00', 70],
|
|
||||||
['2025-10-16 11:45:00', 90],
|
|
||||||
['2025-10-16 12:00:00', 60],
|
|
||||||
['2025-10-16 12:15:00', 60],
|
|
||||||
['2025-10-16 12:30:00', 60],
|
|
||||||
['2025-10-16 12:45:00', 60]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'line',
|
|
||||||
showSymbol: false,
|
|
||||||
// smooth: true,
|
|
||||||
color: '#FFBF00',
|
|
||||||
name: '电压暂降',
|
|
||||||
data: [
|
|
||||||
['2025-10-16 07:00:00', 1],
|
|
||||||
['2025-10-16 07:15:00', 1],
|
|
||||||
['2025-10-16 07:30:00', 1],
|
|
||||||
['2025-10-16 07:45:00', 1],
|
|
||||||
['2025-10-16 08:00:00', 3],
|
|
||||||
['2025-10-16 08:15:00', 5],
|
|
||||||
['2025-10-16 08:30:00', 6],
|
|
||||||
['2025-10-16 08:45:00', 7],
|
|
||||||
['2025-10-16 09:00:00', 10],
|
|
||||||
['2025-10-16 09:15:00', 12],
|
|
||||||
['2025-10-16 09:30:00', 13],
|
|
||||||
['2025-10-16 09:45:00', 14],
|
|
||||||
['2025-10-16 10:00:00', 16],
|
|
||||||
['2025-10-16 10:15:00', 16],
|
|
||||||
['2025-10-16 10:30:00', 13],
|
|
||||||
['2025-10-16 10:45:00', 12],
|
|
||||||
['2025-10-16 11:00:00', 14],
|
|
||||||
['2025-10-16 11:15:00', 8],
|
|
||||||
['2025-10-16 11:30:00', 7],
|
|
||||||
['2025-10-16 11:45:00', 9],
|
|
||||||
['2025-10-16 12:00:00', 6],
|
|
||||||
['2025-10-16 12:15:00', 6],
|
|
||||||
['2025-10-16 12:30:00', 6],
|
|
||||||
['2025-10-16 12:45:00', 6]
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
type: 'line',
|
|
||||||
showSymbol: false,
|
|
||||||
// smooth: true,
|
|
||||||
name: '电压暂升',
|
|
||||||
color: config.layout.elementUiPrimary[0],
|
|
||||||
data: [
|
|
||||||
['2025-10-16 07:00:00', 19],
|
|
||||||
['2025-10-16 07:15:00', 19],
|
|
||||||
['2025-10-16 07:30:00', 19],
|
|
||||||
['2025-10-16 07:45:00', 19],
|
|
||||||
['2025-10-16 08:00:00', 39],
|
|
||||||
['2025-10-16 08:15:00', 59],
|
|
||||||
['2025-10-16 08:30:00', 69],
|
|
||||||
['2025-10-16 08:45:00', 79],
|
|
||||||
['2025-10-16 09:00:00', 109],
|
|
||||||
['2025-10-16 09:15:00', 129],
|
|
||||||
['2025-10-16 09:30:00', 139],
|
|
||||||
['2025-10-16 09:45:00', 149],
|
|
||||||
['2025-10-16 10:00:00', 169],
|
|
||||||
['2025-10-16 10:15:00', 169],
|
|
||||||
['2025-10-16 10:30:00', 139],
|
|
||||||
['2025-10-16 10:45:00', 129],
|
|
||||||
['2025-10-16 11:00:00', 149],
|
|
||||||
['2025-10-16 11:15:00', 89],
|
|
||||||
['2025-10-16 11:30:00', 79],
|
|
||||||
['2025-10-16 11:45:00', 99],
|
|
||||||
['2025-10-16 12:00:00', 69],
|
|
||||||
['2025-10-16 12:15:00', 69],
|
|
||||||
['2025-10-16 12:30:00', 69],
|
|
||||||
['2025-10-16 12:45:00', 69]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
const tableStore: any = new TableStore({
|
const tableStore: any = new TableStore({
|
||||||
url: '/user-boot/dept/deptTree',
|
url: '/cs-harmonic-boot/csevent/getEventCoords',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
showPage: false,
|
showPage: false,
|
||||||
column: [],
|
column: [],
|
||||||
beforeSearchFun: () => {
|
beforeSearchFun: () => {
|
||||||
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
|
setTime()
|
||||||
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
|
|
||||||
},
|
},
|
||||||
loadCallback: () => {
|
loadCallback: () => {
|
||||||
tableStore.table.data = []
|
const processedData = processDataForChart(tableStore.table.data.innerList || [])
|
||||||
|
const trendList = tableStore.table.data.trendList || []
|
||||||
|
const xlist = tableStore.table.data.xlist || []
|
||||||
|
|
||||||
|
// 处理趋势图数据
|
||||||
|
const seriesData = trendList.map((item: any) => {
|
||||||
|
// 根据接口返回的name字段确定系列名称和颜色
|
||||||
|
let name = ''
|
||||||
|
let color = ''
|
||||||
|
|
||||||
|
switch (item.name) {
|
||||||
|
case 'Evt_Sys_DipStr':
|
||||||
|
name = '电压暂降'
|
||||||
|
color = '#FFBF00'
|
||||||
|
break
|
||||||
|
case 'Evt_Sys_IntrStr':
|
||||||
|
name = '电压中断'
|
||||||
|
color = '#FF9100'
|
||||||
|
break
|
||||||
|
case 'Evt_Sys_SwlStr':
|
||||||
|
name = '电压暂升'
|
||||||
|
color = config.layout.elementUiPrimary[0]
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
name = item.name
|
||||||
|
color = '#000000'
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: name,
|
||||||
|
type: 'line',
|
||||||
|
showSymbol: false,
|
||||||
|
color: color,
|
||||||
|
data: item.trendList?.map((value: number, index: number) => [xlist[index], value]) || []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 获取x轴和y轴的标签值
|
||||||
|
const xLabels = [
|
||||||
|
'0-10%',
|
||||||
|
'10%-20%',
|
||||||
|
'20%-30%',
|
||||||
|
'30%-40%',
|
||||||
|
'40%-50%',
|
||||||
|
'50%-60%',
|
||||||
|
'60%-70%',
|
||||||
|
'70%-80%',
|
||||||
|
'80%-90%',
|
||||||
|
'90%-100%'
|
||||||
|
]
|
||||||
|
const yLabels = ['0-0.01s', '0.01s-0.1s', '0.1s-1s', '1s-10s', '10s']
|
||||||
|
|
||||||
|
echartList.value = {
|
||||||
|
options: {
|
||||||
|
xAxis: null,
|
||||||
|
yAxis: null,
|
||||||
|
dataZoom: null,
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
tooltip: {
|
||||||
|
textStyle: {
|
||||||
|
color: '#fff',
|
||||||
|
fontStyle: 'normal',
|
||||||
|
opacity: 0.35,
|
||||||
|
fontSize: 14
|
||||||
|
},
|
||||||
|
backgroundColor: 'rgba(0,0,0,0.55)',
|
||||||
|
borderWidth: 0,
|
||||||
|
formatter: function (params: any) {
|
||||||
|
var tips = ''
|
||||||
|
tips += '持续时间: ' + yLabels[params.value[1]] + '</br>'
|
||||||
|
tips += '特征幅值: ' + xLabels[params.value[0]] + '</br>'
|
||||||
|
tips += '事件次数: ' + params.value[2] + '</br>'
|
||||||
|
return tips
|
||||||
|
}
|
||||||
|
},
|
||||||
|
title: {
|
||||||
|
text: '暂态事件概率分布',
|
||||||
|
x: 'center'
|
||||||
|
},
|
||||||
|
visualMap: {
|
||||||
|
max: 500,
|
||||||
|
show: false,
|
||||||
|
inRange: {
|
||||||
|
color: ['#313695', '#00BB00', '#ff8000', '#a50026']
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xAxis3D: {
|
||||||
|
type: 'category',
|
||||||
|
name: '特征幅值',
|
||||||
|
data: xLabels,
|
||||||
|
nameGap: 40
|
||||||
|
},
|
||||||
|
yAxis3D: {
|
||||||
|
type: 'category',
|
||||||
|
name: '持续时间',
|
||||||
|
data: yLabels,
|
||||||
|
nameGap: 40,
|
||||||
|
|
||||||
|
splitLine: {
|
||||||
|
lineStyle: {
|
||||||
|
type: 'dashed',
|
||||||
|
opacity: 0.5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
zAxis3D: {
|
||||||
|
type: 'value',
|
||||||
|
minInterval: 10,
|
||||||
|
name: '暂态事件次数',
|
||||||
|
nameGap: 30
|
||||||
|
},
|
||||||
|
grid3D: {
|
||||||
|
viewControl: {
|
||||||
|
projection: 'perspective',
|
||||||
|
distance: 260,
|
||||||
|
rotateSensitivity: 10,
|
||||||
|
zoomSensitivity: 2
|
||||||
|
},
|
||||||
|
boxWidth: 150,
|
||||||
|
boxDepth: 100,
|
||||||
|
boxHeight: 100,
|
||||||
|
light: {
|
||||||
|
main: {
|
||||||
|
intensity: 1.2
|
||||||
|
},
|
||||||
|
ambient: {
|
||||||
|
intensity: 0.4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'bar3D',
|
||||||
|
data: processedData,
|
||||||
|
shading: 'realistic',
|
||||||
|
label: {
|
||||||
|
show: false,
|
||||||
|
textStyle: {
|
||||||
|
fontSize: 16,
|
||||||
|
borderWidth: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echartList1.value = {
|
||||||
|
title: {
|
||||||
|
text: '越限时间概率分布'
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'category',
|
||||||
|
data: xlist,
|
||||||
|
axisLabel: {
|
||||||
|
formatter: '{value}'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
name: '次'
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '10px',
|
||||||
|
right: '20px'
|
||||||
|
},
|
||||||
|
series: seriesData
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -324,22 +271,41 @@ provide('tableStore', tableStore)
|
|||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const setTime = () => {
|
||||||
|
const time = getTime(
|
||||||
|
(TableHeaderRef.value?.datePickerRef.interval || prop.interval) ?? 0,
|
||||||
|
prop.timeKey,
|
||||||
|
fullscreen.value
|
||||||
|
? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
|
||||||
|
: prop.timeValue
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(time)) {
|
||||||
|
tableStore.table.params.searchBeginTime = time[0]
|
||||||
|
tableStore.table.params.searchEndTime = time[1]
|
||||||
|
TableHeaderRef.value?.setInterval(time[2] - 0)
|
||||||
|
TableHeaderRef.value?.setTimeInterval([time[0], time[1]])
|
||||||
|
} else {
|
||||||
|
console.warn('获取时间失败,time 不是一个有效数组')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeKey,
|
() => prop.timeKey,
|
||||||
val => {
|
val => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeValue, // 监听的目标(函数形式避免直接传递 props 导致的警告)
|
() => prop.timeValue,
|
||||||
(newVal, oldVal) => {
|
(newVal, oldVal) => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
deep: true // 若 timeValue 是对象/数组,需开启深度监听
|
deep: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const addMenu = () => {}
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped></style>
|
||||||
|
|||||||
@@ -0,0 +1,224 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<!-- 暂态事件详情 -->
|
||||||
|
<el-dialog draggable title="暂态事件详情 " v-model="dialogVisible" append-to-body width="70%">
|
||||||
|
<TableHeader datePicker showExport :showReset="false" ref="tableHeaderRef" @selectChange="selectChange">
|
||||||
|
<template v-slot:select>
|
||||||
|
<el-form-item label="监测点">
|
||||||
|
<el-select filterable v-model="tableStore.table.params.lineId" placeholder="请选择监测点名称">
|
||||||
|
<el-option
|
||||||
|
v-for="item in options"
|
||||||
|
:key="item.lineId"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.lineId"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</template>
|
||||||
|
</TableHeader>
|
||||||
|
<Table ref="tableRef" isGroup :height="heightRef"></Table>
|
||||||
|
</el-dialog>
|
||||||
|
<!-- 查看波形 -->
|
||||||
|
<el-dialog
|
||||||
|
v-model="isWaveCharts"
|
||||||
|
draggable
|
||||||
|
title="波形分析"
|
||||||
|
append-to-body
|
||||||
|
width="70%"
|
||||||
|
@close="handleHideCharts"
|
||||||
|
>
|
||||||
|
<waveFormAnalysis
|
||||||
|
v-loading="loading"
|
||||||
|
v-if="isWaveCharts"
|
||||||
|
ref="waveFormAnalysisRef"
|
||||||
|
@handleHideCharts="handleHideCharts"
|
||||||
|
:wp="wp"
|
||||||
|
/>
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, provide } from 'vue'
|
||||||
|
import Table from '@/components/table/index.vue'
|
||||||
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
|
import TableStore from '@/utils/tableStore'
|
||||||
|
import { mainHeight } from '@/utils/layout'
|
||||||
|
import waveFormAnalysis from '@/views/govern/device/control/tabs/components/waveFormAnalysis.vue'
|
||||||
|
import { analyseWave } from '@/api/common'
|
||||||
|
import { getSimpleLine } from '@/api/harmonic-boot/cockpit/cockpit'
|
||||||
|
|
||||||
|
const dialogVisible: any = ref(false)
|
||||||
|
const waveFormAnalysisRef: any = ref(null)
|
||||||
|
// 波形
|
||||||
|
const isWaveCharts = ref(false)
|
||||||
|
const loading = ref(false)
|
||||||
|
const wp = ref({})
|
||||||
|
const boxoList: any = ref({})
|
||||||
|
|
||||||
|
const tableHeaderRef = ref()
|
||||||
|
|
||||||
|
const options = ref()
|
||||||
|
const heightRef = ref(mainHeight(168, 2.2).height)
|
||||||
|
const selectChange = (flag: boolean, h: any) => {
|
||||||
|
heightRef.value = mainHeight(h, 2.2).height
|
||||||
|
}
|
||||||
|
|
||||||
|
const getSimpleLineList = async () => {
|
||||||
|
const res = await getSimpleLine()
|
||||||
|
options.value = res.data
|
||||||
|
}
|
||||||
|
|
||||||
|
const tableStore: any = new TableStore({
|
||||||
|
url: '/cs-harmonic-boot/event/pageEvent',
|
||||||
|
method: 'POST',
|
||||||
|
showPage: true,
|
||||||
|
exportName: '主要监测点列表',
|
||||||
|
column: [
|
||||||
|
{
|
||||||
|
field: 'index',
|
||||||
|
title: '序号',
|
||||||
|
width: '80',
|
||||||
|
formatter: (row: any) => {
|
||||||
|
return (tableStore.table.params.pageNum - 1) * tableStore.table.params.pageSize + row.rowIndex + 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '暂态时间',
|
||||||
|
field: 'startTime',
|
||||||
|
minWidth: '180'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '测点名称',
|
||||||
|
field: 'lineName',
|
||||||
|
minWidth: '150'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '暂态类型',
|
||||||
|
field: 'tag',
|
||||||
|
minWidth: '100'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '特征幅值(%)',
|
||||||
|
field: 'amplitude',
|
||||||
|
minWidth: '100'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '暂降深度(%)',
|
||||||
|
field: 'depth',
|
||||||
|
minWidth: '100',
|
||||||
|
formatter: (row: any) => {
|
||||||
|
// 当暂态类型不是电压暂升时,计算暂降深度 = 100 - 特征幅值
|
||||||
|
if (row.row.tag !== '电压暂升') {
|
||||||
|
const amplitude = parseFloat(row.row.amplitude)
|
||||||
|
if (!isNaN(amplitude)) {
|
||||||
|
return 100 - amplitude
|
||||||
|
}
|
||||||
|
return '-'
|
||||||
|
} else {
|
||||||
|
// 电压暂升时不显示暂降深度
|
||||||
|
return '/'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '持续时间(S)',
|
||||||
|
field: 'persistTime',
|
||||||
|
minWidth: '100'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '严重度',
|
||||||
|
field: 'severity',
|
||||||
|
minWidth: '80'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '波形',
|
||||||
|
width: '90',
|
||||||
|
render: 'buttons',
|
||||||
|
buttons: [
|
||||||
|
{
|
||||||
|
name: 'edit',
|
||||||
|
text: '波形分析',
|
||||||
|
type: 'primary',
|
||||||
|
icon: 'el-icon-DataLine',
|
||||||
|
render: 'basicButton',
|
||||||
|
disabled: row => {
|
||||||
|
return !row.wavePath
|
||||||
|
},
|
||||||
|
|
||||||
|
click: async row => {
|
||||||
|
row.loading1 = true
|
||||||
|
loading.value = true
|
||||||
|
isWaveCharts.value = true
|
||||||
|
dialogVisible.value = false
|
||||||
|
// 在打开弹窗时立即设置高度
|
||||||
|
nextTick(() => {
|
||||||
|
if (waveFormAnalysisRef.value) {
|
||||||
|
// waveFormAnalysisRef.value.setHeight(false, 360)
|
||||||
|
waveFormAnalysisRef.value.setHeight(999, 130, 1.6666666)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await analyseWave(row.id)
|
||||||
|
.then(res => {
|
||||||
|
row.loading1 = false
|
||||||
|
if (res != undefined) {
|
||||||
|
boxoList.value = row
|
||||||
|
// boxoList.value = {
|
||||||
|
// ...row,
|
||||||
|
// duration: row.persistTime // 将 persistTime 值赋给 duration
|
||||||
|
// }
|
||||||
|
boxoList.value.featureAmplitude =
|
||||||
|
row.evtParamVVaDepth != '-' ? row.evtParamVVaDepth - 0 : null
|
||||||
|
boxoList.value.systemType = 'YPT'
|
||||||
|
wp.value = res.data
|
||||||
|
}
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
row.loading1 = false
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
waveFormAnalysisRef.value &&
|
||||||
|
waveFormAnalysisRef.value.getWpData(wp.value, boxoList.value, true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'edit',
|
||||||
|
text: '暂无波形',
|
||||||
|
type: 'info',
|
||||||
|
icon: 'el-icon-DataLine',
|
||||||
|
render: 'basicButton',
|
||||||
|
disabled: row => {
|
||||||
|
return !!row.wavePath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
beforeSearchFun: () => {},
|
||||||
|
loadCallback: () => {}
|
||||||
|
})
|
||||||
|
|
||||||
|
provide('tableStore', tableStore)
|
||||||
|
const open = async (row: any, searchBeginTime: any, searchEndTime: any) => {
|
||||||
|
dialogVisible.value = true
|
||||||
|
getSimpleLineList()
|
||||||
|
tableStore.table.params.lineId = row.id
|
||||||
|
nextTick(() => {
|
||||||
|
tableHeaderRef.value.setTimeInterval([searchBeginTime, searchEndTime])
|
||||||
|
tableStore.table.params.searchBeginTime = searchBeginTime
|
||||||
|
tableStore.table.params.searchEndTime = searchEndTime
|
||||||
|
tableStore.index()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleHideCharts = () => {
|
||||||
|
isWaveCharts.value = false
|
||||||
|
dialogVisible.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
defineExpose({ open })
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@@ -1,12 +1,28 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!--暂态事件统计 -->
|
<!--暂态事件统计 -->
|
||||||
|
<TableHeader
|
||||||
|
ref="TableHeaderRef"
|
||||||
|
:showReset="false"
|
||||||
|
@selectChange="selectChange"
|
||||||
|
datePicker
|
||||||
|
v-if="fullscreen" :timeKeyList="prop.timeKey"
|
||||||
|
></TableHeader>
|
||||||
<my-echart
|
<my-echart
|
||||||
class="tall"
|
class="tall"
|
||||||
:options="echartList"
|
:options="echartList"
|
||||||
:style="{ width: prop.width, height: `calc(${prop.height} / 2 )` }"
|
:style="{
|
||||||
|
width: prop.width,
|
||||||
|
height: `calc(${prop.height} / 2 - ${headerHeight / 2}px + ${fullscreen ? 0 : 28}px )`
|
||||||
|
}"
|
||||||
/>
|
/>
|
||||||
<Table ref="tableRef" @cell-click="cellClickEvent" :height="`calc(${prop.height} / 2 )`" isGroup></Table>
|
<Table
|
||||||
|
ref="tableRef"
|
||||||
|
@cell-click="cellClickEvent"
|
||||||
|
:height="`calc(${prop.height} / 2 - ${headerHeight / 2}px + ${fullscreen ? 0 : 28}px )`"
|
||||||
|
isGroup
|
||||||
|
></Table>
|
||||||
|
<TransientStatisticsDetail ref="transientStatisticsDetailRef"></TransientStatisticsDetail>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
@@ -14,90 +30,135 @@ import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
|||||||
import TableStore from '@/utils/tableStore'
|
import TableStore from '@/utils/tableStore'
|
||||||
import Table from '@/components/table/index.vue'
|
import Table from '@/components/table/index.vue'
|
||||||
import MyEchart from '@/components/echarts/MyEchart.vue'
|
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||||
import { useDictData } from '@/stores/dictData'
|
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
||||||
import { getTimeOfTheMonth } from '@/utils/formatTime'
|
|
||||||
import { useConfig } from '@/stores/config'
|
import { useConfig } from '@/stores/config'
|
||||||
const config = useConfig()
|
import TransientStatisticsDetail from '@/components/cockpit/transientStatistics/components/transientStatisticsDetail.vue'
|
||||||
const prop = defineProps({
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
width: { type: String },
|
import { netEventEcharts } from '@/api/harmonic-boot/cockpit/cockpit'
|
||||||
height: { type: String },
|
import { getTime } from '@/utils/formatTime'
|
||||||
timeKey: { type: String },
|
|
||||||
timeValue: { type: Object }
|
|
||||||
})
|
|
||||||
const data = [
|
|
||||||
{
|
|
||||||
name: '电压中断',
|
|
||||||
value: 4
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '电压暂降',
|
|
||||||
value: 41
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '电压暂升',
|
|
||||||
value: 46
|
|
||||||
}
|
|
||||||
]
|
|
||||||
const echartList = ref({
|
|
||||||
title: {},
|
|
||||||
|
|
||||||
tooltip: {
|
const prop = defineProps({
|
||||||
trigger: 'item'
|
w: { type: [String, Number] },
|
||||||
},
|
h: { type: [String, Number] },
|
||||||
legend: {
|
width: { type: [String, Number] },
|
||||||
orient: 'vertical',
|
height: { type: [String, Number] },
|
||||||
top: 'center',
|
timeKey: { type: Array as () => string[] },
|
||||||
right: '5%',
|
timeValue: { type: Object },
|
||||||
formatter: function (e: any) {
|
interval: { type: Number }
|
||||||
return e + ' ' + data.filter(item => item.name == e)[0].value + '次'
|
})
|
||||||
}
|
|
||||||
},
|
const TableHeaderRef = ref()
|
||||||
xAxis: {
|
|
||||||
show: false
|
const headerHeight = ref(57)
|
||||||
},
|
|
||||||
yAxis: {
|
|
||||||
show: false
|
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
|
||||||
},
|
headerHeight.value = height
|
||||||
grid: {
|
|
||||||
left: '10px',
|
if (datePickerValue && datePickerValue.timeValue) {
|
||||||
right: '20px'
|
// 更新时间参数
|
||||||
},
|
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
|
||||||
color: ['#FF9100', '#FFBF00', config.layout.elementUiPrimary[0]],
|
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
|
||||||
options: {
|
}
|
||||||
dataZoom: null,
|
}
|
||||||
title: [
|
|
||||||
|
// 计算是否全屏展示
|
||||||
|
const fullscreen = computed(() => {
|
||||||
|
const w = Number(prop.w)
|
||||||
|
const h = Number(prop.h)
|
||||||
|
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
|
||||||
|
// 执行相应逻辑
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
const config = useConfig()
|
||||||
|
|
||||||
|
const data = ref()
|
||||||
|
|
||||||
|
const echartList = ref()
|
||||||
|
|
||||||
|
const eventEcharts = () => {
|
||||||
|
netEventEcharts({
|
||||||
|
searchBeginTime: tableStore.table.params.searchBeginTime || prop.timeValue?.[0],
|
||||||
|
searchEndTime: tableStore.table.params.searchEndTime || prop.timeValue?.[1]
|
||||||
|
}).then(res => {
|
||||||
|
// 整理接口数据为图表所需格式
|
||||||
|
const rawData = res.data || {}
|
||||||
|
data.value = [
|
||||||
{
|
{
|
||||||
text: '暂态事件统计',
|
name: '电压中断',
|
||||||
left: 'center'
|
value: rawData.eventOff || 0
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
text: data[0].value + data[1].value + data[2].value + '次',
|
name: '电压暂降',
|
||||||
left: 'center',
|
value: rawData.eventDown || 0
|
||||||
top: 'center'
|
},
|
||||||
}
|
|
||||||
],
|
|
||||||
series: [
|
|
||||||
{
|
{
|
||||||
type: 'pie',
|
name: '电压暂升',
|
||||||
center: 'center',
|
value: rawData.eventUp || 0
|
||||||
radius: ['50%', '70%'],
|
|
||||||
label: {
|
|
||||||
show: false,
|
|
||||||
position: 'outside',
|
|
||||||
textStyle: {
|
|
||||||
//数值样式
|
|
||||||
}
|
|
||||||
},
|
|
||||||
name: '事件统计',
|
|
||||||
data: data
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
|
||||||
})
|
echartList.value = {
|
||||||
const OverLimitDetailsRef = ref()
|
title: {},
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'item'
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
orient: 'vertical',
|
||||||
|
top: '50',
|
||||||
|
right: '10',
|
||||||
|
formatter: function (e: any) {
|
||||||
|
return e + ' ' + data.value.filter((item: any) => item.name == e)[0].value + '次'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
xAxis: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '10px',
|
||||||
|
right: '20px'
|
||||||
|
},
|
||||||
|
color: ['#FF9100', '#FFBF00', config.layout.elementUiPrimary[0]],
|
||||||
|
options: {
|
||||||
|
dataZoom: null,
|
||||||
|
title: [
|
||||||
|
{
|
||||||
|
text: '暂态事件统计',
|
||||||
|
left: 'center'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: rawData.eventOff + rawData.eventDown + rawData.eventUp + '次',
|
||||||
|
left: 'center',
|
||||||
|
top: 'center'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
type: 'pie',
|
||||||
|
center: 'center',
|
||||||
|
radius: ['50%', '70%'],
|
||||||
|
label: {
|
||||||
|
show: false,
|
||||||
|
position: 'outside'
|
||||||
|
},
|
||||||
|
name: '事件统计',
|
||||||
|
data: data.value
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const transientStatisticsDetailRef = ref()
|
||||||
|
|
||||||
const tableStore: any = new TableStore({
|
const tableStore: any = new TableStore({
|
||||||
url: '/user-boot/dept/deptTree',
|
url: '/cs-harmonic-boot/csevent/netEventTable',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|
||||||
showPage: false,
|
showPage: false,
|
||||||
@@ -119,63 +180,40 @@ const tableStore: any = new TableStore({
|
|||||||
|
|
||||||
{
|
{
|
||||||
title: '电压中断(次)',
|
title: '电压中断(次)',
|
||||||
field: 'type',
|
field: 'eventOff',
|
||||||
minWidth: '70',
|
minWidth: '70',
|
||||||
|
sortable: true,
|
||||||
render: 'customTemplate',
|
render: 'customTemplate',
|
||||||
customTemplate: (row: any) => {
|
customTemplate: (row: any) => {
|
||||||
return `<span style='cursor: pointer;text-decoration: underline;'>${row.type}</span>`
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.eventOff}</span>`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '电压暂降(次)',
|
title: '电压暂降(次)',
|
||||||
field: 'type1',
|
field: 'eventDown',
|
||||||
minWidth: '80',
|
minWidth: '80',
|
||||||
|
sortable: true,
|
||||||
render: 'customTemplate',
|
render: 'customTemplate',
|
||||||
customTemplate: (row: any) => {
|
customTemplate: (row: any) => {
|
||||||
return `<span style='cursor: pointer;text-decoration: underline;'>${row.type1}</span>`
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.eventDown}</span>`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '电压暂升(次)',
|
title: '电压暂升(次)',
|
||||||
field: 'type2',
|
field: 'eventUp',
|
||||||
minWidth: '80',
|
minWidth: '80',
|
||||||
|
sortable: true,
|
||||||
render: 'customTemplate',
|
render: 'customTemplate',
|
||||||
customTemplate: (row: any) => {
|
customTemplate: (row: any) => {
|
||||||
return `<span style='cursor: pointer;text-decoration: underline;'>${row.type2}</span>`
|
return `<span style='cursor: pointer;text-decoration: underline;'>${row.eventUp}</span>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
beforeSearchFun: () => {
|
beforeSearchFun: () => {
|
||||||
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
|
setTime()
|
||||||
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
|
|
||||||
},
|
},
|
||||||
loadCallback: () => {
|
loadCallback: () => {
|
||||||
tableStore.table.data = [
|
eventEcharts()
|
||||||
{
|
|
||||||
name: '35kV1进线',
|
|
||||||
type: '2',
|
|
||||||
type1: '38',
|
|
||||||
type2: '35'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '35kV1变压器',
|
|
||||||
type: '2',
|
|
||||||
type1: '1',
|
|
||||||
type2: '3'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '35kV1母线',
|
|
||||||
type: '0',
|
|
||||||
type1: '1',
|
|
||||||
type2: '4'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: '35kV2母线',
|
|
||||||
type: '0',
|
|
||||||
type1: '1',
|
|
||||||
type2: '4'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -187,8 +225,30 @@ provide('tableStore', tableStore)
|
|||||||
// 点击行
|
// 点击行
|
||||||
const cellClickEvent = ({ row, column }: any) => {
|
const cellClickEvent = ({ row, column }: any) => {
|
||||||
if (column.field != 'name') {
|
if (column.field != 'name') {
|
||||||
console.log(row)
|
transientStatisticsDetailRef.value.open(
|
||||||
OverLimitDetailsRef.value.open(row)
|
row,
|
||||||
|
tableStore.table.params.searchBeginTime || prop.timeValue?.[0],
|
||||||
|
tableStore.table.params.searchEndTime || prop.timeValue?.[1]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const setTime = () => {
|
||||||
|
const time = getTime(
|
||||||
|
(TableHeaderRef.value?.datePickerRef.interval || prop.interval) ?? 0,
|
||||||
|
prop.timeKey,
|
||||||
|
fullscreen.value
|
||||||
|
? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
|
||||||
|
: prop.timeValue
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(time)) {
|
||||||
|
tableStore.table.params.searchBeginTime = time[0]
|
||||||
|
tableStore.table.params.searchEndTime = time[1]
|
||||||
|
TableHeaderRef.value?.setInterval(time[2] - 0)
|
||||||
|
TableHeaderRef.value?.setTimeInterval([time[0], time[1]])
|
||||||
|
} else {
|
||||||
|
console.warn('获取时间失败,time 不是一个有效数组')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,15 +264,13 @@ watch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeValue, // 监听的目标(函数形式避免直接传递 props 导致的警告)
|
() => prop.timeValue,
|
||||||
(newVal, oldVal) => {
|
(newVal, oldVal) => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
deep: true // 若 timeValue 是对象/数组,需开启深度监听
|
deep: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const addMenu = () => {}
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped></style>
|
<style lang="scss" scoped></style>
|
||||||
|
|||||||
@@ -1,260 +1,428 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<!--趋势对比 -->
|
<!--趋势对比 -->
|
||||||
<TableHeader :showReset="false" @selectChange="selectChange">
|
<TableHeader
|
||||||
|
datePicker
|
||||||
|
ref="TableHeaderRef"
|
||||||
|
:timeKeyList="prop.timeKey"
|
||||||
|
:showReset="false"
|
||||||
|
@selectChange="selectChange"
|
||||||
|
v-if="fullscreen"
|
||||||
|
>
|
||||||
<template v-slot:select>
|
<template v-slot:select>
|
||||||
<el-form-item label="监测点名称">
|
<el-form-item label="监测对象">
|
||||||
<el-select
|
<el-select
|
||||||
v-model="tableStore.table.params.power"
|
filterable
|
||||||
placeholder="请选择监测点名称"
|
v-model="tableStore.table.params.sensitiveUserId"
|
||||||
|
placeholder="请选择监测对象"
|
||||||
clearable
|
clearable
|
||||||
style="width: 130px"
|
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option v-for="item in idList" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
v-for="item in powerList"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value"
|
|
||||||
/>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<!-- <el-form-item label="监测点名称">
|
||||||
|
<el-select v-model="tableStore.table.params.lineId" placeholder="请选择监测点名称" clearable>
|
||||||
|
<el-option
|
||||||
|
v-for="item in lineIdList"
|
||||||
|
:key="item.lineId"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.lineId"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item> -->
|
||||||
<el-form-item label="电能质量指标">
|
<el-form-item label="电能质量指标">
|
||||||
<el-select
|
<el-select v-model="tableStore.table.params.indicator" placeholder="请选择电能质量指标" clearable>
|
||||||
v-model="tableStore.table.params.indicator"
|
<el-option v-for="item in indicatorList" :key="item.id" :label="item.name" :value="item.id" />
|
||||||
placeholder="请选择电能质量指标"
|
|
||||||
clearable
|
|
||||||
style="width: 130px"
|
|
||||||
>
|
|
||||||
<el-option
|
|
||||||
v-for="item in indicatorList"
|
|
||||||
:key="item.value"
|
|
||||||
:label="item.label"
|
|
||||||
:value="item.value"
|
|
||||||
/>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="谐波次数">
|
<el-form-item>
|
||||||
|
<el-radio-group v-model="tableStore.table.params.dataLevel">
|
||||||
|
<el-radio-button label="一次值" value="Primary" />
|
||||||
|
<el-radio-button label="二次值" value="Secondary" />
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item label="统计类型">
|
||||||
<el-select
|
<el-select
|
||||||
v-model="tableStore.table.params.exceedingTheLimit"
|
style="min-width: 120px !important"
|
||||||
placeholder="请选择谐波次数"
|
placeholder="请选择"
|
||||||
clearable
|
v-model="tableStore.table.params.valueType"
|
||||||
style="width: 90px"
|
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option value="max" label="最大值"></el-option>
|
||||||
v-for="item in exceedingTheLimitList"
|
<el-option value="min" label="最小值"></el-option>
|
||||||
:key="item.value"
|
<el-option value="avg" label="平均值"></el-option>
|
||||||
:label="item.label"
|
<el-option value="cp95" label="cp95"></el-option>
|
||||||
:value="item.value"
|
|
||||||
/>
|
|
||||||
</el-select>
|
</el-select>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<div v-if="shouldShowHarmonicCount()" style="display: flex; color: var(--el-text-color-regular)">
|
||||||
|
<span style="width: 160px">{{ getHarmonicTypeName() }}谐波次数</span>
|
||||||
|
<el-select
|
||||||
|
v-model="tableStore.table.params.harmonicCount"
|
||||||
|
placeholder="请选择谐波次数"
|
||||||
|
style="min-width: 80px !important"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="num in harmonicCountOptions"
|
||||||
|
:key="num"
|
||||||
|
:label="num"
|
||||||
|
:value="num"
|
||||||
|
></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
</template>
|
</template>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<my-echart
|
<my-echart
|
||||||
|
v-loading="tableStore.table.loading"
|
||||||
class="tall"
|
class="tall"
|
||||||
:options="echartList"
|
:options="echartList"
|
||||||
:style="{ width: prop.width, height: `calc(${prop.height} - ${headerHeight}px )` }"
|
:style="{
|
||||||
|
width: prop.width,
|
||||||
|
height: `calc(${prop.height} - ${headerHeight}px + ${fullscreen ? 0 : 56}px)`
|
||||||
|
}"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, provide, reactive, watch, h } from 'vue'
|
import { ref, onMounted, provide, reactive, watch, h, computed, nextTick } from 'vue'
|
||||||
import TableStore from '@/utils/tableStore'
|
import TableStore from '@/utils/tableStore'
|
||||||
import Table from '@/components/table/index.vue'
|
|
||||||
import TableHeader from '@/components/table/header/index.vue'
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
import { useDictData } from '@/stores/dictData'
|
|
||||||
import { ElMessage, ElMessageBox } from 'element-plus'
|
|
||||||
import { getTimeOfTheMonth } from '@/utils/formatTime'
|
|
||||||
import MyEchart from '@/components/echarts/MyEchart.vue'
|
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||||
import { useConfig } from '@/stores/config'
|
import { useConfig } from '@/stores/config'
|
||||||
const prop = defineProps({
|
import { queryByCode, queryCsDictTree } from '@/api/system-boot/dictTree'
|
||||||
width: { type: String },
|
import { getListByIds } from '@/api/harmonic-boot/cockpit/cockpit'
|
||||||
height: { type: String },
|
import { getTime } from '@/utils/formatTime'
|
||||||
timeKey: { type: String },
|
|
||||||
timeValue: { type: Object }
|
|
||||||
})
|
|
||||||
const config = useConfig()
|
|
||||||
const powerList: any = ref([
|
|
||||||
{
|
|
||||||
label: '1#变压器',
|
|
||||||
value: '1'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '2#变压器',
|
|
||||||
value: '2'
|
|
||||||
}
|
|
||||||
])
|
|
||||||
const exceedingTheLimitList: any = ref([
|
|
||||||
{
|
|
||||||
label: '2次',
|
|
||||||
value: '2'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '3次',
|
|
||||||
value: '3'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '4次',
|
|
||||||
value: '4'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '5次',
|
|
||||||
value: '5'
|
|
||||||
}
|
|
||||||
])
|
|
||||||
const indicatorList: any = ref([
|
|
||||||
{
|
|
||||||
label: '谐波电压总畸变率',
|
|
||||||
value: '1'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '各次谐波电压',
|
|
||||||
value: '2'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '各次谐波电压',
|
|
||||||
value: '3'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '三相电压不平衡',
|
|
||||||
value: '4'
|
|
||||||
}
|
|
||||||
])
|
|
||||||
const echartList = ref({
|
|
||||||
title: {
|
|
||||||
text: '趋势对比'
|
|
||||||
},
|
|
||||||
|
|
||||||
xAxis: {
|
const prop = defineProps({
|
||||||
type: 'time',
|
w: { type: [String, Number] },
|
||||||
axisLabel: {
|
h: { type: [String, Number] },
|
||||||
formatter: {
|
width: { type: [String, Number] },
|
||||||
day: '{MM}-{dd}',
|
height: { type: [String, Number] },
|
||||||
month: '{MM}',
|
timeKey: { type: Array as () => string[] },
|
||||||
year: '{yyyy}'
|
timeValue: { type: Object },
|
||||||
|
interval: { type: Number }
|
||||||
|
})
|
||||||
|
|
||||||
|
const TableHeaderRef = ref()
|
||||||
|
const config = useConfig()
|
||||||
|
|
||||||
|
// 计算是否全屏展示
|
||||||
|
const fullscreen = computed(() => {
|
||||||
|
const w = Number(prop.w)
|
||||||
|
const h = Number(prop.h)
|
||||||
|
if (!isNaN(w) && !isNaN(h) && w === 12 && h === 6) {
|
||||||
|
// 执行相应逻辑
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// 添加谐波次数选项(2-50)
|
||||||
|
const harmonicCountOptions = ref(Array.from({ length: 49 }, (_, i) => i + 2))
|
||||||
|
|
||||||
|
const indicatorList = ref()
|
||||||
|
|
||||||
|
const echartList = ref()
|
||||||
|
|
||||||
|
const headerHeight = ref(57)
|
||||||
|
|
||||||
|
// 监测对象
|
||||||
|
const idList = ref()
|
||||||
|
|
||||||
|
// 监测对象
|
||||||
|
const initListByIds = () => {
|
||||||
|
getListByIds({}).then((res: any) => {
|
||||||
|
if (res.data.length > 0) {
|
||||||
|
idList.value = res.data
|
||||||
|
initCode()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const selectChange = (showSelect: any, height: any, datePickerValue?: any) => {
|
||||||
|
headerHeight.value = height
|
||||||
|
|
||||||
|
if (datePickerValue && datePickerValue.timeValue) {
|
||||||
|
// 更新时间参数
|
||||||
|
tableStore.table.params.searchBeginTime = datePickerValue.timeValue[0]
|
||||||
|
tableStore.table.params.searchEndTime = datePickerValue.timeValue[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const initCode = () => {
|
||||||
|
queryByCode('steady_state_limit_trend').then(res => {
|
||||||
|
queryCsDictTree(res.data.id).then(item => {
|
||||||
|
indicatorList.value = item.data
|
||||||
|
tableStore.table.params.indicator = indicatorList.value[0].id
|
||||||
|
nextTick(() => {
|
||||||
|
tableStore.index()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 治理前
|
||||||
|
const chartsListBefore = ref()
|
||||||
|
// 治理后
|
||||||
|
const chartsListAfter = ref()
|
||||||
|
|
||||||
|
const setEchart = () => {
|
||||||
|
// 从接口数据中提取治理前和治理后的数据
|
||||||
|
const beforeData = chartsListBefore.value || []
|
||||||
|
const afterData = chartsListAfter.value || []
|
||||||
|
|
||||||
|
// 按相位分组数据
|
||||||
|
const beforeGroupedByPhase: any = {}
|
||||||
|
const afterGroupedByPhase: any = {}
|
||||||
|
|
||||||
|
// 处理治理前数据
|
||||||
|
beforeData.forEach((item: any) => {
|
||||||
|
const phase = item.phase || 'default'
|
||||||
|
if (!beforeGroupedByPhase[phase]) {
|
||||||
|
beforeGroupedByPhase[phase] = []
|
||||||
|
}
|
||||||
|
beforeGroupedByPhase[phase].push([item.time, item.statisticalData])
|
||||||
|
})
|
||||||
|
|
||||||
|
// 处理治理后数据
|
||||||
|
afterData.forEach((item: any) => {
|
||||||
|
const phase = item.phase || 'default'
|
||||||
|
if (!afterGroupedByPhase[phase]) {
|
||||||
|
afterGroupedByPhase[phase] = []
|
||||||
|
}
|
||||||
|
afterGroupedByPhase[phase].push([item.time, item.statisticalData])
|
||||||
|
})
|
||||||
|
|
||||||
|
// 构建系列数据
|
||||||
|
const series: any = []
|
||||||
|
|
||||||
|
// 定义相位颜色
|
||||||
|
const phaseColors: any = {
|
||||||
|
A: '#DAA520',
|
||||||
|
B: '#2E8B57',
|
||||||
|
C: '#A52a2a'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加治理前数据系列(实线)
|
||||||
|
Object.keys(beforeGroupedByPhase).forEach(phase => {
|
||||||
|
const phaseName = phase === 'default' ? '' : `${phase}相`
|
||||||
|
const color = phaseColors[phase] || config.layout.elementUiPrimary[0]
|
||||||
|
|
||||||
|
series.push({
|
||||||
|
name: `治理前${phaseName}`,
|
||||||
|
type: 'line',
|
||||||
|
showSymbol: false,
|
||||||
|
smooth: true,
|
||||||
|
symbol: 'none',
|
||||||
|
data: beforeGroupedByPhase[phase],
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
color: color
|
||||||
|
}
|
||||||
|
},
|
||||||
|
lineStyle: {
|
||||||
|
type: 'solid', // 实线
|
||||||
|
width: 2 // 线条宽度
|
||||||
|
},
|
||||||
|
yAxisIndex: 0
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 添加治理后数据系列(虚线)
|
||||||
|
Object.keys(afterGroupedByPhase).forEach(phase => {
|
||||||
|
const phaseName = phase === 'default' ? '' : `${phase}相`
|
||||||
|
const color = phaseColors[phase] || config.layout.elementUiPrimary[0]
|
||||||
|
|
||||||
|
series.push({
|
||||||
|
name: `治理后${phaseName}`,
|
||||||
|
type: 'line',
|
||||||
|
showSymbol: false,
|
||||||
|
smooth: true,
|
||||||
|
symbol: 'none',
|
||||||
|
data: afterGroupedByPhase[phase],
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
color: color
|
||||||
|
}
|
||||||
|
},
|
||||||
|
lineStyle: {
|
||||||
|
type: 'dashed', // 虚线
|
||||||
|
width: 2 // 线条宽度
|
||||||
|
},
|
||||||
|
yAxisIndex: 0
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// 获取指标名称用于图表标题
|
||||||
|
let titleText = '治理前后对比'
|
||||||
|
if (beforeData.length > 0 && beforeData[0].anotherName) {
|
||||||
|
titleText = beforeData[0].anotherName
|
||||||
|
} else if (afterData.length > 0 && afterData[0].anotherName) {
|
||||||
|
titleText = afterData[0].anotherName
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建图例数据
|
||||||
|
const legendData = series.map((item: any, index: number) => {
|
||||||
|
let color = config.layout.elementUiPrimary[0]
|
||||||
|
const name = item.name
|
||||||
|
if (name.includes('A相')) {
|
||||||
|
color = '#DAA520'
|
||||||
|
} else if (name.includes('B相')) {
|
||||||
|
color = '#2E8B57'
|
||||||
|
} else if (name.includes('C相')) {
|
||||||
|
color = '#A52a2a'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是治理前还是治理后,设置不同的线条样式
|
||||||
|
const isBefore = name.includes('治理前')
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: item.name,
|
||||||
|
icon: isBefore
|
||||||
|
? 'rect'
|
||||||
|
: 'path://M0,2 L8,2 L8,6 L0,6 Z M12,2 L20,2 L20,6 L12,6 Z M24,2 L32,2 L32,6 L24,6 Z M36,2 L44,2 L44,6 L36,6 Z', // 矩形组成的粗虚线
|
||||||
|
itemStyle: {
|
||||||
|
color: color // 明确指定图例图标的颜色
|
||||||
|
},
|
||||||
|
lineStyle: {
|
||||||
|
type: isBefore ? 'solid' : 'dashed', // 治理前实线,治理后虚线
|
||||||
|
width: 2
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
})
|
||||||
|
|
||||||
yAxis: {},
|
echartList.value = {
|
||||||
grid: {
|
title: {
|
||||||
left: '10px',
|
text: titleText
|
||||||
right: '20px'
|
},
|
||||||
},
|
legend: {
|
||||||
options: {
|
data: legendData,
|
||||||
series: [
|
icon: 'rect',
|
||||||
{
|
itemWidth: 18,
|
||||||
// name: '暂降次数',
|
itemHeight: 3,
|
||||||
type: 'line',
|
itemStyle: {
|
||||||
name: '治理前',
|
borderWidth: 0
|
||||||
showSymbol: false,
|
|
||||||
smooth: true,
|
|
||||||
data: [
|
|
||||||
['2025-10-16 07:00:00', 1],
|
|
||||||
['2025-10-16 07:15:00', 1],
|
|
||||||
['2025-10-16 07:30:00', 1],
|
|
||||||
['2025-10-16 07:45:00', 1],
|
|
||||||
['2025-10-16 08:00:00', 3],
|
|
||||||
['2025-10-16 08:15:00', 5],
|
|
||||||
['2025-10-16 08:30:00', 6],
|
|
||||||
['2025-10-16 08:45:00', 7],
|
|
||||||
['2025-10-16 09:00:00', 10],
|
|
||||||
['2025-10-16 09:15:00', 12],
|
|
||||||
['2025-10-16 09:30:00', 13],
|
|
||||||
['2025-10-16 09:45:00', 14],
|
|
||||||
['2025-10-16 10:00:00', 16],
|
|
||||||
['2025-10-16 10:15:00', 16],
|
|
||||||
['2025-10-16 10:30:00', 13],
|
|
||||||
['2025-10-16 10:45:00', 12],
|
|
||||||
['2025-10-16 11:00:00', 14],
|
|
||||||
['2025-10-16 11:15:00', 8],
|
|
||||||
['2025-10-16 11:30:00', 7],
|
|
||||||
['2025-10-16 11:45:00', 9],
|
|
||||||
['2025-10-16 12:00:00', 6],
|
|
||||||
['2025-10-16 12:15:00', 6],
|
|
||||||
['2025-10-16 12:30:00', 6],
|
|
||||||
['2025-10-16 12:45:00', 6]
|
|
||||||
],
|
|
||||||
itemStyle: {
|
|
||||||
normal: {
|
|
||||||
//这里是颜色
|
|
||||||
color: function (params: any) {
|
|
||||||
if (params.value[1] == 0 || params.value[1] == 3.14159) {
|
|
||||||
return '#ccc'
|
|
||||||
} else {
|
|
||||||
return config.layout.elementUiPrimary[0]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
yAxisIndex: 0
|
|
||||||
},
|
},
|
||||||
{
|
lineStyle: {
|
||||||
name: '治理后',
|
width: 2 // 确保图例线条宽度与系列线条宽度一致
|
||||||
type: 'line',
|
|
||||||
showSymbol: false,
|
|
||||||
smooth: true,
|
|
||||||
data: [
|
|
||||||
['2025-10-16 07:00:00', 10],
|
|
||||||
['2025-10-16 07:15:00', 10],
|
|
||||||
['2025-10-16 07:30:00', 10],
|
|
||||||
['2025-10-16 07:45:00', 10],
|
|
||||||
['2025-10-16 08:00:00', 30],
|
|
||||||
['2025-10-16 08:15:00', 50],
|
|
||||||
['2025-10-16 08:30:00', 60],
|
|
||||||
['2025-10-16 08:45:00', 70],
|
|
||||||
['2025-10-16 09:00:00', 100],
|
|
||||||
['2025-10-16 09:15:00', 120],
|
|
||||||
['2025-10-16 09:30:00', 130],
|
|
||||||
['2025-10-16 09:45:00', 140],
|
|
||||||
['2025-10-16 10:00:00', 160],
|
|
||||||
['2025-10-16 10:15:00', 160],
|
|
||||||
['2025-10-16 10:30:00', 130],
|
|
||||||
['2025-10-16 10:45:00', 120],
|
|
||||||
['2025-10-16 11:00:00', 140],
|
|
||||||
['2025-10-16 11:15:00', 80],
|
|
||||||
['2025-10-16 11:30:00', 70],
|
|
||||||
['2025-10-16 11:45:00', 90],
|
|
||||||
['2025-10-16 12:00:00', 60],
|
|
||||||
['2025-10-16 12:15:00', 60],
|
|
||||||
['2025-10-16 12:30:00', 60],
|
|
||||||
['2025-10-16 12:45:00', 60]
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
},
|
||||||
|
xAxis: {
|
||||||
|
type: 'time',
|
||||||
|
axisLabel: {
|
||||||
|
formatter: {
|
||||||
|
day: '{MM}-{dd}',
|
||||||
|
month: '{MM}',
|
||||||
|
year: '{yyyy}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
yAxis: {
|
||||||
|
name: beforeData.length > 0 ? beforeData[0].unit : afterData.length > 0 ? afterData[0].unit : ''
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '10px',
|
||||||
|
right: '20px'
|
||||||
|
},
|
||||||
|
series: series
|
||||||
}
|
}
|
||||||
})
|
|
||||||
const headerHeight = ref(57)
|
|
||||||
const selectChange = (showSelect: any, height: any) => {
|
|
||||||
headerHeight.value = height
|
|
||||||
}
|
}
|
||||||
const tableStore: any = new TableStore({
|
|
||||||
url: '/user-boot/role/selectRoleDetail?id=0',
|
|
||||||
method: 'POST',
|
|
||||||
|
|
||||||
|
const tableStore: any = new TableStore({
|
||||||
|
url: '/cs-device-boot/csGroup/sensitiveUserTrendData',
|
||||||
|
method: 'POST',
|
||||||
showPage: false,
|
showPage: false,
|
||||||
exportName: '主要监测点列表',
|
exportName: '趋势对比',
|
||||||
column: [],
|
column: [],
|
||||||
beforeSearchFun: () => {
|
beforeSearchFun: () => {
|
||||||
tableStore.table.params.searchBeginTime = prop.timeValue?.[0] || getTimeOfTheMonth(prop.timeKey)[0]
|
setTime()
|
||||||
tableStore.table.params.searchEndTime = prop.timeValue?.[1] || getTimeOfTheMonth(prop.timeKey)[1]
|
if (!tableStore.table.params.sensitiveUserId && idList.value?.length > 0) {
|
||||||
|
tableStore.table.params.sensitiveUserId = idList.value[0].id
|
||||||
|
}
|
||||||
|
let lists: any = []
|
||||||
|
// 处理电能质量指标
|
||||||
|
const selectedIndicator = indicatorList.value?.find(
|
||||||
|
(item: any) => item.id === tableStore.table.params.indicator
|
||||||
|
)
|
||||||
|
if (selectedIndicator) {
|
||||||
|
let frequencys = ''
|
||||||
|
if (selectedIndicator.name.includes('谐波含有率')) {
|
||||||
|
frequencys = tableStore.table.params.harmonicCount
|
||||||
|
}
|
||||||
|
|
||||||
|
lists.push({
|
||||||
|
statisticalId: tableStore.table.params.indicator,
|
||||||
|
frequency: frequencys !== null && frequencys !== undefined ? String(frequencys) : ''
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将 lists 添加到请求参数中
|
||||||
|
tableStore.table.params.list = lists
|
||||||
},
|
},
|
||||||
loadCallback: () => {
|
loadCallback: () => {
|
||||||
tableStore.table.height = `calc(${prop.height} - 80px)`
|
tableStore.table.height = `calc(${prop.height} - 80px)`
|
||||||
|
// 数据加载完成后的处理
|
||||||
|
if (tableStore.table.data) {
|
||||||
|
chartsListBefore.value = tableStore.table.data.before
|
||||||
|
chartsListAfter.value = tableStore.table.data.after
|
||||||
|
setEchart()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const tableRef = ref()
|
|
||||||
provide('tableRef', tableRef)
|
|
||||||
tableStore.table.params.power = '1'
|
|
||||||
tableStore.table.params.indicator = '1'
|
tableStore.table.params.indicator = '1'
|
||||||
tableStore.table.params.exceedingTheLimit = '1'
|
tableStore.table.params.exceedingTheLimit = '1'
|
||||||
tableStore.table.params.searchValue = ''
|
tableStore.table.params.dataLevel = 'Primary'
|
||||||
|
tableStore.table.params.valueType = 'avg'
|
||||||
provide('tableStore', tableStore)
|
provide('tableStore', tableStore)
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
tableStore.index()
|
initListByIds()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const setTime = () => {
|
||||||
|
const time = getTime(
|
||||||
|
(TableHeaderRef.value?.datePickerRef.interval || prop.interval) ?? 0,
|
||||||
|
prop.timeKey,
|
||||||
|
fullscreen.value
|
||||||
|
? [tableStore.table.params.searchBeginTime, tableStore.table.params.searchEndTime]
|
||||||
|
: prop.timeValue
|
||||||
|
)
|
||||||
|
|
||||||
|
if (Array.isArray(time)) {
|
||||||
|
tableStore.table.params.searchBeginTime = time[0]
|
||||||
|
tableStore.table.params.searchEndTime = time[1]
|
||||||
|
TableHeaderRef.value?.setInterval(time[2] - 0)
|
||||||
|
TableHeaderRef.value?.setTimeInterval([time[0], time[1]])
|
||||||
|
} else {
|
||||||
|
console.warn('获取时间失败,time 不是一个有效数组')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断是否应该显示谐波次数选择框
|
||||||
|
const shouldShowHarmonicCount = () => {
|
||||||
|
if (!tableStore.table.params.indicator || !indicatorList.value) return false
|
||||||
|
|
||||||
|
const currentIndicator = indicatorList.value.find((item: any) => item.id === tableStore.table.params.indicator)
|
||||||
|
|
||||||
|
return (
|
||||||
|
currentIndicator &&
|
||||||
|
(currentIndicator.name.includes('电压谐波含有率') || currentIndicator.name.includes('电流谐波含有率'))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取谐波类型名称
|
||||||
|
const getHarmonicTypeName = () => {
|
||||||
|
const currentIndicator = indicatorList.value.find((item: any) => item.id === tableStore.table.params.indicator)
|
||||||
|
|
||||||
|
if (currentIndicator) {
|
||||||
|
if (currentIndicator.name.includes('电压谐波含有率')) {
|
||||||
|
return '电压'
|
||||||
|
} else if (currentIndicator.name.includes('电流谐波含有率')) {
|
||||||
|
return '电流'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ''
|
||||||
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeKey,
|
() => prop.timeKey,
|
||||||
val => {
|
val => {
|
||||||
@@ -262,19 +430,33 @@ watch(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
watch(
|
watch(
|
||||||
() => prop.timeValue, // 监听的目标(函数形式避免直接传递 props 导致的警告)
|
() => prop.timeValue,
|
||||||
(newVal, oldVal) => {
|
(newVal, oldVal) => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
deep: true // 若 timeValue 是对象/数组,需开启深度监听
|
deep: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
const addMenu = () => {}
|
// 监听指标变化,当指标变化时重置谐波次数
|
||||||
|
watch(
|
||||||
|
() => tableStore.table.params.indicator,
|
||||||
|
newVal => {
|
||||||
|
if (shouldShowHarmonicCount()) {
|
||||||
|
// 如果之前没有设置过谐波次数,则默认设置为2
|
||||||
|
if (!tableStore.table.params.harmonicCount) {
|
||||||
|
tableStore.table.params.harmonicCount = 2
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 如果不是谐波含有率指标,则清除谐波次数设置
|
||||||
|
tableStore.table.params.harmonicCount = ''
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
:deep(.el-select) {
|
// :deep(.el-select) {
|
||||||
min-width: 80px;
|
// min-width: 80px;
|
||||||
}
|
// }
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { color, gradeColor3 } from './color'
|
|||||||
import { useConfig } from '@/stores/config'
|
import { useConfig } from '@/stores/config'
|
||||||
// import { nextTick } from 'process'
|
// import { nextTick } from 'process'
|
||||||
|
|
||||||
|
const emit = defineEmits(['chartClick'])
|
||||||
const config = useConfig()
|
const config = useConfig()
|
||||||
color[0] = config.layout.elementUiPrimary[0]
|
color[0] = config.layout.elementUiPrimary[0]
|
||||||
const chartRef = ref<HTMLDivElement>()
|
const chartRef = ref<HTMLDivElement>()
|
||||||
@@ -89,7 +90,7 @@ const initChart = () => {
|
|||||||
...(props.options?.legend || null)
|
...(props.options?.legend || null)
|
||||||
},
|
},
|
||||||
grid: {
|
grid: {
|
||||||
top: '50px',
|
top: '50px',
|
||||||
left: '30px',
|
left: '30px',
|
||||||
right: '70px',
|
right: '70px',
|
||||||
bottom: props.options?.options?.dataZoom === null ? '10px' : '40px',
|
bottom: props.options?.options?.dataZoom === null ? '10px' : '40px',
|
||||||
@@ -131,6 +132,10 @@ const initChart = () => {
|
|||||||
// 处理柱状图
|
// 处理柱状图
|
||||||
chart.setOption(options, true)
|
chart.setOption(options, true)
|
||||||
chart.group = 'group'
|
chart.group = 'group'
|
||||||
|
// 添加点击事件
|
||||||
|
chart.on('click', function (params: any) {
|
||||||
|
emit('chartClick', params)
|
||||||
|
})
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
chart.resize()
|
chart.resize()
|
||||||
}, 0)
|
}, 0)
|
||||||
|
|||||||
324
src/components/echarts/rmsWorker.js
Normal file
324
src/components/echarts/rmsWorker.js
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
// 辅助函数
|
||||||
|
const getMax = (temp, tempA, tempB, tempC) => {
|
||||||
|
temp = temp > tempA ? temp : tempA
|
||||||
|
temp = temp > tempB ? temp : tempB
|
||||||
|
if (tempC !== undefined) {
|
||||||
|
temp = temp > tempC ? temp : tempC
|
||||||
|
}
|
||||||
|
return temp
|
||||||
|
}
|
||||||
|
|
||||||
|
const getMaxTwo = (temp, tempA, tempB) => {
|
||||||
|
temp = temp > tempA ? temp : tempA
|
||||||
|
temp = temp > tempB ? temp : tempB
|
||||||
|
return temp
|
||||||
|
}
|
||||||
|
|
||||||
|
const getMin = (temp, tempA, tempB, tempC) => {
|
||||||
|
temp = temp < tempA ? temp : tempA
|
||||||
|
temp = temp < tempB ? temp : tempB
|
||||||
|
if (tempC !== undefined) {
|
||||||
|
temp = temp < tempC ? temp : tempC
|
||||||
|
}
|
||||||
|
return temp
|
||||||
|
}
|
||||||
|
|
||||||
|
const getMinOpen = (temp, tempA, tempB) => {
|
||||||
|
temp = temp < tempA ? temp : tempA
|
||||||
|
temp = temp < tempB ? temp : tempB
|
||||||
|
return temp
|
||||||
|
}
|
||||||
|
|
||||||
|
// 数据处理函数
|
||||||
|
const fliteWaveData = (wp, step, iphasicValue, isOpen) => {
|
||||||
|
const rmsData = wp.listRmsData
|
||||||
|
const pt = Number(wp.pt) / 1000
|
||||||
|
const ct = Number(wp.ct)
|
||||||
|
const titleList = wp.waveTitle
|
||||||
|
let xishu = pt
|
||||||
|
let aTitle = '',
|
||||||
|
bTitle = '',
|
||||||
|
cTitle = '',
|
||||||
|
unit = '电压'
|
||||||
|
let rmsvFirstX = 0,
|
||||||
|
rmsvFirstY = 0,
|
||||||
|
rmsvSecondX = 0,
|
||||||
|
rmsvSecondY = 0,
|
||||||
|
firstZhou = 'a',
|
||||||
|
secondeZhou = 'a'
|
||||||
|
let ifmax = 0,
|
||||||
|
ifmin = 0,
|
||||||
|
ismax = 0,
|
||||||
|
ismin = 0,
|
||||||
|
rfmax = 0,
|
||||||
|
rfmin = 0,
|
||||||
|
rsmax = 0,
|
||||||
|
rsmin = 0
|
||||||
|
|
||||||
|
const shunshiFA = []
|
||||||
|
const shunshiFB = []
|
||||||
|
const shunshiFC = []
|
||||||
|
const shunshiSA = []
|
||||||
|
const shunshiSB = []
|
||||||
|
const shunshiSC = []
|
||||||
|
const rmsFA = []
|
||||||
|
const rmsFB = []
|
||||||
|
const rmsFC = []
|
||||||
|
const rmsSA = []
|
||||||
|
const rmsSB = []
|
||||||
|
const rmsSC = []
|
||||||
|
|
||||||
|
if (titleList[iphasicValue * step + 1]?.substring(0, 1) !== 'U') {
|
||||||
|
xishu = ct
|
||||||
|
unit = '电流'
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 1; i <= iphasicValue; i++) {
|
||||||
|
switch (i) {
|
||||||
|
case 1:
|
||||||
|
aTitle = titleList[iphasicValue * step + i]?.substring(1) || ''
|
||||||
|
break
|
||||||
|
case 2:
|
||||||
|
bTitle = titleList[iphasicValue * step + i]?.substring(1) || ''
|
||||||
|
break
|
||||||
|
case 3:
|
||||||
|
cTitle = titleList[iphasicValue * step + i]?.substring(1) || ''
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rmsData[0] && rmsData[0][iphasicValue * step + 1] !== undefined) {
|
||||||
|
rfmax = rmsData[0][iphasicValue * step + 1] * xishu
|
||||||
|
rfmin = rmsData[0][iphasicValue * step + 1] * xishu
|
||||||
|
rmsvFirstY = rmsData[0][iphasicValue * step + 1] * xishu
|
||||||
|
rmsvFirstX = rmsData[0][0]
|
||||||
|
rsmax = rmsData[0][iphasicValue * step + 1]
|
||||||
|
rsmin = rmsData[0][iphasicValue * step + 1]
|
||||||
|
rmsvSecondY = rmsData[0][iphasicValue * step + 1]
|
||||||
|
rmsvSecondX = rmsData[0][0]
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let rms = 0; rms < rmsData.length; rms++) {
|
||||||
|
if (!rmsData[rms] || rmsData[rms][iphasicValue * step + 1] === undefined) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (iphasicValue) {
|
||||||
|
case 1:
|
||||||
|
const rmsFirstA = rmsData[rms][iphasicValue * step + 1] * xishu
|
||||||
|
rmsFA.push([rmsData[rms][0], rmsFirstA])
|
||||||
|
rfmax = rfmax > rmsFirstA ? rfmax : rmsFirstA
|
||||||
|
rfmin = rfmin < rmsFirstA ? rfmin : rmsFirstA
|
||||||
|
if (rfmin < rmsvFirstY) {
|
||||||
|
rmsvFirstY = rfmin
|
||||||
|
firstZhou = 'a'
|
||||||
|
rmsvFirstX = rmsData[rms][0]
|
||||||
|
}
|
||||||
|
|
||||||
|
const rmsSecondA = rmsData[rms][iphasicValue * step + 1]
|
||||||
|
rmsSA.push([rmsData[rms][0], rmsSecondA])
|
||||||
|
rsmax = rsmax > rmsSecondA ? rsmax : rmsSecondA
|
||||||
|
rsmin = rsmin < rmsSecondA ? rsmin : rmsSecondA
|
||||||
|
if (rsmin < rmsvSecondY) {
|
||||||
|
rmsvSecondY = rsmin
|
||||||
|
secondeZhou = 'a'
|
||||||
|
rmsvSecondX = rmsData[rms][0]
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 2:
|
||||||
|
const rmsFirstA2 = rmsData[rms][iphasicValue * step + 1] * xishu
|
||||||
|
const rmsFirstB2 = rmsData[rms][iphasicValue * step + 2] * xishu
|
||||||
|
rmsFA.push([rmsData[rms][0], rmsFirstA2])
|
||||||
|
rmsFB.push([rmsData[rms][0], rmsFirstB2])
|
||||||
|
rfmax = getMaxTwo(rfmax, rmsFirstA2, rmsFirstB2)
|
||||||
|
rfmin = getMinOpen(rfmin, rmsFirstA2, rmsFirstB2)
|
||||||
|
if (rfmin < rmsvFirstY) {
|
||||||
|
rmsvFirstY = rfmin
|
||||||
|
if (rfmin === rmsFirstA2) {
|
||||||
|
firstZhou = 'a'
|
||||||
|
} else if (rfmin === rmsFirstB2) {
|
||||||
|
firstZhou = 'b'
|
||||||
|
}
|
||||||
|
rmsvFirstX = rmsData[rms][0]
|
||||||
|
}
|
||||||
|
|
||||||
|
const rmsSecondA2 = rmsData[rms][iphasicValue * step + 1]
|
||||||
|
const rmsSecondB2 = rmsData[rms][iphasicValue * step + 2]
|
||||||
|
rmsSA.push([rmsData[rms][0], rmsSecondA2])
|
||||||
|
rmsSB.push([rmsData[rms][0], rmsSecondB2])
|
||||||
|
rsmax = getMaxTwo(rsmax, rmsSecondA2, rmsSecondB2)
|
||||||
|
rsmin = getMinOpen(rsmin, rmsSecondA2, rmsSecondB2)
|
||||||
|
if (rsmin < rmsvSecondY) {
|
||||||
|
rmsvSecondY = rsmin
|
||||||
|
if (rsmin === rmsSecondA2) {
|
||||||
|
secondeZhou = 'a'
|
||||||
|
} else if (rsmin === rmsSecondB2) {
|
||||||
|
secondeZhou = 'b'
|
||||||
|
}
|
||||||
|
rmsvSecondX = rmsData[rms][0]
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 3:
|
||||||
|
const rmsFirstA3 = rmsData[rms][iphasicValue * step + 1] * xishu
|
||||||
|
const rmsFirstB3 = rmsData[rms][iphasicValue * step + 2] * xishu
|
||||||
|
const rmsFirstC3 = rmsData[rms][iphasicValue * step + 3] * xishu
|
||||||
|
rmsFA.push([rmsData[rms][0], rmsFirstA3])
|
||||||
|
rmsFB.push([rmsData[rms][0], rmsFirstB3])
|
||||||
|
rmsFC.push([rmsData[rms][0], rmsFirstC3])
|
||||||
|
rfmax = getMax(rfmax, rmsFirstA3, rmsFirstB3, rmsFirstC3)
|
||||||
|
rfmin = isOpen
|
||||||
|
? getMinOpen(rfmin, rmsFirstA3, rmsFirstC3)
|
||||||
|
: getMin(rfmin, rmsFirstA3, rmsFirstB3, rmsFirstC3)
|
||||||
|
if (rfmin < rmsvFirstY) {
|
||||||
|
rmsvFirstY = rfmin
|
||||||
|
if (rfmin === rmsFirstA3) {
|
||||||
|
firstZhou = 'a'
|
||||||
|
} else if (rfmin === rmsFirstB3) {
|
||||||
|
firstZhou = 'b'
|
||||||
|
} else {
|
||||||
|
firstZhou = 'c'
|
||||||
|
}
|
||||||
|
rmsvFirstX = rmsData[rms][0]
|
||||||
|
}
|
||||||
|
|
||||||
|
const rmsSecondA3 = rmsData[rms][iphasicValue * step + 1]
|
||||||
|
const rmsSecondB3 = rmsData[rms][iphasicValue * step + 2]
|
||||||
|
const rmsSecondC3 = rmsData[rms][iphasicValue * step + 3]
|
||||||
|
rmsSA.push([rmsData[rms][0], rmsSecondA3])
|
||||||
|
rmsSB.push([rmsData[rms][0], rmsSecondB3])
|
||||||
|
rmsSC.push([rmsData[rms][0], rmsSecondC3])
|
||||||
|
rsmax = getMax(rsmax, rmsSecondA3, rmsSecondB3, rmsSecondC3)
|
||||||
|
rsmin = isOpen
|
||||||
|
? getMinOpen(rsmin, rmsSecondA3, rmsSecondC3)
|
||||||
|
: getMin(rsmin, rmsSecondA3, rmsSecondB3, rmsSecondC3)
|
||||||
|
if (rsmin < rmsvSecondY) {
|
||||||
|
rmsvSecondY = rsmin
|
||||||
|
if (rsmin === rmsSecondA3) {
|
||||||
|
secondeZhou = 'a'
|
||||||
|
} else if (rsmin === rmsSecondB3) {
|
||||||
|
secondeZhou = 'b'
|
||||||
|
} else {
|
||||||
|
secondeZhou = 'c'
|
||||||
|
}
|
||||||
|
rmsvSecondX = rmsData[rms][0]
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const instantF = { max: ifmax, min: ifmin }
|
||||||
|
const instantS = { max: ismax, min: ismin }
|
||||||
|
const RMSF = { max: rfmax, min: rfmin }
|
||||||
|
const RMSS = { max: rsmax, min: rsmin }
|
||||||
|
const RMSFMinDetail = { rmsvFirstX, rmsvFirstY, firstZhou }
|
||||||
|
const RMSSMinDetail = { rmsvSecondX, rmsvSecondY, secondeZhou }
|
||||||
|
const shunshiF = { shunshiFA, shunshiFB, shunshiFC }
|
||||||
|
const shunshiS = { shunshiSA, shunshiSB, shunshiSC }
|
||||||
|
const RMSFWave = { rmsFA, rmsFB, rmsFC }
|
||||||
|
const RMSSWave = { rmsSA, rmsSB, rmsSC }
|
||||||
|
const title = { aTitle, bTitle, cTitle, unit }
|
||||||
|
|
||||||
|
return {
|
||||||
|
instantF,
|
||||||
|
instantS,
|
||||||
|
RMSF,
|
||||||
|
RMSS,
|
||||||
|
RMSFMinDetail,
|
||||||
|
RMSSMinDetail,
|
||||||
|
shunshiF,
|
||||||
|
shunshiS,
|
||||||
|
RMSFWave,
|
||||||
|
RMSSWave,
|
||||||
|
title,
|
||||||
|
unit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 监听消息
|
||||||
|
self.onmessage = function (e) {
|
||||||
|
const { wp, isOpen, value, boxoList } = JSON.parse(e.data)
|
||||||
|
|
||||||
|
try {
|
||||||
|
const iphasicValue = wp.iphasic || 1
|
||||||
|
|
||||||
|
const picCounts = (wp.waveTitle.length - 1) / iphasicValue
|
||||||
|
const waveDatas = []
|
||||||
|
|
||||||
|
for (let i = 0; i < picCounts; i++) {
|
||||||
|
const data = fliteWaveData(wp, i, iphasicValue, isOpen, boxoList)
|
||||||
|
waveDatas.push(data)
|
||||||
|
}
|
||||||
|
// 处理标题
|
||||||
|
let titles = ''
|
||||||
|
if (boxoList.systemType == 'pms') {
|
||||||
|
titles =
|
||||||
|
'变电站名称:' +
|
||||||
|
boxoList.powerStationName +
|
||||||
|
' 监测点名称:' +
|
||||||
|
boxoList.measurementPointName +
|
||||||
|
' 发生时刻:' +
|
||||||
|
boxoList.startTime +
|
||||||
|
' 暂降(骤升)幅值:' +
|
||||||
|
(boxoList.featureAmplitude * 100).toFixed(2) +
|
||||||
|
'% 持续时间:' +
|
||||||
|
boxoList.duration +
|
||||||
|
's'
|
||||||
|
} else if (boxoList.systemType == 'ZL') {
|
||||||
|
titles =
|
||||||
|
(boxoList.engineeringName == undefined ? '' : ' 项目名称:' + boxoList.engineeringName) +
|
||||||
|
' 项目名称:' +
|
||||||
|
boxoList.engineeringName +
|
||||||
|
' 监测点名称:' +
|
||||||
|
boxoList.equipmentName +
|
||||||
|
' 发生时刻:' +
|
||||||
|
boxoList.startTime +
|
||||||
|
' 暂降(骤升)幅值:' +
|
||||||
|
boxoList.evtParamVVaDepth +
|
||||||
|
'% 持续时间:' +
|
||||||
|
boxoList.evtParamTm +
|
||||||
|
's'
|
||||||
|
} else if (boxoList.systemType == 'YPT') {
|
||||||
|
titles =
|
||||||
|
(boxoList.engineeringName == undefined ? '' : ' 项目名称:' + boxoList.engineeringName) +
|
||||||
|
' 项目名称:' +
|
||||||
|
boxoList.engineeringName +
|
||||||
|
' 监测点名称:' +
|
||||||
|
boxoList.lineName +
|
||||||
|
' 发生时刻:' +
|
||||||
|
boxoList.startTime +
|
||||||
|
' 暂降(骤升)幅值:' +
|
||||||
|
(boxoList.featureAmplitude * 100).toFixed(2) +
|
||||||
|
'% 持续时间:' +
|
||||||
|
boxoList.persistTime +
|
||||||
|
's'
|
||||||
|
} else {
|
||||||
|
titles =
|
||||||
|
'变电站名称:' +
|
||||||
|
boxoList.subName +
|
||||||
|
' 监测点名称:' +
|
||||||
|
boxoList.lineName +
|
||||||
|
' 发生时刻:' +
|
||||||
|
boxoList.startTime +
|
||||||
|
' 暂降(骤升)幅值:' +
|
||||||
|
(boxoList.featureAmplitude * 100).toFixed(2) +
|
||||||
|
'% 持续时间:' +
|
||||||
|
boxoList.duration +
|
||||||
|
's'
|
||||||
|
}
|
||||||
|
// 发送处理结果回主线程
|
||||||
|
self.postMessage({
|
||||||
|
titles: titles,
|
||||||
|
success: true,
|
||||||
|
waveDatas,
|
||||||
|
time: wp.time,
|
||||||
|
type: wp.waveType,
|
||||||
|
severity: wp.yzd,
|
||||||
|
iphasic: iphasicValue
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
self.postMessage({
|
||||||
|
success: false,
|
||||||
|
error: error.message
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
1596
src/components/echarts/rmsboxi1.vue
Normal file
1596
src/components/echarts/rmsboxi1.vue
Normal file
File diff suppressed because it is too large
Load Diff
205
src/components/echarts/shuWorker.js
Normal file
205
src/components/echarts/shuWorker.js
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
// waveData.worker.js
|
||||||
|
self.addEventListener('message', function (e) {
|
||||||
|
const { wp, value, iphasic, isOpen, boxoList } = JSON.parse(e.data)
|
||||||
|
|
||||||
|
// 处理波形数据的函数
|
||||||
|
const fliteWaveData = (wp, step) => {
|
||||||
|
// 将原有的fliteWaveData函数实现复制到这里
|
||||||
|
const shunData = wp.listWaveData
|
||||||
|
const pt = Number(wp.pt) / 1000
|
||||||
|
const ct = Number(wp.ct)
|
||||||
|
const titleList = wp.waveTitle
|
||||||
|
let xishu = pt
|
||||||
|
let aTitle = '',
|
||||||
|
bTitle = '',
|
||||||
|
cTitle = '',
|
||||||
|
unit = '电压'
|
||||||
|
let ifmax = 0,
|
||||||
|
ifmin = 0,
|
||||||
|
ismax = 0,
|
||||||
|
ismin = 0
|
||||||
|
|
||||||
|
const shunshiFA = []
|
||||||
|
const shunshiFB = []
|
||||||
|
const shunshiFC = []
|
||||||
|
const shunshiSA = []
|
||||||
|
const shunshiSB = []
|
||||||
|
const shunshiSC = []
|
||||||
|
|
||||||
|
if (shunData.length > 0) {
|
||||||
|
if (titleList[iphasic * step + 1]?.substring(0, 1) !== 'U') {
|
||||||
|
xishu = ct
|
||||||
|
unit = '电流'
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 1; i <= iphasic; i++) {
|
||||||
|
switch (i) {
|
||||||
|
case 1:
|
||||||
|
aTitle = titleList[iphasic * step + i]?.substring(1) || ''
|
||||||
|
break
|
||||||
|
case 2:
|
||||||
|
bTitle = titleList[iphasic * step + i]?.substring(1) || ''
|
||||||
|
break
|
||||||
|
case 3:
|
||||||
|
cTitle = titleList[iphasic * step + i]?.substring(1) || ''
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (shunData[0][iphasic * step + 1] !== undefined) {
|
||||||
|
ifmax = shunData[0][iphasic * step + 1] * xishu
|
||||||
|
ifmin = shunData[0][iphasic * step + 1] * xishu
|
||||||
|
ismax = shunData[0][iphasic * step + 1]
|
||||||
|
ismin = shunData[0][iphasic * step + 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let shun = 0; shun < shunData.length; shun++) {
|
||||||
|
if (shunData[shun][iphasic * step + 1] === undefined) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (iphasic) {
|
||||||
|
case 1:
|
||||||
|
const shunFirstA = shunData[shun][iphasic * step + 1] * xishu
|
||||||
|
shunshiFA.push([shunData[shun][0], shunFirstA])
|
||||||
|
ifmax = Math.max(ifmax, shunFirstA)
|
||||||
|
ifmin = Math.min(ifmin, shunFirstA)
|
||||||
|
|
||||||
|
const shunSecondA = shunData[shun][iphasic * step + 1]
|
||||||
|
shunshiSA.push([shunData[shun][0], shunSecondA])
|
||||||
|
ismax = Math.max(ismax, shunSecondA)
|
||||||
|
ismin = Math.min(ismin, shunSecondA)
|
||||||
|
break
|
||||||
|
case 2:
|
||||||
|
const shunFirstA2 = shunData[shun][iphasic * step + 1] * xishu
|
||||||
|
const shunFirstB2 = shunData[shun][iphasic * step + 2] * xishu
|
||||||
|
shunshiFA.push([shunData[shun][0], shunFirstA2])
|
||||||
|
shunshiFB.push([shunData[shun][0], shunFirstB2])
|
||||||
|
ifmax = Math.max(ifmax, shunFirstA2, shunFirstB2)
|
||||||
|
ifmin = Math.min(ifmin, shunFirstA2, shunFirstB2)
|
||||||
|
|
||||||
|
const shunSecondA2 = shunData[shun][iphasic * step + 1]
|
||||||
|
const shunSecondB2 = shunData[shun][iphasic * step + 2]
|
||||||
|
shunshiSA.push([shunData[shun][0], shunSecondA2])
|
||||||
|
shunshiSB.push([shunData[shun][0], shunSecondB2])
|
||||||
|
ismax = Math.max(ismax, shunSecondA2, shunSecondB2)
|
||||||
|
ismin = Math.min(ismin, shunSecondA2, shunSecondB2)
|
||||||
|
break
|
||||||
|
case 3:
|
||||||
|
const shunFirstA3 = shunData[shun][iphasic * step + 1] * xishu
|
||||||
|
const shunFirstB3 = shunData[shun][iphasic * step + 2] * xishu
|
||||||
|
const shunFirstC3 = shunData[shun][iphasic * step + 3] * xishu
|
||||||
|
shunshiFA.push([shunData[shun][0], shunFirstA3])
|
||||||
|
shunshiFB.push([shunData[shun][0], shunFirstB3])
|
||||||
|
shunshiFC.push([shunData[shun][0], shunFirstC3])
|
||||||
|
ifmax = Math.max(ifmax, shunFirstA3, shunFirstB3, shunFirstC3)
|
||||||
|
ifmin = isOpen
|
||||||
|
? Math.min(ifmin, shunFirstA3, shunFirstC3)
|
||||||
|
: Math.min(ifmin, shunFirstA3, shunFirstB3, shunFirstC3)
|
||||||
|
|
||||||
|
const shunSecondA3 = shunData[shun][iphasic * step + 1]
|
||||||
|
const shunSecondB3 = shunData[shun][iphasic * step + 2]
|
||||||
|
const shunSecondC3 = shunData[shun][iphasic * step + 3]
|
||||||
|
shunshiSA.push([shunData[shun][0], shunSecondA3])
|
||||||
|
shunshiSB.push([shunData[shun][0], shunSecondB3])
|
||||||
|
shunshiSC.push([shunData[shun][0], shunSecondC3])
|
||||||
|
ismax = Math.max(ismax, shunSecondA3, shunSecondB3, shunSecondC3)
|
||||||
|
ismin = isOpen
|
||||||
|
? Math.min(ismin, shunSecondA3, shunSecondC3)
|
||||||
|
: Math.min(ismin, shunSecondA3, shunSecondB3, shunSecondC3)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const instantF = { max: ifmax, min: ifmin }
|
||||||
|
const instantS = { max: ismax, min: ismin }
|
||||||
|
const shunshiF = { shunshiFA, shunshiFB, shunshiFC }
|
||||||
|
const shunshiS = { shunshiSA, shunshiSB, shunshiSC }
|
||||||
|
const title = { aTitle, bTitle, cTitle, unit }
|
||||||
|
|
||||||
|
return { instantF, instantS, shunshiF, shunshiS, title, unit }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理标题
|
||||||
|
let titles = ''
|
||||||
|
if (boxoList.systemType == 'pms') {
|
||||||
|
titles =
|
||||||
|
'变电站名称:' +
|
||||||
|
boxoList.powerStationName +
|
||||||
|
' 监测点名称:' +
|
||||||
|
boxoList.measurementPointName +
|
||||||
|
' 发生时刻:' +
|
||||||
|
boxoList.startTime +
|
||||||
|
' 暂降(骤升)幅值:' +
|
||||||
|
(boxoList.featureAmplitude * 100).toFixed(2) +
|
||||||
|
'% 持续时间:' +
|
||||||
|
boxoList.duration +
|
||||||
|
's'
|
||||||
|
} else if (boxoList.systemType == 'ZL') {
|
||||||
|
titles =
|
||||||
|
(boxoList.engineeringName == undefined ? '' : ' 项目名称:' + boxoList.engineeringName) +
|
||||||
|
' 监测点名称:' +
|
||||||
|
boxoList.equipmentName +
|
||||||
|
' 发生时刻:' +
|
||||||
|
boxoList.startTime +
|
||||||
|
' 暂降(骤升)幅值:' +
|
||||||
|
boxoList.evtParamVVaDepth +
|
||||||
|
'% 持续时间:' +
|
||||||
|
boxoList.evtParamTm +
|
||||||
|
's'
|
||||||
|
} else if (boxoList.systemType == 'YPT') {
|
||||||
|
titles =
|
||||||
|
(boxoList.engineeringName == undefined ? '' : ' 项目名称:' + boxoList.engineeringName) +
|
||||||
|
' 监测点名称:' +
|
||||||
|
boxoList.lineName +
|
||||||
|
' 发生时刻:' +
|
||||||
|
boxoList.startTime +
|
||||||
|
' 暂降(骤升)幅值:' +
|
||||||
|
(boxoList.featureAmplitude * 100).toFixed(2) +
|
||||||
|
'% 持续时间:' +
|
||||||
|
boxoList.persistTime +
|
||||||
|
's'
|
||||||
|
} else {
|
||||||
|
titles =
|
||||||
|
'变电站名称:' +
|
||||||
|
boxoList.subName +
|
||||||
|
' 监测点名称:' +
|
||||||
|
boxoList.lineName +
|
||||||
|
' 发生时刻:' +
|
||||||
|
boxoList.startTime +
|
||||||
|
' 暂降(骤升)幅值:' +
|
||||||
|
(boxoList.featureAmplitude * 100).toFixed(2) +
|
||||||
|
'% 持续时间:' +
|
||||||
|
boxoList.duration +
|
||||||
|
's'
|
||||||
|
}
|
||||||
|
|
||||||
|
const iphasicValue = wp.iphasic || 1
|
||||||
|
const picCounts = (wp.waveTitle.length - 1) / iphasicValue
|
||||||
|
const waveDatas = []
|
||||||
|
|
||||||
|
for (let i = 0; i < picCounts; i++) {
|
||||||
|
const data = fliteWaveData(wp, i)
|
||||||
|
waveDatas.push(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
const time = wp.time
|
||||||
|
const type = wp.waveType
|
||||||
|
let severity = wp.yzd
|
||||||
|
|
||||||
|
if (severity < 0) {
|
||||||
|
severity = '/'
|
||||||
|
type = '/'
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将处理结果发送回主线程
|
||||||
|
self.postMessage({
|
||||||
|
waveDatas,
|
||||||
|
time,
|
||||||
|
type,
|
||||||
|
severity,
|
||||||
|
titles,
|
||||||
|
iphasic: iphasicValue
|
||||||
|
})
|
||||||
|
})
|
||||||
File diff suppressed because it is too large
Load Diff
1201
src/components/echarts/shushiboxi1.vue
Normal file
1201
src/components/echarts/shushiboxi1.vue
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,26 @@
|
|||||||
<template>
|
<template>
|
||||||
<div style="width: 540px">
|
<div style="width: 540px">
|
||||||
<el-select v-model.trim="interval" style="min-width: 90px; width: 90px; margin-right: 10px"
|
<el-select
|
||||||
@change="timeChange">
|
v-model.trim="interval"
|
||||||
<el-option v-for="item in timeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
style="min-width: 90px; width: 90px; margin-right: 10px"
|
||||||
|
@change="timeChange"
|
||||||
|
>
|
||||||
|
<el-option v-for="item in filteredTimeOptions" :key="item.value" :label="item.label" :value="item.value" />
|
||||||
</el-select>
|
</el-select>
|
||||||
|
<el-date-picker
|
||||||
|
v-model.trim="timeValue"
|
||||||
|
type="daterange"
|
||||||
|
:disabled="disabledPicker"
|
||||||
|
style="width: 220px; margin-right: 10px"
|
||||||
|
unlink-panels
|
||||||
|
:clearable="false"
|
||||||
|
range-separator="至"
|
||||||
|
start-placeholder="开始日期"
|
||||||
|
end-placeholder="结束日期"
|
||||||
|
value-format="YYYY-MM-DD"
|
||||||
|
:shortcuts="shortcuts"
|
||||||
|
/>
|
||||||
|
|
||||||
<el-date-picker v-model.trim="timeValue" type="daterange" :disabled="disabledPicker"
|
|
||||||
style="width: 220px; margin-right: 10px" unlink-panels :clearable="false" range-separator="至"
|
|
||||||
start-placeholder="开始日期" end-placeholder="结束日期" value-format="YYYY-MM-DD" :shortcuts="shortcuts" />
|
|
||||||
<el-button :disabled="backDisabled" type="primary" :icon="DArrowLeft" @click="preClick"></el-button>
|
<el-button :disabled="backDisabled" type="primary" :icon="DArrowLeft" @click="preClick"></el-button>
|
||||||
<el-button type="primary" :icon="VideoPause" @click="nowTime">当前</el-button>
|
<el-button type="primary" :icon="VideoPause" @click="nowTime">当前</el-button>
|
||||||
<el-button :disabled="preDisabled" type="primary" :icon="DArrowRight" @click="next"></el-button>
|
<el-button :disabled="preDisabled" type="primary" :icon="DArrowRight" @click="next"></el-button>
|
||||||
@@ -21,13 +34,21 @@ import { ref, onMounted, nextTick, watch } from 'vue'
|
|||||||
interface Props {
|
interface Props {
|
||||||
nextFlag?: boolean
|
nextFlag?: boolean
|
||||||
theCurrentTime?: boolean
|
theCurrentTime?: boolean
|
||||||
|
initialInterval?: number
|
||||||
|
initialTimeValue?: any
|
||||||
|
timeKeyList?: string[] //日期下拉
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
nextFlag: false,
|
nextFlag: false,
|
||||||
theCurrentTime: true
|
theCurrentTime: true,
|
||||||
|
initialInterval: 3,
|
||||||
|
initialTimeValue: undefined,
|
||||||
|
timeKeyList: () => []
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['change'])
|
||||||
|
|
||||||
const interval = ref(3)
|
const interval = ref(3)
|
||||||
const timeFlag = ref(1)
|
const timeFlag = ref(1)
|
||||||
const count = ref(0)
|
const count = ref(0)
|
||||||
@@ -71,17 +92,67 @@ const shortcuts = [
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
// 计算过滤后的 timeOptions
|
||||||
|
const filteredTimeOptions = computed(() => {
|
||||||
|
if (!props.timeKeyList || props.timeKeyList.length === 0) {
|
||||||
|
return timeOptions.value
|
||||||
|
}
|
||||||
|
|
||||||
|
return timeOptions.value.filter((option: any) => props.timeKeyList.includes(option.value.toString()))
|
||||||
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
// 使用传入的初始值
|
||||||
|
if (props.initialInterval !== undefined) {
|
||||||
|
interval.value = props.initialInterval
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.initialTimeValue) {
|
||||||
|
timeValue.value = props.initialTimeValue
|
||||||
|
}
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
// 初始化时检查按钮状态
|
||||||
|
checkInitialButtonStatus()
|
||||||
|
})
|
||||||
|
|
||||||
timeChange(3)
|
timeChange(3)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 添加初始化按钮状态检查方法
|
||||||
|
const checkInitialButtonStatus = () => {
|
||||||
|
if (timeValue.value && timeValue.value.length >= 2) {
|
||||||
|
const endTime = timeValue.value[1]
|
||||||
|
const currentDate = window.XEUtils.toDateString(new Date(), 'yyyy-MM-dd')
|
||||||
|
|
||||||
|
// 只有当 props.nextFlag 为 false 时才应用限制
|
||||||
|
if (!props.nextFlag) {
|
||||||
|
// 如果结束时间早于当前日期,则按钮可用(preDisabled = false)
|
||||||
|
// 如果结束时间晚于或等于当前日期,则按钮禁用(preDisabled = true)
|
||||||
|
const endDateTime = new Date(endTime).getTime()
|
||||||
|
const currentDateTime = new Date(currentDate).getTime()
|
||||||
|
preDisabled.value = endDateTime >= currentDateTime
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 添加统一的事件触发方法
|
||||||
|
const emitChange = () => {
|
||||||
|
nextTick(() => {
|
||||||
|
emit('change', {
|
||||||
|
interval: interval.value,
|
||||||
|
timeValue: timeValue.value,
|
||||||
|
timeFlag: timeFlag.value
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
// 选择时间范围
|
// 选择时间范围
|
||||||
const timeChange = (e: number) => {
|
const timeChange = (e: number) => {
|
||||||
backDisabled.value = false
|
backDisabled.value = false
|
||||||
preDisabled.value = true
|
|
||||||
count.value = 0
|
count.value = 0
|
||||||
if (e == 1) {
|
if (e == 1) {
|
||||||
disabledPicker.value = true
|
disabledPicker.value = true
|
||||||
|
|
||||||
timeValue.value = [setTime(1), setTime()]
|
timeValue.value = [setTime(1), setTime()]
|
||||||
} else if (e == 2) {
|
} else if (e == 2) {
|
||||||
disabledPicker.value = true
|
disabledPicker.value = true
|
||||||
@@ -102,7 +173,6 @@ const timeChange = (e: number) => {
|
|||||||
} else if (e == 5) {
|
} else if (e == 5) {
|
||||||
disabledPicker.value = false
|
disabledPicker.value = false
|
||||||
backDisabled.value = true
|
backDisabled.value = true
|
||||||
preDisabled.value = true
|
|
||||||
timeValue.value = [setTime(), setTime()]
|
timeValue.value = [setTime(), setTime()]
|
||||||
}
|
}
|
||||||
if (e == 1 || e == 2) {
|
if (e == 1 || e == 2) {
|
||||||
@@ -110,6 +180,14 @@ const timeChange = (e: number) => {
|
|||||||
} else {
|
} else {
|
||||||
timeFlag.value = 1
|
timeFlag.value = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nextTick(() => {
|
||||||
|
// 检查按钮状态
|
||||||
|
checkInitialButtonStatus()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 触发 change 事件
|
||||||
|
emitChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 当前
|
// 当前
|
||||||
@@ -178,6 +256,9 @@ const preClick = () => {
|
|||||||
// 判断向后键的状态
|
// 判断向后键的状态
|
||||||
// var temp = NowgetEndTime()
|
// var temp = NowgetEndTime()
|
||||||
// timeStatus(temp, endTime)
|
// timeStatus(temp, endTime)
|
||||||
|
|
||||||
|
// 触发 change 事件
|
||||||
|
emitChange()
|
||||||
}
|
}
|
||||||
//下一个
|
//下一个
|
||||||
const next = () => {
|
const next = () => {
|
||||||
@@ -383,7 +464,6 @@ const next = () => {
|
|||||||
if (year >= presentY && !props.nextFlag) {
|
if (year >= presentY && !props.nextFlag) {
|
||||||
startTime = presentY + '-01-01'
|
startTime = presentY + '-01-01'
|
||||||
if (presentM < 10) {
|
if (presentM < 10) {
|
||||||
|
|
||||||
if (presentD < 10) {
|
if (presentD < 10) {
|
||||||
endTime = presentY + '-0' + presentM + '-0' + presentD
|
endTime = presentY + '-0' + presentM + '-0' + presentD
|
||||||
} else {
|
} else {
|
||||||
@@ -400,18 +480,31 @@ const next = () => {
|
|||||||
startTime = year + '-01-01'
|
startTime = year + '-01-01'
|
||||||
endTime = year + '-12-31'
|
endTime = year + '-12-31'
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
if (!props.nextFlag) {
|
if (!props.nextFlag) {
|
||||||
if (new Date(endTime + ' 00:00:00').getTime() >= new Date(window.XEUtils.toDateString(new Date(), 'yyyy-MM-dd ') + ' 00:00:00').getTime()) {
|
if (
|
||||||
|
new Date(endTime + ' 00:00:00').getTime() >=
|
||||||
|
new Date(window.XEUtils.toDateString(new Date(), 'yyyy-MM-dd ') + ' 00:00:00').getTime()
|
||||||
|
) {
|
||||||
preDisabled.value = true
|
preDisabled.value = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
timeValue.value = [startTime, endTime]
|
timeValue.value = [startTime, endTime]
|
||||||
|
|
||||||
|
// 触发 change 事件
|
||||||
|
emitChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 监听值变化并触发事件
|
||||||
|
watch(
|
||||||
|
[interval, timeValue],
|
||||||
|
() => {
|
||||||
|
emitChange()
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
)
|
||||||
|
|
||||||
const setTime = (flag = 0, e = 0) => {
|
const setTime = (flag = 0, e = 0) => {
|
||||||
let dd = window.XEUtils.toDateString(new Date().getTime() - e * 3600 * 1000 * 24, 'dd')
|
let dd = window.XEUtils.toDateString(new Date().getTime() - e * 3600 * 1000 * 24, 'dd')
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,13 @@
|
|||||||
:inline="true"
|
:inline="true"
|
||||||
>
|
>
|
||||||
<el-form-item label="日期" v-if="datePicker" style="grid-column: span 2; max-width: 570px">
|
<el-form-item label="日期" v-if="datePicker" style="grid-column: span 2; max-width: 570px">
|
||||||
<DatePicker ref="datePickerRef" :nextFlag="nextFlag" :theCurrentTime="theCurrentTime"></DatePicker>
|
<DatePicker
|
||||||
|
ref="datePickerRef"
|
||||||
|
:nextFlag="nextFlag"
|
||||||
|
:theCurrentTime="theCurrentTime"
|
||||||
|
@change="handleDatePickerChange"
|
||||||
|
:timeKeyList="props.timeKeyList"
|
||||||
|
></DatePicker>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
|
||||||
<el-form-item label="区域" v-if="area">
|
<el-form-item label="区域" v-if="area">
|
||||||
@@ -57,6 +63,9 @@ import { mainHeight } from '@/utils/layout'
|
|||||||
import { useDictData } from '@/stores/dictData'
|
import { useDictData } from '@/stores/dictData'
|
||||||
import { Search, RefreshLeft } from '@element-plus/icons-vue'
|
import { Search, RefreshLeft } from '@element-plus/icons-vue'
|
||||||
import { defineProps } from 'vue'
|
import { defineProps } from 'vue'
|
||||||
|
import { useTimeCacheStore } from '@/stores/timeCache'
|
||||||
|
import { useRoute } from 'vue-router'
|
||||||
|
|
||||||
const emit = defineEmits(['selectChange'])
|
const emit = defineEmits(['selectChange'])
|
||||||
|
|
||||||
const tableStore = inject('tableStore') as TableStore
|
const tableStore = inject('tableStore') as TableStore
|
||||||
@@ -67,6 +76,11 @@ const areaRef = ref()
|
|||||||
const headerForm = ref()
|
const headerForm = ref()
|
||||||
const headerFormSecond = ref()
|
const headerFormSecond = ref()
|
||||||
const num = ref(0)
|
const num = ref(0)
|
||||||
|
|
||||||
|
// 获取路由和缓存 store
|
||||||
|
const route = useRoute()
|
||||||
|
const timeCacheStore = useTimeCacheStore()
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
datePicker?: boolean
|
datePicker?: boolean
|
||||||
area?: boolean
|
area?: boolean
|
||||||
@@ -75,6 +89,8 @@ interface Props {
|
|||||||
theCurrentTime?: boolean //控制时间前3天展示上个月时间
|
theCurrentTime?: boolean //控制时间前3天展示上个月时间
|
||||||
showReset?: boolean //是否显示重置
|
showReset?: boolean //是否显示重置
|
||||||
showExport?: boolean //导出控制
|
showExport?: boolean //导出控制
|
||||||
|
timeCacheFlag?: boolean //是否取缓存时间
|
||||||
|
timeKeyList?: string[] //日期下拉列表
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
@@ -84,8 +100,22 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
nextFlag: false,
|
nextFlag: false,
|
||||||
theCurrentTime: true,
|
theCurrentTime: true,
|
||||||
showReset: true,
|
showReset: true,
|
||||||
showExport: false
|
showExport: false,
|
||||||
|
timeCacheFlag: true,
|
||||||
|
timeKeyList: () => ['1', '2', '3', '4', '5'] // 修改为箭头函数返回空数组
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// 处理 DatePicker 值变化事件
|
||||||
|
const handleDatePickerChange = (value: any) => {
|
||||||
|
// 将值缓存到 timeCache
|
||||||
|
// if (value) {
|
||||||
|
// timeCacheStore.setCache(route.path, value.interval, value.timeValue)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 将 datePicker 的变化传递给父组件
|
||||||
|
emit('selectChange', true, tableHeader.value.offsetHeight, value)
|
||||||
|
}
|
||||||
|
|
||||||
// 动态计算table高度
|
// 动态计算table高度
|
||||||
let resizeObserver = new ResizeObserver(entries => {
|
let resizeObserver = new ResizeObserver(entries => {
|
||||||
for (const entry of entries) {
|
for (const entry of entries) {
|
||||||
@@ -105,16 +135,31 @@ const headerFormSecondStyleClose = {
|
|||||||
padding: '0'
|
padding: '0'
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
if (props.datePicker && tableStore) {
|
// 设置初始值到 DatePicker
|
||||||
tableStore.table.params.searchBeginTime = datePickerRef.value?.timeValue[0]
|
if (props.datePicker && datePickerRef.value) {
|
||||||
tableStore.table.params.searchEndTime = datePickerRef.value?.timeValue[1]
|
// 从缓存中获取值并设置
|
||||||
tableStore.table.params.startTime = datePickerRef.value?.timeValue[0]
|
const cached = timeCacheStore.getCache(route.path)
|
||||||
tableStore.table.params.endTime = datePickerRef.value?.timeValue[1]
|
if (props.timeCacheFlag && cached) {
|
||||||
|
if (cached.interval !== undefined) {
|
||||||
|
datePickerRef.value.setInterval(cached.interval)
|
||||||
|
}
|
||||||
|
if (cached.timeValue) {
|
||||||
|
datePickerRef.value.timeValue = cached.timeValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新 tableStore 参数
|
||||||
|
tableStore.table.params.searchBeginTime = datePickerRef.value?.timeValue?.[0]
|
||||||
|
tableStore.table.params.searchEndTime = datePickerRef.value?.timeValue?.[1]
|
||||||
|
tableStore.table.params.startTime = datePickerRef.value?.timeValue?.[0]
|
||||||
|
tableStore.table.params.endTime = datePickerRef.value?.timeValue?.[1]
|
||||||
tableStore.table.params.timeFlag = datePickerRef.value?.timeFlag
|
tableStore.table.params.timeFlag = datePickerRef.value?.timeFlag
|
||||||
}
|
}
|
||||||
|
|
||||||
if (props.area) {
|
if (props.area) {
|
||||||
tableStore.table.params.deptIndex = dictData.state.area[0].id
|
tableStore.table.params.deptIndex = dictData.state.area[0].id
|
||||||
}
|
}
|
||||||
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
resizeObserver.observe(tableHeader.value)
|
resizeObserver.observe(tableHeader.value)
|
||||||
computedSearchRow()
|
computedSearchRow()
|
||||||
@@ -189,12 +234,29 @@ const onResetForm = () => {
|
|||||||
const setInterval = (val: any) => {
|
const setInterval = (val: any) => {
|
||||||
datePickerRef.value.setInterval(val)
|
datePickerRef.value.setInterval(val)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const setTimeInterval = (val: any) => {
|
||||||
|
datePickerRef.value.timeValue = val
|
||||||
|
tableStore.table.params.searchBeginTime = val[0]
|
||||||
|
tableStore.table.params.searchEndTime = val[1]
|
||||||
|
tableStore.table.params.startTime = val[0]
|
||||||
|
tableStore.table.params.endTime = val[1]
|
||||||
|
}
|
||||||
// 导出
|
// 导出
|
||||||
const onExport = () => {
|
const onExport = () => {
|
||||||
tableStore.onTableAction('export', { showAllFlag: true })
|
tableStore.onTableAction('export', { showAllFlag: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
defineExpose({ onComSearch, areaRef, setDatePicker, setInterval, datePickerRef, showSelectChange, computedSearchRow })
|
defineExpose({
|
||||||
|
onComSearch,
|
||||||
|
areaRef,
|
||||||
|
setDatePicker,
|
||||||
|
setInterval,
|
||||||
|
setTimeInterval,
|
||||||
|
datePickerRef,
|
||||||
|
showSelectChange,
|
||||||
|
computedSearchRow
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -1,24 +1,45 @@
|
|||||||
<template>
|
<template>
|
||||||
<div :style="{ height: typeof props.height === 'string' ? props.height : tableStore.table.height }">
|
<div :style="{ height: typeof props.height === 'string' ? props.height : tableStore.table.height }">
|
||||||
<vxe-table ref="tableRef" height="auto" :key="key" :data="tableStore.table.data"
|
<vxe-table
|
||||||
v-loading="tableStore.table.loading" v-bind="Object.assign({}, defaultAttribute, $attrs)"
|
ref="tableRef"
|
||||||
@checkbox-all="selectChangeEvent" @checkbox-change="selectChangeEvent" :showOverflow="showOverflow"
|
height="auto"
|
||||||
:sort-config="{ remote: true }" @sort-change="handleSortChange">
|
:key="key"
|
||||||
|
:data="tableStore.table.data"
|
||||||
|
v-loading="tableStore.table.loading"
|
||||||
|
v-bind="Object.assign({}, defaultAttribute, $attrs)"
|
||||||
|
@checkbox-all="selectChangeEvent"
|
||||||
|
@checkbox-change="selectChangeEvent"
|
||||||
|
:showOverflow="showOverflow"
|
||||||
|
:sort-config="{ remote: true }"
|
||||||
|
@sort-change="handleSortChange"
|
||||||
|
>
|
||||||
|
|
||||||
<!-- Column 组件内部是 el-table-column -->
|
<!-- Column 组件内部是 el-table-column -->
|
||||||
<template v-if="isGroup">
|
<template v-if="isGroup">
|
||||||
<GroupColumn :column="tableStore.table.column" />
|
<GroupColumn :column="tableStore.table.column" />
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<Column :attr="item" :key="key + '-column'" v-for="(item, key) in tableStore.table.column"
|
<Column
|
||||||
:tree-node="item.treeNode">
|
:attr="item"
|
||||||
|
:key="key + '-column'"
|
||||||
|
v-for="(item, key) in tableStore.table.column"
|
||||||
|
:tree-node="item.treeNode"
|
||||||
|
>
|
||||||
<!-- tableStore 预设的列 render 方案 -->
|
<!-- tableStore 预设的列 render 方案 -->
|
||||||
<template v-if="item.render" #default="scope">
|
<template v-if="item.render" #default="scope">
|
||||||
<FieldRender :field="item" :row="scope.row" :column="scope.column" :index="scope.rowIndex" :key="key +
|
<FieldRender
|
||||||
'-' +
|
:field="item"
|
||||||
item.render +
|
:row="scope.row"
|
||||||
'-' +
|
:column="scope.column"
|
||||||
(item.field ? '-' + item.field + '-' + scope.row[item.field] : '')
|
:index="scope.rowIndex"
|
||||||
" />
|
:key="
|
||||||
|
key +
|
||||||
|
'-' +
|
||||||
|
item.render +
|
||||||
|
'-' +
|
||||||
|
(item.field ? '-' + item.field + '-' + scope.row[item.field] : '')
|
||||||
|
"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
</Column>
|
</Column>
|
||||||
</template>
|
</template>
|
||||||
@@ -27,11 +48,16 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="tableStore.showPage" class="table-pagination">
|
<div v-if="tableStore.showPage" class="table-pagination">
|
||||||
<el-pagination :currentPage="tableStore.table.params!.pageNum" :page-size="tableStore.table.params!.pageSize"
|
<el-pagination
|
||||||
:page-sizes="pageSizes" background
|
:currentPage="tableStore.table.params!.pageNum"
|
||||||
|
:page-size="tableStore.table.params!.pageSize"
|
||||||
|
:page-sizes="pageSizes"
|
||||||
|
background
|
||||||
:layout="config.layout.shrink ? 'prev, next, jumper' : 'sizes,total, ->, prev, pager, next, jumper'"
|
:layout="config.layout.shrink ? 'prev, next, jumper' : 'sizes,total, ->, prev, pager, next, jumper'"
|
||||||
:total="tableStore.table.total" @size-change="onTableSizeChange"
|
:total="tableStore.table.total"
|
||||||
@current-change="onTableCurrentChange"></el-pagination>
|
@size-change="onTableSizeChange"
|
||||||
|
@current-change="onTableCurrentChange"
|
||||||
|
></el-pagination>
|
||||||
</div>
|
</div>
|
||||||
<slot name="footer"></slot>
|
<slot name="footer"></slot>
|
||||||
</template>
|
</template>
|
||||||
@@ -66,6 +92,8 @@ const props = withDefaults(defineProps<Props>(), {
|
|||||||
})
|
})
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
tableStore.table.ref = tableRef.value as VxeTableInstance
|
tableStore.table.ref = tableRef.value as VxeTableInstance
|
||||||
|
|
||||||
|
|
||||||
})
|
})
|
||||||
// console.log(props)
|
// console.log(props)
|
||||||
const onTableSizeChange = (val: number) => {
|
const onTableSizeChange = (val: number) => {
|
||||||
@@ -125,6 +153,7 @@ watch(
|
|||||||
() => tableStore.table.allFlag,
|
() => tableStore.table.allFlag,
|
||||||
newVal => {
|
newVal => {
|
||||||
if (tableStore.table.allFlag) {
|
if (tableStore.table.allFlag) {
|
||||||
|
console.log('🚀 ~ tableStore.table.allData:', tableStore.table.allData)
|
||||||
|
|
||||||
tableRef.value?.exportData({
|
tableRef.value?.exportData({
|
||||||
filename: tableStore.exportName || document.querySelectorAll('.ba-nav-tab.active')[0].textContent || '', // 文件名字
|
filename: tableStore.exportName || document.querySelectorAll('.ba-nav-tab.active')[0].textContent || '', // 文件名字
|
||||||
|
|||||||
187
src/components/tree/allocation.vue
Normal file
187
src/components/tree/allocation.vue
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
<template>
|
||||||
|
<div :style="{ width: menuCollapse ? '40px' : props.width }" style="transition: all 0.3s; overflow: hidden">
|
||||||
|
<div class="mt15 mr10" style="display: flex; justify-content: end">
|
||||||
|
<el-button type="primary" icon="el-icon-Select" @click="save" :loading="loading">保存</el-button>
|
||||||
|
</div>
|
||||||
|
<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"
|
||||||
|
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" show-word-limit v-model.trim="filterText" placeholder="请输入内容" clearable>
|
||||||
|
<template #prefix>
|
||||||
|
<Icon name="el-icon-Search" style="font-size: 16px" />
|
||||||
|
</template>
|
||||||
|
</el-input>
|
||||||
|
<el-tooltip placement="bottom" :hide-after="0" v-if="props.showPush">
|
||||||
|
<template #content>
|
||||||
|
<span>台账推送</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<Icon
|
||||||
|
name="el-icon-Promotion"
|
||||||
|
size="20"
|
||||||
|
class="fold ml10 menu-collapse"
|
||||||
|
style="cursor: pointer"
|
||||||
|
:style="{ color: config.getColorVal('elementUiPrimary') }"
|
||||||
|
@click="onAdd"
|
||||||
|
/>
|
||||||
|
</el-tooltip>
|
||||||
|
<!-- <Icon @click='onMenuCollapse' :name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'" v-else
|
||||||
|
:class="menuCollapse ? 'unfold' : ''" size='18' class='fold ml10 menu-collapse'
|
||||||
|
style='cursor: pointer' v-if='props.canExpand' /> -->
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<el-tree
|
||||||
|
:style="{ height: 'calc(100vh - 235px)' }"
|
||||||
|
style="overflow: auto"
|
||||||
|
ref="treeRef"
|
||||||
|
:props="defaultProps"
|
||||||
|
highlight-current
|
||||||
|
:default-expand-all="false"
|
||||||
|
@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>
|
||||||
|
</template>
|
||||||
|
</el-tree>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import useCurrentInstance from '@/utils/useCurrentInstance'
|
||||||
|
import { ElTree } from 'element-plus'
|
||||||
|
import { emit } from 'process'
|
||||||
|
import { ref, watch } from 'vue'
|
||||||
|
import { t } from 'vxe-table'
|
||||||
|
import { useConfig } from '@/stores/config'
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'govern/tree'
|
||||||
|
})
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
width?: string
|
||||||
|
canExpand?: boolean
|
||||||
|
showPush?: boolean
|
||||||
|
}
|
||||||
|
const loading = ref(false)
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
width: '280px',
|
||||||
|
canExpand: true,
|
||||||
|
showPush: false
|
||||||
|
})
|
||||||
|
const config = useConfig()
|
||||||
|
const { proxy } = useCurrentInstance()
|
||||||
|
const menuCollapse = ref(false)
|
||||||
|
const filterText = ref('')
|
||||||
|
const defaultProps = {
|
||||||
|
label: 'name',
|
||||||
|
value: 'id'
|
||||||
|
}
|
||||||
|
const emit = defineEmits(['checkTreeNodeChange', 'onAdd', 'checkChange'])
|
||||||
|
watch(filterText, val => {
|
||||||
|
treeRef.value!.filter(val)
|
||||||
|
})
|
||||||
|
const onMenuCollapse = () => {
|
||||||
|
menuCollapse.value = !menuCollapse.value
|
||||||
|
proxy.eventBus.emit('cnTreeCollapse', menuCollapse)
|
||||||
|
}
|
||||||
|
const save = () => {
|
||||||
|
loading.value = true
|
||||||
|
emit('checkChange')
|
||||||
|
}
|
||||||
|
const filterNode = (value: string, data: any, node: any) => {
|
||||||
|
console.log(value, data, node, 'filterNode')
|
||||||
|
if (!value) return true
|
||||||
|
// return data.name.includes(value)
|
||||||
|
if (data.name) {
|
||||||
|
return chooseNode(value, data, node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 过滤父节点 / 子节点 (如果输入的参数是父节点且能匹配,则返回该节点以及其下的所有子节点;如果参数是子节点,则返回该节点的父节点。name是中文字符,enName是英文字符.
|
||||||
|
const chooseNode = (value: string, data: any, node: any) => {
|
||||||
|
if (data.name.indexOf(value) !== -1) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
const level = node.level
|
||||||
|
// 如果传入的节点本身就是一级节点就不用校验了
|
||||||
|
if (level === 1) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
// 先取当前节点的父节点
|
||||||
|
let parentData = node.parent
|
||||||
|
// 遍历当前节点的父节点
|
||||||
|
let index = 0
|
||||||
|
while (index < level - 1) {
|
||||||
|
// 如果匹配到直接返回,此处name值是中文字符,enName是英文字符。判断匹配中英文过滤
|
||||||
|
if (parentData.data.name.indexOf(value) !== -1) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
// 否则的话再往上一层做匹配
|
||||||
|
parentData = parentData.parent
|
||||||
|
index++
|
||||||
|
}
|
||||||
|
// 没匹配到返回false
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
const checkTreeNodeChange = () => {
|
||||||
|
// console.log(treeRef.value?.getCheckedNodes(), "ikkkkkiisiiisis");
|
||||||
|
emit('checkTreeNodeChange', treeRef.value?.getCheckedNodes())
|
||||||
|
}
|
||||||
|
|
||||||
|
const onAdd = () => {
|
||||||
|
emit('onAdd')
|
||||||
|
}
|
||||||
|
|
||||||
|
const treeRef = ref<InstanceType<typeof ElTree>>()
|
||||||
|
defineExpose({ treeRef, loading })
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.cn-tree {
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 10px;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
:deep(.el-tree) {
|
||||||
|
border: 1px solid var(--el-border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
:deep(.el-tree--highlight-current .el-tree-node.is-current > .el-tree-node__content) {
|
||||||
|
background-color: var(--el-color-primary-light-7);
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-collapse {
|
||||||
|
color: var(--el-color-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-tree-node {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -14,8 +14,8 @@
|
|||||||
: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 - 200px)' }"
|
<el-tree :style="{ height: 'calc(100vh - 230px)' }"
|
||||||
style=' overflow: auto;' ref='treeRef' :props='defaultProps' highlight-current
|
style=' overflow: auto;' ref='treeRef' :props='defaultProps' highlight-current :default-expand-all="false"
|
||||||
@check-change="checkTreeNodeChange" :filter-node-method='filterNode' node-key='id' v-bind='$attrs'>
|
@check-change="checkTreeNodeChange" :filter-node-method='filterNode' node-key='id' v-bind='$attrs'>
|
||||||
<template #default='{ node, data }'>
|
<template #default='{ node, data }'>
|
||||||
<span class='custom-tree-node'>
|
<span class='custom-tree-node'>
|
||||||
@@ -32,7 +32,6 @@
|
|||||||
<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'
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
@@ -75,7 +74,6 @@ const filterNode = (value: string, data: any, node: any) => {
|
|||||||
|
|
||||||
// 过滤父节点 / 子节点 (如果输入的参数是父节点且能匹配,则返回该节点以及其下的所有子节点;如果参数是子节点,则返回该节点的父节点。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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,27 +1,48 @@
|
|||||||
<!-- 设备管理使用折叠面板渲染多个tree -->
|
<!-- 设备管理使用折叠面板渲染多个tree -->
|
||||||
<template>
|
<template>
|
||||||
<div :style="{ width: menuCollapse ? '40px' : props.width }" style="display: flex; overflow: hidden">
|
<div :style="{ width: menuCollapse ? '40px' : props.width }" style="display: flex; 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"
|
||||||
|
:name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
|
||||||
|
:class="menuCollapse ? 'unfold' : ''"
|
||||||
|
size="18"
|
||||||
|
class="fold ml10 mt20 menu-collapse"
|
||||||
|
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-form-item> -->
|
<!-- <el-form-item> -->
|
||||||
<el-input maxlength="32" show-word-limit v-model.trim="filterText" autocomplete="off"
|
<el-input
|
||||||
placeholder="请输入内容" clearable>
|
maxlength="32"
|
||||||
|
show-word-limit
|
||||||
|
v-model.trim="filterText"
|
||||||
|
autocomplete="off"
|
||||||
|
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-form-item> -->
|
<!-- </el-form-item> -->
|
||||||
<Icon @click="onMenuCollapse" :name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
|
<Icon
|
||||||
:class="menuCollapse ? 'unfold' : ''" size="18" class="fold ml10 menu-collapse"
|
@click="onMenuCollapse"
|
||||||
style="cursor: pointer" v-if="props.canExpand" />
|
:name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
|
||||||
|
:class="menuCollapse ? 'unfold' : ''"
|
||||||
|
size="18"
|
||||||
|
class="fold ml10 menu-collapse"
|
||||||
|
style="cursor: pointer"
|
||||||
|
v-if="props.canExpand"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-collapse :accordion="true" v-model.trim="activeName" style="flex: 1; height: 100%"
|
<el-collapse
|
||||||
@change="changeDevice">
|
:accordion="true"
|
||||||
|
v-model.trim="activeName"
|
||||||
|
style="flex: 1; height: 100%"
|
||||||
|
@change="changeDevice"
|
||||||
|
>
|
||||||
<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">
|
||||||
<el-option label="功能调试" value="2"></el-option>
|
<el-option label="功能调试" value="2"></el-option>
|
||||||
@@ -29,13 +50,30 @@
|
|||||||
<el-option label="正式投运" value="4"></el-option>
|
<el-option label="正式投运" value="4"></el-option>
|
||||||
</el-select>
|
</el-select>
|
||||||
<el-tree
|
<el-tree
|
||||||
:style="{ height: bxsDeviceData.length != 0 ? 'calc(100vh - 340px)' : 'calc(100vh - 278px)' }"
|
:style="{
|
||||||
ref="treeRef1" :props="defaultProps" highlight-current :filter-node-method="filterNode"
|
height:
|
||||||
node-key="id" default-expand-all v-bind="$attrs" :data="zlDevList" style="overflow: auto">
|
bxsDeviceData.length != 0
|
||||||
|
? `calc(100vh - 380px - ${props.height}px)`
|
||||||
|
: 'calc(100vh - 278px)'
|
||||||
|
}"
|
||||||
|
ref="treeRef1"
|
||||||
|
:props="defaultProps"
|
||||||
|
highlight-current
|
||||||
|
:filter-node-method="filterNode"
|
||||||
|
node-key="id"
|
||||||
|
:default-expand-all="false"
|
||||||
|
v-bind="$attrs"
|
||||||
|
:data="zlDevList"
|
||||||
|
style="overflow: auto"
|
||||||
|
>
|
||||||
<template #default="{ node, data }">
|
<template #default="{ node, data }">
|
||||||
<span class="custom-tree-node">
|
<span class="custom-tree-node">
|
||||||
<Icon :name="data.icon" style="font-size: 16px" :style="{ color: data.color }"
|
<Icon
|
||||||
v-if="data.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 style="margin-left: 4px">{{ node.label }}</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
@@ -43,14 +81,30 @@
|
|||||||
</el-collapse-item>
|
</el-collapse-item>
|
||||||
<el-collapse-item title="便携式设备" name="1" v-if="bxsDeviceData.length != 0">
|
<el-collapse-item title="便携式设备" name="1" v-if="bxsDeviceData.length != 0">
|
||||||
<el-tree
|
<el-tree
|
||||||
:style="{ height: zlDeviceData.length != 0 ? 'calc(100vh - 280px)' : 'calc(100vh - 238px)' }"
|
:style="{
|
||||||
ref="treeRef2" :props="defaultProps" highlight-current default-expand-all
|
height:
|
||||||
:filter-node-method="filterNode" node-key="id" :data="bxsDeviceData" v-bind="$attrs"
|
zlDeviceData.length != 0
|
||||||
style="overflow: auto">
|
? `calc(100vh - 340px - ${props.height}px)`
|
||||||
|
: 'calc(100vh - 238px)'
|
||||||
|
}"
|
||||||
|
ref="treeRef2"
|
||||||
|
:props="defaultProps"
|
||||||
|
highlight-current
|
||||||
|
:default-expand-all="false"
|
||||||
|
:filter-node-method="filterNode"
|
||||||
|
node-key="id"
|
||||||
|
:data="bxsDeviceData"
|
||||||
|
v-bind="$attrs"
|
||||||
|
style="overflow: auto"
|
||||||
|
>
|
||||||
<template #default="{ node, data }">
|
<template #default="{ node, data }">
|
||||||
<span class="custom-tree-node">
|
<span class="custom-tree-node">
|
||||||
<Icon :name="data.icon" style="font-size: 16px" :style="{ color: data.color }"
|
<Icon
|
||||||
v-if="data.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 style="margin-left: 4px">{{ node.label }}</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
@@ -58,14 +112,30 @@
|
|||||||
</el-collapse-item>
|
</el-collapse-item>
|
||||||
<el-collapse-item title="在线设备" name="2" v-if="frontDeviceData.length != 0">
|
<el-collapse-item title="在线设备" name="2" v-if="frontDeviceData.length != 0">
|
||||||
<el-tree
|
<el-tree
|
||||||
:style="{ height: zlDeviceData.length != 0 ? 'calc(100vh - 280px)' : 'calc(100vh - 238px)' }"
|
:style="{
|
||||||
ref="treeRef3" :props="defaultProps" highlight-current default-expand-all
|
height:
|
||||||
:filter-node-method="filterNode" node-key="id" :data="frontDeviceData" v-bind="$attrs"
|
zlDeviceData.length != 0
|
||||||
style="overflow: auto">
|
? `calc(100vh - 340px - ${props.height}px)`
|
||||||
|
: 'calc(100vh - 238px)'
|
||||||
|
}"
|
||||||
|
ref="treeRef3"
|
||||||
|
:props="defaultProps"
|
||||||
|
highlight-current
|
||||||
|
:default-expand-all="false"
|
||||||
|
:filter-node-method="filterNode"
|
||||||
|
node-key="id"
|
||||||
|
:data="frontDeviceData"
|
||||||
|
v-bind="$attrs"
|
||||||
|
style="overflow: auto"
|
||||||
|
>
|
||||||
<template #default="{ node, data }">
|
<template #default="{ node, data }">
|
||||||
<span class="custom-tree-node">
|
<span class="custom-tree-node">
|
||||||
<Icon :name="data.icon" style="font-size: 16px" :style="{ color: data.color }"
|
<Icon
|
||||||
v-if="data.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 style="margin-left: 4px">{{ node.label }}</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
@@ -90,13 +160,15 @@ interface Props {
|
|||||||
canExpand?: boolean
|
canExpand?: boolean
|
||||||
type?: string
|
type?: string
|
||||||
data?: any
|
data?: any
|
||||||
|
height?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
width: '280px',
|
width: '280px',
|
||||||
canExpand: true,
|
canExpand: true,
|
||||||
type: '',
|
type: '',
|
||||||
data: []
|
data: [],
|
||||||
|
height: 0
|
||||||
})
|
})
|
||||||
const { proxy } = useCurrentInstance()
|
const { proxy } = useCurrentInstance()
|
||||||
const menuCollapse = ref(false)
|
const menuCollapse = ref(false)
|
||||||
@@ -124,18 +196,18 @@ watch(
|
|||||||
item.children.map((vv: any) => {
|
item.children.map((vv: any) => {
|
||||||
zlDeviceData.value.push(vv)
|
zlDeviceData.value.push(vv)
|
||||||
})
|
})
|
||||||
|
zlDevList.value = JSON.parse(JSON.stringify(zlDeviceData.value))
|
||||||
} else if (item.name == '便携式设备') {
|
} else if (item.name == '便携式设备') {
|
||||||
bxsDeviceData.value = []
|
bxsDeviceData.value = []
|
||||||
item.children.map((vv: any) => {
|
item.children.map((vv: any) => {
|
||||||
bxsDeviceData.value.push(vv)
|
bxsDeviceData.value.push(vv)
|
||||||
})
|
})
|
||||||
}else if (item.name == '在线设备') {
|
} else if (item.name == '在线设备') {
|
||||||
frontDeviceData.value = []
|
frontDeviceData.value = []
|
||||||
|
|
||||||
item.children.map((vv: any) => {
|
item.children.map((vv: any) => {
|
||||||
frontDeviceData.value.push(vv)
|
frontDeviceData.value.push(vv)
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -156,10 +228,9 @@ watch(filterText, val => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
watch(process, val => {
|
watch(process, val => {
|
||||||
|
if (val == '' || val == undefined) {
|
||||||
|
|
||||||
if (val == '') {
|
|
||||||
zlDevList.value = JSON.parse(JSON.stringify(zlDeviceData.value))
|
zlDevList.value = JSON.parse(JSON.stringify(zlDeviceData.value))
|
||||||
|
console.log('🚀 ~ zlDevList.value:', zlDeviceData.value)
|
||||||
} else {
|
} else {
|
||||||
zlDevList.value = filterProcess(JSON.parse(JSON.stringify(zlDeviceData.value)))
|
zlDevList.value = filterProcess(JSON.parse(JSON.stringify(zlDeviceData.value)))
|
||||||
}
|
}
|
||||||
@@ -180,7 +251,7 @@ function filterProcess(nodes: any) {
|
|||||||
if (node.process == process.value || children.length > 0) {
|
if (node.process == process.value || children.length > 0) {
|
||||||
return {
|
return {
|
||||||
...node,
|
...node,
|
||||||
children: node.children
|
children: children
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -284,7 +355,7 @@ 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 })
|
defineExpose({ treeRef1, treeRef2, treeRef3 })
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (zlDeviceData.value.length != 0) {
|
if (zlDeviceData.value.length != 0) {
|
||||||
@@ -294,6 +365,9 @@ onMounted(() => {
|
|||||||
if (zlDeviceData.value.length === 0 && bxsDeviceData.value.length != 0) {
|
if (zlDeviceData.value.length === 0 && bxsDeviceData.value.length != 0) {
|
||||||
activeName.value = '1'
|
activeName.value = '1'
|
||||||
}
|
}
|
||||||
|
if (zlDeviceData.value.length === 0 && bxsDeviceData.value.length === 0) {
|
||||||
|
activeName.value = '2'
|
||||||
|
}
|
||||||
if (!zlDeviceData.value && !bxsDeviceData.value) {
|
if (!zlDeviceData.value && !bxsDeviceData.value) {
|
||||||
activeName.value = ''
|
activeName.value = ''
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<Tree ref="treRef" :width="width" :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>
|
||||||
@@ -12,9 +12,11 @@ import { useDictData } from '@/stores/dictData'
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
template?: boolean
|
template?: boolean
|
||||||
|
showPush?: boolean
|
||||||
}
|
}
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
template: false
|
template: false,
|
||||||
|
showPush: false
|
||||||
})
|
})
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'govern/deviceTree'
|
name: 'govern/deviceTree'
|
||||||
@@ -95,13 +97,16 @@ const info = (selectedNodeId?: string) => {
|
|||||||
tree.value = []
|
tree.value = []
|
||||||
}
|
}
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
|
|
||||||
if (arr1.length) {
|
if (arr1.length) {
|
||||||
// 安全检查 treRef 和 treeRef1 是否存在
|
// 安全检查 treRef 和 treeRef 是否存在
|
||||||
if (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) {
|
||||||
// 如果传入了要选中的节点ID,则选中该节点,否则选中第一个节点
|
// 如果传入了要选中的节点ID,则选中该节点,否则选中第一个节点
|
||||||
console.log('selectedNodeId:', selectedNodeId);
|
console.log('selectedNodeId:', selectedNodeId);
|
||||||
if (selectedNodeId) {
|
if (selectedNodeId) {
|
||||||
treRef.value.treeRef1.setCurrentKey(selectedNodeId);
|
treRef.value.treeRef.setCurrentKey(selectedNodeId);
|
||||||
// 查找对应的节点数据并触发事件
|
// 查找对应的节点数据并触发事件
|
||||||
let selectedNode = null;
|
let selectedNode = null;
|
||||||
const findNode = (nodes: any[]) => {
|
const findNode = (nodes: any[]) => {
|
||||||
@@ -127,7 +132,7 @@ const info = (selectedNodeId?: string) => {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 初始化选中第一个节点
|
// 初始化选中第一个节点
|
||||||
treRef.value.treeRef1.setCurrentKey(arr1[0].id);
|
treRef.value.treeRef.setCurrentKey(arr1[0].id);
|
||||||
emit('init', {
|
emit('init', {
|
||||||
level: 2,
|
level: 2,
|
||||||
...arr1[0]
|
...arr1[0]
|
||||||
@@ -153,7 +158,7 @@ const onAdd = () => {
|
|||||||
emit('onAdd')
|
emit('onAdd')
|
||||||
}
|
}
|
||||||
if (props.template) {
|
if (props.template) {
|
||||||
getTemplateByDept({ id: dictData.state.area[0].id })
|
getTemplateByDept({ id: dictData.state.area[0]?.id })
|
||||||
.then((res: any) => {
|
.then((res: any) => {
|
||||||
emit('Policy', res.data)
|
emit('Policy', res.data)
|
||||||
info()
|
info()
|
||||||
|
|||||||
106
src/components/tree/govern/cloudDeviceEntryTreeZL.vue
Normal file
106
src/components/tree/govern/cloudDeviceEntryTreeZL.vue
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
<template>
|
||||||
|
<Tree
|
||||||
|
ref="treRef"
|
||||||
|
:width="width"
|
||||||
|
:showPush="props.showPush"
|
||||||
|
:data="tree"
|
||||||
|
default-expand-all
|
||||||
|
@changePointType="changePointType"
|
||||||
|
@onAdd="onAdd"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ref, nextTick, onMounted, defineProps } from 'vue'
|
||||||
|
import Tree from '../index.vue'
|
||||||
|
import { getLineTree, objTree } from '@/api/cs-device-boot/csLedger'
|
||||||
|
import { useConfig } from '@/stores/config'
|
||||||
|
import { getTemplateByDept } from '@/api/harmonic-boot/luckyexcel'
|
||||||
|
import { useDictData } from '@/stores/dictData'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
template?: boolean
|
||||||
|
showPush?: boolean
|
||||||
|
}
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
template: false,
|
||||||
|
showPush: false
|
||||||
|
})
|
||||||
|
defineOptions({
|
||||||
|
name: 'govern/deviceTree'
|
||||||
|
})
|
||||||
|
|
||||||
|
const emit = defineEmits(['init', 'checkChange', 'pointTypeChange', 'Policy', 'onAdd'])
|
||||||
|
const config = useConfig()
|
||||||
|
const tree = ref()
|
||||||
|
const dictData = useDictData()
|
||||||
|
const treRef = ref()
|
||||||
|
const width = ref('')
|
||||||
|
|
||||||
|
const info = (selectedNodeId?: string) => {
|
||||||
|
tree.value = []
|
||||||
|
let arr1: any[] = []
|
||||||
|
objTree().then(res => {
|
||||||
|
try {
|
||||||
|
res.data.map((item: any) => {
|
||||||
|
item.icon = 'el-icon-HomeFilled'
|
||||||
|
item.level = 1
|
||||||
|
item.color = config.getColorVal('elementUiPrimary')
|
||||||
|
item.children.forEach((item: any) => {
|
||||||
|
item.icon = 'el-icon-List'
|
||||||
|
item.level = 2
|
||||||
|
item.color = config.getColorVal('elementUiPrimary')
|
||||||
|
item.children.forEach((item2: any) => {
|
||||||
|
arr1.push(item2)
|
||||||
|
item2.icon = 'el-icon-Platform'
|
||||||
|
item2.level = 3
|
||||||
|
item2.color = config.getColorVal('elementUiPrimary')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
tree.value = res.data
|
||||||
|
nextTick(() => {
|
||||||
|
if (arr1.length) {
|
||||||
|
//初始化选中
|
||||||
|
treRef.value.treeRef.setCurrentKey(arr1[0].id)
|
||||||
|
// 注册父组件事件
|
||||||
|
emit('init', arr1[0])
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
emit('init')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error in processing getCldTree response:', error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const changePointType = (val: any, obj: any) => {
|
||||||
|
emit('pointTypeChange', val, obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
const onAdd = () => {
|
||||||
|
emit('onAdd')
|
||||||
|
}
|
||||||
|
if (props.template) {
|
||||||
|
getTemplateByDept({ id: dictData.state.area[0]?.id })
|
||||||
|
.then((res: any) => {
|
||||||
|
emit('Policy', res.data)
|
||||||
|
info()
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
info()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
info()
|
||||||
|
}
|
||||||
|
|
||||||
|
// 暴露 info 方法给父组件调用
|
||||||
|
defineExpose({
|
||||||
|
info
|
||||||
|
})
|
||||||
|
|
||||||
|
onMounted(() => {})
|
||||||
|
</script>
|
||||||
@@ -5,6 +5,7 @@
|
|||||||
:default-checked-keys="defaultCheckedKeys"
|
:default-checked-keys="defaultCheckedKeys"
|
||||||
:show-checkbox="props.showCheckbox"
|
:show-checkbox="props.showCheckbox"
|
||||||
:data="tree"
|
:data="tree"
|
||||||
|
:height="props.height"
|
||||||
@changeDeviceType="changeDeviceType"
|
@changeDeviceType="changeDeviceType"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
@@ -21,10 +22,12 @@ const props = withDefaults(
|
|||||||
defineProps<{
|
defineProps<{
|
||||||
showCheckbox?: boolean
|
showCheckbox?: boolean
|
||||||
defaultCheckedKeys?: any
|
defaultCheckedKeys?: any
|
||||||
|
height?: number
|
||||||
}>(),
|
}>(),
|
||||||
{
|
{
|
||||||
showCheckbox: false,
|
showCheckbox: false,
|
||||||
defaultCheckedKeys: []
|
defaultCheckedKeys: [],
|
||||||
|
height:0
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
const emit = defineEmits(['init', 'checkChange', 'deviceTypeChange'])
|
const emit = defineEmits(['init', 'checkChange', 'deviceTypeChange'])
|
||||||
@@ -32,7 +35,7 @@ const config = useConfig()
|
|||||||
const tree = ref()
|
const tree = ref()
|
||||||
const treRef = ref()
|
const treRef = ref()
|
||||||
const changeDeviceType = (val: any, obj: any) => {
|
const changeDeviceType = (val: any, obj: any) => {
|
||||||
console.log("🚀 ~ changeDeviceType ~ val:", val,obj)
|
console.log('🚀 ~ changeDeviceType ~ val:', val, obj)
|
||||||
emit('deviceTypeChange', val, obj)
|
emit('deviceTypeChange', val, obj)
|
||||||
}
|
}
|
||||||
getDeviceTree().then(res => {
|
getDeviceTree().then(res => {
|
||||||
@@ -50,6 +53,7 @@ getDeviceTree().then(res => {
|
|||||||
item2.color = config.getColorVal('elementUiPrimary')
|
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 = 2
|
||||||
item3.color = config.getColorVal('elementUiPrimary')
|
item3.color = config.getColorVal('elementUiPrimary')
|
||||||
if (item3.comFlag === 1) {
|
if (item3.comFlag === 1) {
|
||||||
item3.color = '#e26257 !important'
|
item3.color = '#e26257 !important'
|
||||||
@@ -82,8 +86,8 @@ getDeviceTree().then(res => {
|
|||||||
// })
|
// })
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}else if (item.name == '在线设备') {
|
} else if (item.name == '在线设备') {
|
||||||
item.children.forEach((item: any) => {
|
item.children.forEach((item: any) => {
|
||||||
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((item2: any) => {
|
||||||
@@ -101,43 +105,42 @@ getDeviceTree().then(res => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
console.log("🚀 ~ file: deviceTree.vue ~ line 18 ~ getDeviceTree ~ tree:", arr,arr2,arr3)
|
console.log('🚀 ~ file: deviceTree.vue ~ line 18 ~ getDeviceTree ~ tree:', arr, arr2, arr3)
|
||||||
tree.value = res.data
|
tree.value = res.data
|
||||||
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
if (arr.length) {
|
setTimeout(() => {
|
||||||
treRef.value.treeRef1.setCurrentKey(arr[0].id)
|
if (arr.length > 0) {
|
||||||
// 注册父组件事件
|
treRef.value.treeRef1.setCurrentKey(arr[0].id)
|
||||||
emit('init', {
|
// 注册父组件事件
|
||||||
level: 2,
|
emit('init', {
|
||||||
...arr[0]
|
level: 2,
|
||||||
})
|
...arr[0]
|
||||||
return
|
})
|
||||||
}
|
return
|
||||||
if (arr2.length) {
|
} else if (arr2.length > 0) {
|
||||||
treRef.value.treeRef2.setCurrentKey(arr2[0].id)
|
treRef.value.treeRef2.setCurrentKey(arr2[0].id)
|
||||||
// 注册父组件事件
|
// 注册父组件事件
|
||||||
emit('init', {
|
emit('init', {
|
||||||
level: 2,
|
level: 2,
|
||||||
...arr2[0]
|
...arr2[0]
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
} else if (arr3.length > 0) {
|
||||||
console.log("🚀 ~ file: deviceTree.vue ~ line 33 ~ getDeviceTree ~ tree:", arr3.length)
|
console.log('🚀 ~ arr3:', arr3)
|
||||||
if (arr3.length) {
|
|
||||||
console.log("🚀 ~ file: deviceTree.vue ~ line 33 ~ getDeviceTree ~ tree:", arr3)
|
treRef.value.treeRef3.setCurrentKey(arr3[0].id)
|
||||||
treRef.value.treeRef3.setCurrentKey(arr3[0].id)
|
// 注册父组件事件
|
||||||
// 注册父组件事件
|
emit('init', {
|
||||||
emit('init', {
|
level: 2,
|
||||||
level: 2,
|
...arr3[0]
|
||||||
...arr3[0]
|
})
|
||||||
})
|
return
|
||||||
return
|
} else {
|
||||||
}
|
emit('init')
|
||||||
else {
|
return
|
||||||
emit('init')
|
}
|
||||||
return
|
}, 500)
|
||||||
}
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
const handleCheckChange = (data: any, checked: any, indeterminate: any) => {
|
const handleCheckChange = (data: any, checked: any, indeterminate: any) => {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
</template>
|
</template>
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { getMarketList } from '@/api/user-boot/user'
|
import { getMarketList } from '@/api/user-boot/user'
|
||||||
import Tree from '../index.vue'
|
import Tree from '../cloudDevice.vue'
|
||||||
import { useConfig } from '@/stores/config'
|
import { useConfig } from '@/stores/config'
|
||||||
import { ref, reactive, nextTick } from 'vue'
|
import { ref, reactive, nextTick } from 'vue'
|
||||||
const config = useConfig()
|
const config = useConfig()
|
||||||
|
|||||||
29
src/components/tree/govern/officialUserTree.vue
Normal file
29
src/components/tree/govern/officialUserTree.vue
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
<template>
|
||||||
|
<Tree ref="treRef" :data="tree" />
|
||||||
|
</template>
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { getFormalUserList } from '@/api/user-boot/official'
|
||||||
|
import Tree from '../cloudDevice.vue'
|
||||||
|
import { useConfig } from '@/stores/config'
|
||||||
|
import { ref, reactive, nextTick } from 'vue'
|
||||||
|
const config = useConfig()
|
||||||
|
const tree = ref()
|
||||||
|
const treRef = ref()
|
||||||
|
const emit = defineEmits(['selectUser'])
|
||||||
|
getFormalUserList().then((res: any) => {
|
||||||
|
if (res.code === 'A0000') {
|
||||||
|
tree.value = res.data.map((item: any) => {
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
icon: 'el-icon-User',
|
||||||
|
color: 'royalblue'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
emit('selectUser', tree.value[0])
|
||||||
|
nextTick(() => {
|
||||||
|
treRef.value.treeRef.setCurrentKey(tree.value[0].id)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped></style>
|
||||||
@@ -46,7 +46,7 @@ const info = () => {
|
|||||||
item2.color = config.getColorVal('elementUiPrimary')
|
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.level = 2
|
||||||
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) => {
|
item3.children.forEach((item4: any) => {
|
||||||
@@ -99,38 +99,38 @@ const info = () => {
|
|||||||
})
|
})
|
||||||
tree.value = res.data
|
tree.value = res.data
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
if (arr1.length) {
|
setTimeout(() => {
|
||||||
//初始化选中
|
if (arr1.length > 0) {
|
||||||
treRef.value.treeRef1.setCurrentKey(arr1[0].id)
|
//初始化选中
|
||||||
// 注册父组件事件
|
treRef.value?.treeRef1.setCurrentKey(arr1[0].id)
|
||||||
emit('init', {
|
// 注册父组件事件
|
||||||
level: 2,
|
emit('init', {
|
||||||
...arr1[0]
|
level: 2,
|
||||||
})
|
...arr1[0]
|
||||||
return
|
})
|
||||||
}
|
return
|
||||||
if (arr2.length) {
|
} else if (arr2.length > 0) {
|
||||||
//初始化选中
|
//初始化选中
|
||||||
treRef.value.treeRef2.setCurrentKey(arr2[0].id)
|
treRef.value?.treeRef2.setCurrentKey(arr2[0].id)
|
||||||
// 注册父组件事件
|
// 注册父组件事件
|
||||||
emit('init', {
|
emit('init', {
|
||||||
level: 2,
|
level: 2,
|
||||||
...arr2[0]
|
...arr2[0]
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
} else if (arr3.length > 0) {
|
||||||
if(arr3.length){
|
|
||||||
treRef.value.treeRef3.setCurrentKey(arr3[0].id)
|
treRef.value?.treeRef3?.setCurrentKey(arr3[0].id)
|
||||||
emit('init', {
|
emit('init', {
|
||||||
level: 2,
|
level: 2,
|
||||||
...arr3[0]
|
...arr3[0]
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
} else {
|
||||||
else {
|
emit('init')
|
||||||
emit('init')
|
return
|
||||||
return
|
}
|
||||||
}
|
}, 500)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -138,7 +138,7 @@ const changePointType = (val: any, obj: any) => {
|
|||||||
emit('pointTypeChange', val, obj)
|
emit('pointTypeChange', val, obj)
|
||||||
}
|
}
|
||||||
if (props.template) {
|
if (props.template) {
|
||||||
getTemplateByDept({ id: dictData.state.area[0].id })
|
getTemplateByDept({ id: dictData.state.area[0]?.id })
|
||||||
.then((res: any) => {
|
.then((res: any) => {
|
||||||
emit('Policy', res.data)
|
emit('Policy', res.data)
|
||||||
info()
|
info()
|
||||||
|
|||||||
@@ -1,26 +1,44 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<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 maxlength="32" show-word-limit v-model.trim="filterText" placeholder="请输入内容" clearable>
|
<el-input
|
||||||
|
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>
|
||||||
</el-input>
|
</el-input>
|
||||||
</div>
|
</div>
|
||||||
<el-tree style="flex: 1; overflow: auto" :props="defaultProps" highlight-current
|
<el-tree
|
||||||
:filter-node-method="filterNode" node-key="id" v-bind="$attrs" default-expand-all :data="tree"
|
style="flex: 1; overflow: auto"
|
||||||
ref="treRef" @node-click="clickNode" :expand-on-click-node="false">
|
:props="defaultProps"
|
||||||
|
highlight-current
|
||||||
|
: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"
|
||||||
|
>
|
||||||
<template #default="{ node, data }">
|
<template #default="{ node, data }">
|
||||||
<span class="custom-tree-node">
|
<span class="custom-tree-node">
|
||||||
<div class="left">
|
<div class="left" style="display: flex; align-items: center">
|
||||||
<Icon :name="data.icon" style="font-size: 16px" :style="{ color: data.color }"
|
<Icon
|
||||||
v-if="data.icon" />
|
:name="data.icon"
|
||||||
<span>{{ node.label }}</span>
|
style="font-size: 16px"
|
||||||
|
:style="{ color: data.color }"
|
||||||
|
v-if="data.icon"
|
||||||
|
/>
|
||||||
|
<span style="margin-left: 5px;">{{ node.label }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
</el-tree>
|
</el-tree>
|
||||||
@@ -43,12 +61,10 @@ defineOptions({
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
template?: boolean
|
template?: boolean
|
||||||
|
|
||||||
}
|
}
|
||||||
const dictData = useDictData()
|
const dictData = useDictData()
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
template: false,
|
template: false
|
||||||
|
|
||||||
})
|
})
|
||||||
const filterText = ref('')
|
const filterText = ref('')
|
||||||
watch(filterText, val => {
|
watch(filterText, val => {
|
||||||
@@ -94,7 +110,6 @@ const defaultProps = {
|
|||||||
value: 'id'
|
value: 'id'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const emit = defineEmits(['init', 'checkChange', 'nodeChange', 'editNode', 'getChart', 'Policy'])
|
const emit = defineEmits(['init', 'checkChange', 'nodeChange', 'editNode', 'getChart', 'Policy'])
|
||||||
const config = useConfig()
|
const config = useConfig()
|
||||||
const tree = ref()
|
const tree = ref()
|
||||||
@@ -141,18 +156,18 @@ const clickNode = (e: anyObj) => {
|
|||||||
emit('nodeChange', e)
|
emit('nodeChange', e)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (props.template) {
|
if (props.template) {
|
||||||
getTemplateByDept({ id: dictData.state.area[0].id }).then((res: any) => {
|
getTemplateByDept({ id: dictData.state.area[0]?.id })
|
||||||
emit('Policy', res.data)
|
.then((res: any) => {
|
||||||
getTreeList()
|
emit('Policy', res.data)
|
||||||
}).catch(err => {
|
getTreeList()
|
||||||
getTreeList()
|
})
|
||||||
})
|
.catch(err => {
|
||||||
|
getTreeList()
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
getTreeList()
|
getTreeList()
|
||||||
}
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.cn-tree {
|
.cn-tree {
|
||||||
|
|||||||
@@ -63,7 +63,7 @@ const info = () => {
|
|||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
if (arr3.length) {
|
if (arr3.length) {
|
||||||
//初始化选中
|
//初始化选中
|
||||||
treRef.value.treeRef1.setCurrentKey(arr3[0].id)
|
treRef.value.treeRef.setCurrentKey(arr3[0].id)
|
||||||
// 注册父组件事件
|
// 注册父组件事件
|
||||||
emit('init', {
|
emit('init', {
|
||||||
level: 2,
|
level: 2,
|
||||||
@@ -87,7 +87,7 @@ const handleCheckedNodesChange = (nodes: any[]) => {
|
|||||||
|
|
||||||
|
|
||||||
if (props.template) {
|
if (props.template) {
|
||||||
getTemplateByDept({ id: dictData.state.area[0].id })
|
getTemplateByDept({ id: dictData.state.area[0]?.id })
|
||||||
.then((res: any) => {
|
.then((res: any) => {
|
||||||
emit('Policy', res.data)
|
emit('Policy', res.data)
|
||||||
info()
|
info()
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
<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" v-if="props.showPush">
|
||||||
<template #content>
|
<template #content>
|
||||||
<span>台账推送</span>
|
<span>台账推送</span>
|
||||||
</template>
|
</template>
|
||||||
@@ -23,13 +23,13 @@
|
|||||||
: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'"
|
<!-- <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 - 200px)' }"
|
<el-tree :style="{ height: 'calc(100vh - 190px)' }"
|
||||||
style=' overflow: auto;' ref='treeRef' :props='defaultProps' highlight-current
|
style=' overflow: auto;' ref='treeRef' :props='defaultProps' highlight-current :default-expand-all="false"
|
||||||
@check-change="checkTreeNodeChange" :filter-node-method='filterNode' node-key='id' v-bind='$attrs'>
|
@check-change="checkTreeNodeChange" :filter-node-method='filterNode' node-key='id' v-bind='$attrs'>
|
||||||
<template #default='{ node, data }'>
|
<template #default='{ node, data }'>
|
||||||
<span class='custom-tree-node'>
|
<span class='custom-tree-node'>
|
||||||
@@ -58,11 +58,13 @@ defineOptions({
|
|||||||
interface Props {
|
interface Props {
|
||||||
width?: string
|
width?: string
|
||||||
canExpand?: boolean
|
canExpand?: boolean
|
||||||
|
showPush?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
width: '280px',
|
width: '280px',
|
||||||
canExpand: true
|
canExpand: true,
|
||||||
|
showPush: false
|
||||||
})
|
})
|
||||||
const config = useConfig()
|
const config = useConfig()
|
||||||
const { proxy } = useCurrentInstance()
|
const { proxy } = useCurrentInstance()
|
||||||
|
|||||||
@@ -1,9 +1,16 @@
|
|||||||
<!-- 设备监控使用折叠面板渲染多个tree -->
|
<!-- 设备监控使用折叠面板渲染多个tree -->
|
||||||
<template>
|
<template>
|
||||||
<div :style="{ width: menuCollapse ? '40px' : props.width }" style="display: flex; overflow: hidden">
|
<div :style="{ width: menuCollapse ? '40px' : props.width }" style="display: flex; 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" style="cursor: pointer"
|
v-show="menuCollapse"
|
||||||
v-if="route.path != '/admin/govern/reportCore/statistics/index'" />
|
@click="onMenuCollapse"
|
||||||
|
:name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
|
||||||
|
:class="menuCollapse ? 'unfold' : ''"
|
||||||
|
size="18"
|
||||||
|
class="fold ml10 mt20 menu-collapse"
|
||||||
|
style="cursor: pointer"
|
||||||
|
v-if="route.path != '/admin/govern/reportCore/statistics/index'"
|
||||||
|
/>
|
||||||
<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" show-word-limit v-model.trim="filterText" placeholder="请输入内容" clearable>
|
||||||
@@ -11,13 +18,23 @@
|
|||||||
<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 @click="onMenuCollapse" :name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
|
<Icon
|
||||||
:class="menuCollapse ? 'unfold' : ''" size="18" class="fold ml10 menu-collapse"
|
@click="onMenuCollapse"
|
||||||
|
:name="menuCollapse ? 'el-icon-Expand' : 'el-icon-Fold'"
|
||||||
|
:class="menuCollapse ? 'unfold' : ''"
|
||||||
|
size="18"
|
||||||
|
class="fold ml10 menu-collapse"
|
||||||
style="cursor: pointer"
|
style="cursor: pointer"
|
||||||
v-if="props.canExpand && route.path != '/admin/govern/reportCore/statistics/index'" />
|
v-if="props.canExpand && route.path != '/admin/govern/reportCore/statistics/index'"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<el-collapse :accordion="true" v-model.trim="activeName" style="flex: 1; height: 100%"
|
|
||||||
@change="changeDevice">
|
<el-collapse
|
||||||
|
:accordion="true"
|
||||||
|
v-model.trim="activeName"
|
||||||
|
style="flex: 1; height: 100%"
|
||||||
|
@change="changeDevice"
|
||||||
|
>
|
||||||
<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">
|
||||||
<el-option label="功能调试" value="2"></el-option>
|
<el-option label="功能调试" value="2"></el-option>
|
||||||
@@ -26,13 +43,25 @@
|
|||||||
</el-select>
|
</el-select>
|
||||||
|
|
||||||
<el-tree
|
<el-tree
|
||||||
:style="{ height: bxsDeviceData.length != 0 ? 'calc(100vh - 340px)' : 'calc(100vh - 278px)' }"
|
:style="{ height: bxsDeviceData.length != 0 ? 'calc(100vh - 380px)' : 'calc(100vh - 278px)' }"
|
||||||
ref="treeRef1" :props="defaultProps" highlight-current :filter-node-method="filterNode"
|
ref="treeRef1"
|
||||||
node-key="id" default-expand-all v-bind="$attrs" :data="zlDevList" style="overflow: auto">
|
:props="defaultProps"
|
||||||
|
highlight-current
|
||||||
|
:filter-node-method="filterNode"
|
||||||
|
node-key="id"
|
||||||
|
v-bind="$attrs"
|
||||||
|
:data="zlDevList"
|
||||||
|
style="overflow: auto"
|
||||||
|
:default-expand-all="false"
|
||||||
|
>
|
||||||
<template #default="{ node, data }">
|
<template #default="{ node, data }">
|
||||||
<span class="custom-tree-node">
|
<span class="custom-tree-node">
|
||||||
<Icon :name="data.icon" style="font-size: 16px" :style="{ color: data.color }"
|
<Icon
|
||||||
v-if="data.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 style="margin-left: 4px">{{ node.label }}</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
@@ -40,14 +69,25 @@
|
|||||||
</el-collapse-item>
|
</el-collapse-item>
|
||||||
<el-collapse-item title="便携式设备" name="1" v-if="bxsDeviceData.length != 0">
|
<el-collapse-item title="便携式设备" name="1" v-if="bxsDeviceData.length != 0">
|
||||||
<el-tree
|
<el-tree
|
||||||
:style="{ height: zlDeviceData.length != 0 ? 'calc(100vh - 330px)' : 'calc(100vh - 238px)' }"
|
:style="{ height: zlDeviceData.length != 0 ? 'calc(100vh - 340px)' : 'calc(100vh - 238px)' }"
|
||||||
ref="treeRef2" :props="defaultProps" highlight-current default-expand-all
|
ref="treeRef2"
|
||||||
:filter-node-method="filterNode" node-key="id" :data="bxsDeviceData" v-bind="$attrs"
|
:props="defaultProps"
|
||||||
style="overflow: auto">
|
highlight-current
|
||||||
|
:default-expand-all="false"
|
||||||
|
:filter-node-method="filterNode"
|
||||||
|
node-key="id"
|
||||||
|
:data="bxsDeviceData"
|
||||||
|
v-bind="$attrs"
|
||||||
|
style="overflow: auto"
|
||||||
|
>
|
||||||
<template #default="{ node, data }">
|
<template #default="{ node, data }">
|
||||||
<span class="custom-tree-node">
|
<span class="custom-tree-node">
|
||||||
<Icon :name="data.icon" style="font-size: 16px" :style="{ color: data.color }"
|
<Icon
|
||||||
v-if="data.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 style="margin-left: 4px">{{ node.label }}</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
@@ -55,14 +95,25 @@
|
|||||||
</el-collapse-item>
|
</el-collapse-item>
|
||||||
<el-collapse-item title="在线设备" name="2" v-if="yqfDeviceData.length != 0">
|
<el-collapse-item title="在线设备" name="2" v-if="yqfDeviceData.length != 0">
|
||||||
<el-tree
|
<el-tree
|
||||||
:style="{ height: zlDeviceData.length != 0 ? 'calc(100vh - 330px)' : 'calc(100vh - 238px)' }"
|
:style="{ height: zlDeviceData.length != 0 ? 'calc(100vh - 340px)' : 'calc(100vh - 238px)' }"
|
||||||
ref="treeRef3" :props="defaultProps" highlight-current default-expand-all
|
ref="treeRef3"
|
||||||
:filter-node-method="filterNode" node-key="id" :data="yqfDeviceData" v-bind="$attrs"
|
:props="defaultProps"
|
||||||
style="overflow: auto">
|
highlight-current
|
||||||
|
:default-expand-all="false"
|
||||||
|
:filter-node-method="filterNode"
|
||||||
|
node-key="id"
|
||||||
|
:data="yqfDeviceData"
|
||||||
|
v-bind="$attrs"
|
||||||
|
style="overflow: auto"
|
||||||
|
>
|
||||||
<template #default="{ node, data }">
|
<template #default="{ node, data }">
|
||||||
<span class="custom-tree-node">
|
<span class="custom-tree-node">
|
||||||
<Icon :name="data.icon" style="font-size: 16px" :style="{ color: data.color }"
|
<Icon
|
||||||
v-if="data.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 style="margin-left: 4px">{{ node.label }}</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
@@ -76,7 +127,7 @@
|
|||||||
<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 { el } from 'element-plus/es/locale'
|
import { el, fa } from 'element-plus/es/locale'
|
||||||
import { ref, watch, defineEmits, onMounted, nextTick, computed } from 'vue'
|
import { ref, watch, defineEmits, onMounted, nextTick, computed } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
defineOptions({
|
defineOptions({
|
||||||
@@ -123,20 +174,19 @@ watch(
|
|||||||
item.children.map((vv: any) => {
|
item.children.map((vv: any) => {
|
||||||
zlDeviceData.value.push(vv)
|
zlDeviceData.value.push(vv)
|
||||||
})
|
})
|
||||||
// console.log('🚀 ~ item.children.map ~ zlDeviceData.value:', zlDeviceData.value)
|
zlDevList.value = JSON.parse(JSON.stringify(zlDeviceData.value))
|
||||||
} else if (item.name == '便携式设备') {
|
} else if (item.name == '便携式设备') {
|
||||||
bxsDeviceData.value = []
|
bxsDeviceData.value = []
|
||||||
item.children.map((vv: any) => {
|
item.children.map((vv: any) => {
|
||||||
bxsDeviceData.value.push(vv)
|
bxsDeviceData.value.push(vv)
|
||||||
})
|
})
|
||||||
}else if (item.name == '在线设备') {
|
} else if (item.name == '在线设备') {
|
||||||
yqfDeviceData.value = []
|
yqfDeviceData.value = []
|
||||||
item.children.map((vv: any) => {
|
item.children.map((vv: any) => {
|
||||||
yqfDeviceData.value.push(vv)
|
yqfDeviceData.value.push(vv)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -155,18 +205,20 @@ watch(filterText, val => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
watch(process, val => {
|
watch(process, val => {
|
||||||
if (val == '') {
|
if (val == '' || val == undefined) {
|
||||||
zlDevList.value = JSON.parse(JSON.stringify(zlDeviceData.value))
|
zlDevList.value = JSON.parse(JSON.stringify(zlDeviceData.value))
|
||||||
} else {
|
} else {
|
||||||
zlDevList.value = filterProcess(JSON.parse(JSON.stringify(zlDeviceData.value)))
|
zlDevList.value = filterProcess(JSON.parse(JSON.stringify(zlDeviceData.value)))
|
||||||
}
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
changeDevice(activeName.value)
|
changeDevice(activeName.value)
|
||||||
}, 0)
|
}, 0)
|
||||||
})
|
})
|
||||||
|
|
||||||
const changeDevice = (val: any) => {
|
const changeDevice = (val: any) => {
|
||||||
console.log('changeDevice', val)
|
console.log('🚀 ~ changeDevice ~ val:', val)
|
||||||
|
|
||||||
let arr1: any = []
|
let arr1: any = []
|
||||||
//zlDeviceData
|
//zlDeviceData
|
||||||
zlDevList.value.forEach((item: any) => {
|
zlDevList.value.forEach((item: any) => {
|
||||||
@@ -231,6 +283,7 @@ const filterNode = (value: string, data: any, node: any) => {
|
|||||||
return chooseNode(value, data, node)
|
return chooseNode(value, data, node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function filterProcess(nodes: any) {
|
function filterProcess(nodes: any) {
|
||||||
if (process.value == '') {
|
if (process.value == '') {
|
||||||
return nodes
|
return nodes
|
||||||
@@ -240,20 +293,56 @@ function filterProcess(nodes: any) {
|
|||||||
// 递归处理子节点
|
// 递归处理子节点
|
||||||
const children = node.children ? filterProcess(node.children) : []
|
const children = node.children ? filterProcess(node.children) : []
|
||||||
|
|
||||||
// 如果当前节点的process=4,或者有子节点满足条件,则保留当前节点
|
// 对于装置层级(level=2),只保留 process 值匹配的节点
|
||||||
|
if (node.level === 2) {
|
||||||
|
if (node.process == process.value) {
|
||||||
|
return {
|
||||||
|
...node,
|
||||||
|
children: children
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
if (node.process == process.value || children.length > 0) {
|
// 对于其他节点:
|
||||||
|
// 1. 如果有满足条件的子节点则保留
|
||||||
|
// 2. 如果本身 process 值匹配则保留
|
||||||
|
// 3. 如果是叶子节点也保留(监测点通常没有子节点)
|
||||||
|
if (children.length > 0 || node.process == process.value || !node.children || node.children.length === 0) {
|
||||||
return {
|
return {
|
||||||
...node,
|
...node,
|
||||||
children: node.children
|
children: children
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 否则过滤掉当前节点
|
|
||||||
return null
|
return null
|
||||||
})
|
})
|
||||||
.filter(Boolean) // 移除null节点
|
.filter(Boolean) // 移除null节点
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// function filterProcess(nodes: any) {
|
||||||
|
// if (process.value == '') {
|
||||||
|
// return nodes
|
||||||
|
// }
|
||||||
|
// return nodes
|
||||||
|
// .map(node => {
|
||||||
|
// // 递归处理子节点
|
||||||
|
// const children = node.children ? filterProcess(node.children) : []
|
||||||
|
|
||||||
|
// // 如果当前节点的process=4,或者有子节点满足条件,则保留当前节点
|
||||||
|
|
||||||
|
// if (node.process == process.value || children.length > 0) {
|
||||||
|
// return {
|
||||||
|
// ...node,
|
||||||
|
// children: node.children
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// // 否则过滤掉当前节点
|
||||||
|
// return null
|
||||||
|
// })
|
||||||
|
// .filter(Boolean) // 移除null节点
|
||||||
|
// }
|
||||||
// 过滤父节点 / 子节点 (如果输入的参数是父节点且能匹配,则返回该节点以及其下的所有子节点;如果参数是子节点,则返回该节点的父节点。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) {
|
||||||
@@ -286,7 +375,7 @@ 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 })
|
defineExpose({ treeRef1, treeRef2, treeRef3 })
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (zlDeviceData.value.length != 0) {
|
if (zlDeviceData.value.length != 0) {
|
||||||
@@ -296,8 +385,11 @@ onMounted(() => {
|
|||||||
if (zlDeviceData.value.length === 0 && bxsDeviceData.value.length != 0) {
|
if (zlDeviceData.value.length === 0 && bxsDeviceData.value.length != 0) {
|
||||||
activeName.value = '1'
|
activeName.value = '1'
|
||||||
}
|
}
|
||||||
|
if (zlDeviceData.value.length === 0 && bxsDeviceData.value.length === 0) {
|
||||||
|
activeName.value = '2'
|
||||||
|
}
|
||||||
if (!zlDeviceData.value && !bxsDeviceData.value) {
|
if (!zlDeviceData.value && !bxsDeviceData.value) {
|
||||||
activeName.value = ''
|
activeName.value = '2'
|
||||||
}
|
}
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
changeDevice(activeName.value)
|
changeDevice(activeName.value)
|
||||||
|
|||||||
@@ -24,8 +24,7 @@
|
|||||||
@node-click="handleNodeClick"
|
@node-click="handleNodeClick"
|
||||||
:default-checked-keys="defaultCheckedKeys"
|
:default-checked-keys="defaultCheckedKeys"
|
||||||
v-bind='$attrs'
|
v-bind='$attrs'
|
||||||
|
:default-expand-all="false"
|
||||||
|
|
||||||
>
|
>
|
||||||
<template #default='{ node, data }'>
|
<template #default='{ node, data }'>
|
||||||
<span class='custom-tree-node'>
|
<span class='custom-tree-node'>
|
||||||
@@ -121,8 +120,69 @@ const handleNodeClick = (data: any, node: any, event: any) => {
|
|||||||
// 存储所有勾选的节点
|
// 存储所有勾选的节点
|
||||||
const checkedNodes = ref<any[]>([])
|
const checkedNodes = ref<any[]>([])
|
||||||
const defaultCheckedKeys = ref<string[]>([])
|
const defaultCheckedKeys = ref<string[]>([])
|
||||||
|
|
||||||
// 处理节点勾选变化
|
// 处理节点勾选变化
|
||||||
const handleCheckChange = (data: any, checkInfo: any) => {
|
const handleCheckChange = (data: any, checkInfo: any) => {
|
||||||
|
const { checkedNodes: nodes } = checkInfo
|
||||||
|
// 过滤出监测点层级(level=3)的节点
|
||||||
|
const monitoringPointNodes = nodes.filter((node: any) => {
|
||||||
|
return node.level === 3
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
// 限制最多只能勾选5个监测点
|
||||||
|
if (monitoringPointNodes.length > 5) {
|
||||||
|
// 获取之前选中的节点
|
||||||
|
const previousCheckedNodes = checkedNodes.value || []
|
||||||
|
|
||||||
|
// 计算新增的节点
|
||||||
|
const newNodes = monitoringPointNodes.filter(
|
||||||
|
(node: any) => !previousCheckedNodes.some((prev: any) => prev.id === node.id)
|
||||||
|
)
|
||||||
|
|
||||||
|
// 如果是从父级勾选导致超过限制,保留前几个直到达到限制数量
|
||||||
|
if (newNodes.length > 0) {
|
||||||
|
const allowedNewCount = 5 - previousCheckedNodes.length
|
||||||
|
if (allowedNewCount > 0) {
|
||||||
|
// 允许添加allowedNewCount个新节点
|
||||||
|
const allowedNewNodes = newNodes.slice(0, allowedNewCount)
|
||||||
|
const finalNodes = [...previousCheckedNodes, ...allowedNewNodes]
|
||||||
|
|
||||||
|
checkedNodes.value = finalNodes
|
||||||
|
|
||||||
|
// 设置树的勾选状态为正确的节点
|
||||||
|
treeRef.value?.setCheckedNodes(finalNodes)
|
||||||
|
|
||||||
|
// 将勾选的监测点节点暴露出去
|
||||||
|
emit('checkedNodesChange', finalNodes)
|
||||||
|
|
||||||
|
// 更新节点的可勾选状态
|
||||||
|
updateNodeCheckStatus(finalNodes.length)
|
||||||
|
|
||||||
|
// 只有在真正超过5个时才提示警告
|
||||||
|
if (monitoringPointNodes.length > 5) {
|
||||||
|
ElMessage.warning('最多只能选择5个监测点')
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 其他情况回滚到之前的状态
|
||||||
|
ElMessage.warning('最多只能选择5个监测点')
|
||||||
|
treeRef.value?.setCheckedNodes(checkedNodes.value)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
checkedNodes.value = monitoringPointNodes
|
||||||
|
|
||||||
|
// 将勾选的监测点节点暴露出去
|
||||||
|
emit('checkedNodesChange', monitoringPointNodes)
|
||||||
|
|
||||||
|
// 更新节点的可勾选状态
|
||||||
|
updateNodeCheckStatus(monitoringPointNodes.length)
|
||||||
|
}
|
||||||
|
// 处理节点勾选变化
|
||||||
|
const handleCheckChange2 = (data: any, checkInfo: any) => {
|
||||||
const { checkedNodes: nodes } = checkInfo
|
const { checkedNodes: nodes } = checkInfo
|
||||||
// 过滤出监测点层级(level=3)的节点
|
// 过滤出监测点层级(level=3)的节点
|
||||||
const monitoringPointNodes = nodes.filter((node: any) => {
|
const monitoringPointNodes = nodes.filter((node: any) => {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="nav-tabs" ref="tabScrollbarRef">
|
<div class="nav-tabs" ref="tabScrollbarRef">
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-for="(item, idx) in navTabs.state.tabsView"
|
v-for="(item, idx) in navTabs.state.tabsView"
|
||||||
@click="onTab(item)"
|
@click="onTab(item)"
|
||||||
@@ -71,8 +72,11 @@ const onTab = (menu: RouteLocationNormalized) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const onContextmenu = (menu: RouteLocationNormalized, el: MouseEvent) => {
|
const onContextmenu = (menu: RouteLocationNormalized, el: MouseEvent) => {
|
||||||
|
|
||||||
// 禁用刷新
|
// 禁用刷新
|
||||||
state.contextmenuItems[0].disabled = route.path !== menu.path
|
state.contextmenuItems[0].disabled = route.path !== menu.path
|
||||||
|
|
||||||
|
|
||||||
// 禁用关闭其他和关闭全部
|
// 禁用关闭其他和关闭全部
|
||||||
state.contextmenuItems[4].disabled = state.contextmenuItems[3].disabled =
|
state.contextmenuItems[4].disabled = state.contextmenuItems[3].disabled =
|
||||||
navTabs.state.tabsView.length == 1 ? true : false
|
navTabs.state.tabsView.length == 1 ? true : false
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ const init = async () => {
|
|||||||
handleAdminRoute(res.data)
|
handleAdminRoute(res.data)
|
||||||
if (route.params.to) {
|
if (route.params.to) {
|
||||||
const lastRoute = JSON.parse(route.params.to as string)
|
const lastRoute = JSON.parse(route.params.to as string)
|
||||||
|
|
||||||
if (lastRoute.path != adminBaseRoutePath) {
|
if (lastRoute.path != adminBaseRoutePath) {
|
||||||
let query = !isEmpty(lastRoute.query) ? lastRoute.query : {}
|
let query = !isEmpty(lastRoute.query) ? lastRoute.query : {}
|
||||||
routePush({ path: lastRoute.path, query: query })
|
routePush({ path: lastRoute.path, query: query })
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { STORE_TAB_VIEW_CONFIG } from '@/stores/constant/cacheKey'
|
|||||||
import type { NavTabs } from '@/stores/interface/index'
|
import type { NavTabs } from '@/stores/interface/index'
|
||||||
import type { RouteLocationNormalized, RouteRecordRaw } from 'vue-router'
|
import type { RouteLocationNormalized, RouteRecordRaw } from 'vue-router'
|
||||||
import { adminBaseRoutePath } from '@/router/static'
|
import { adminBaseRoutePath } from '@/router/static'
|
||||||
|
import { set } from 'lodash'
|
||||||
|
|
||||||
export const useNavTabs = defineStore(
|
export const useNavTabs = defineStore(
|
||||||
'navTabs',
|
'navTabs',
|
||||||
@@ -20,15 +21,17 @@ export const useNavTabs = defineStore(
|
|||||||
// 从后台加载到的菜单路由列表
|
// 从后台加载到的菜单路由列表
|
||||||
tabsViewRoutes: [],
|
tabsViewRoutes: [],
|
||||||
// 按钮权限节点
|
// 按钮权限节点
|
||||||
authNode: new Map(),
|
authNode: new Map()
|
||||||
})
|
})
|
||||||
|
|
||||||
function addTab(route: RouteLocationNormalized) {
|
function addTab(route: RouteLocationNormalized) {
|
||||||
|
console.log('🚀 ~ addTab ~ route:', route)
|
||||||
if (!route.meta.addtab) return
|
if (!route.meta.addtab) return
|
||||||
for (const key in state.tabsView) {
|
for (const key in state.tabsView) {
|
||||||
if (state.tabsView[key].path === route.path) {
|
if (state.tabsView[key].path === route.path) {
|
||||||
state.tabsView[key].params = route.params ? route.params : state.tabsView[key].params
|
state.tabsView[key].params = route.params ? route.params : state.tabsView[key].params
|
||||||
state.tabsView[key].query = route.query ? route.query : state.tabsView[key].query
|
state.tabsView[key].query = route.query ? route.query : state.tabsView[key].query
|
||||||
|
state.tabsView[key].meta = route.query ? route.meta : state.tabsView[key].meta
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -81,21 +84,79 @@ export const useNavTabs = defineStore(
|
|||||||
state.tabFullScreen = fullScreen
|
state.tabFullScreen = fullScreen
|
||||||
}
|
}
|
||||||
|
|
||||||
return { state, addTab, closeTab, closeTabs, setActiveRoute, setTabsViewRoutes, setAuthNode, fillAuthNode, setFullScreen }
|
const refresh = () => {
|
||||||
|
// setTimeout(() => {
|
||||||
|
// console.log(123, state.tabsViewRoutes)
|
||||||
|
|
||||||
|
let list = matchAndReturnRouteData(state.tabsViewRoutes, state.tabsView)
|
||||||
|
state.tabsView = []
|
||||||
|
list.forEach(item => {
|
||||||
|
addTab(item)
|
||||||
|
})
|
||||||
|
// }, 1000)
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
state,
|
||||||
|
addTab,
|
||||||
|
closeTab,
|
||||||
|
closeTabs,
|
||||||
|
setActiveRoute,
|
||||||
|
setTabsViewRoutes,
|
||||||
|
setAuthNode,
|
||||||
|
fillAuthNode,
|
||||||
|
setFullScreen,
|
||||||
|
refresh
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
persist: {
|
persist: {
|
||||||
key: STORE_TAB_VIEW_CONFIG,
|
key: STORE_TAB_VIEW_CONFIG,
|
||||||
paths: ['state.tabFullScreen'],
|
paths: ['state.tabFullScreen']
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 核心逻辑:
|
||||||
|
* 1. 递归遍历树形菜单,筛选出与routeList中name匹配的节点
|
||||||
|
* 2. 将匹配到的节点格式转换为routeList的结构并返回
|
||||||
|
*/
|
||||||
|
function matchAndReturnRouteData(tree, routeList) {
|
||||||
|
// 1. 构建路由name映射(name -> 完整路由对象)
|
||||||
|
const routeMap = new Map()
|
||||||
|
routeList.forEach(route => {
|
||||||
|
if (route.name) {
|
||||||
|
routeMap.set(route.name, route)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 2. 递归遍历树形菜单,收集匹配的节点
|
||||||
|
const matchedNodes = []
|
||||||
|
function recursion(node) {
|
||||||
|
// 匹配当前节点
|
||||||
|
if (routeMap.has(node.name)) {
|
||||||
|
// 深度克隆路由对象,避免修改原数据
|
||||||
|
const matchedRoute = JSON.parse(JSON.stringify(routeMap.get(node.name)))
|
||||||
|
matchedNodes.push(matchedRoute)
|
||||||
|
}
|
||||||
|
// 递归处理子节点
|
||||||
|
if (node.children && node.children.length) {
|
||||||
|
node.children.forEach(child => recursion(child))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历所有顶级节点
|
||||||
|
tree.forEach(node => recursion(node))
|
||||||
|
|
||||||
|
// 3. 返回匹配后的第二个数据格式(和routeList结构一致)
|
||||||
|
return matchedNodes
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对iframe的url进行编码
|
* 对iframe的url进行编码
|
||||||
*/
|
*/
|
||||||
function encodeRoutesURI(data: RouteRecordRaw[]) {
|
function encodeRoutesURI(data: RouteRecordRaw[]) {
|
||||||
data.forEach((item) => {
|
data.forEach(item => {
|
||||||
if (item.meta?.menu_type == 'iframe') {
|
if (item.meta?.menu_type == 'iframe') {
|
||||||
item.path = adminBaseRoutePath + '/iframe/' + encodeURIComponent(item.path)
|
item.path = adminBaseRoutePath + '/iframe/' + encodeURIComponent(item.path)
|
||||||
}
|
}
|
||||||
|
|||||||
34
src/stores/timeCache.ts
Normal file
34
src/stores/timeCache.ts
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// src/stores/timeCache.ts
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { RouteLocationNormalizedLoaded } from 'vue-router'
|
||||||
|
|
||||||
|
// 时间组件的缓存值 用于驾驶舱放大的时候和内部的时间组件同步
|
||||||
|
interface TimeCacheState {
|
||||||
|
cache: Map<string, {
|
||||||
|
interval: number | undefined // 时间组件的月份、年份、时间、时间格式的缓存值
|
||||||
|
timeValue: any // 时间组件的值
|
||||||
|
}>
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useTimeCacheStore = defineStore('timeCache', {
|
||||||
|
state: (): TimeCacheState => ({
|
||||||
|
cache: new Map()
|
||||||
|
}),
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
setCache(routePath: string, interval: number | undefined, timeValue: any) {
|
||||||
|
this.cache.set(routePath, {
|
||||||
|
interval,
|
||||||
|
timeValue
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
getCache(routePath: string) {
|
||||||
|
return this.cache.get(routePath)
|
||||||
|
},
|
||||||
|
|
||||||
|
hasCache(routePath: string) {
|
||||||
|
return this.cache.has(routePath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
58
src/styles/vxeTable.css
Normal file
58
src/styles/vxeTable.css
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
.vxe-header--row {
|
||||||
|
background: var(--vxe-table-header-background-color);
|
||||||
|
color: var(--vxe-table-header-font-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.is--checked.vxe-checkbox,
|
||||||
|
.is--checked.vxe-checkbox .vxe-checkbox--icon,
|
||||||
|
.is--checked.vxe-custom--checkbox-option,
|
||||||
|
.is--checked.vxe-custom--checkbox-option .vxe-checkbox--icon,
|
||||||
|
.is--checked.vxe-export--panel-column-option,
|
||||||
|
.is--checked.vxe-export--panel-column-option .vxe-checkbox--icon,
|
||||||
|
.is--checked.vxe-table--filter-option,
|
||||||
|
.is--checked.vxe-table--filter-option .vxe-checkbox--icon,
|
||||||
|
.is--indeterminate.vxe-checkbox,
|
||||||
|
.is--indeterminate.vxe-checkbox .vxe-checkbox--icon,
|
||||||
|
.is--indeterminate.vxe-custom--checkbox-option,
|
||||||
|
.is--indeterminate.vxe-custom--checkbox-option .vxe-checkbox--icon,
|
||||||
|
.is--indeterminate.vxe-export--panel-column-option,
|
||||||
|
.is--indeterminate.vxe-export--panel-column-option .vxe-checkbox--icon,
|
||||||
|
.is--indeterminate.vxe-table--filter-option,
|
||||||
|
.is--indeterminate.vxe-table--filter-option .vxe-checkbox--icon,
|
||||||
|
.vxe-table--render-default .is--checked.vxe-cell--checkbox,
|
||||||
|
.vxe-table--render-default .is--checked.vxe-cell--checkbox .vxe-checkbox--icon,
|
||||||
|
.vxe-table--render-default .is--indeterminate.vxe-cell--checkbox,
|
||||||
|
.vxe-table--render-default .is--indeterminate.vxe-cell--checkbox .vxe-checkbox--icon,
|
||||||
|
.vxe-table--render-default .is--checked.vxe-cell--radio .vxe-radio--icon {
|
||||||
|
color: var(--el-color-primary-light-3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-checkbox:not(.is--disabled):hover .vxe-checkbox--icon,
|
||||||
|
.vxe-custom--checkbox-option:not(.is--disabled):hover .vxe-checkbox--icon,
|
||||||
|
.vxe-export--panel-column-option:not(.is--disabled):hover .vxe-checkbox--icon,
|
||||||
|
.vxe-table--filter-option:not(.is--disabled):hover .vxe-checkbox--icon,
|
||||||
|
.vxe-table--render-default .vxe-cell--checkbox:not(.is--disabled):hover .vxe-checkbox--icon,
|
||||||
|
.vxe-radio:not(.is--disabled):hover .vxe-radio--icon,
|
||||||
|
.vxe-custom--radio-option:not(.is--disabled):hover .vxe-radio--icon,
|
||||||
|
.vxe-export--panel-column-option:not(.is--disabled):hover .vxe-radio--icon,
|
||||||
|
.vxe-table--filter-option:not(.is--disabled):hover .vxe-radio--icon,
|
||||||
|
.vxe-table--render-default .vxe-cell--radio:not(.is--disabled):hover .vxe-radio--icon {
|
||||||
|
color: var(--el-color-primary-light-5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-table--render-default .vxe-body--row.row--current,
|
||||||
|
.vxe-table--render-default .vxe-body--row.row--current:hover {
|
||||||
|
background-color: var(--el-color-primary-light-8);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-table--tooltip-wrapper {
|
||||||
|
z-index: 10000 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.is--disabled {
|
||||||
|
background-color: var(--vxe-input-disabled-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.vxe-modal--wrapper {
|
||||||
|
z-index: 5000 !important;
|
||||||
|
}
|
||||||
1
src/styles/vxeTable.min.css
vendored
Normal file
1
src/styles/vxeTable.min.css
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.vxe-header--row{background:var(--vxe-table-header-background-color);color:var(--vxe-table-header-font-color)}.is--checked.vxe-checkbox,.is--checked.vxe-checkbox .vxe-checkbox--icon,.is--checked.vxe-custom--checkbox-option,.is--checked.vxe-custom--checkbox-option .vxe-checkbox--icon,.is--checked.vxe-export--panel-column-option,.is--checked.vxe-export--panel-column-option .vxe-checkbox--icon,.is--checked.vxe-table--filter-option,.is--checked.vxe-table--filter-option .vxe-checkbox--icon,.is--indeterminate.vxe-checkbox,.is--indeterminate.vxe-checkbox .vxe-checkbox--icon,.is--indeterminate.vxe-custom--checkbox-option,.is--indeterminate.vxe-custom--checkbox-option .vxe-checkbox--icon,.is--indeterminate.vxe-export--panel-column-option,.is--indeterminate.vxe-export--panel-column-option .vxe-checkbox--icon,.is--indeterminate.vxe-table--filter-option,.is--indeterminate.vxe-table--filter-option .vxe-checkbox--icon,.vxe-table--render-default .is--checked.vxe-cell--checkbox,.vxe-table--render-default .is--checked.vxe-cell--checkbox .vxe-checkbox--icon,.vxe-table--render-default .is--indeterminate.vxe-cell--checkbox,.vxe-table--render-default .is--indeterminate.vxe-cell--checkbox .vxe-checkbox--icon,.vxe-table--render-default .is--checked.vxe-cell--radio .vxe-radio--icon{color:var(--el-color-primary-light-3)}.vxe-checkbox:not(.is--disabled):hover .vxe-checkbox--icon,.vxe-custom--checkbox-option:not(.is--disabled):hover .vxe-checkbox--icon,.vxe-export--panel-column-option:not(.is--disabled):hover .vxe-checkbox--icon,.vxe-table--filter-option:not(.is--disabled):hover .vxe-checkbox--icon,.vxe-table--render-default .vxe-cell--checkbox:not(.is--disabled):hover .vxe-checkbox--icon,.vxe-radio:not(.is--disabled):hover .vxe-radio--icon,.vxe-custom--radio-option:not(.is--disabled):hover .vxe-radio--icon,.vxe-export--panel-column-option:not(.is--disabled):hover .vxe-radio--icon,.vxe-table--filter-option:not(.is--disabled):hover .vxe-radio--icon,.vxe-table--render-default .vxe-cell--radio:not(.is--disabled):hover .vxe-radio--icon{color:var(--el-color-primary-light-5)}.vxe-table--render-default .vxe-body--row.row--current,.vxe-table--render-default .vxe-body--row.row--current:hover{background-color:var(--el-color-primary-light-8)}.vxe-table--tooltip-wrapper{z-index:10000 !important}.is--disabled{background-color:var(--vxe-input-disabled-color)}.vxe-modal--wrapper{z-index:5000 !important}
|
||||||
@@ -60,7 +60,10 @@
|
|||||||
.vxe-table--render-default .vxe-cell--radio:not(.is--disabled):hover .vxe-radio--icon {
|
.vxe-table--render-default .vxe-cell--radio:not(.is--disabled):hover .vxe-radio--icon {
|
||||||
color: var(--el-color-primary-light-5);
|
color: var(--el-color-primary-light-5);
|
||||||
}
|
}
|
||||||
|
.vxe-table--render-default .vxe-body--row.row--current,
|
||||||
|
.vxe-table--render-default .vxe-body--row.row--current:hover {
|
||||||
|
background-color: var(--el-color-primary-light-8);
|
||||||
|
}
|
||||||
// .vxe-table--render-default .is--disabled.vxe-cell--checkbox .vxe-checkbox--icon{
|
// .vxe-table--render-default .is--disabled.vxe-cell--checkbox .vxe-checkbox--icon{
|
||||||
// color: #fff0;
|
// color: #fff0;
|
||||||
// }
|
// }
|
||||||
@@ -74,11 +77,11 @@
|
|||||||
.vxe-modal--wrapper {
|
.vxe-modal--wrapper {
|
||||||
z-index: 5000 !important;
|
z-index: 5000 !important;
|
||||||
}
|
}
|
||||||
.vxe-table--body .vxe-body--row:nth-child(even) {
|
// .vxe-table--body .vxe-body--row:nth-child(even) {
|
||||||
background-color: #f9f9f9;
|
// background-color: #f9f9f9;
|
||||||
// background-color: var(--el-color-primary-light-9);
|
// // background-color: var(--el-color-primary-light-9);
|
||||||
}
|
// }
|
||||||
|
|
||||||
.vxe-table--body .vxe-body--row:nth-child(odd) {
|
// .vxe-table--body .vxe-body--row:nth-child(odd) {
|
||||||
background-color: #ffffff;
|
// background-color: #ffffff;
|
||||||
}
|
// }
|
||||||
|
|||||||
@@ -1,17 +1,20 @@
|
|||||||
|
import { number } from 'vue-types'
|
||||||
|
|
||||||
const dataProcessing = (arr: any[]) => {
|
const dataProcessing = (arr: any[]) => {
|
||||||
return arr
|
return arr
|
||||||
.filter(item => typeof item === 'number' || (typeof item === 'string' && !isNaN(parseFloat(item))))
|
.filter(item => typeof item === 'number' || (typeof item === 'string' && !isNaN(parseFloat(item))))
|
||||||
.map(item => (typeof item === 'number' ? item : parseFloat(item)))
|
.map(item => (typeof item === 'number' ? item : parseFloat(item)))
|
||||||
}
|
}
|
||||||
|
|
||||||
const calculateValue = (o:number,value: number, num: number, isMin: boolean) => {
|
const calculateValue = (o: number, value: number, num: number, isMin: boolean) => {
|
||||||
if (value === 0) {
|
if (value === 0) {
|
||||||
return 0
|
return 0
|
||||||
}else if(value>0&& Math.abs(value)<1 && isMin==true){
|
} else if (value > 0 && Math.abs(value) < 1 && isMin == true) {
|
||||||
return 0
|
return 0
|
||||||
}else if(value>-1&& value<0 && isMin==false){
|
} else if (value > -1 && value < 0 && isMin == false) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
let base
|
let base
|
||||||
if (Math.abs(o) >= 100) {
|
if (Math.abs(o) >= 100) {
|
||||||
base = 100
|
base = 100
|
||||||
@@ -20,8 +23,11 @@ const calculateValue = (o:number,value: number, num: number, isMin: boolean) =>
|
|||||||
} else if (Math.abs(o) >= 1) {
|
} else if (Math.abs(o) >= 1) {
|
||||||
base = 1
|
base = 1
|
||||||
} else {
|
} else {
|
||||||
base = 0.1
|
const multiple = 1 / 0.1
|
||||||
|
|
||||||
|
base = Math.ceil(Math.abs(o) * multiple) / multiple
|
||||||
}
|
}
|
||||||
|
|
||||||
let calculatedValue
|
let calculatedValue
|
||||||
if (isMin) {
|
if (isMin) {
|
||||||
if (value < 0) {
|
if (value < 0) {
|
||||||
@@ -36,6 +42,7 @@ const calculateValue = (o:number,value: number, num: number, isMin: boolean) =>
|
|||||||
calculatedValue = value + num * value
|
calculatedValue = value + num * value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (base === 0.1) {
|
if (base === 0.1) {
|
||||||
return parseFloat(calculatedValue.toFixed(1))
|
return parseFloat(calculatedValue.toFixed(1))
|
||||||
} else if (isMin) {
|
} else if (isMin) {
|
||||||
@@ -55,9 +62,10 @@ export const yMethod = (arr: any) => {
|
|||||||
let min = 0
|
let min = 0
|
||||||
maxValue = Math.max(...numList)
|
maxValue = Math.max(...numList)
|
||||||
minValue = Math.min(...numList)
|
minValue = Math.min(...numList)
|
||||||
const o=maxValue-minValue
|
const o = maxValue - minValue == 0 ? maxValue : maxValue - minValue
|
||||||
min = calculateValue( o,minValue, num, true)
|
min = calculateValue(o, minValue, num, true)
|
||||||
max = calculateValue(o,maxValue, num, false)
|
|
||||||
|
max = calculateValue(o, maxValue, num, false)
|
||||||
// if (-100 >= minValue) {
|
// if (-100 >= minValue) {
|
||||||
// min = Math.floor((minValue + num * minValue) / 100) * 100
|
// min = Math.floor((minValue + num * minValue) / 100) * 100
|
||||||
// } else if (-10 >= minValue && minValue > -100) {
|
// } else if (-10 >= minValue && minValue > -100) {
|
||||||
@@ -128,20 +136,18 @@ export const yMethod = (arr: any) => {
|
|||||||
return [min, max]
|
return [min, max]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* title['A相','B相',]
|
* title['A相','B相',]
|
||||||
* data[[1,2],[3,4]]
|
* data[[1,2],[3,4]]
|
||||||
*/
|
*/
|
||||||
// 导出csv文件
|
// 导出csv文件
|
||||||
const convertToCSV = (title: object, data: any) => {
|
const convertToCSV = (title: object, data: any) => {
|
||||||
console.log('🚀 ~ convertToCSV ~ data:', data)
|
|
||||||
let csv = ''
|
let csv = ''
|
||||||
// 添加列头
|
// 添加列头
|
||||||
csv += ',' + title.join(',') + '\n'
|
csv += ',' + title.join(',') + '\n'
|
||||||
// 遍历数据并添加到CSV字符串中
|
// 遍历数据并添加到CSV字符串中
|
||||||
data?.map(item => {
|
data?.map(item => {
|
||||||
csv += item.join(',') + '\n'
|
csv += '\u200B' + item.join(',') + '\n'
|
||||||
})
|
})
|
||||||
return csv
|
return csv
|
||||||
}
|
}
|
||||||
@@ -155,3 +161,144 @@ export const exportCSV = (title: object, data: any, filename: string) => {
|
|||||||
// 释放URL对象
|
// 释放URL对象
|
||||||
URL.revokeObjectURL(link.href)
|
URL.revokeObjectURL(link.href)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 补全时间序列数据中缺失的条目
|
||||||
|
* @param rawData 原始数据,格式为 [["时间字符串", "数值", "单位", "类型"], ...]
|
||||||
|
* @returns 补全后的数据,缺失条目数值为 null
|
||||||
|
*/
|
||||||
|
export const completeTimeSeries = (rawData: string[][]): (string | null)[][] => {
|
||||||
|
// 步骤1:校验原始数据并解析时间
|
||||||
|
if (rawData.length < 2) {
|
||||||
|
console.warn('数据量不足2条,无法计算时间间隔,直接返回原始数据')
|
||||||
|
return rawData.map(item => [...item])
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析所有时间为Date对象,过滤无效时间并按时间排序
|
||||||
|
const validData = rawData
|
||||||
|
.map(item => {
|
||||||
|
// 确保至少有时间和数值字段
|
||||||
|
if (!item[0]) {
|
||||||
|
return { time: new Date(0), item, isValid: false }
|
||||||
|
}
|
||||||
|
const time = new Date(item[0])
|
||||||
|
return { time, item, isValid: !isNaN(time.getTime()) }
|
||||||
|
})
|
||||||
|
.filter(data => data.isValid)
|
||||||
|
.sort((a, b) => a.time.getTime() - b.time.getTime()) // 确保数据按时间排序
|
||||||
|
.map(data => data.item)
|
||||||
|
|
||||||
|
if (validData.length < 2) {
|
||||||
|
throw new Error('有效时间数据不足2条,无法继续处理')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 步骤2:计算时间间隔(分析前几条数据确定最可能的间隔)
|
||||||
|
const intervals: number[] = []
|
||||||
|
// 分析前10条数据来确定间隔,避免单一间隔出错
|
||||||
|
const analyzeCount = Math.min(10, validData.length - 1)
|
||||||
|
for (let i = 0; i < analyzeCount; i++) {
|
||||||
|
const currentTime = new Date(validData[i][0]!).getTime()
|
||||||
|
const nextTime = new Date(validData[i + 1][0]!).getTime()
|
||||||
|
const interval = nextTime - currentTime
|
||||||
|
if (interval > 0) {
|
||||||
|
intervals.push(interval)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取最常见的间隔作为标准间隔
|
||||||
|
const timeInterval = getMostFrequentValue(intervals)
|
||||||
|
if (timeInterval <= 0) {
|
||||||
|
throw new Error('无法确定有效的时间间隔')
|
||||||
|
}
|
||||||
|
|
||||||
|
// 步骤3:生成完整的时间序列范围(从第一条到最后一条)
|
||||||
|
const startTime = new Date(validData[0][0]!).getTime()
|
||||||
|
const endTime = new Date(validData[validData.length - 1][0]!).getTime()
|
||||||
|
const completeTimes: Date[] = []
|
||||||
|
|
||||||
|
// 生成从 startTime 到 endTime 的所有间隔时间点
|
||||||
|
for (let time = startTime; time <= endTime; time += timeInterval) {
|
||||||
|
completeTimes.push(new Date(time))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 步骤4:将原始数据转为时间映射表,使用精确的时间字符串匹配
|
||||||
|
const timeDataMap = new Map<string, (string | undefined)[]>()
|
||||||
|
validData.forEach(item => {
|
||||||
|
// 使用原始时间字符串作为键,避免格式转换导致的匹配问题
|
||||||
|
if (item[0]) {
|
||||||
|
timeDataMap.set(item[0], item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 提取模板数据(从第一条有效数据中提取单位和类型,处理可能的缺失)
|
||||||
|
const template = validData[0]
|
||||||
|
|
||||||
|
// 步骤5:对比补全数据,缺失条目数值为 null
|
||||||
|
const completedData = completeTimes.map(time => {
|
||||||
|
// 保持与原始数据相同的时间格式
|
||||||
|
const timeStr = formatTime(time)
|
||||||
|
const existingItem = timeDataMap.get(timeStr)
|
||||||
|
|
||||||
|
if (existingItem) {
|
||||||
|
// 存在该时间,返回原始数据
|
||||||
|
return [...existingItem]
|
||||||
|
} else {
|
||||||
|
// 缺失该时间,数值设为 null,其他字段沿用第一个有效数据的格式
|
||||||
|
// 处理可能缺失的单位和类型字段
|
||||||
|
const result: (string | null | undefined)[] = [timeStr, '/']
|
||||||
|
// 仅在原始数据有单位字段时才添加
|
||||||
|
if (template.length > 2) {
|
||||||
|
result.push(template[2])
|
||||||
|
}
|
||||||
|
// 仅在原始数据有类型字段时才添加
|
||||||
|
if (template.length > 3) {
|
||||||
|
result.push(template[3])
|
||||||
|
}
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return completedData
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 格式化时间为 "YYYY-MM-DD HH:mm:ss" 格式
|
||||||
|
* @param date 日期对象
|
||||||
|
* @returns 格式化后的时间字符串
|
||||||
|
*/
|
||||||
|
function formatTime(date: Date): string {
|
||||||
|
const year = date.getFullYear()
|
||||||
|
const month = String(date.getMonth() + 1).padStart(2, '0')
|
||||||
|
const day = String(date.getDate()).padStart(2, '0')
|
||||||
|
const hours = String(date.getHours()).padStart(2, '0')
|
||||||
|
const minutes = String(date.getMinutes()).padStart(2, '0')
|
||||||
|
const seconds = String(date.getSeconds()).padStart(2, '0')
|
||||||
|
|
||||||
|
return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取数组中出现频率最高的值
|
||||||
|
* @param arr 数字数组
|
||||||
|
* @returns 出现频率最高的值
|
||||||
|
*/
|
||||||
|
function getMostFrequentValue(arr: number[]): number {
|
||||||
|
if (arr.length === 0) return 0
|
||||||
|
|
||||||
|
const frequencyMap = new Map<number, number>()
|
||||||
|
arr.forEach(num => {
|
||||||
|
frequencyMap.set(num, (frequencyMap.get(num) || 0) + 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
let maxFrequency = 0
|
||||||
|
let mostFrequent = arr[0]
|
||||||
|
|
||||||
|
frequencyMap.forEach((frequency, num) => {
|
||||||
|
if (frequency > maxFrequency) {
|
||||||
|
maxFrequency = frequency
|
||||||
|
mostFrequent = num
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return mostFrequent
|
||||||
|
}
|
||||||
|
|||||||
@@ -352,7 +352,9 @@ export function getTimeOfTheMonth(key: any): [string, string] {
|
|||||||
const dayOfWeek = now.getDay() // 0是周日
|
const dayOfWeek = now.getDay() // 0是周日
|
||||||
const diff = now.getDate() - dayOfWeek + (dayOfWeek === 0 ? -6 : 1) // 调整为周一
|
const diff = now.getDate() - dayOfWeek + (dayOfWeek === 0 ? -6 : 1) // 调整为周一
|
||||||
const weekStart = new Date(year, month, diff)
|
const weekStart = new Date(year, month, diff)
|
||||||
return [formatDate(weekStart, 'YYYY-MM-DD'), formatDate(now, 'YYYY-MM-DD')]
|
const weekEnd = new Date(weekStart)
|
||||||
|
weekEnd.setDate(weekEnd.getDate() + 6)
|
||||||
|
return [formatDate(weekStart, 'YYYY-MM-DD'), formatDate(weekEnd, 'YYYY-MM-DD')]
|
||||||
|
|
||||||
case '5': // 日
|
case '5': // 日
|
||||||
return [formatDate(now, 'YYYY-MM-DD'), formatDate(now, 'YYYY-MM-DD')]
|
return [formatDate(now, 'YYYY-MM-DD'), formatDate(now, 'YYYY-MM-DD')]
|
||||||
@@ -361,3 +363,23 @@ export function getTimeOfTheMonth(key: any): [string, string] {
|
|||||||
throw new Error('Invalid key')
|
throw new Error('Invalid key')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当月时间
|
||||||
|
* @param interval 组件外部时间 1 年 2 季 3 月 4 周 5 日
|
||||||
|
* @param timeList 驾驶舱里面组件勾选时间 []
|
||||||
|
* @param externalTime //外部传入时间
|
||||||
|
* @param fullscreen // 全屏是否全屏
|
||||||
|
*/
|
||||||
|
export function getTime(interval: number | 3, timeList: any, externalTime: any) {
|
||||||
|
// console.log('🚀 ~ getTime ~ timeList:', timeList)
|
||||||
|
// 1、先匹配时间
|
||||||
|
// 检查 interval 是否在 timeList 中
|
||||||
|
if (timeList && timeList.includes(interval.toString())) {
|
||||||
|
return [externalTime[0], externalTime[1], interval]
|
||||||
|
} else {
|
||||||
|
if (timeList && timeList.length > 0) {
|
||||||
|
return [...getTimeOfTheMonth(timeList[0]), timeList[0]]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const bubble: {
|
|||||||
ctx: {},
|
ctx: {},
|
||||||
circles: [],
|
circles: [],
|
||||||
animate: true,
|
animate: true,
|
||||||
requestId: null,
|
requestId: null
|
||||||
}
|
}
|
||||||
|
|
||||||
export const init = function (): void {
|
export const init = function (): void {
|
||||||
@@ -76,7 +76,7 @@ class Circle {
|
|||||||
constructor() {
|
constructor() {
|
||||||
this.pos = {
|
this.pos = {
|
||||||
x: Math.random() * bubble.width,
|
x: Math.random() * bubble.width,
|
||||||
y: bubble.height + Math.random() * 100,
|
y: bubble.height + Math.random() * 100
|
||||||
}
|
}
|
||||||
this.alpha = 0.1 + Math.random() * 0.3
|
this.alpha = 0.1 + Math.random() * 0.3
|
||||||
this.scale = 0.1 + Math.random() * 0.3
|
this.scale = 0.1 + Math.random() * 0.3
|
||||||
@@ -84,6 +84,16 @@ class Circle {
|
|||||||
this.draw = function () {
|
this.draw = function () {
|
||||||
this.pos.y -= this.velocity
|
this.pos.y -= this.velocity
|
||||||
this.alpha -= 0.0005
|
this.alpha -= 0.0005
|
||||||
|
// 当气泡超出顶部或透明度为 0 时,重置位置和属性
|
||||||
|
if (this.pos.y < -10 || this.alpha < 0) {
|
||||||
|
this.pos = {
|
||||||
|
x: Math.random() * bubble.width,
|
||||||
|
y: bubble.height + Math.random() * 100
|
||||||
|
}
|
||||||
|
this.alpha = 0.1 + Math.random() * 0.35
|
||||||
|
this.scale = 0.1 + Math.random() * 0.35
|
||||||
|
this.velocity = Math.random()
|
||||||
|
}
|
||||||
bubble.ctx.beginPath()
|
bubble.ctx.beginPath()
|
||||||
bubble.ctx.arc(this.pos.x, this.pos.y, this.scale * 10, 0, 2 * Math.PI, false)
|
bubble.ctx.arc(this.pos.x, this.pos.y, this.scale * 10, 0, 2 * Math.PI, false)
|
||||||
bubble.ctx.fillStyle = 'rgba(255,255,255,' + this.alpha + ')'
|
bubble.ctx.fillStyle = 'rgba(255,255,255,' + this.alpha + ')'
|
||||||
|
|||||||
@@ -66,7 +66,14 @@ function createAxios<Data = any, T = ApiPromise<Data>>(
|
|||||||
!(
|
!(
|
||||||
config.url == '/system-boot/file/upload' ||
|
config.url == '/system-boot/file/upload' ||
|
||||||
config.url == '/harmonic-boot/grid/getAssessOverview' ||
|
config.url == '/harmonic-boot/grid/getAssessOverview' ||
|
||||||
config.url == '/harmonic-boot/gridDiagram/getGridDiagramAreaData'
|
config.url == '/harmonic-boot/gridDiagram/getGridDiagramAreaData' ||
|
||||||
|
config.url == '/cs-device-boot/csline/list' ||
|
||||||
|
config.url == '/cs-harmonic-boot/pqSensitiveUser/getListByIds'||
|
||||||
|
config.url == '/cs-harmonic-boot/csevent/getEventCoords'||
|
||||||
|
config.url == '/cs-harmonic-boot/limitRateDetailD/limitTimeProbabilityData'||
|
||||||
|
config.url == '/cs-harmonic-boot/limitRateDetailD/limitProbabilityData'||
|
||||||
|
config.url == '/system-boot/dictTree/queryByCode'||
|
||||||
|
config.url == '/system-boot/dictTree/query'
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
removePending(config)
|
removePending(config)
|
||||||
@@ -172,6 +179,8 @@ function createAxios<Data = any, T = ApiPromise<Data>>(
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
ElMessage.error(response.data.message || '未知错误')
|
ElMessage.error(response.data.message || '未知错误')
|
||||||
}, 6000)
|
}, 6000)
|
||||||
|
}else if (response.config.url == '/cs-harmonic-boot/cspage/getByUserId') {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
ElMessage.error(response.data.message || '未知错误')
|
ElMessage.error(response.data.message || '未知错误')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import router from '@/router/index'
|
import router from '@/router/index'
|
||||||
import { isNavigationFailure, NavigationFailureType } from 'vue-router'
|
import { isNavigationFailure, NavigationFailureType ,useRouter} from 'vue-router'
|
||||||
import type { RouteRecordRaw, RouteLocationRaw } from 'vue-router'
|
import type { RouteRecordRaw, RouteLocationRaw } from 'vue-router'
|
||||||
import { ElNotification } from 'element-plus'
|
import { ElNotification } from 'element-plus'
|
||||||
import { useConfig } from '@/stores/config'
|
import { useConfig } from '@/stores/config'
|
||||||
@@ -8,8 +8,9 @@ import { closeShade } from '@/utils/pageShade'
|
|||||||
import { adminBaseRoute } from '@/router/static'
|
import { adminBaseRoute } from '@/router/static'
|
||||||
import { compact, isEmpty, reverse } from 'lodash-es'
|
import { compact, isEmpty, reverse } from 'lodash-es'
|
||||||
import { isAdminApp } from '@/utils/common'
|
import { isAdminApp } from '@/utils/common'
|
||||||
import { log } from 'console'
|
import { getRouteMenu, dictDataCache } from '@/api/auth'
|
||||||
|
import { adminBaseRoutePath } from '@/router/static'
|
||||||
|
const route:any = useRouter()
|
||||||
/**
|
/**
|
||||||
* 导航失败有错误消息的路由push
|
* 导航失败有错误消息的路由push
|
||||||
* @param to — 导航位置,同 router.push
|
* @param to — 导航位置,同 router.push
|
||||||
@@ -279,6 +280,41 @@ export const addRouteItem = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 刷新菜单
|
||||||
|
export const getMenu = () => {
|
||||||
|
getRouteMenu().then((res: any) => {
|
||||||
|
const handlerMenu = (data: any) => {
|
||||||
|
data.forEach((item: any) => {
|
||||||
|
item.routePath =
|
||||||
|
item.routePath[0] == '/' ? item.routePath.substring(1, item.routePath.length) : item.routePath
|
||||||
|
item.path = item.routePath
|
||||||
|
item.name = item.routePath
|
||||||
|
item.keepalive = item.routePath
|
||||||
|
item.component = item.routeName
|
||||||
|
? item.routeName.indexOf('/src/views/') > -1
|
||||||
|
? item.routeName
|
||||||
|
: `/src/views/${item.routeName}/index.vue`
|
||||||
|
: ''
|
||||||
|
item.type = item.children && item.children.length > 0 ? 'menu_dir' : 'menu'
|
||||||
|
item.menu_type = item.children && item.children.length > 0 ? null : 'tab'
|
||||||
|
if (item.children) {
|
||||||
|
handlerMenu(item.children)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
handlerMenu(res.data)
|
||||||
|
handleAdminRoute(res.data)
|
||||||
|
if (route.params.to) {
|
||||||
|
const lastRoute = JSON.parse(route.params.to as string)
|
||||||
|
if (lastRoute.path != adminBaseRoutePath) {
|
||||||
|
let query = !isEmpty(lastRoute.query) ? lastRoute.query : {}
|
||||||
|
routePush({ path: lastRoute.path, query: query })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据name字符串,获取父级name组合的数组
|
* 根据name字符串,获取父级name组合的数组
|
||||||
* @param name
|
* @param name
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ interface TableStoreParams {
|
|||||||
publicHeight?: number //计算高度
|
publicHeight?: number //计算高度
|
||||||
resetCallback?: () => void // 重置
|
resetCallback?: () => void // 重置
|
||||||
loadCallback?: () => void // 接口调用后的回调
|
loadCallback?: () => void // 接口调用后的回调
|
||||||
|
exportProcessingData?: () => void //导出处理数据
|
||||||
beforeSearchFun?: () => void // 接口调用前的回调
|
beforeSearchFun?: () => void // 接口调用前的回调
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,9 +48,11 @@ export default class TableStore {
|
|||||||
column: [],
|
column: [],
|
||||||
loadCallback: null,
|
loadCallback: null,
|
||||||
resetCallback: null,
|
resetCallback: null,
|
||||||
|
exportProcessingData: null,
|
||||||
beforeSearchFun: null,
|
beforeSearchFun: null,
|
||||||
height: '',
|
height: '',
|
||||||
publicHeight: 0
|
publicHeight: 0,
|
||||||
|
filename: ''
|
||||||
})
|
})
|
||||||
|
|
||||||
constructor(public options: TableStoreParams) {
|
constructor(public options: TableStoreParams) {
|
||||||
@@ -64,6 +67,7 @@ export default class TableStore {
|
|||||||
this.table.publicHeight = options.publicHeight || 0
|
this.table.publicHeight = options.publicHeight || 0
|
||||||
this.table.resetCallback = options.resetCallback || null
|
this.table.resetCallback = options.resetCallback || null
|
||||||
this.table.loadCallback = options.loadCallback || null
|
this.table.loadCallback = options.loadCallback || null
|
||||||
|
this.table.exportProcessingData = options.exportProcessingData || null
|
||||||
this.table.beforeSearchFun = options.beforeSearchFun || null
|
this.table.beforeSearchFun = options.beforeSearchFun || null
|
||||||
Object.assign(this.table.params, options.params)
|
Object.assign(this.table.params, options.params)
|
||||||
this.table.height = mainHeight(20 + (this.showPage ? 58 : 0) + this.table.publicHeight).height as string
|
this.table.height = mainHeight(20 + (this.showPage ? 58 : 0) + this.table.publicHeight).height as string
|
||||||
@@ -94,14 +98,19 @@ export default class TableStore {
|
|||||||
this.table.data = []
|
this.table.data = []
|
||||||
this.table.total = 0
|
this.table.total = 0
|
||||||
}
|
}
|
||||||
this.table.copyData = filtration(this.table.data)
|
// 只有当 this.table.data 是数组时才执行 filtration 处理
|
||||||
|
if (Array.isArray(this.table.data)) {
|
||||||
|
this.table.copyData = filtration(this.table.data)
|
||||||
|
}
|
||||||
if (Array.isArray(res)) {
|
if (Array.isArray(res)) {
|
||||||
this.table.data = res
|
this.table.data = res
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isWebPaging) {
|
if (this.isWebPaging) {
|
||||||
this.table.webPagingData = window.XEUtils.chunk(this.table.data, this.table.params.pageSize)
|
this.table.webPagingData = window.XEUtils.chunk(this.table.data, this.table.params.pageSize)
|
||||||
this.table.data = this.table.webPagingData[this.table.params.pageNum - 1]
|
this.table.data = this.table.webPagingData[this.table.params.pageNum - 1]
|
||||||
}
|
}
|
||||||
|
|
||||||
this.table.loadCallback && this.table.loadCallback()
|
this.table.loadCallback && this.table.loadCallback()
|
||||||
this.table.loading = false
|
this.table.loading = false
|
||||||
})
|
})
|
||||||
@@ -187,26 +196,21 @@ export default class TableStore {
|
|||||||
[
|
[
|
||||||
'export',
|
'export',
|
||||||
() => {
|
() => {
|
||||||
ElMessage({
|
// this.index()
|
||||||
message: '正在导出,请稍等...',
|
|
||||||
type: 'info',
|
|
||||||
duration: 1000
|
|
||||||
})
|
|
||||||
let params = { ...this.table.params, pageNum: 1, pageSize: this.table.total }
|
let params = { ...this.table.params, pageNum: 1, pageSize: this.table.total }
|
||||||
setTimeout(() => {
|
createAxios(
|
||||||
createAxios(
|
Object.assign(
|
||||||
Object.assign(
|
{
|
||||||
{
|
url: this.url,
|
||||||
url: this.url,
|
method: this.method
|
||||||
method: this.method
|
},
|
||||||
},
|
requestPayload(this.method, params, this.paramsPOST)
|
||||||
requestPayload(this.method, params, this.paramsPOST)
|
)
|
||||||
)
|
).then(res => {
|
||||||
).then(res => {
|
this.table.allData = filtration(res.data.records || res.data)
|
||||||
this.table.allData = filtration(res.data.records || res.data)
|
this.table.exportProcessingData && this.table.exportProcessingData()
|
||||||
this.table.allFlag = data.showAllFlag || true
|
this.table.allFlag = data.showAllFlag || true
|
||||||
})
|
})
|
||||||
}, 1500)
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
])
|
])
|
||||||
|
|||||||
214
src/utils/webSocketClient.ts
Normal file
214
src/utils/webSocketClient.ts
Normal file
@@ -0,0 +1,214 @@
|
|||||||
|
import { ElMessage, EVENT_CODE } from "element-plus";
|
||||||
|
|
||||||
|
// 定义消息类型,用于类型检查
|
||||||
|
type MessageType = {
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default class SocketService {
|
||||||
|
// 单例模式实例
|
||||||
|
private static instance: SocketService | null = null;
|
||||||
|
// 和服务端连接的socket对象
|
||||||
|
private ws: WebSocket | null = null;
|
||||||
|
// 存储回调函数
|
||||||
|
private callBackMapping: {
|
||||||
|
[key: string]: ((message: MessageType) => void) | null;
|
||||||
|
} = {};
|
||||||
|
// 标识是否连接成功
|
||||||
|
private connected: boolean = false;
|
||||||
|
// 记录重试的次数
|
||||||
|
private sendRetryCount: number = 0;
|
||||||
|
// 重新连接尝试的次数
|
||||||
|
private connectRetryCount: number = 0;
|
||||||
|
// Web Worker 实例
|
||||||
|
private work: Worker | null = null;
|
||||||
|
// 临时的 Blob URL
|
||||||
|
private workerBlobUrl: string | null = null;
|
||||||
|
// 上次活动时间戳
|
||||||
|
private lastActivityTime: number = 0;
|
||||||
|
// 最后一次收到心跳回复时间
|
||||||
|
private lastResponseHeartTime: number = Date.now();
|
||||||
|
// 重新连接延迟,单位毫秒
|
||||||
|
private reconnectDelay: number = 5000;
|
||||||
|
|
||||||
|
// 单例模式获取实例
|
||||||
|
public static get Instance(): SocketService {
|
||||||
|
if (!this.instance) {
|
||||||
|
this.instance = new SocketService();
|
||||||
|
}
|
||||||
|
return this.instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 定义连接服务器的方法
|
||||||
|
public async connect(id: any) {
|
||||||
|
if (!window.WebSocket) {
|
||||||
|
console.log("您的浏览器不支持WebSocket");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let response = null;
|
||||||
|
if (import.meta.env.VITE_NAME == "beijing") {
|
||||||
|
response = await fetch("/vue/");
|
||||||
|
} else if (import.meta.env.VITE_NAME == "wuxi") {
|
||||||
|
response = await fetch("");
|
||||||
|
}
|
||||||
|
// const response = await fetch("/vue/");
|
||||||
|
|
||||||
|
const mqttUrl = response.headers.get("X-Mqtt-Url");
|
||||||
|
console.log("🚀 ~ SocketService ~ connect ~ mqttUrl:", mqttUrl);
|
||||||
|
setTimeout(() => {
|
||||||
|
//"ws://10.156.193.182:18093/ws/screen" 北京
|
||||||
|
//"ws://192.168.1.130:19001/ws/askRealTimeData/" 无锡
|
||||||
|
const url = (mqttUrl || "ws://192.168.1.127:19001/ws/") + id;
|
||||||
|
// const url = (mqttUrl || "ws://192.168.1.63:18093/ws/screen") + id;
|
||||||
|
console.log("🚀 ~ SocketService ~ connect ~ url:", url);
|
||||||
|
this.ws = new WebSocket(url);
|
||||||
|
|
||||||
|
this.ws.onopen = () => this.handleOpen();
|
||||||
|
this.ws.onclose = () => this.handleClose();
|
||||||
|
this.ws.onerror = () => this.handleError();
|
||||||
|
this.ws.onmessage = (event) => this.handleMessage(event);
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理连接成功事件
|
||||||
|
private handleOpen(): void {
|
||||||
|
ElMessage.success("webSocket连接服务端成功了");
|
||||||
|
console.log("连接服务端成功了");
|
||||||
|
this.connected = true;
|
||||||
|
this.connectRetryCount = 0;
|
||||||
|
this.updateLastActivityTime();
|
||||||
|
this.startHeartbeat();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理连接关闭事件
|
||||||
|
private handleClose(): void {
|
||||||
|
console.log("连接webSocket服务端关闭");
|
||||||
|
this.connected = false;
|
||||||
|
this.connectRetryCount++;
|
||||||
|
this.clearHeartbeat();
|
||||||
|
// 可根据需要添加重连逻辑
|
||||||
|
// setTimeout(() => this.connect(), 500 * this.connectRetryCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理连接错误事件
|
||||||
|
private handleError(): void {
|
||||||
|
ElMessage.error("webSocket连接异常!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理服务端发送过来的数据
|
||||||
|
private handleMessage(event: MessageEvent): void {
|
||||||
|
// console.log('🚀 ~ SocketService ~ handleMessage ~ event.data:', event.data)
|
||||||
|
|
||||||
|
if (event.data == "连接成功") {
|
||||||
|
this.sendHeartbeat();
|
||||||
|
} else if (event.data.length > 10) {
|
||||||
|
let message: MessageType;
|
||||||
|
try {
|
||||||
|
// console.log(
|
||||||
|
// 'Received message:', event.data)
|
||||||
|
message = JSON.parse(event.data);
|
||||||
|
this.callBackMapping["message"]!(message);
|
||||||
|
} catch (e) {
|
||||||
|
// console.error("消息解析失败", event.data, e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// console.log("🚀 ~ SocketService ~ handleMessage ~ message:", message)
|
||||||
|
|
||||||
|
// this.callBackMapping["message"]!(message);
|
||||||
|
} else {
|
||||||
|
// ElMessage.error(event.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 启动心跳检测
|
||||||
|
private startHeartbeat(): void {
|
||||||
|
this.lastResponseHeartTime = Date.now();
|
||||||
|
const url = window.URL.createObjectURL(
|
||||||
|
new Blob([
|
||||||
|
"(function(e){setInterval(function(){this.postMessage(null)},30000)})()",
|
||||||
|
])
|
||||||
|
);
|
||||||
|
this.workerBlobUrl = url;
|
||||||
|
this.work = new Worker(url);
|
||||||
|
this.work.onmessage = (e) => this.handleWorkerMessage(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理 Web Worker 消息
|
||||||
|
private handleWorkerMessage(e: MessageEvent): void {
|
||||||
|
// if (this.lastActivityTime - this.lastResponseHeartTime > 30000) {
|
||||||
|
// // 说明已经三轮心跳没收到回复了,关闭检测,提示用户。
|
||||||
|
// // ElMessage.error('业务主体模块发生未知异常,请尝试重新启动!')
|
||||||
|
// this.clearHeartbeat()
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// console.log(123);
|
||||||
|
|
||||||
|
this.sendHeartbeat();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送心跳消息
|
||||||
|
private sendHeartbeat(): void {
|
||||||
|
// console.log(new Date() + '进入心跳消息发送。。。。。。。。。。。。。')
|
||||||
|
if (this.ws) {
|
||||||
|
this.ws.send("alive");
|
||||||
|
this.updateLastActivityTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新活动时间
|
||||||
|
private updateLastActivityTime(): void {
|
||||||
|
this.lastActivityTime = Date.now();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清除心跳检测
|
||||||
|
private clearHeartbeat(): void {
|
||||||
|
if (this.work) {
|
||||||
|
this.work.terminate();
|
||||||
|
this.work = null;
|
||||||
|
}
|
||||||
|
if (this.workerBlobUrl) {
|
||||||
|
window.URL.revokeObjectURL(this.workerBlobUrl);
|
||||||
|
this.workerBlobUrl = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 回调函数的注册
|
||||||
|
public registerCallBack(
|
||||||
|
socketType: string,
|
||||||
|
callBack: (message: MessageType) => void
|
||||||
|
): void {
|
||||||
|
this.callBackMapping[socketType] = callBack;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取消某一个回调函数
|
||||||
|
public unRegisterCallBack(socketType: string): void {
|
||||||
|
this.callBackMapping[socketType] = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发送数据的方法
|
||||||
|
public send(data: any): void {
|
||||||
|
if (this.connected) {
|
||||||
|
this.sendRetryCount = 0;
|
||||||
|
try {
|
||||||
|
if (this.ws) {
|
||||||
|
this.ws.send(JSON.stringify(data));
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (this.ws) {
|
||||||
|
this.ws.send(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.sendRetryCount++;
|
||||||
|
setTimeout(() => this.send(data), this.sendRetryCount * 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 断开方法
|
||||||
|
public closeWs(): void {
|
||||||
|
if (this.connected && this.ws) {
|
||||||
|
this.ws.close();
|
||||||
|
}
|
||||||
|
console.log("执行WS关闭命令..");
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@
|
|||||||
<el-scrollbar>
|
<el-scrollbar>
|
||||||
<el-form :inline="false" :model="form" label-width="auto" class="form-one">
|
<el-form :inline="false" :model="form" label-width="auto" class="form-one">
|
||||||
<el-form-item label="上级菜单">
|
<el-form-item label="上级菜单">
|
||||||
<el-cascader v-model.trim="form.pid" :options="tableStore.table.data" :props="cascaderProps"
|
<el-cascader v-model.trim="form.pid" :options="tableStore.table.data" :props="cascaderProps" clearable
|
||||||
style="width: 100%" />
|
style="width: 100%" />
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="菜单名称">
|
<el-form-item label="菜单名称">
|
||||||
@@ -92,6 +92,7 @@ const open = (text: string, data: anyObj) => {
|
|||||||
}
|
}
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
if (form.id) {
|
if (form.id) {
|
||||||
|
form.pid = form.pid||'0'
|
||||||
await updateMenu(form)
|
await updateMenu(form)
|
||||||
} else {
|
} else {
|
||||||
form.code = 'menu'
|
form.code = 'menu'
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<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" :row-config="{ isCurrent: true, isHover: true }" @currentChange="currentChange" />
|
||||||
</div>
|
</div>
|
||||||
<Tree
|
<Tree
|
||||||
v-if="menuListId"
|
v-if="menuListId"
|
||||||
@@ -13,8 +13,8 @@
|
|||||||
show-checkbox
|
show-checkbox
|
||||||
width="350px"
|
width="350px"
|
||||||
:data="menuTree"
|
:data="menuTree"
|
||||||
:checkStrictly="checkStrictly"
|
:checkStrictly="false"
|
||||||
@check-change="checkChange"
|
@checkChange="checkChange"
|
||||||
></Tree>
|
></Tree>
|
||||||
<el-empty style="width: 350px; padding-top: 300px; box-sizing: border-box" description="请选择角色" v-else />
|
<el-empty style="width: 350px; padding-top: 300px; box-sizing: border-box" description="请选择角色" v-else />
|
||||||
<PopupForm ref="popupRef"></PopupForm>
|
<PopupForm ref="popupRef"></PopupForm>
|
||||||
@@ -26,7 +26,7 @@ import { ref, onMounted, provide } from 'vue'
|
|||||||
import TableStore from '@/utils/tableStore'
|
import TableStore from '@/utils/tableStore'
|
||||||
import Table from '@/components/table/index.vue'
|
import Table from '@/components/table/index.vue'
|
||||||
import TableHeader from '@/components/table/header/index.vue'
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
import Tree from '@/components/tree/index.vue'
|
import Tree from '@/components/tree/allocation.vue'
|
||||||
import { functionTree } from '@/api/user-boot/function'
|
import { functionTree } from '@/api/user-boot/function'
|
||||||
import { getFunctionsByRoleIndex, updateRoleMenu } from '@/api/user-boot/roleFuction'
|
import { getFunctionsByRoleIndex, updateRoleMenu } from '@/api/user-boot/roleFuction'
|
||||||
import { mainHeight } from '@/utils/layout'
|
import { mainHeight } from '@/utils/layout'
|
||||||
@@ -43,6 +43,7 @@ const height = mainHeight(20).height
|
|||||||
const treeRef = ref()
|
const treeRef = ref()
|
||||||
const menuTree = ref<treeData[]>([])
|
const menuTree = ref<treeData[]>([])
|
||||||
const popupRef = ref()
|
const popupRef = ref()
|
||||||
|
const tableRef = ref()
|
||||||
const checkStrictly = ref(true)
|
const checkStrictly = ref(true)
|
||||||
const menuListId = ref('')
|
const menuListId = ref('')
|
||||||
const tableStore = new TableStore({
|
const tableStore = new TableStore({
|
||||||
@@ -104,7 +105,13 @@ const tableStore = new TableStore({
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
loadCallback: () => {
|
||||||
|
tableRef.value.getRef().setCurrentRow(tableStore.table.data[0])
|
||||||
|
currentChange({
|
||||||
|
row: tableStore.table.data[0]
|
||||||
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
tableStore.table.params.searchValue = ''
|
tableStore.table.params.searchValue = ''
|
||||||
|
|
||||||
@@ -139,19 +146,22 @@ const currentChange = (data: any) => {
|
|||||||
|
|
||||||
const timeout = ref<NodeJS.Timeout>()
|
const timeout = ref<NodeJS.Timeout>()
|
||||||
const checkChange = (data: any) => {
|
const checkChange = (data: any) => {
|
||||||
if (checkStrictly.value) {
|
// if (checkStrictly.value) {
|
||||||
checkStrictly.value = false
|
// checkStrictly.value = false
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
if (timeout.value) {
|
|
||||||
clearTimeout(timeout.value)
|
updateRoleMenu({
|
||||||
}
|
id: menuListId.value,
|
||||||
timeout.value = setTimeout(() => {
|
idList: treeRef.value.treeRef.getCheckedNodes(false, true).map((node: any) => node.id)
|
||||||
updateRoleMenu({
|
})
|
||||||
id: menuListId.value,
|
.then(() => {
|
||||||
idList: treeRef.value.treeRef.getCheckedNodes(false, true).map((node: any) => node.id)
|
ElMessage.success('操作成功!')
|
||||||
|
treeRef.value.loading = false
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
treeRef.value.loading = false
|
||||||
})
|
})
|
||||||
}, 1000)
|
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
tableStore.index()
|
tableStore.index()
|
||||||
|
|||||||
@@ -107,7 +107,7 @@ const tableStore = new TableStore({
|
|||||||
return row.state !== 1
|
return row.state !== 1
|
||||||
},
|
},
|
||||||
click: row => {
|
click: row => {
|
||||||
ElMessageBox.prompt('二次校验密码确认', '注销用户', {
|
ElMessageBox.prompt('二次校验密码确认', '修改密码', {
|
||||||
confirmButtonText: '确认',
|
confirmButtonText: '确认',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
inputType: 'password'
|
inputType: 'password'
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-dialog width=“500px” v-model.trim="dialogVisible" title="修改密码">
|
<el-dialog width='500px' draggable v-model.trim="dialogVisible" title="修改密码">
|
||||||
<el-scrollbar>
|
<el-scrollbar>
|
||||||
<el-form :inline="false" :model="form" label-width="120px" class="form-one" :rules="rules" ref="formRef">
|
<el-form :inline="false" :model="form" label-width="120px" class="form-one" :rules="rules" ref="formRef">
|
||||||
<el-form-item label="新密码" prop="newPwd">
|
<el-form-item label="新密码" prop="newPwd">
|
||||||
|
|||||||
@@ -94,7 +94,15 @@ const tableStore = new TableStore({
|
|||||||
},
|
},
|
||||||
{ title: '设备名称', field: 'ndid', align: 'center' },
|
{ title: '设备名称', field: 'ndid', align: 'center' },
|
||||||
{ title: '异常时间', field: 'evtTime', align: 'center', sortable: true },
|
{ title: '异常时间', field: 'evtTime', align: 'center', sortable: true },
|
||||||
{ title: '告警代码', field: 'code', align: 'center', sortable: true }
|
{
|
||||||
|
title: '告警代码',
|
||||||
|
field: 'code',
|
||||||
|
align: 'center',
|
||||||
|
sortable: true,
|
||||||
|
formatter: (row: any) => {
|
||||||
|
return row.cellValue ? '\u200B' + row.cellValue : '/'
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -83,14 +83,14 @@ 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: 'equipmentName', align: 'center' },
|
{ title: '设备名称', field: 'equipmentName', align: 'center',minWidth: 100 },
|
||||||
{ title: '工程名称', field: 'engineeringName', align: 'center' },
|
{ title: '工程名称', field: 'engineeringName', align: 'center',minWidth: 100 },
|
||||||
{ title: '项目名称', field: 'projectName', align: 'center' },
|
{ title: '项目名称', field: 'projectName', align: 'center',minWidth: 100 },
|
||||||
{ title: '发生时刻', field: 'startTime', align: 'center', minWidth: 110, sortable: true },
|
{ title: '发生时刻', field: 'startTime', align: 'center', minWidth: 180, sortable: true },
|
||||||
{
|
{
|
||||||
title: '模块信息',
|
title: '模块信息',
|
||||||
field: 'moduleNo',
|
field: 'moduleNo',
|
||||||
align: 'center',
|
align: 'center',minWidth: 100 ,
|
||||||
formatter: (row: any) => {
|
formatter: (row: any) => {
|
||||||
return row.cellValue ? row.cellValue : '/'
|
return row.cellValue ? row.cellValue : '/'
|
||||||
}
|
}
|
||||||
@@ -99,20 +99,21 @@ const tableStore = new TableStore({
|
|||||||
title: '告警代码',
|
title: '告警代码',
|
||||||
field: 'code',
|
field: 'code',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
width: 100,
|
||||||
formatter: (row: any) => {
|
formatter: (row: any) => {
|
||||||
return row.cellValue ? row.cellValue : '/'
|
return row.cellValue ? '\u200B' + row.cellValue : '/'
|
||||||
},
|
},
|
||||||
sortable: true
|
sortable: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '事件描述',
|
title: '事件描述',
|
||||||
|
minWidth: 250,
|
||||||
field: 'showName'
|
field: 'showName'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '级别',
|
title: '级别',
|
||||||
field: 'level',
|
field: 'level',
|
||||||
|
width: 100,
|
||||||
render: 'tag',
|
render: 'tag',
|
||||||
custom: {
|
custom: {
|
||||||
1: 'danger',
|
1: 'danger',
|
||||||
@@ -133,7 +134,8 @@ const tableStore = new TableStore({
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
],
|
],
|
||||||
beforeSearchFun: () => {}
|
beforeSearchFun: () => {},
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
provide('tableStore', tableStore)
|
provide('tableStore', tableStore)
|
||||||
|
|||||||
@@ -35,10 +35,10 @@ 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: 'lineId', align: 'center' },
|
{ title: '前置服务器名称', field: 'lineId', align: 'center' ,minWidth: 120 },
|
||||||
{ title: '前置服务器ip', field: 'wavePath', align: 'center' },
|
{ title: '前置服务器ip', field: 'wavePath', align: 'center' ,minWidth: 100 },
|
||||||
{ title: '进程号', field: 'clDid', align: 'center' },
|
{ title: '进程号', field: 'clDid', align: 'center',minWidth: 60 },
|
||||||
{ title: '发生时刻', field: 'startTime', align: 'center', minWidth: 80, sortable: true },
|
{ title: '发生时刻', field: 'startTime', align: 'center', minWidth: 180, sortable: true },
|
||||||
|
|
||||||
{
|
{
|
||||||
title: '事件描述',
|
title: '事件描述',
|
||||||
@@ -48,10 +48,11 @@ const tableStore = new TableStore({
|
|||||||
{
|
{
|
||||||
title: '告警代码',
|
title: '告警代码',
|
||||||
field: 'code',
|
field: 'code',
|
||||||
align: 'center',
|
align: 'center',minWidth: 100 ,
|
||||||
|
|
||||||
|
|
||||||
formatter: (row: any) => {
|
formatter: (row: any) => {
|
||||||
return row.cellValue ? row.cellValue : '/'
|
return row.cellValue ? '\u200B' + row.cellValue : '/'
|
||||||
},
|
},
|
||||||
sortable: true
|
sortable: true
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ import TableHeader from '@/components/table/header/index.vue'
|
|||||||
import shushiboxi from '@/components/echarts/shushiboxi.vue'
|
import shushiboxi from '@/components/echarts/shushiboxi.vue'
|
||||||
import waveFormAnalysis from '@/views/govern/device/control/tabs/components/waveFormAnalysis.vue'
|
import waveFormAnalysis from '@/views/govern/device/control/tabs/components/waveFormAnalysis.vue'
|
||||||
import rmsboxi from '@/components/echarts/rmsboxi.vue'
|
import rmsboxi from '@/components/echarts/rmsboxi.vue'
|
||||||
import { analyseWave } from '@/api/common'
|
import { analyseWave, getFileByEventId } from '@/api/common'
|
||||||
import { mainHeight } from '@/utils/layout'
|
import { mainHeight } from '@/utils/layout'
|
||||||
import { ElMessage } from 'element-plus'
|
import { ElMessage } from 'element-plus'
|
||||||
import { getFileZip } from '@/api/cs-harmonic-boot/datatrend'
|
import { getFileZip } from '@/api/cs-harmonic-boot/datatrend'
|
||||||
@@ -128,15 +128,15 @@ 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: 'equipmentName', align: 'center' },
|
{ title: '设备名称', field: 'equipmentName', minWidth: 120,align: 'center' },
|
||||||
{ title: '工程名称', field: 'engineeringName', align: 'center' },
|
{ title: '工程名称', field: 'engineeringName', minWidth: 120,align: 'center' },
|
||||||
{ title: '项目名称', field: 'projectName', align: 'center' },
|
{ title: '项目名称', field: 'projectName', minWidth: 120,align: 'center' },
|
||||||
{ title: '发生时刻', field: 'startTime', align: 'center', width: '240',sortable: true },
|
{ title: '发生时刻', field: 'startTime', align: 'center', minWidth: 180,sortable: true },
|
||||||
{ title: '监测点名称', field: 'lineName', align: 'center' },
|
{ title: '监测点名称', field: 'lineName', minWidth: 120,align: 'center' },
|
||||||
{ title: '事件描述', field: 'showName', align: 'center' },
|
{ title: '事件描述', field: 'showName', minWidth: 120,align: 'center' },
|
||||||
{ title: '事件发生位置', field: 'evtParamPosition', align: 'center' },
|
{ title: '事件发生位置', field: 'evtParamPosition',minWidth: 150, align: 'center' },
|
||||||
{ title: '相别', field: 'evtParamPhase', align: 'center' },
|
{ title: '相别', field: 'evtParamPhase',minWidth: 80, align: 'center' },
|
||||||
{ title: '持续时间(s)', field: 'evtParamTm', align: 'center',sortable: true },
|
{ title: '持续时间(s)', field: 'evtParamTm',minWidth: 80, align: 'center',sortable: true },
|
||||||
{ title: '暂降(聚升)幅值(%)', minWidth: 100, field: 'evtParamVVaDepth', align: 'center',sortable: true },
|
{ title: '暂降(聚升)幅值(%)', minWidth: 100, field: 'evtParamVVaDepth', align: 'center',sortable: true },
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -153,7 +153,7 @@ const tableStore = new TableStore({
|
|||||||
render: 'basicButton',
|
render: 'basicButton',
|
||||||
loading: 'loading1',
|
loading: 'loading1',
|
||||||
disabled: row => {
|
disabled: row => {
|
||||||
return !row.wavePath && row.evtParamTm < 20
|
return !row.wavePath
|
||||||
},
|
},
|
||||||
click: async row => {
|
click: async row => {
|
||||||
row.loading1 = true
|
row.loading1 = true
|
||||||
@@ -166,7 +166,7 @@ const tableStore = new TableStore({
|
|||||||
boxoList.value = row
|
boxoList.value = row
|
||||||
boxoList.value.featureAmplitude =
|
boxoList.value.featureAmplitude =
|
||||||
row.evtParamVVaDepth != '-' ? row.evtParamVVaDepth - 0 : null
|
row.evtParamVVaDepth != '-' ? row.evtParamVVaDepth - 0 : null
|
||||||
boxoList.value.systemType = 'WX'
|
boxoList.value.systemType = 'ZL'
|
||||||
wp.value = res.data
|
wp.value = res.data
|
||||||
}
|
}
|
||||||
loading.value = false
|
loading.value = false
|
||||||
@@ -212,7 +212,6 @@ const tableStore = new TableStore({
|
|||||||
loading: 'loading2',
|
loading: 'loading2',
|
||||||
render: 'basicButton',
|
render: 'basicButton',
|
||||||
disabled: row => {
|
disabled: row => {
|
||||||
// && row.evtParamTm < 20
|
|
||||||
return !row.wavePath
|
return !row.wavePath
|
||||||
},
|
},
|
||||||
click: row => {
|
click: row => {
|
||||||
@@ -235,8 +234,24 @@ const tableStore = new TableStore({
|
|||||||
icon: 'el-icon-DataLine',
|
icon: 'el-icon-DataLine',
|
||||||
render: 'basicButton',
|
render: 'basicButton',
|
||||||
disabled: row => {
|
disabled: row => {
|
||||||
return !(!row.wavePath && row.evtParamTm < 20)
|
return row.showName != '未知';
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'edit',
|
||||||
|
title: '波形补召',
|
||||||
|
type: 'primary',
|
||||||
|
icon: 'el-icon-Check',
|
||||||
|
render: 'basicButton',
|
||||||
|
disabled: row => {
|
||||||
|
return row.wavePath || row.showName === '未知';
|
||||||
|
},
|
||||||
|
click: row => {
|
||||||
|
getFileByEventId(row.id).then(res => {
|
||||||
|
ElMessage.success(res.message)
|
||||||
|
tableStore.index()
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -298,6 +313,7 @@ const sourceChange = (e: any) => {
|
|||||||
tableStore.table.params.engineeringid = e[1] || ''
|
tableStore.table.params.engineeringid = e[1] || ''
|
||||||
tableStore.table.params.projectId = e[2] || ''
|
tableStore.table.params.projectId = e[2] || ''
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// tableStore.table.params.engineeringid = e[1] || ''
|
// tableStore.table.params.engineeringid = e[1] || ''
|
||||||
|
|||||||
@@ -52,6 +52,9 @@
|
|||||||
</template>
|
</template>
|
||||||
<template v-slot:operation>
|
<template v-slot:operation>
|
||||||
<el-button type="primary" @click="search" icon="el-icon-Search">查询</el-button>
|
<el-button type="primary" @click="search" icon="el-icon-Search">查询</el-button>
|
||||||
|
<el-button :type="timeControl ? 'primary' : ''" icon="el-icon-Sort" @click="setTimeControl">
|
||||||
|
缺失数据
|
||||||
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
</div>
|
</div>
|
||||||
@@ -76,9 +79,9 @@ import { getDevCapacity } from '@/api/cs-device-boot/capacity'
|
|||||||
import { queryCommonStatisticalByTime } from '@/api/cs-harmonic-boot/stable'
|
import { queryCommonStatisticalByTime } from '@/api/cs-harmonic-boot/stable'
|
||||||
import DatePicker from '@/components/form/datePicker/index.vue'
|
import DatePicker from '@/components/form/datePicker/index.vue'
|
||||||
import MyEchart from '@/components/echarts/MyEchart.vue'
|
import MyEchart from '@/components/echarts/MyEchart.vue'
|
||||||
import { yMethod } from '@/utils/echartMethod'
|
import { yMethod, completeTimeSeries } from '@/utils/echartMethod'
|
||||||
import TableHeader from '@/components/table/header/index.vue'
|
import TableHeader from '@/components/table/header/index.vue'
|
||||||
|
const timeControl = ref(false)
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'govern/analyze/APF'
|
name: 'govern/analyze/APF'
|
||||||
})
|
})
|
||||||
@@ -98,6 +101,7 @@ const formInline = reactive({
|
|||||||
devId: '',
|
devId: '',
|
||||||
frequency: ''
|
frequency: ''
|
||||||
})
|
})
|
||||||
|
const dataLists = ref<any[]>([])
|
||||||
const timeFlag = ref(true)
|
const timeFlag = ref(true)
|
||||||
const frequencyShow = ref(false)
|
const frequencyShow = ref(false)
|
||||||
const devCapacity = ref(0)
|
const devCapacity = ref(0)
|
||||||
@@ -180,225 +184,242 @@ const search = () => {
|
|||||||
|
|
||||||
queryCommonStatisticalByTime(formInline)
|
queryCommonStatisticalByTime(formInline)
|
||||||
.then(({ data }: { data: any[] }) => {
|
.then(({ data }: { data: any[] }) => {
|
||||||
if (data.length) {
|
dataLists.value = data
|
||||||
let list = processingOfData(data, 'unit')
|
setEchart()
|
||||||
|
|
||||||
echartsData.value = {}
|
|
||||||
let legend: any[] = []
|
|
||||||
let xAxis: any[] = []
|
|
||||||
let yAxis: any[] = []
|
|
||||||
let series: any[] = []
|
|
||||||
let color: any[] = []
|
|
||||||
let title = ''
|
|
||||||
data.forEach(item => {
|
|
||||||
if (!xAxis.includes(item.time)) {
|
|
||||||
xAxis.push(item.time)
|
|
||||||
}
|
|
||||||
// if (!legend.includes(item.anotherName)) {
|
|
||||||
// legend.push(item.anotherName)
|
|
||||||
// }
|
|
||||||
})
|
|
||||||
let units = Object.keys(list)
|
|
||||||
// console.log('🚀 ~ .then ~ units:', units)
|
|
||||||
for (let unit in list) {
|
|
||||||
console.log('🚀 ~ .then ~ unit:', unit)
|
|
||||||
let [min, max] = yMethod(list[unit].map((item: any) => item.statisticalData))
|
|
||||||
yAxis.push({
|
|
||||||
name: unit == 'null' ? '' : unit,
|
|
||||||
type: 'value',
|
|
||||||
// max: 10,
|
|
||||||
min: min,
|
|
||||||
max: max,
|
|
||||||
// splitNumber: 5,
|
|
||||||
// minInterval: 1,
|
|
||||||
|
|
||||||
axisLine: {
|
|
||||||
show: true,
|
|
||||||
//symbol: ["none", "arrow"],
|
|
||||||
lineStyle: {
|
|
||||||
color: '#333'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
// processingOfData(list[unit], 'anotherName')
|
|
||||||
let anotherList = processingOfData(list[unit], 'anotherName')
|
|
||||||
for (let k in anotherList) {
|
|
||||||
title = k
|
|
||||||
let lineName = lineStyle[Object.keys(anotherList).indexOf(k)]
|
|
||||||
let phaseList = processingOfData(anotherList[k], 'phase')
|
|
||||||
for (let j in phaseList) {
|
|
||||||
color.push(j == 'A' ? '#DAA520' : j == 'B' ? '#2E8B57' : j == 'C' ? '#A52a2a' : '#0000CC')
|
|
||||||
legend.push(
|
|
||||||
j == 'M' ? k : j == 'A' ? `A相_${k}` : j == 'B' ? `B相_${k}` : j == 'C' ? `C相_${k}` : j
|
|
||||||
)
|
|
||||||
series.push({
|
|
||||||
name:
|
|
||||||
j == 'M'
|
|
||||||
? k
|
|
||||||
: j == 'A'
|
|
||||||
? `A相_${k}`
|
|
||||||
: j == 'B'
|
|
||||||
? `B相_${k}`
|
|
||||||
: j == 'C'
|
|
||||||
? `C相_${k}`
|
|
||||||
: j,
|
|
||||||
symbol: 'none',
|
|
||||||
smooth: true,
|
|
||||||
type: 'line',
|
|
||||||
|
|
||||||
data: phaseList[j].map(item => [
|
|
||||||
item.time,
|
|
||||||
Math.floor(item.statisticalData * 100) / 100,
|
|
||||||
unit,
|
|
||||||
lineName.type
|
|
||||||
]),
|
|
||||||
lineStyle: lineName,
|
|
||||||
yAxisIndex: unit.indexOf(units)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
echartsData.value = {
|
|
||||||
title: {
|
|
||||||
text: zblist.value.filter(item => item.id == formInline.statisticalId)[0].name
|
|
||||||
},
|
|
||||||
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,
|
|
||||||
formatter(params: any) {
|
|
||||||
const xname = params[0].value[0]
|
|
||||||
let str = `${xname}<br>`
|
|
||||||
params.forEach((el: any, index: any) => {
|
|
||||||
let marker = ''
|
|
||||||
if (el.value[3] == 'dashed') {
|
|
||||||
for (let i = 0; i < 3; i++) {
|
|
||||||
marker += `<span style="display:inline-block;border: 2px ${el.color} solid;margin-right:5px;width:10px;height:0px;background-color:#ffffff00;"></span>`
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
marker = `<span style="display:inline-block;border: 2px ${el.color} ${el.value[3]};margin-right:5px;width:40px;height:0px;background-color:#ffffff00;"></span>`
|
|
||||||
}
|
|
||||||
|
|
||||||
str += `${marker}${el.seriesName.split('(')[0]}:${
|
|
||||||
el.value[1] != null
|
|
||||||
? el.value[1] + ' ' + (el.value[2] == 'null' ? '' : el.value[2])
|
|
||||||
: '-'
|
|
||||||
}<br>`
|
|
||||||
})
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
},
|
|
||||||
legend: {
|
|
||||||
itemWidth: 20,
|
|
||||||
itemHeight: 20,
|
|
||||||
itemStyle: { opacity: 0 }, //去圆点
|
|
||||||
type: 'scroll', // 开启滚动分页
|
|
||||||
top: 25
|
|
||||||
// data: legend
|
|
||||||
},
|
|
||||||
grid: {
|
|
||||||
left: '20px',
|
|
||||||
right: '40px',
|
|
||||||
bottom: '50px',
|
|
||||||
top: '80px',
|
|
||||||
containLabel: true
|
|
||||||
},
|
|
||||||
toolbox: {
|
|
||||||
feature: {
|
|
||||||
saveAsImage: {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
color: color,
|
|
||||||
xAxis: {
|
|
||||||
name: '',
|
|
||||||
type: 'time',
|
|
||||||
axisLabel: {
|
|
||||||
formatter: {
|
|
||||||
day: '{MM}-{dd}',
|
|
||||||
month: '{MM}',
|
|
||||||
year: '{yyyy}'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// boundaryGap: false,
|
|
||||||
// data: xAxis,
|
|
||||||
// axisLabel: {
|
|
||||||
// formatter: function (value: string) {
|
|
||||||
// return value.split(' ').join('\n')
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// axisLine: {
|
|
||||||
// show: true,
|
|
||||||
// // symbol: ["none", "arrow"],
|
|
||||||
// lineStyle: {
|
|
||||||
// color: '#333'
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
},
|
|
||||||
yAxis: yAxis,
|
|
||||||
// [
|
|
||||||
// {
|
|
||||||
// name: '畸变率:(%)',
|
|
||||||
// type: 'value',
|
|
||||||
// // max: 10,
|
|
||||||
// min: min1,
|
|
||||||
// max: max1,
|
|
||||||
// splitNumber: 5,
|
|
||||||
// minInterval: 1,
|
|
||||||
|
|
||||||
// axisLine: {
|
|
||||||
// show: true,
|
|
||||||
// //symbol: ["none", "arrow"],
|
|
||||||
// lineStyle: {
|
|
||||||
// color: '#333'
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: '电流:(A)',
|
|
||||||
// type: 'value',
|
|
||||||
// min: min,
|
|
||||||
// max: max,
|
|
||||||
// splitNumber: 5,
|
|
||||||
// minInterval: 1,
|
|
||||||
// splitLine: {
|
|
||||||
// show: false
|
|
||||||
// },
|
|
||||||
// axisLine: {
|
|
||||||
// show: true,
|
|
||||||
// //symbol: ["none", "arrow"],
|
|
||||||
// lineStyle: {
|
|
||||||
// color: '#333'
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// ],
|
|
||||||
options: {
|
|
||||||
series: series
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
echartsData.value = null
|
|
||||||
}
|
|
||||||
loading.value = false
|
loading.value = false
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
loading.value = false
|
loading.value = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
const setEchart = () => {
|
||||||
|
loading.value = true
|
||||||
|
let data = JSON.parse(JSON.stringify(dataLists.value))
|
||||||
|
if (data.length) {
|
||||||
|
let list = processingOfData(data, 'unit')
|
||||||
|
|
||||||
|
echartsData.value = {}
|
||||||
|
let legend: any[] = []
|
||||||
|
let xAxis: any[] = []
|
||||||
|
let yAxis: any[] = []
|
||||||
|
let series: any[] = []
|
||||||
|
let color: any[] = []
|
||||||
|
let title = ''
|
||||||
|
data.forEach(item => {
|
||||||
|
if (!xAxis.includes(item.time)) {
|
||||||
|
xAxis.push(item.time)
|
||||||
|
}
|
||||||
|
// if (!legend.includes(item.anotherName)) {
|
||||||
|
// legend.push(item.anotherName)
|
||||||
|
// }
|
||||||
|
})
|
||||||
|
let units = Object.keys(list)
|
||||||
|
// console.log('🚀 ~ .then ~ units:', units)
|
||||||
|
for (let unit in list) {
|
||||||
|
console.log('🚀 ~ .then ~ unit:', unit)
|
||||||
|
let [min, max] = yMethod(list[unit].map((item: any) => item.statisticalData))
|
||||||
|
yAxis.push({
|
||||||
|
name: unit == 'null' ? '' : unit,
|
||||||
|
type: 'value',
|
||||||
|
// max: 10,
|
||||||
|
min: min,
|
||||||
|
max: max,
|
||||||
|
// splitNumber: 5,
|
||||||
|
// minInterval: 1,
|
||||||
|
|
||||||
|
axisLine: {
|
||||||
|
show: true,
|
||||||
|
//symbol: ["none", "arrow"],
|
||||||
|
lineStyle: {
|
||||||
|
color: '#333'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// processingOfData(list[unit], 'anotherName')
|
||||||
|
let anotherList = processingOfData(list[unit], 'anotherName')
|
||||||
|
for (let k in anotherList) {
|
||||||
|
title = k
|
||||||
|
let lineName = lineStyle[Object.keys(anotherList).indexOf(k)]
|
||||||
|
let phaseList = processingOfData(anotherList[k], 'phase')
|
||||||
|
for (let j in phaseList) {
|
||||||
|
color.push(j == 'A' ? '#DAA520' : j == 'B' ? '#2E8B57' : j == 'C' ? '#A52a2a' : '#0000CC')
|
||||||
|
legend.push(
|
||||||
|
j == 'M' ? k : j == 'A' ? `A相_${k}` : j == 'B' ? `B相_${k}` : j == 'C' ? `C相_${k}` : j
|
||||||
|
)
|
||||||
|
series.push({
|
||||||
|
name: j == 'M' ? k : j == 'A' ? `A相_${k}` : j == 'B' ? `B相_${k}` : j == 'C' ? `C相_${k}` : j,
|
||||||
|
symbol: 'none',
|
||||||
|
smooth: true,
|
||||||
|
type: 'line',
|
||||||
|
|
||||||
|
// data: phaseList[j].map(item => [
|
||||||
|
// item.time,
|
||||||
|
// Math.floor(item.statisticalData * 100) / 100,
|
||||||
|
// unit,
|
||||||
|
// lineName.type
|
||||||
|
// ]),
|
||||||
|
data: timeControl.value
|
||||||
|
? completeTimeSeries(
|
||||||
|
phaseList[j].map(item => [
|
||||||
|
item.time,
|
||||||
|
Math.floor(item.statisticalData * 100) / 100,
|
||||||
|
unit,
|
||||||
|
lineName.type
|
||||||
|
])
|
||||||
|
)
|
||||||
|
: phaseList[j].map(item => [
|
||||||
|
item.time,
|
||||||
|
Math.floor(item.statisticalData * 100) / 100,
|
||||||
|
unit,
|
||||||
|
lineName.type
|
||||||
|
]),
|
||||||
|
|
||||||
|
lineStyle: lineName,
|
||||||
|
yAxisIndex: unit.indexOf(units)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
echartsData.value = {
|
||||||
|
title: {
|
||||||
|
text: zblist.value.filter(item => item.id == formInline.statisticalId)[0].name
|
||||||
|
},
|
||||||
|
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,
|
||||||
|
formatter(params: any) {
|
||||||
|
const xname = params[0].value[0]
|
||||||
|
let str = `${xname}<br>`
|
||||||
|
params.forEach((el: any, index: any) => {
|
||||||
|
let marker = ''
|
||||||
|
if (el.value[3] == 'dashed') {
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
marker += `<span style="display:inline-block;border: 2px ${el.color} solid;margin-right:5px;width:10px;height:0px;background-color:#ffffff00;"></span>`
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
marker = `<span style="display:inline-block;border: 2px ${el.color} ${el.value[3]};margin-right:5px;width:40px;height:0px;background-color:#ffffff00;"></span>`
|
||||||
|
}
|
||||||
|
|
||||||
|
str += `${marker}${el.seriesName.split('(')[0]}:${
|
||||||
|
el.value[1] != null ? el.value[1] + ' ' + (el.value[2] == 'null' ? '' : el.value[2]) : '-'
|
||||||
|
}<br>`
|
||||||
|
})
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
itemWidth: 20,
|
||||||
|
itemHeight: 20,
|
||||||
|
itemStyle: { opacity: 0 }, //去圆点
|
||||||
|
type: 'scroll', // 开启滚动分页
|
||||||
|
top: 25
|
||||||
|
// data: legend
|
||||||
|
},
|
||||||
|
grid: {
|
||||||
|
left: '20px',
|
||||||
|
right: '40px',
|
||||||
|
bottom: '50px',
|
||||||
|
top: '80px',
|
||||||
|
containLabel: true
|
||||||
|
},
|
||||||
|
toolbox: {
|
||||||
|
feature: {
|
||||||
|
saveAsImage: {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
color: color,
|
||||||
|
xAxis: {
|
||||||
|
name: '',
|
||||||
|
type: 'time',
|
||||||
|
axisLabel: {
|
||||||
|
formatter: {
|
||||||
|
day: '{MM}-{dd}',
|
||||||
|
month: '{MM}',
|
||||||
|
year: '{yyyy}'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// boundaryGap: false,
|
||||||
|
// data: xAxis,
|
||||||
|
// axisLabel: {
|
||||||
|
// formatter: function (value: string) {
|
||||||
|
// return value.split(' ').join('\n')
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// axisLine: {
|
||||||
|
// show: true,
|
||||||
|
// // symbol: ["none", "arrow"],
|
||||||
|
// lineStyle: {
|
||||||
|
// color: '#333'
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
},
|
||||||
|
yAxis: yAxis,
|
||||||
|
// [
|
||||||
|
// {
|
||||||
|
// name: '畸变率:(%)',
|
||||||
|
// type: 'value',
|
||||||
|
// // max: 10,
|
||||||
|
// min: min1,
|
||||||
|
// max: max1,
|
||||||
|
// splitNumber: 5,
|
||||||
|
// minInterval: 1,
|
||||||
|
|
||||||
|
// axisLine: {
|
||||||
|
// show: true,
|
||||||
|
// //symbol: ["none", "arrow"],
|
||||||
|
// lineStyle: {
|
||||||
|
// color: '#333'
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
// {
|
||||||
|
// name: '电流:(A)',
|
||||||
|
// type: 'value',
|
||||||
|
// min: min,
|
||||||
|
// max: max,
|
||||||
|
// splitNumber: 5,
|
||||||
|
// minInterval: 1,
|
||||||
|
// splitLine: {
|
||||||
|
// show: false
|
||||||
|
// },
|
||||||
|
// axisLine: {
|
||||||
|
// show: true,
|
||||||
|
// //symbol: ["none", "arrow"],
|
||||||
|
// lineStyle: {
|
||||||
|
// color: '#333'
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// ],
|
||||||
|
options: {
|
||||||
|
series: series
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
echartsData.value = null
|
||||||
|
}
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
const setTimeControl = () => {
|
||||||
|
timeControl.value = !timeControl.value
|
||||||
|
setEchart()
|
||||||
|
}
|
||||||
|
|
||||||
const processingOfData = (data: any, type: string) => {
|
const processingOfData = (data: any, type: string) => {
|
||||||
let groupedData: any = {}
|
let groupedData: any = {}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user