首页,生态调查,智能告警页面线上接口对接,二级页面开发

This commit is contained in:
王兴凯 2026-07-01 18:23:41 +08:00
parent 78eb7f9b87
commit 03fb75980f
62 changed files with 11362 additions and 1085 deletions

View File

@ -7,7 +7,7 @@ VITE_APP_TITLE = '水电水利建设项目全过程环境管理信息平台'
VITE_APP_PORT = 3000 VITE_APP_PORT = 3000
VITE_APP_BASE_API = '/dev-api' VITE_APP_BASE_API = '/dev-api'
# 本地环境 # 本地环境
VITE_APP_BASE_URL = 'http://localhost:8093' # VITE_APP_BASE_URL = 'http://10.84.121.122:8093'
# 测试环境 # 测试环境
# VITE_APP_BASE_URL = 'http://172.16.21.142:8093' # VITE_APP_BASE_URL = 'http://172.16.21.142:8093'
# VITE_APP_BASE_URL = 'http://172.16.21.142:8096' # VITE_APP_BASE_URL = 'http://172.16.21.142:8096'

View File

@ -8,3 +8,102 @@ export function getBaseWbsb(data: any) {
data: data data: data
}); });
} }
// 水电开发及环境监测 - 获取列表数据
export function getVmsstbprptKendoList(data: any) {
return request({
url: '/api/dec-lygk-base-server/base/vmsstbprpt/GetKendoList',
method: 'post',
data: data
});
}
// 环保设施建设情况
export function environmentalProtectionConstruction(data: any) {
return request({
url: '/api/wmp-env-server/env/operat/GetKendoListCust',
method: 'post',
data: data
});
}
// 环保设施弹框表格
export function envOpdGetKendoListCust(data: any) {
return request({
url: '/api/wmp-env-server/env/oped/GetKendoListCust',
method: 'post',
data: data
});
}
// 获取基地列表
export function getBaseList(data: any) {
return request({
url: '/api/dec-lygk-base-server/base/wbsb/GetKendoList',
method: 'post',
data: data
});
}
// 获取设施介绍列表
export function getMsstbprptKendoList(data: any) {
return request({
url: '/api/dec-lygk-base-server/base/msstbprpt/GetKendoList',
method: 'post',
data: data
});
}
// 环保自动监测工作开展情况
export function baseEvnmAutoMonitorGetKendoListCust(data: any) {
return request({
url: '/api/dec-lygk-base-server/base/evnmAutoMonitor/GetKendoListCust',
method: 'post',
data: data
});
}
// 环保自动监测弹窗列表
export function vmsstbprptGetKendoList(data: any) {
return request({
url: '/api/dec-lygk-base-server/base/vmsstbprpt/GetKendoList',
method: 'post',
data: data
});
}
// 获取基本信息
export function baseMsstbprptGetKendoList(data: any) {
return request({
url: '/api/dec-lygk-base-server/base/msstbprpt/GetKendoList',
method: 'post',
data: data
});
}
// 降水量实时数据
export function getBaseStbprpDataPPTNR(data: any) {
return request({
url: '/api/dec-lygk-base-server/base/stbprpData/GetKendoListCust?tbCode=PPTN_R',
method: 'post',
data: data
});
}
// 气温气压实时数据
export function getBaseStbprpDataTMPR(data: any) {
return request({
url: '/api/dec-lygk-base-server/base/stbprpData/GetKendoListCust?tbCode=TMP_R',
method: 'post',
data: data
});
}
// 风速风向实时数据
export function getBaseStbprpDataWNDR(data: any) {
return request({
url: '/api/dec-lygk-base-server/base/stbprpData/GetKendoListCust?tbCode=WND_R',
method: 'post',
data: data
});
}

View File

@ -547,7 +547,7 @@ export function getFlowDischargeYear(data: any) {
} }
export function getFlowDischargeList(code: string, data: any) { export function getFlowDischargeList(code: string, data: any) {
return request({ return request({
url: `/apo/dec-lygk-base-server/base/stbprpData/GetKendoListCust?tbCode=${code}`, url: `/api/dec-lygk-base-server/base/stbprpData/GetKendoListCust?tbCode=${code}`,
method: 'post', method: 'post',
data data
}); });

View File

@ -3,16 +3,16 @@ import request from '@/utils/request';
//水生生态调查情况-下拉选择框 //水生生态调查情况-下拉选择框
export function wbsbGetKendoList(data: any) { export function wbsbGetKendoList(data: any) {
return request({ return request({
url: '/api/dec-lygk-base-server/base/wbsb/GetKendoList', url: '/eq/wbsb/GetKendoList',
method: 'post', method: 'post',
data data
}); });
} }
// 水生生态调查情况-获取默认年份 // 水生生态调查情况-获取默认年份
export function getDftYear(data: any) { export function getDftYear(data: any) {
return request({ return request({
url: '/api/wmp-env-server/env/we/fisht/year/qgc/GetKendoListCust', url: '/wte/we/fisht/year/qgc/GetKendoListCust',
method: 'post', method: 'post',
data data
}); });
@ -21,7 +21,7 @@ export function getDftYear(data: any) {
// 水生生态调查情况-获取统计数据 // 水生生态调查情况-获取统计数据
export function getWeFisht(data: any) { export function getWeFisht(data: any) {
return request({ return request({
url: '/api/wmp-env-server/env/we/fisht/statics/GetKendoListCust', url: '/wte/we/fisht/statics/GetKendoListCust',
method: 'post', method: 'post',
data data
}); });
@ -30,7 +30,7 @@ export function getWeFisht(data: any) {
// 水生生态调查概况-表格数据接口 // 水生生态调查概况-表格数据接口
export function getWeStaticsSecond(data: any) { export function getWeStaticsSecond(data: any) {
return request({ return request({
url: '/api/wmp-env-server/env/we/fisht/statics/getWeStaticsSecond', url: '/wte/we/fisht/statics/getWeStaticsSecond',
method: 'post', method: 'post',
data data
}); });
@ -39,7 +39,7 @@ export function getWeStaticsSecond(data: any) {
// 沿程鱼类变化-图表数据接口 // 沿程鱼类变化-图表数据接口
export function fishChanges2(data: any) { export function fishChanges2(data: any) {
return request({ return request({
url: '/api/wmp-env-server/env/we/fisht/stat/GetKendoListCust', url: '/wte/we/fisht/stat/GetKendoListCust',
method: 'post', method: 'post',
data data
}); });
@ -48,7 +48,7 @@ export function fishChanges2(data: any) {
// 沿程鱼类变化-详情表格接口 // 沿程鱼类变化-详情表格接口
export function fishDetail(data: any) { export function fishDetail(data: any) {
return request({ return request({
url: '/api/wmp-env-server/env/we/fisht/detail/GetKendoListCust', url: '/wte/we/fisht/detail/GetKendoListCust',
method: 'post', method: 'post',
data data
}); });
@ -57,7 +57,7 @@ export function fishDetail(data: any) {
// 沿程鱼类变化-Tab数量统计接口 // 沿程鱼类变化-Tab数量统计接口
export function getTabNum(data: any) { export function getTabNum(data: any) {
return request({ return request({
url: '/api/wmp-env-server/env/we/fisht/statTab/GetKendoListCust', url: '/wte/we/fisht/statTab/GetKendoListCust',
method: 'post', method: 'post',
data data
}); });
@ -66,11 +66,11 @@ export function getTabNum(data: any) {
// 沿程鱼类变化-获取断面列表 // 沿程鱼类变化-获取断面列表
export function getStcdList(data: any) { export function getStcdList(data: any) {
return request({ return request({
url: '/api/dec-lygk-base-server/base/vmsstbprpt/noWqDtinType0Auth/GetKendoList', url: '/eq/base/vmsstbprpt/GetKendoList',
method: 'post', method: 'post',
data: { data: {
filter: data, filter: data,
orders: JSON.stringify({ siteStepSort: 'asc' }) orders: { siteStepSort: 'asc' }
} }
}); });
} }
@ -78,7 +78,16 @@ export function getStcdList(data: any) {
// 沿程鱼类变化-基地模式详情表格接口 // 沿程鱼类变化-基地模式详情表格接口
export function fishQgcDetail(data: any) { export function fishQgcDetail(data: any) {
return request({ return request({
url: '/api/wmp-env-server/env/we/fisht/qgcDetail/GetKendoListCust', url: '/wte/we/fisht/qgcDetail/GetKendoListCust',
method: 'post',
data
});
}
// 水生生态调查-鱼类列表统计
export function getFishListStat(data: any) {
return request({
url: '/wte/we/fishList/stat/qgc/GetKendoListCust',
method: 'post', method: 'post',
data data
}); });
@ -87,7 +96,7 @@ export function fishQgcDetail(data: any) {
// 陆生生态监测情况-获取统计数据 // 陆生生态监测情况-获取统计数据
export function getEvnmAutoMonitor(data: any) { export function getEvnmAutoMonitor(data: any) {
return request({ return request({
url: '/api/dec-lygk-base-server/base/evnmAutoMonitor/GetKendoListCust', url: '/wte/base/evnmAutoMonitor/GetKendoListCust',
method: 'post', method: 'post',
data data
}); });
@ -96,7 +105,7 @@ export function getEvnmAutoMonitor(data: any) {
// 陆生生态监测-红外相机信息表格 // 陆生生态监测-红外相机信息表格
export function getVmsstbprptList(data: any) { export function getVmsstbprptList(data: any) {
return request({ return request({
url: '/api/dec-lygk-base-server/base/vmsstbprpt/GetKendoList', url: '/wte/vmsstbprpt/GetKendoList',
method: 'post', method: 'post',
data data
}); });
@ -105,7 +114,7 @@ export function getVmsstbprptList(data: any) {
// 陆生生态监测-重点陆生动物表格 // 陆生生态监测-重点陆生动物表格
export function getTetSpecList(data: any) { export function getTetSpecList(data: any) {
return request({ return request({
url: '/api/wmp-env-server/te/tet/spec/GetKendoListCust', url: '/wte/te/tet/spec/GetKendoListCust',
method: 'post', method: 'post',
data data
}); });
@ -114,7 +123,7 @@ export function getTetSpecList(data: any) {
// 野生动物监测-获取运行数据 // 野生动物监测-获取运行数据
export function getWvaData(data: any) { export function getWvaData(data: any) {
return request({ return request({
url: '/api/wmp-env-server/env/wva/GetKendoListCust', url: '/wte/wva/GetKendoListCust',
method: 'post', method: 'post',
data data
}); });
@ -123,7 +132,7 @@ export function getWvaData(data: any) {
// 野生动物监测-获取默认数据 // 野生动物监测-获取默认数据
export function getWvaDftData(data: any) { export function getWvaDftData(data: any) {
return request({ return request({
url: '/api/wmp-env-server/env/wva/default/GetKendoListCust', url: '/wte/wva/default/GetKendoListCust',
method: 'post', method: 'post',
data data
}); });
@ -132,7 +141,25 @@ export function getWvaDftData(data: any) {
// 野生动物监测-获取默认年份列表 // 野生动物监测-获取默认年份列表
export function getWvaDftTm(data: any) { export function getWvaDftTm(data: any) {
return request({ return request({
url: '/api/wmp-env-server/env/wva/year/GetKendoListCust', url: '/wte/wva/year/GetKendoListCust',
method: 'post',
data
});
}
// 水生生态调查对比-获取断面和批次列表
export function getFishtKendoList(data: any) {
return request({
url: '/wte/we/fisht/GetKendoListCust',
method: 'post',
data
});
}
// 水生生态调查对比-获取对比柱状图数据
export function getCompareBar(data: any) {
return request({
url: '/wte/we/compareBar/GetKendoListCust',
method: 'post', method: 'post',
data data
}); });

View File

@ -39,6 +39,13 @@ export function vmsstbprptGetKendoList(queryParams: any) {
data: queryParams data: queryParams
}); });
} }
export function vmsstbprptGetKendoList1(queryParams: any) {
return request({
url: '/eq/vmsstbprpt/GetKendoList',
method: 'post',
data: queryParams
});
}
//生态流量达标情况 //生态流量达标情况
export function eqqecRateCount(queryParams: any) { export function eqqecRateCount(queryParams: any) {
return request({ return request({

View File

@ -15,6 +15,13 @@ export function msstbprptGetKendoList(data: any) {
data data
}); });
} }
export function VDmsstbprptGetKendoList(data: any) {
return request({
url: '/vd/msstbprpt/GetKendoList',
method: 'post',
data
});
}
//获取鱼类介绍 //获取鱼类介绍
export function fishDicGetKendoList(data: any) { export function fishDicGetKendoList(data: any) {
return request({ return request({

View File

@ -0,0 +1,91 @@
import request from '@/utils/request';
// AI识别大坝环境-获取统计数据Tab数量
export function getAisbdbyxList(data: any) {
return request({
url: '/api/wmp-env-server/env/ai/com/qgcDmRun/GetKendoListCust',
method: 'post',
data
});
}
// AI识别大坝环境-获取饼图+表格数据
export function getAiChartTable(data: any) {
return request({
url: '/api/wmp-env-server/env/ai/com/GetKendoListCust',
method: 'post',
data
});
}
// AI识别大坝环境-获取电站列表
export function getAiRstcd(data: any) {
return request({
url: '/api/wmp-env-server/env/ai/com/qgc/aiRstcd/GetKendoListCust',
method: 'post',
data
});
}
// AI识别过鱼设施运行-获取统计数据
export function getAiGyssList(data: any) {
return request({
url: '/api/wmp-env-server/env/ai/com/qgcProtect/GetKendoListCust',
method: 'post',
data
});
}
// 生态流量低于限值告警-获取统计数据
export function getStllGaojingList(data: any) {
return request({
url: '/api/wmp-env-server/env/warn/stcd/eng/GetKendoListCust',
method: 'post',
data
});
}
// 生态流量低于限值告警-获取表格详情数据
export function getStllGaojingDetail(data: any) {
return request({
url: '/api/wmp-env-server/env/warn/stcd/GetKendoListCust',
method: 'post',
data
});
}
// 水质监测数据告警-获取统计数据
export function getShuizhiGaojingList(data: any) {
return request({
url: '/api/dec-lygk-base-server/base/msstbprpt/GetKendoList',
method: 'post',
data
});
}
// AI识别大坝环境-获取漂浮物/清漂日历数据
export function getAiPfwRecord(data: any) {
return request({
url: '/api/wmp-env-server/env/ai/com/qgc/aiPfwRecord/GetKendoListCust',
method: 'post',
data
});
}
// AI识别大坝环境-获取叠梁门日历数据
export function getAiRecord(data: any) {
return request({
url: '/api/wmp-env-server/env/ai/com/qgc/aiRecord/GetKendoListCust',
method: 'post',
data
});
}
// AI识别大坝环境-获取日历详情视频数据
export function getAiFile(data: any) {
return request({
url: '/api/wmp-env-server/env/ai/com/qgc/aiFile/GetKendoListCust',
method: 'post',
data
});
}

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<svg t="1686656066409" class="icon" viewBox="0 0 1125 1024" version="1.1" p-id="8027" width="200px" height="200" xmlns="http://www.w3.org/2000/svg">
<path d="M 30.838 832.939 C 50.02 828.843 69.932 838.571 77.414 856.645 L 81.464 865.553 C 105.989 914.859 157.741 946.705 215.059 946.757 L 225.073 946.449 C 281.324 942.712 330.824 908.254 351.919 857.26 L 354.337 852.497 C 363.718 835.933 385.453 828.642 404.401 835.704 L 409.969 838.418 C 418.957 843.814 425.415 852.065 428.082 861.56 L 432.582 870.418 C 457.895 916.651 507.621 946.757 563.027 946.757 C 622.204 946.705 675.642 912.401 698.593 859.717 L 701.518 855.212 L 704.387 851.115 C 708.712 844.518 715.206 839.324 722.949 836.267 L 728.181 834.732 C 748.135 830.289 768.547 840.308 775.431 857.925 L 779.763 867.294 C 794.916 897.625 821.636 921.927 854.971 935.697 C 929.953 966.11 1016.355 932.114 1047.911 859.717 L 1048.08 859.205 C 1057.136 839.544 1080.423 830.892 1100.393 839.391 L 1105.624 842.104 C 1122.559 852.451 1129.395 872.075 1122.105 889.413 C 1108.341 921.238 1086.593 949.694 1058.598 972.509 C 962.24 1050.589 818.52 1038.506 737.631 945.527 L 729.193 954.744 C 723.357 960.686 717.16 966.327 710.63 971.64 C 614.497 1050.334 470.439 1038.916 388.931 946.142 L 379.481 956.279 C 357.028 978.957 329.35 996.841 298.424 1008.657 C 181.14 1053.149 48.669 997.495 2.544 884.395 L 0.969 878.917 C -3.323 860.632 6.954 842.094 25.662 834.373 Z M 544.971 0.023 C 636.098 -1.411 711.868 63.459 718.675 146.709 L 719.125 156.029 L 719.125 331.388 C 728.125 338.043 736.562 345.365 744.268 353.352 L 752.594 362.568 C 843.888 463.944 832.582 613.139 729.08 701.612 L 717.886 710.675 C 605.682 797.944 436.511 783.877 343.536 679.546 C 251.848 577.863 262.986 428.053 366.713 338.914 L 376.725 330.722 L 376.725 156.029 C 378.356 70.525 452.663 1.559 544.916 0.023 Z M 546.21 64.022 C 494.965 64.893 452.663 101.603 447.545 148.144 L 447.038 156.029 L 447.038 360.212 L 422.401 379.361 C 338.587 444.59 327.561 560.967 397.876 638.944 C 463.053 712.486 580.631 725.591 663.379 668.537 L 673.561 661.011 C 754 598.752 767.219 488.928 705.399 411.669 L 696.061 400.763 C 691.954 395.945 687.44 391.426 682.561 387.246 L 675.08 381.256 L 648.81 362.056 L 648.81 157.104 C 647.854 107.184 606.06 67.299 554.421 64.227 L 546.21 64.022 Z M 547.784 192.022 L 553.072 192.38 C 570.284 194.735 583.447 208.252 583.503 224.534 L 583.503 436.552 C 613.879 446.177 637.561 467.989 647.854 495.687 L 650.386 503.264 C 664.467 552.032 635.116 602.481 582.884 619.283 L 574.334 621.536 C 494.627 638.949 424.1 571.296 447.385 499.76 C 456.868 470.627 480.812 447.228 512.064 436.552 L 512.064 224.584 C 512.096 206.632 528.06 192.078 547.784 192.022 Z" p-id="8028" fill="#ffffff"/>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>guojiashuiwenzhan</title>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="画板" transform="translate(-304.000000, -319.000000)">
<g id="BGSM备份-11" transform="translate(177.000000, 156.000000)">
<g id="ControlRates备份-2" transform="translate(121.000000, 157.000000)">
<g id="guojiashuiwenzhan" transform="translate(6.000000, 6.000000)">
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
<polygon id="路径" fill="#FFFFFF" fill-rule="nonzero" points="3 14 8 0 13 14"></polygon>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 931 B

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>guojiashuizhizhan</title>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="画板" transform="translate(-304.000000, -250.000000)" fill="#FFFFFF" fill-rule="nonzero">
<g id="BGSM备份-11" transform="translate(177.000000, 156.000000)">
<g id="ControlRates备份-5" transform="translate(121.000000, 88.000000)">
<path d="M14.0127685,18.7975456 C15.186503,18.7996035 16.3093298,18.3553149 17.1170051,17.5692308 C17.9474718,16.7610359 18.4087696,15.6886498 18.405125,14.5747692 C18.405125,12.2387692 16.6849722,9.84000002 14.014102,6 C11.3352311,9.84 9.62310059,12.24 9.62310059,14.5747692 C9.62310059,15.6984616 10.087136,16.7766154 10.9111988,17.5692308 C11.7185556,18.3550038 12.8408306,18.7992648 14.014102,18.7975456 L14.0127685,18.7975456 Z M13.9807661,8.72123079 C14.3341264,9.24430771 14.5274744,9.85353848 14.5434757,10.48 C14.5434757,12.56 12.3286402,12.9107692 12.3286402,11.6307692 C12.3606426,10.8 13.4513924,9.49046156 13.9820995,8.71876924 L13.9820995,8.72123079 L13.9807661,8.72123079 Z M14.014102,21.9975385 C12.0619532,21.9975385 9.2844081,21.5175385 7.9949765,20.1095385 C8.5283505,19.8166154 9.09372692,19.5803077 9.68177174,19.4055385 C10.4084938,19.8855385 11.8952738,20.3975385 14.014102,20.3975385 C16.1315967,20.3975385 17.6183767,19.8855385 18.3784346,19.4055385 C18.9664794,19.5815385 19.5331893,19.8178462 20.0678967,20.112 C18.7464627,21.52 15.9689176,22 14.0167688,22 L14.014102,21.9975385 L14.014102,21.9975385 Z M19.9305529,13.136 C20.4612601,12.3027693 21.3853305,12.6867692 21.8520327,11.9187692 C22.4147423,11.0227692 21.2559873,10.0947693 20.3319169,10.8947692 C19.8332122,11.3501538 19.734538,12.2067692 19.9318864,13.1347692 L19.9305529,13.136 Z M7.66561805,10.8898462 C6.77221663,10.0578462 5.58279261,10.9858462 6.1455022,11.9138462 C6.64020657,12.6806154 7.53494144,12.2978462 8.06564855,13.1298462 C8.29366592,12.2067692 8.19499175,11.3489231 7.66561805,10.8935385 L7.66561805,10.8898462 Z" id="guojiashuizhizhan"></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg t="1686656243919" class="icon" viewBox="0 0 1024 1024" version="1.1" p-id="8195" width="200" height="200" xmlns="http://www.w3.org/2000/svg">
<path d="M 1001.523 839.355 C 983.397 830.856 962.199 839.509 954.16 858.709 C 954.019 859.048 953.882 859.389 953.751 859.733 C 925.077 932.077 846.431 966.073 778.126 935.661 C 744.625 920.365 718.592 892.363 705.777 857.838 C 698.097 838.024 676.848 828.399 658.005 836.283 C 650.963 839.326 645.054 844.502 641.108 851.08 C 639.419 853.538 637.626 856.661 635.886 859.681 C 614.945 912.365 566.302 946.668 512.437 946.72 C 458.879 946.72 411.107 912.723 389.551 861.525 C 386.669 850.094 378.761 840.585 368.046 835.669 C 349.254 827.784 327.955 837.359 320.274 857.173 C 299.947 911.239 250.587 946.668 195.699 946.72 C 140.502 946.668 90.887 910.983 70.407 856.609 C 62.982 836.898 42.091 827.068 23.3 834.389 C 4.662 842.274 -4.657 864.443 2.307 884.41 C 44.293 997.509 164.824 1053.162 271.58 1008.67 C 303.882 995.076 332.235 973.558 354.016 946.105 C 428.209 1038.878 559.338 1050.295 646.792 971.602 C 655.699 963.6 663.92 954.865 671.369 945.491 C 744.999 1038.468 875.821 1050.551 963.53 972.473 C 988.773 950.048 1008.589 921.53 1021.338 889.377 C 1028.772 870.087 1020.151 848.322 1001.523 839.355" p-id="8196" fill="#ffffff"/>
<path d="M 1001.523 647.359 C 983.397 638.86 962.199 647.513 954.16 666.713 C 954.019 667.052 953.882 667.393 953.751 667.737 C 925.077 740.081 846.431 774.077 778.126 743.665 C 744.625 728.369 718.592 700.367 705.777 665.842 C 698.097 646.028 676.848 636.403 658.005 644.287 C 650.963 647.33 645.054 652.506 641.108 659.084 C 639.419 661.542 637.626 664.665 635.886 667.685 C 614.945 720.369 566.302 754.672 512.437 754.724 C 458.879 754.724 411.107 720.727 389.551 669.529 C 386.669 658.098 378.761 648.589 368.046 643.673 C 349.254 635.788 327.955 645.363 320.274 665.177 C 299.947 719.243 250.587 754.672 195.699 754.724 C 140.502 754.672 90.887 718.987 70.407 664.613 C 62.982 644.902 42.091 635.072 23.3 642.393 C 4.662 650.278 -4.657 672.447 2.307 692.414 C 44.293 805.513 164.824 861.166 271.58 816.674 C 303.882 803.08 332.235 781.562 354.016 754.109 C 428.209 846.882 559.338 858.299 646.792 779.606 C 655.699 771.604 663.92 762.869 671.369 753.495 C 744.999 846.472 875.821 858.555 963.53 780.477 C 988.773 758.052 1008.589 729.534 1021.338 697.381 C 1028.772 678.091 1020.151 656.326 1001.523 647.359" p-id="8197" fill="#ffffff"/>
<path d="M 486.067 0 C 493.031 0 499.892 2.918 504.705 8.089 L 523.343 28.723 L 544.95 54.168 L 557.853 69.989 L 579 97.124 L 593.849 117.246 L 609.056 138.749 L 624.314 161.379 C 632.25 173.513 640.033 186.108 647.56 198.959 L 659.644 182.831 L 710.334 116.99 L 761.024 182.78 C 776.283 202.492 790.722 222.715 804.342 243.758 C 847.608 310.829 871.418 369.349 871.418 418.347 C 871.264 508.559 799.529 582.593 710.232 582.593 C 689.034 582.593 668.143 578.343 648.789 570.203 L 646.792 572.353 C 630.3 589.037 611.36 603.108 590.623 614.08 C 563.154 628.721 532.895 637.376 501.838 639.475 L 486.169 639.987 C 424.662 639.992 365.829 614.832 323.347 570.356 C 279.817 525.2 255.64 464.834 255.964 402.116 C 255.964 331.052 291.959 242.837 362.874 139.773 L 370.555 128.714 L 385.864 107.569 L 400.662 87.96 L 414.691 70.04 L 433.636 46.745 L 449.304 28.313 L 467.43 8.192 C 471.017 4.302 475.722 1.619 480.896 0.512 L 486.067 0 Z M 486.374 83.454 L 482.79 87.806 C 459.046 116.192 436.629 145.663 415.613 176.124 C 351.353 269.511 319.967 346.463 319.967 402.168 C 319.967 449.117 337.53 492.892 369.326 525.813 C 400.815 558.324 442.034 575.988 486.169 575.988 C 512.59 575.988 537.424 569.844 560.823 557.454 C 573.112 551.003 584.684 542.811 595.232 533.186 C 565.653 502.252 549.162 461.093 549.2 418.295 C 549.2 373.65 570.193 318.969 607.469 258.145 L 597.945 241.045 C 566.996 187.231 531.229 136.336 491.085 88.984 L 486.374 83.454 Z M 710.386 221.845 L 696.407 240.481 C 688.88 250.824 680.637 262.599 672.393 275.246 C 634.247 333.766 613.204 384.658 613.204 418.295 C 613.204 454.237 631.943 487.619 662.204 505.436 C 676.694 514.089 693.386 518.594 710.232 518.594 C 763.738 518.594 807.312 473.59 807.363 418.244 C 807.363 384.453 787.701 336.07 750.529 278.471 L 741.927 265.364 L 733.376 253.025 L 717.452 231.112 L 710.386 221.845 Z" p-id="8198" fill="#ffffff"/>
</svg>

After

Width:  |  Height:  |  Size: 4.3 KiB

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>qixiangzhan</title>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="画板" transform="translate(-522.000000, -250.000000)">
<g id="BGSM备份-11" transform="translate(177.000000, 156.000000)">
<g id="ControlRates备份-7" transform="translate(339.000000, 88.000000)">
<g id="qixiangzhan" transform="translate(6.000000, 6.000000)">
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
<path d="M4.18299415,15.9992261 L4.18299412,15.9992261 C3.83124298,16.0006517 3.54495776,15.7117042 3.54355562,15.353845 C3.54355359,15.3533269 3.54355217,15.3528089 3.54355137,15.3522908 L3.54355136,15.3522926 C3.54410794,14.9944303 3.82971065,14.7047834 4.18146487,14.7053506 C4.18197411,14.7053514 4.18248336,14.7053529 4.1829926,14.7053549 L5.59022295,14.7053549 L5.59022295,12.9351129 L5.59022322,12.9351131 C4.92309208,12.6326872 4.31659847,12.2075125 3.80125929,11.6809803 C1.0497029,8.89944383 1.91133518,4.43178623 3.3446963,2.9846379 C4.47215455,1.84559646 6.52618578,2.47034106 8.41051975,3.86201396 L8.41051975,3.86201396 C8.48839992,3.9188462 8.52814235,4.0154854 8.5132465,4.11180806 L8.34609399,5.18994934 L8.21648072,5.2493013 L8.2164807,5.2493013 C8.12524474,5.29020431 8.01913074,5.2752241 7.94228952,5.2105935 C6.43563014,3.92033441 4.93530726,3.36190221 4.31286797,3.94949393 C3.55192865,4.66636217 4.38896191,6.82419779 6.18350306,8.76835318 C7.97805712,10.7125086 10.0478021,11.7073039 10.8087507,10.9899169 C11.3961948,10.4371704 11.0314528,9.02304391 10.007736,7.5129299 L10.1299935,7.28223175 L11.2843381,6.90547665 C12.4909335,8.8098996 12.9216314,10.905282 11.8438823,11.9945103 C10.9008261,12.9472373 8.90868096,13.7172702 6.87089489,13.3363793 L6.87089489,14.7061189 L9.30260071,14.7061189 L9.30260068,14.7061189 C9.65477108,14.7045498 9.94151088,14.9937268 9.94305431,15.3520141 C9.9430558,15.352361 9.94305702,15.352708 9.94305797,15.353055 L9.94305799,15.3530468 C9.94208524,15.7113356 9.65580525,16.000984 9.30363178,15.9999975 C9.30329072,15.9999975 9.30294967,15.9999975 9.30260861,15.9999975 L4.18299415,15.9992261 Z M7.50575723,7.98025697 L7.36219336,7.83523184 L7.36219336,7.83523184 C7.09216098,7.57607102 7.07976134,7.14327333 7.3344975,6.86855076 C7.35873317,6.8424136 7.38495609,6.8182604 7.41292255,6.79631553 L8.92795176,5.54347337 L8.92795181,5.54347332 C9.16901074,5.35273729 9.49064738,5.30436933 9.77563796,5.41599578 L9.77563797,5.4159958 C9.67430292,5.28150984 9.6197855,5.11656818 9.62065934,4.94711549 L9.62065934,4.94711537 C9.6137222,4.53702595 9.9339031,4.19836431 10.336956,4.18947567 L10.3369559,4.18947567 C10.7404296,4.19766401 11.0612277,4.53661816 11.0540143,4.94711537 L11.0540143,4.94711598 C11.0619159,5.35691948 10.7417826,5.69564674 10.3389754,5.70368542 C10.3383024,5.70369885 10.3376292,5.70371133 10.3369561,5.70372287 L10.3369561,5.70372287 C10.1781212,5.70409339 10.023995,5.64887913 9.90043162,5.54734298 L9.90043163,5.54734302 C10.0095216,5.8340025 9.96126958,6.15799768 9.77360851,6.39891408 L8.53353222,7.92941929 L8.53353223,7.92941928 C8.40386137,8.09512059 8.20753406,8.19233305 7.99935246,8.19392203 L7.9993525,8.19392203 C7.81323194,8.19271444 7.63535221,8.11566084 7.50550305,7.97999651 L7.50575723,7.98025697 Z M13.9666402,5.69907111 C13.9666402,3.1598353 12.0178815,1.09310774 9.62269583,1.09310774 L9.62269583,0 C12.5880746,0 15,2.55651622 15,5.69881643 L13.9666402,5.69907111 Z M12.1375932,5.6990789 L12.1375932,5.6990789 C12.141703,4.99638806 11.8773236,4.31956162 11.4002445,3.8114301 L11.4002446,3.81143013 C10.9389177,3.31261691 10.2959024,3.02930569 9.62269125,3.02824325 L9.62269125,1.93719946 C11.5813555,1.93719946 13.1737435,3.62485171 13.1737435,5.6990789 L12.1375932,5.6990789 Z" id="形状" fill="#FFFFFF" fill-rule="nonzero"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<svg t="1686655935321" class="icon" viewBox="0 0 1137 1024" version="1.1" p-id="7860" width="200px" height="200" xmlns="http://www.w3.org/2000/svg">
<path d="M 147.788 0 L 1095.449 263.002 L 1020.134 361.087 L 1137 392.397 L 1058.218 686.879 L 819.484 622.78 L 744.226 720.978 L 404.882 625.854 L 404.882 833.466 L 73.667 833.466 L 73.667 1024 L 0 1024 L 0 642.989 L 73.61 642.989 L 73.61 757.241 L 331.329 757.241 L 331.272 605.246 L 9.947 515.245 L 147.788 0 Z M 851.77 274.387 L 605.078 602.855 L 717.34 634.279 L 968.465 306.779 L 851.77 274.33 Z M 970 426.496 L 869.618 557.371 L 1006.72 594.145 L 1046.111 446.933 L 969.943 426.439 Z M 198.945 93.189 L 100.382 461.506 L 528.626 581.394 L 775.318 253.097 L 198.945 93.132 Z" p-id="7861" fill="#ffffff"/>
</svg>

After

Width:  |  Height:  |  Size: 807 B

View File

@ -0,0 +1 @@
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1686656318145" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="8365" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><path d="M665.211904 0l0.512 307.8144c0 33.5872 7.8848 67.1744 22.2208 97.28l324.5056 460.6976 0.7168 2.048c16.4352 34.304 14.336 73.5744-6.4512 105.728a114.3296 114.3296 0 0 1-95.0784 50.432H112.507904c-38.6048 0-74.3424-18.944-95.0784-51.0976a107.4176 107.4176 0 0 1-6.4512-105.728l1.4336-2.816 307.3536-458.5472c14.336-30.8224 22.1696-64.4096 22.1696-97.9968L341.423104 0h323.7888z m-63.8464 64H405.525504l0.4096 243.8144c0 36.5568-7.168 73.216-20.7872 107.8272l-7.3216 17.1008-4.864 8.704L68.168704 896l-1.9968 5.12a42.8032 42.8032 0 0 0 1.8432 31.2832l3.2256 5.8368a47.7184 47.7184 0 0 0 33.9968 21.248l7.2704 0.512h799.1296a49.664 49.664 0 0 0 41.2672-21.0432 43.0592 43.0592 0 0 0 5.0688-37.12l-2.0992-5.2736-320.256-454.6048-5.5296-9.3696a293.376 293.376 0 0 1-27.8528-108.6464l-0.512-16.0256-0.3584-243.9168z" p-id="8366" fill="#ffffff"></path><path d="M256.072704 0h512v64H256.072704z" p-id="8367" fill="#ffffff"></path><path d="M365.231104 686.4896a83.968 83.968 0 0 1 83.6096 83.6096c0 43.008-33.1776 78.848-75.1104 83.0976l-8.4992 0.4608A83.968 83.968 0 0 1 281.672704 770.0992c0-43.008 33.1264-78.848 75.0592-83.1488l8.4992-0.4608z m245.0944-18.8416c51.5072 0 92.9792 41.472 92.9792 93.0304 0 48.4864-36.7104 88.064-83.968 92.5696l-9.0112 0.4096a92.7744 92.7744 0 0 1-93.0304-92.9792c0-48.5376 36.7616-88.064 84.0192-92.6208l9.0112-0.4096z m-245.0944 82.8416a19.968 19.968 0 0 0-19.5584 19.6096 19.968 19.968 0 0 0 19.5584 19.5584 19.968 19.968 0 0 0 19.6096-19.5584 19.968 19.968 0 0 0-19.6096-19.6096z m245.0944-18.8416a28.7744 28.7744 0 0 0-29.0304 29.0304c0 16.1792 12.8 28.9792 29.0304 28.9792 16.1792 0 28.9792-12.8 28.9792-28.9792a28.7744 28.7744 0 0 0-28.9792-29.0304zM502.242304 421.9392a116.3776 116.3776 0 0 1 116.224 116.224c0 60.928-47.616 111.0528-106.8032 115.9168l-9.4208 0.3584a116.3776 116.3776 0 0 1-116.224-116.224c0-60.928 47.0528-111.0016 106.7008-115.8656l9.5232-0.4096z m0 64c-28.7744 0-52.224 23.552-52.224 52.224 0 28.7744 23.4496 52.2752 52.224 52.2752 28.3648 0 52.224-23.7568 52.224-52.224 0-28.7744-23.5008-52.224-52.224-52.224z" p-id="8368" fill="#ffffff"></path></svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="48px" height="48px" viewBox="0 0 48 48" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>zengzhizhanshuizhizhan</title>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="zengzhizhanshuizhizhan" transform="translate(0.750000, 0.000000)" fill="#FFFFFF" fill-rule="nonzero">
<path d="M23.25,0 C36.09,0 46.5,10.74525 46.5,24 C46.5,37.25475 36.09,48 23.25,48 C10.41,48 0,37.25475 0,24 C0,10.74525 10.41,0 23.25,0 Z M23.24475,6.6675 C13.74375,6.6675 6.04275,14.49225 6.04275,24.144 C6.04275,32.4705 11.775,39.432 19.44825,41.18925 L27.0405,41.18925 C34.71375,39.432 40.4475,32.4705 40.4475,24.144 C40.4475,14.4915 32.7465,6.6675 23.2455,6.6675 L23.24475,6.6675 Z M23.44275,8.361 C31.84275,8.361 38.65275,15.02025 38.65275,23.235 C38.65275,23.3325 38.64675,23.42775 38.64525,23.52525 L38.598,23.52525 C38.595,23.472 38.586,23.42025 38.5815,23.36775 C38.34075,27.62025 35.07225,30.98925 31.074,30.98925 C30.1862354,30.9895698 29.3064559,30.821605 28.48125,30.49425 L28.34475,30.5955 C26.9708322,29.6968211 25.3634685,29.2209226 23.72175,29.22675 C22.2366664,29.2236863 20.7773263,29.6144655 19.4925,30.35925 C18.35025,31.15725 16.99425,31.62225 15.53925,31.62225 C11.45925,31.62225 8.15175,27.98325 8.15175,23.49675 C8.15175,22.94175 8.202,22.40025 8.29875,21.87675 C9.00075,14.2995 15.5115,8.361 23.44275,8.361 L23.44275,8.361 Z M23.24775,11.0925 L23.24325,11.24475 L23.2395,11.0925 C23.238,11.08275 23.17875,11.18325 23.0745,11.37 L22.98825,11.52525 C22.6125,12.20775 21.86475,13.60275 21.10275,15.03075 L20.88675,15.43575 C20.2208976,16.6865315 19.5563972,17.9380322 18.89325,19.19025 C18.2049855,20.1371924 17.8354525,21.2783585 17.8379869,22.449 C17.8379869,25.482 20.25825,27.9405 23.24475,27.9405 C26.22975,27.9405 28.6500122,25.482 28.6500122,22.449 C28.6524544,21.2784908 28.2832171,20.1374264 27.5955,19.19025 C26.9682775,18.0058222 26.3397771,16.8220715 25.71,15.639 L25.278,14.829 C24.23775,12.879 23.25525,11.052 23.24775,11.0925 L23.24775,11.0925 Z M27.3,22.434 C27.30225,22.48275 27.306,22.5315 27.306,22.581 C27.306,24.768 25.764,26.54175 23.86125,26.54175 C22.623,26.54175 21.53775,25.791 20.93175,24.66225 C21.61425,25.38675 22.545,25.83375 23.57175,25.83375 C25.43475,25.83375 26.982,24.36675 27.3,22.434 L27.3,22.434 Z" id="形状"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>zijianshuiwenzhan</title>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="画板" transform="translate(-413.000000, -319.000000)">
<g id="BGSM备份-11" transform="translate(177.000000, 156.000000)">
<g id="ControlRates备份-3" transform="translate(230.000000, 157.000000)">
<g id="zijianshuiwenzhan" transform="translate(6.000000, 6.000000)">
<rect id="矩形" x="0" y="0" width="16" height="16"></rect>
<path d="M9.97229576,12.7591246 C11.0763098,12.7591246 11.6579969,12.9166253 12.1726968,13.0531252 C12.6534766,13.1808752 13.0664219,13.2928757 13.9584577,13.2928757 L13.9584577,15 C12.8578363,15 12.2727566,14.8460002 11.7589154,14.7068753 C11.2781355,14.5791253 10.8643429,14.4671249 9.97230984,14.4671249 C9.08028104,14.4671249 8.66648695,14.5791249 8.1857043,14.7068753 C7.67185461,14.8425003 7.0876266,15 5.98616196,15 C4.88469309,15 4.30046086,14.8460002 3.78576092,14.7068753 C3.30498108,14.5791253 2.89118839,14.4671249 2,14.4671249 L2,12.7582428 C3.10062143,12.7582428 3.68485647,12.9131172 4.19954234,13.0522435 C4.68032218,13.1799934 5.09411486,13.2919939 5.98614788,13.2919939 C6.87817668,13.2919939 7.29197077,13.1799939 7.77275342,13.0522435 C8.28660311,12.9157434 8.87083112,12.7582428 9.97229576,12.7582428 L9.97229576,12.7591246 Z M9.99773387,10.0650032 C11.1000516,10.0650032 11.683435,10.2225068 12.1981349,10.3581308 C12.6789148,10.4867559 13.0927074,10.5987558 13.9847405,10.5987558 L13.9847405,12.3058801 C12.8832716,12.3058801 12.2990394,12.1510058 11.7843394,12.0127554 C11.3035596,11.8841304 10.8897669,11.7721305 9.9985785,11.7721305 C9.1065497,11.7721305 8.69275561,11.8841305 8.21197296,12.0127554 C7.69727583,12.1483804 7.11304782,12.3058801 6.01157192,12.3058801 C4.91095049,12.3058801 4.32671544,12.1510058 3.81202958,12.0127554 C3.33124974,11.8841304 2.91745705,11.7721305 2.02542403,11.7721305 L2.02542403,10.0658777 C3.1268929,10.0658777 3.71112513,10.2198776 4.22582508,10.3581279 C4.70660491,10.4867529 5.1203976,10.5987528 6.01158599,10.5987528 C6.90361479,10.5987528 7.31740888,10.4867528 7.79819153,10.3581279 C8.31288866,10.2225029 8.89711667,10.0650032 9.99859257,10.0650032 L9.99773387,10.0650032 Z M14,1 L14,8.84875684 L12.3456767,8.84875684 L12.3456767,2.70801044 L3.66450187,2.70801044 L3.66450187,8.84875684 L2.01017857,8.84875684 L2.01017857,1 L14,1 Z M8.88439241,4.12375034 L8.88439241,8.84875684 L7.22922448,8.84875684 L7.22922448,4.12375034 L8.88439241,4.12375034 Z" id="形状" fill="#FFFFFF" fill-rule="nonzero"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@ -3288,6 +3288,45 @@ const DwSixPointColumns: Array<any> = [
url: '' url: ''
} }
]; ];
//DW
const DwPointColumnsyuan: Array<any> = [
{
name: '基本属性',
visible: false,
ruleTips: '',
type: '',
url: ''
},
{
name: '设施名称',
filed: 'stnm',
visible: true,
type: 'input',
url: ''
},
{
name: '站址',
filed: 'stlc',
visible: true,
type: 'select',
url: ''
},
{
name: '所属流域',
filed: 'hbrvcdName',
visible: true,
type: 'select',
url: ''
},
{
name: '所属电站',
filed: 'ennm',
visible: true,
type: 'select',
url: ''
},
];
//夹岩双层取水 //夹岩双层取水
const DwOnePointColumns: Array<any> = [ const DwOnePointColumns: Array<any> = [
{ {
@ -4145,8 +4184,7 @@ const EQPointColumns7: Array<any> = [
visible: true, visible: true,
type: 'select', type: 'select',
url: '' url: ''
}, }
]; ];
//阶段属性 //阶段属性
const basicFilterColumns: Array<any> = [ const basicFilterColumns: Array<any> = [
@ -4831,6 +4869,58 @@ const tableColumns5: Array<any> = [
setting: {} setting: {}
} }
]; ];
//气象监测
const MMColumns: Array<any> = [
{
name: '基本属性',
visible: false,
ruleTips: '',
type: '',
url: ''
}, {
name: '测站名称',
filed: 'stnm',
visible: true,
type: 'input',
url: ''
},
{
name: '测站类型',
filed: 'sttpName',
visible: true,
type: 'select',
url: ''
},
{
name: '站址',
filed: 'addvcdName',
visible: true,
type: 'input',
url: ''
},
{
name: '所属流域',
filed: 'hbrvcdName',
visible: true,
type: 'select',
url: ''
},
{
name: '所在水系',
filed: 'addvcdName',
visible: true,
type: 'input',
url: ''
},
{
name: '建成日期',
filed: 'jcdt',
visible: true,
type: 'date',
format: 'YYYY-MM-DD',
url: ''
},
];
//生态流量 //生态流量
const EcologicalFlowColumns: Array<any> = []; const EcologicalFlowColumns: Array<any> = [];
@ -4873,6 +4963,7 @@ export {
DwFivePointColumns, DwFivePointColumns,
DwSixPointColumns, DwSixPointColumns,
DwOnePointColumns, DwOnePointColumns,
DwPointColumnsyuan,
EQPointColumns2, EQPointColumns2,
EQPointColumns5, EQPointColumns5,
EQPointColumns3, EQPointColumns3,
@ -4886,5 +4977,6 @@ export {
tableColumns2, tableColumns2,
tableColumns3, tableColumns3,
tableColumns4, tableColumns4,
tableColumns5 tableColumns5,
MMColumns
}; };

View File

@ -142,6 +142,8 @@ import {
DwFivePointColumns, DwFivePointColumns,
DwSixPointColumns, DwSixPointColumns,
DwOnePointColumns, DwOnePointColumns,
DwPointColumnsyuan,
MMColumns,
StinfoAiVidoPointColumns StinfoAiVidoPointColumns
} from '../column.config'; } from '../column.config';
import { useModelStore } from '@/store/modules/model'; import { useModelStore } from '@/store/modules/model';
@ -318,6 +320,14 @@ const columnsConfig = ref([
{ {
type: 'ZQ', type: 'ZQ',
columns: FhZQPointColumns columns: FhZQPointColumns
},
{
type: 'DW',
columns: DwPointColumnsyuan
},
{
type:'MM',
columns:MMColumns
} }
//DW_1 //DW_1

View File

@ -199,14 +199,14 @@ const ENGEQTabs: Array<any> = [
].filter(Boolean); ].filter(Boolean);
// // 水电站生态流量 - 江局单独看 √ // // 水电站生态流量 - 江局单独看 √
// const ENGEQTabsJuangJu: Array<any> = [ const ENGEQTabsJuangJu: Array<any> = [
// { {
// name: '生态流量', name: '生态流量',
// key: 'EcologicalFlow', key: 'EcologicalFlow',
// type: 'EcologicalFlow' type: 'EcologicalFlow',
// }, default: true
}
// ].filter(Boolean) ].filter(Boolean);
// //生态流量泄放设施 √ // //生态流量泄放设施 √
const EQTabs: Array<any> = [ const EQTabs: Array<any> = [
{ {
@ -310,9 +310,8 @@ const FPTabs1: Array<any> = [
name: '基础信息', name: '基础信息',
key: 'basicInfo', key: 'basicInfo',
type: 'basic', type: 'basic',
default: true, // 默认显示 default: true, // 默认显示
url: '/api/dec-lygk-base-server/base/msstbprpt/getStcdInfo', url: '/api/dec-lygk-base-server/base/msstbprpt/getStcdInfo'
}, },
{ {
name: '实时视频', name: '实时视频',
@ -956,15 +955,23 @@ const CommonTabs: any = [
} }
]; ];
// // 气象站 // 气象站
// const WeatherTabs: any = [ const WeatherTabs: any = [
// { {
// name: '基础信息', name: '基础信息',
// key: 'basicInfo', key: 'basicInfo',
// type: 'basic', type: 'basic',
// url: '/bbi/siteBipc/getSiteBasicInfo' url: '/api/dec-lygk-base-server/base/msstbprpt/getStcdInfo',
// } default: true // 默认显示
// ] },
{
name: '监测数据',
key: '',
type: '',
url: ''
},
]
// const WaterQualityMonitoring: any = [ // const WaterQualityMonitoring: any = [
// { // {
@ -1033,6 +1040,8 @@ const handleTabs = (modaldata: any) => {
const sttp = modaldata?.sttp ? modaldata?.sttp.toUpperCase() : ''; const sttp = modaldata?.sttp ? modaldata?.sttp.toUpperCase() : '';
console.log('sttp', sttp); console.log('sttp', sttp);
switch (sttp) { switch (sttp) {
case 'ENGJJ':
return ENGEQTabsJuangJu;
case 'ENG': case 'ENG':
if (modaldata?.eqtp == 'QEC') { if (modaldata?.eqtp == 'QEC') {
return ENGEQTabs; return ENGEQTabs;
@ -1223,8 +1232,8 @@ const handleTabs = (modaldata: any) => {
// } // }
// case 'WE': // case 'WE':
// return WETabs // return WETabs
// case 'MM': case 'MM':
// return WeatherTabs return WeatherTabs
// case 'WARN': // case 'WARN':
// return WaterQualityMonitoring // return WaterQualityMonitoring
// case 'AI': // case 'AI':

View File

@ -47,7 +47,6 @@
</span> </span>
</div> </div>
<div class="title_right"> <div class="title_right">
<div v-if="shrink" class="title_shrink" @click="isExpand = !isExpand"> <div v-if="shrink" class="title_shrink" @click="isExpand = !isExpand">
<img v-if="isExpand" src="@/assets/components/arrow-up.png" alt="" /> <img v-if="isExpand" src="@/assets/components/arrow-up.png" alt="" />
<img v-else src="@/assets/components/arrow-down.png" alt="" /> <img v-else src="@/assets/components/arrow-down.png" alt="" />
@ -78,7 +77,7 @@
> >
</a-tree-select> </a-tree-select>
</div> </div>
<div v-if="select.show"> <div v-if="select.show">
<a-select <a-select
v-model:value="selectValue" v-model:value="selectValue"
show-search show-search
@ -88,14 +87,14 @@
:dropdown-style="{ :dropdown-style="{
maxHeight: '400px', maxHeight: '400px',
overflow: 'auto', overflow: 'auto',
minWidth: '200px' minWidth: select.minWidth ? select.minWidth : '200px'
}" }"
:options="select.options" :options="select.options"
:filter-option="filterOption" :filter-option="filterOption"
@focus="handleFocus" @focus="handleFocus"
@blur="handleBlur" @blur="handleBlur"
@change="handleChange" @change="handleChange"
@select="handleTreeSelect1" @select="handleTreeSelect1"
></a-select> ></a-select>
</div> </div>
<div v-if="datetimePicker.show"> <div v-if="datetimePicker.show">
@ -190,6 +189,7 @@ interface SelectConfig {
value?: string | undefined; value?: string | undefined;
options?: SelectProps['options']; options?: SelectProps['options'];
width?: string; width?: string;
minWidth?: string;
} }
// 便 // 便
@ -248,7 +248,8 @@ const props = defineProps({
show: false, show: false,
value: undefined, value: undefined,
options: [], options: [],
width: '' width: '',
minWidth: ''
}) })
}, },
moreSelect: { moreSelect: {
@ -661,7 +662,7 @@ const handleTreeSelect = (selectedKeys: string | string[], info: any) => {
} }
moreSelectValue.value = selectedValue; moreSelectValue.value = selectedValue;
// //
// lgtdlttd // lgtdlttd
if (info && typeof info === 'object') { if (info && typeof info === 'object') {
selectedNodeExtra.value = { selectedNodeExtra.value = {
@ -690,7 +691,6 @@ const handleTreeExpand = (keys: string[]) => {
// //
const handleChange = (value: string) => { const handleChange = (value: string) => {
// Handle change // Handle change
}; };

View File

@ -1,49 +1,29 @@
<!-- SidePanelItem.vue --> <!-- developStatusChart/index.vue -->
<template> <template>
<div class="basic_body"> <div class="basic_body">
<div ref="chartContainer" class="chart-container"></div> <div ref="chartContainer" class="chart-container"></div>
<!-- 水电开发情况弹框 -->
<a-modal
v-model:open="modalVisible"
title="水电开发情况"
:width="1540"
@ok="handleModalOk"
@cancel="handleModalCancel"
>
<div class="modal-content">
<!-- 内容区域供用户自定义 -->
<!-- <p>选中类型{{ selectedType }}</p> -->
<SDKFQKPie :defaultTab="selectedType" />
<!-- 用户可在此处自定义内容 -->
</div>
</a-modal>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted, onUnmounted } from 'vue'; import { ref, onMounted, onUnmounted, watch } from 'vue';
import * as echarts from 'echarts'; import * as echarts from 'echarts';
import { message } from 'ant-design-vue'; import { getVmsstbprptKendoList } from '@/api/home';
import SDKFQKPie from '@/modules/shuidianhuangjingjieruMod/TwoLayer/ShuiDianKaiFQKTwoLayer.vue' import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
// 便
defineOptions({ defineOptions({
name: 'developStatusChart' name: 'developStatusChart'
}); });
const emit = defineEmits<{
(e: 'chart-click', params: any): void;
}>();
const JidiSelectEventStore = useJidiSelectEventStore();
const baseid = ref('');
const chartContainer = ref<HTMLDivElement | null>(null); const chartContainer = ref<HTMLDivElement | null>(null);
let chartInstance: echarts.ECharts | null = null; let chartInstance: echarts.ECharts | null = null;
const dataLoading = ref(false);
//
const modalVisible = ref(false);
const selectedType = ref('');
//
onMounted(() => {
if (chartContainer.value) {
initChart();
}
});
onUnmounted(() => { onUnmounted(() => {
if (chartInstance) { if (chartInstance) {
@ -52,98 +32,238 @@ onUnmounted(() => {
} }
}); });
const transUnit = (value: number) => {
return value * 0.1;
};
const getData = async () => {
if (!baseid.value) return;
const baseFilters: any[] = [
{ field: 'sttpCode', operator: 'eq', dataType: 'string', value: 'ENG' },
{ field: 'prsc', operator: 'in', dataType: 'string', value: ['1', '2', '3'] }
];
if (baseid.value !== 'all') {
baseFilters.unshift({ field: 'baseId', operator: 'eq', dataType: 'string', value: baseid.value });
}
const params1 = {
filter: {
logic: 'and',
filters: [
...baseFilters,
{ field: 'ttpwr', operator: 'isnotnull' }
]
},
group: [{ dir: 'desc', field: 'bldsttCcode', aggregates: [{ field: 'ttpwr', aggregate: 'sum' }] }]
};
const params2 = {
filter: {
logic: 'and',
filters: [...baseFilters]
},
group: [{ dir: 'desc', field: 'bldsttCcode' }]
};
try {
dataLoading.value = true;
const [res1, res2] = await Promise.all([
getVmsstbprptKendoList(params1),
getVmsstbprptKendoList(params2)
]);
const res1Data = res1?.data?.data || [];
const res2Data = res2?.data?.data || [];
// debugger
if (res1Data.length > 0 || res2Data.length > 0) {
const ttpwrlist = res1Data.map((item: any) => ({
key: item.key,
ttpwr: transUnit(item.items[0].SUM_TTPWR)
}));
const engTotalList = res2Data.map((item: any) => ({
key: item.key,
engTotal: item.count
}));
const result: any = Object.values(
[...engTotalList, ...ttpwrlist].reduce((result: any, item: any) => {
const { key, engTotal = 0, ttpwr = 0 } = item;
const existingItem = result[key] || { key, engTotal: 0, ttpwr: 0 };
existingItem.bldstt = item.key == 0 ? '未建' : item.key == 1 ? '在建' : '已建';
existingItem.engTotal += engTotal;
existingItem.ttpwr += ttpwr;
return { ...result, [key]: existingItem };
}, {})
);
result.sort((a: any, b: any) => {
if (a.bldstt === '已建' && b.bldstt !== '已建') return -1;
else if (a.bldstt !== '已建' && b.bldstt === '已建') return 1;
else if (a.bldstt === '在建' && b.bldstt === '未建') return -1;
else if (a.bldstt === '未建' && b.bldstt === '在建') return 1;
else return 0;
});
const legendData: string[] = [];
const capData: { name: string; value: number }[] = [];
const countData: { name: string; value: number }[] = [];
result.forEach((item: any) => {
const name = item.bldstt;
if (name !== '未建') {
legendData.push(name);
countData.push({ name, value: Number(item.engTotal) });
capData.push({ name, value: Number(item.ttpwr).toFixed(2) });
}
});
const colors = ['#78c300', '#2196F3'];
const option = {
tooltip: {
trigger: 'item',
formatter: '{b}电站{a}: {c}',
position: 'right'
},
legend: {
data: legendData,
left: '60%',
orient: 'vertical',
top: 'center',
itemWidth: 20,
itemHeight: 12
},
color: colors,
series: [
{
name: '数量(座)',
type: 'pie',
radius: [0, '55%'],
label: { show: false },
labelLine: { show: false },
data: countData,
center: ['30%', '50%'],
itemStyle: {
borderRadius: 2,
borderColor: '#fff',
borderWidth: 2
}
},
{
name: '装机容量(万kW)',
type: 'pie',
radius: ['70%', '90%'],
labelLine: { length: 30 },
label: { show: false },
data: capData,
center: ['30%', '50%'],
itemStyle: {
borderRadius: 2,
borderColor: '#fff',
borderWidth: 2
}
}
]
};
if (chartInstance) {
chartInstance.setOption(option, true);
}
}
} catch (error) {
console.error('DevelopStatusChart getData error:', error);
} finally {
dataLoading.value = false;
}
};
const initChart = () => { const initChart = () => {
if (!chartContainer.value) return; if (!chartContainer.value) return;
chartInstance = echarts.init(chartContainer.value); chartInstance = echarts.init(chartContainer.value);
const option = { const option = {
tooltip: { tooltip: {
trigger: 'item', trigger: 'item',
formatter: '{a} {b}: {c} ({d}%)', formatter: '{a} {b}: {c} ({d}%)',
position: 'right' position: 'right'
},
legend: {
data: ['已建', '在建'],
left: '60%',
orient: 'vertical',
top: 'center',
itemWidth: 20,
itemHeight: 12
}, },
legend: {
data: ['已建', '在建'],
left: '60%',
orient: 'vertical',
top: 'center',
itemWidth: 20,
itemHeight: 12
},
color: ['#78c300', '#2196F3'],
series: [ series: [
{ {
name: '装机容量', name: '装机容量(万kW)',
type: 'pie', type: 'pie',
radius: ['70%', '90%'], // radius: ['70%', '90%'],
center: ['30%', '50%'], // center: ['30%', '50%'],
itemStyle: {
itemStyle: { borderRadius: 2,
borderRadius: 2, borderColor: '#fff',
borderColor: '#fff', borderWidth: 2
borderWidth: 2
},
label: {
show: false //
}, },
labelLine: { label: { show: false },
show: false // 线 labelLine: { show: false },
}, data: []
data: [
{ value: 80, name: '已建', itemStyle: { color: '#78c300' } },
{ value: 20, name: '在建', itemStyle: { color: '#2196F3' } }
]
}, },
{ {
name: '数量(座)', name: '数量(座)',
type: 'pie', type: 'pie',
radius: ['0%', '50%'], // radius: ['0%', '50%'],
center: ['30%', '50%'], // center: ['30%', '50%'],
itemStyle: { itemStyle: {
borderRadius: 2, borderRadius: 2,
borderColor: '#fff', borderColor: '#fff',
borderWidth: 2 borderWidth: 2
},
label: {
show: false
}, },
labelLine: { label: { show: false },
show: false labelLine: { show: false },
}, data: []
data: [
{ value: 80, name: '已建', itemStyle: { color: '#78c300' } },
{ value: 20, name: '在建', itemStyle: { color: '#2196F3' } }
]
} }
] ]
}; };
chartInstance.setOption(option); chartInstance.setOption(option);
// //
chartInstance.on('click', (params: any) => {
emit('chart-click', {
seriesName: params.seriesName,
name: params.name,
dataIndex: params.dataIndex
});
});
window.addEventListener('resize', () => { window.addEventListener('resize', () => {
chartInstance?.resize(); chartInstance?.resize();
}); });
};
// onMounted(() => {
chartInstance.on('click', (params: any) => { if (chartContainer.value) {
if (params.data && params.data.name) { initChart();
selectedType.value = params.data.name; }
modalVisible.value = true; });
watch(
() => JidiSelectEventStore.selectedItem,
newVal => {
if (newVal && newVal.wbsCode) {
baseid.value = newVal.wbsCode;
getData();
} }
}); },
}; { deep: true, immediate: true }
);
//
const handleModalOk = () => {
modalVisible.value = false;
};
//
const handleModalCancel = () => {
modalVisible.value = false;
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -152,13 +272,8 @@ const handleModalCancel = () => {
height: 100%; height: 100%;
.chart-container { .chart-container {
width: 203px; // width: 203px;
height: 100px; // height: 100px;
}
.modal-content {
padding: 10px 0;
min-height: 100px;
} }
} }
</style> </style>

View File

@ -1,9 +1,6 @@
<template> <template>
<div> <div>
<!-- <div v-if="dataLoading"> <div style="width: 100%; height: 100%; display: flex; flex-direction: column; align-items: center">
<EmptyPanel :loading="dataLoading" :data="data" />
</div> -->
<div style="width: 100%; height: 100%; display: flex; flex-direction: column; align-items: center">
<span style="font-size: 14px; line-height: 22px; font-weight: 400; color: #000; margin-bottom: 4px"> <span style="font-size: 14px; line-height: 22px; font-weight: 400; color: #000; margin-bottom: 4px">
监测数据接入情况 监测数据接入情况
</span> </span>
@ -11,7 +8,7 @@
<div style="display: flex; flex-direction: column"> <div style="display: flex; flex-direction: column">
<div <div
style="width: 190px; height: 36px; border: 1px solid #EDF2F8; padding: 4px; display: flex; justify-content: space-between; cursor: pointer" style="width: 190px; height: 36px; border: 1px solid #EDF2F8; padding: 4px; display: flex; justify-content: space-between; cursor: pointer"
@click="handleItemClick('notAccess')"
> >
<div> <div>
<span style="border-right: 2px solid #00A14D; margin-right: 6px"></span> <span style="border-right: 2px solid #00A14D; margin-right: 6px"></span>
@ -21,6 +18,7 @@
</div> </div>
<div <div
style="width: 190px; height: 36px; border: 1px solid #EDF2F8; padding: 4px; display: flex; justify-content: space-between; margin: 3px 0; cursor: pointer" style="width: 190px; height: 36px; border: 1px solid #EDF2F8; padding: 4px; display: flex; justify-content: space-between; margin: 3px 0; cursor: pointer"
@click="handleItemClick('partAccess')"
> >
<div> <div>
<span style="border-right: 2px solid #4978AD; margin-right: 6px"></span> <span style="border-right: 2px solid #4978AD; margin-right: 6px"></span>
@ -30,6 +28,7 @@
</div> </div>
<div <div
style="width: 190px; height: 36px; border: 1px solid #EDF2F8; padding: 4px; display: flex; justify-content: space-between; cursor: pointer" style="width: 190px; height: 36px; border: 1px solid #EDF2F8; padding: 4px; display: flex; justify-content: space-between; cursor: pointer"
@click="handleItemClick('isAccess')"
> >
<div> <div>
<span style="border-right: 2px solid #606060; margin-right: 6px"></span> <span style="border-right: 2px solid #606060; margin-right: 6px"></span>
@ -39,16 +38,115 @@
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { ref, watch } from 'vue';
import { getVmsstbprptKendoList } from '@/api/home';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
defineOptions({
name: 'EngEnvironmentData'
});
// const emit = defineEmits<{
(e: 'item-click', params: any): void;
}>();
const JidiSelectEventStore = useJidiSelectEventStore();
const baseid = ref('');
const dataLoading = ref(false);
const data = ref<Record<string, number>>({ one: 0, two: 0, three: 0 }); const data = ref<Record<string, number>>({ one: 0, two: 0, three: 0 });
const getData = async () => {
if (!baseid.value) return;
</script> const baseFilters: any[] = [
{ field: 'sttpCode', operator: 'eq', dataType: 'string', value: 'ENG' },
{ field: 'bldsttCcode', operator: 'in', dataType: 'string', value: ['1', '2'] }
];
if (baseid.value !== 'all') {
baseFilters.unshift({ field: 'baseId', operator: 'eq', dataType: 'string', value: baseid.value });
}
const params1 = {
filter: {
logic: 'and',
filters: [
...baseFilters,
{ field: 'prsc', operator: 'in', dataType: 'string', value: ['1', '2', '3'] }
]
}
};
const params2 = {
filter: {
logic: 'and',
filters: [
...baseFilters,
{ field: 'runState', operator: 'eq', dataType: 'number', value: 4 },
{ field: 'dtin', operator: 'eq', dataType: 'number', value: 1 }
]
}
};
const params3 = {
filter: {
logic: 'and',
filters: [
...baseFilters,
{ field: 'prsc', operator: 'in', dataType: 'string', value: ['1', '2', '3'] },
{ field: 'dtinEnv', operator: 'in', dataType: 'string', value: ['2'] }
]
}
};
try {
dataLoading.value = true;
const [res1, res2, res3] = await Promise.all([
getVmsstbprptKendoList(params1),
getVmsstbprptKendoList(params2),
getVmsstbprptKendoList(params3)
]);
const record = { one: 0, two: 0, three: 0 };
const responses = [res1, res2, res3];
responses.forEach((res, index) => {
const total = res?.data?.total ?? 0;
switch (index) {
case 0:
record.one = total;
break;
case 1:
record.two = total;
break;
case 2:
record.three = total;
break;
}
});
data.value = record;
// debugger
} catch (error) {
console.error('EngEnvironmentData getData error:', error);
} finally {
dataLoading.value = false;
}
};
const handleItemClick = (name: string) => {
emit('item-click', { name });
};
watch(
() => JidiSelectEventStore.selectedItem,
newVal => {
if (newVal && newVal.wbsCode) {
baseid.value = newVal.wbsCode;
getData();
}
},
{ deep: true, immediate: true }
);
</script>

View File

@ -3,15 +3,22 @@
<div class="yancheng-yulei"> <div class="yancheng-yulei">
<!-- 搜索表单 --> <!-- 搜索表单 -->
<a-form layout="inline" class="search-form"> <a-form layout="inline" class="search-form">
<!-- 基地名称非沿程模式显示 --> <!-- 基地名称 -->
<a-form-item v-if="!props.ly" label="基地名称"> <a-form-item label="基地名称">
<a-select <a-select
v-model:value="formState.baseId" v-model:value="formState.baseId"
placeholder="请选择" placeholder="请选择"
style="width: 150px" style="width: 150px"
:options="baseOptions"
@change="handleBaseChange" @change="handleBaseChange"
/> >
<a-select-option
v-for="opt in baseOptions"
:key="opt.value"
:value="opt.value"
>
{{ opt.label }}
</a-select-option>
</a-select>
</a-form-item> </a-form-item>
<!-- 所在流域 --> <!-- 所在流域 -->
@ -20,21 +27,35 @@
v-model:value="formState.rvcd" v-model:value="formState.rvcd"
placeholder="请选择" placeholder="请选择"
style="width: 150px" style="width: 150px"
:options="lyOptions"
@change="handleRvcdChange" @change="handleRvcdChange"
/> >
<a-select-option
v-for="opt in lyOptions"
:key="opt.value"
:value="opt.value"
>
{{ opt.label }}
</a-select-option>
</a-select>
</a-form-item> </a-form-item>
<!-- 断面名称沿程模式显示 --> <!-- 断面名称沿程模式显示 -->
<a-form-item v-if="props.ly" label="断面名称"> <!-- <a-form-item v-if="props.ly" label="断面名称">
<a-select <a-select
v-model:value="formState.stcd" v-model:value="formState.stcd"
placeholder="请选择" placeholder="请选择"
style="width: 150px" style="width: 150px"
:options="dmOptions"
@change="handleStcdChange" @change="handleStcdChange"
/> >
</a-form-item> <a-select-option
v-for="opt in dmOptions"
:key="opt.value"
:value="opt.value"
>
{{ opt.label }}
</a-select-option>
</a-select>
</a-form-item> -->
<!-- 年份 --> <!-- 年份 -->
<a-form-item label="年份"> <a-form-item label="年份">
@ -57,11 +78,20 @@
</a-form> </a-form>
<!-- Tab 切换 + 表格 --> <!-- Tab 切换 + 表格 -->
<a-tabs v-model:activeKey="tabIndex" class="ylycbh-tabs" @change="handleTabChange"> <a-tabs
<a-tab-pane v-for="item in tabList" :key="item.key" :tab="item.labelWithTooltip"> v-model:activeKey="tabIndex"
class="ylycbh-tabs"
@change="handleTabChange"
>
<a-tab-pane
v-for="item in tabList"
:key="item.key"
:tab="item.labelWithTooltip"
>
<div class="table-wrapper"> <div class="table-wrapper">
<BasicTable <!-- 沿程模式表格 -->
v-if="tabIndex === item.key" <!-- <BasicTable
v-if="props.ly && tabIndex === item.key"
:ref="el => setTableRef(el, item.key)" :ref="el => setTableRef(el, item.key)"
:columns="tableColumns" :columns="tableColumns"
:scroll-y="500" :scroll-y="500"
@ -70,34 +100,46 @@
:search-params="searchParams" :search-params="searchParams"
:transform-data="customTransform" :transform-data="customTransform"
> >
<!-- 沿程模式断面名称列带电站名称分组 --> <template #rsctdName="{ record }">
<template v-if="props.ly" #rsctdName="{ record }">
{{ record.rsctdName || '-' }} {{ record.rsctdName || '-' }}
</template> </template>
<template v-if="props.ly" #stcdList="{ record }"> <template #stcdList="{ record }">
<div v-for="st in record.stcdList" :key="st.stcd"> <div v-for="st in record.stcdList" :key="st.stcd">
<a @click="handleViewDetail(st.stcd, st.stnm)" class="text-link"> <a
@click="handleViewDetail(st.stcd, st.stnm)"
class="text-link"
>
{{ st.stnm }} {{ st.stnm }}
</a> </a>
</div> </div>
</template> </template>
<template v-if="props.ly" #fishList="{ record }"> <template #fishList="{ record }">
<a-list size="small" :data-source="record.fishList"> <a-list size="small" :data-source="record.fishList">
<template #renderItem="{ item }"> <template #renderItem="{ item: fish }">
<a-list-item>{{ item }}</a-list-item> <a-list-item>{{ fish }}</a-list-item>
</template> </template>
</a-list> </a-list>
</template> </template>
</BasicTable> -->
<!-- 基地模式调查断面列 --> <!-- 基地模式表格 -->
<template v-else #stnm="{ record }"> <BasicTable
<a @click="handleViewDetail(record.stcd, record.stnm)" class="text-link"> :ref="el => setTableRef(el, item.key)"
:columns="tableColumns"
:scroll-y="500"
:scroll-x="800"
:list-url="listUrl"
:search-params="searchParams"
:transform-data="customTransform"
>
<template #stnm="{ record }">
<a
@click="handleViewDetail(record.stcd, record.stnm)"
class="text-link"
>
{{ record.stnm }} {{ record.stnm }}
</a> </a>
</template> </template>
<template v-else #name="{ record }">
{{ record.name || '-' }}
</template>
</BasicTable> </BasicTable>
</div> </div>
</a-tab-pane> </a-tab-pane>
@ -123,21 +165,33 @@ const modelStore = useModelStore();
// ==================== Props ==================== // ==================== Props ====================
const props = defineProps<{ const props = defineProps<{
tm: string; // "2024" tm: string; // "2024"
dataDimensionVal: string; // ID dataDimensionVal: string; // ID
hbrvcd: string; // hbrvcd: string; //
jdList: any[]; // jdList: any[]; //
stateName: string; // "" stateName: string; // ""
sectionName: string; // sectionName: string; //
stcd: string; // stcd: string; //
ly: boolean; // 沿 ly: boolean; // 沿
}>(); }>();
// ==================== Tab ==================== // ==================== Tab ====================
const TAB_CONFIG = [ const TAB_CONFIG = [
{ key: '1', label: '外来鱼类', prompt: '通过人为行为引入的本流域原生态没有的鱼类' }, {
{ key: '2', label: '本土受威胁鱼类', prompt: '流域原生态鱼类中处于近危或者濒危的鱼类' }, key: '1',
{ key: '3', label: '本土无危鱼类', prompt: '分类属于本土且保护类型属于无危的鱼类' } label: '外来鱼类',
prompt: '通过人为行为引入的本流域原生态没有的鱼类'
},
{
key: '2',
label: '本土受威胁鱼类',
prompt: '流域原生态鱼类中处于近危或者濒危的鱼类'
},
{
key: '3',
label: '本土无危鱼类',
prompt: '分类属于本土且保护类型属于无危的鱼类'
}
]; ];
// ==================== ==================== // ==================== ====================
@ -214,7 +268,7 @@ const lyColumns = [
title: '电站名称', title: '电站名称',
dataIndex: 'rsctdName', dataIndex: 'rsctdName',
width: 200, width: 200,
ellipsis: true, // ellipsis: true,
slots: { customRender: 'rsctdName' } slots: { customRender: 'rsctdName' }
}, },
{ {
@ -222,7 +276,7 @@ const lyColumns = [
title: '调查断面', title: '调查断面',
dataIndex: 'stcdList', dataIndex: 'stcdList',
width: 200, width: 200,
ellipsis: true, // ellipsis: true,
slots: { customRender: 'stcdList' } slots: { customRender: 'stcdList' }
}, },
{ {
@ -230,7 +284,7 @@ const lyColumns = [
title: '渔获物种类', title: '渔获物种类',
dataIndex: 'fishList', dataIndex: 'fishList',
width: 300, width: 300,
ellipsis: true, // ellipsis: true,
slots: { customRender: 'fishList' } slots: { customRender: 'fishList' }
} }
]; ];
@ -259,10 +313,10 @@ const baseColumns = [
]; ];
/** 根据 ly 模式切换表格列 */ /** 根据 ly 模式切换表格列 */
const tableColumns = computed(() => (props.ly ? lyColumns : baseColumns)); const tableColumns = computed(() => (props.ly ? baseColumns : lyColumns));
/** 根据 ly 模式切换表格 API */ /** 根据 ly 模式切换表格 API */
const listUrl = computed(() => (props.ly ? fishDetail : fishQgcDetail)); const listUrl = computed(() => (props.ly ?fishQgcDetail : fishDetail));
/** 表格搜索参数 */ /** 表格搜索参数 */
const searchParams = computed(() => ({ const searchParams = computed(() => ({
@ -291,22 +345,41 @@ const fetchLyList = async () => {
filter: { filter: {
logic: 'and', logic: 'and',
filters: [ filters: [
{ field: 'wbsType', operator: 'eq', value: 'PSB_RVCD' }, formState.value.baseId != 'all'
? {
field: 'fullPath',
operator: 'startswith',
dataType: 'string',
value: " formState.value.baseId+','"
}
: null,
{ {
field: 'fullPath', field: 'wbsType',
operator: 'contains', operator: 'eq',
dataType: 'string', dataType: 'string',
value: formState.value.baseId + ',' value: 'PSB_RVCD'
} }
] ].filter(Boolean)
}, },
group: [ group: [
{ dir: 'asc', field: 'objId' }, {
{ dir: 'asc', field: 'orderIndex' }, dir: 'asc',
{ dir: 'des', field: 'wbsCode' }, field: 'objId'
{ dir: 'des', field: 'wbsName' } },
{
dir: 'asc',
field: 'orderIndex'
},
{
dir: 'des',
field: 'wbsCode'
},
{
dir: 'des',
field: 'wbsName'
}
], ],
groupResultFlat: true groupResultFlat: 'true'
}; };
const res = await wbsbGetKendoList(params); const res = await wbsbGetKendoList(params);
@ -375,27 +448,45 @@ const fetchDmList = async () => {
// ==================== Tab ==================== // ==================== Tab ====================
const getTabNumData = async () => { const getTabNumData = async () => {
const params: any = { let params = {
baseId: formState.value.baseId, filter: {
rvcd: formState.value.rvcd, logic: 'and',
yr: dayjs(yearValue.value).format('YYYY'), filters: [
ty: tabIndex.value formState.value.baseId != 'all'
? {
field: 'baseId',
operator: 'eq',
dataType: 'string',
value: formState.value.baseId
}
: null,
{
field: 'rvcd',
operator: 'eq',
dataType: 'string',
value: formState.value.rvcd
},
{
field: 'yr',
operator: 'eq',
dataType: 'string',
value: dayjs(yearValue.value).format('YYYY')
},
{
field: 'ty',
operator: 'isnotnull',
dataType: 'string',
value: tabIndex.value
}
].filter(Boolean)
}
}; };
// 沿 stcd
if (props.ly) {
params.stcd = formState.value.stcd;
}
//
if (!params.stcd) delete params.stcd;
if (params.baseId === 'all') delete params.baseId;
try { try {
const res = await getTabNum(params); const res = await getTabNum(params);
// getTabNum res.data [{ty, num}, ...] // getTabNum res.data [{ty, num}, ...]
const data = res?.data || []; const data = res?.data?.data || [];
// debugger
const list = TAB_CONFIG.map(item => ({ const list = TAB_CONFIG.map(item => ({
...item, ...item,
labelWithTooltip: renderTabLabel(item.label, item.prompt) labelWithTooltip: renderTabLabel(item.label, item.prompt)
@ -427,12 +518,14 @@ const getTabNumData = async () => {
/** 构建表格过滤条件 */ /** 构建表格过滤条件 */
const getFilter = () => { const getFilter = () => {
const filters: any[] = [ const filters: any[] = [
{ formState.value.baseId != 'all'
field: 'baseId', ? {
operator: 'eq', field: 'baseId',
dataType: 'string', operator: 'eq',
value: formState.value.baseId dataType: 'string',
}, value: formState.value.baseId
}
: null,
{ {
field: 'rvcd', field: 'rvcd',
operator: 'eq', operator: 'eq',
@ -454,14 +547,14 @@ const getFilter = () => {
]; ];
// 沿 stcd // 沿 stcd
if (props.ly && formState.value.stcd) { // if (props.ly && formState.value.stcd) {
filters.push({ // filters.push({
field: 'stcd', // field: 'stcd',
operator: 'eq', // operator: 'eq',
dataType: 'string', // dataType: 'string',
value: formState.value.stcd // value: formState.value.stcd
}); // });
} // }
return { return {
logic: 'and', logic: 'and',
@ -516,7 +609,9 @@ const handleYearChange = () => {
}; };
/** Tab 切换 */ /** Tab 切换 */
const handleTabChange = () => { const handleTabChange = async () => {
// Tab BasicTable
await nextTick();
handleSearch(); handleSearch();
}; };

View File

@ -32,7 +32,7 @@
@cancel="handleModalClose" @cancel="handleModalClose"
> >
<Yanchengyulei <Yanchengyulei
v-if="modalVisible" v-if="modalVisible && JidiSelectEventStore.jidiData.length > 0"
:tm="modalYear" :tm="modalYear"
:dataDimensionVal="baseid" :dataDimensionVal="baseid"
:hbrvcd="modalHbrvcd" :hbrvcd="modalHbrvcd"
@ -525,12 +525,12 @@ const filterSelectOptions = (options: any[]) => {
* 点击图表柱子时触发传递当前选中的年份流域站点名称等参数 * 点击图表柱子时触发传递当前选中的年份流域站点名称等参数
*/ */
const openDetail = (params: any) => { const openDetail = (params: any) => {
// chartData stcd // chartData stcd
const found = chartData.value.find((el: any) => el.stnm === params.name); const found = chartData.value.find((el: any) => el.stnm === params.name);
modalYear.value = select.value.value; modalYear.value = select.value.value;
modalHbrvcd.value = moreSelect.value.value || ''; modalHbrvcd.value = moreSelect.value.value || '';
modalStateName.value = params.name || ''; modalStateName.value = params.seriesName || '';
modalSectionName.value = params.name || ''; modalSectionName.value = params.name || '';
modalStcd.value = found?.stcd || ''; modalStcd.value = found?.stcd || '';
modalVisible.value = true; modalVisible.value = true;

View File

@ -1,130 +1,418 @@
<!-- SidePanelItem.vue --> <!-- SidePanelItem.vue -->
<template> <template>
<SidePanelItem title="典型设施介绍"> <SidePanelItem
<div v-if="carouselData.length > 0" class="carousel-wrapper"> title="典型设施介绍"
<a-carousel v-model:current="currentIndex" autoplay class="tech-carousel" :dot-style="{ bottom: '0px' }"> :select="selectConfig"
<!-- --> @update-values="handlePanelChange"
<div v-for="(item, index) in carouselData" :key="index" class="carousel-item"> >
<div class="image-container"> <a-spin :spinning="loading">
<img :src="item.image" :alt="item.title" class="carousel-image" /> <template v-if="originalMediaData.length > 0">
</div> <div
</div> class="container"
</a-carousel> @mouseenter="handleMouseEnter"
@mouseleave="handleMouseLeave"
<!-- 文字描述区域 --> >
<div v-if="carouselData[currentIndex]" class="description-container"> <!-- 跑马灯轨道容器 -->
<p class="item-description">{{ carouselData[currentIndex].description }}</p> <div
class="carousel-track"
:class="{ 'no-transition': isTransitioning }"
:style="{ transform: `translateX(-${currentIndex * 100}%)` }"
>
<!-- 遍历所有媒体项包含克隆项 -->
<div
v-for="(item, index) in renderMediaData"
:key="index"
class="carousel-item"
@click="handleItemClick"
>
<img :src="item.image" :alt="item.title" />
<!-- 说明文字随媒体项移动 -->
<!-- <div class="text">{{ item.title }}</div> -->
</div> </div>
</div>
<!-- 面板指示器固定在底部右侧 -->
<div class="pagination-dots-fixed">
<span
v-for="(dot, index) in originalMediaData"
:key="index"
class="dot"
:class="{ active: getCurrentRealIndex() === index }"
@click="goToSlide(index)"
></span>
</div>
</div> </div>
<div v-else>
<a-empty /> <!-- 独立的文字说明区域随跑马灯切换而变化 -->
<div class="description-text">
{{ currentDescription }}
</div> </div>
</SidePanelItem> </template>
<a-empty v-else description="暂无数据" />
</a-spin>
</SidePanelItem>
<!-- 设施详情弹框 -->
<a-modal v-model:open="modalVisible" :title="'设施详情'" width="1536px" :footer="null">
<div v-if="currentItem" class="detail-container">
<ArtsDetail :dataSource="currentItem" :index="getCurrentRealIndex()" />
</div>
</a-modal>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted } from 'vue'; import { ref, onMounted, onUnmounted, computed, watch } from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue'; import SidePanelItem from '@/components/SidePanelItem/index.vue';
import ArtsDetail from '@/components/carouselIntroduce/ArtsDetail.vue';
import { getMsstbprptKendoList } from '@/api/home';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
// 便 // 便
defineOptions({ defineOptions({
name: 'dianxingcuoshijieshao' name: 'dianxingcuoshijieshao'
}); });
// // store
const currentIndex = ref(0); const JidiSelectEventStore = useJidiSelectEventStore();
const baseid = ref('');
// //
const carouselData = ref([ interface MediaItem {
{ title: string;
title: '叠梁门', description: string;
description: '叠梁门是一种用于调节水库流量和控制水位的设施。在低温季节,可以通过控制叠梁门的开闭程度来调节流量,减少低温水体的进...', image: string;
image: 'https://img.shetu66.com/2024/02/19/170835076078361368.png' // }
},
{ //
title: '环保设施', const modalVisible = ref(false);
description: '现代化环保设施,采用先进技术,有效处理工业废水废气,实现达标排放,保护生态环境...', const currentItem = ref<any>(null);
image: 'https://img.shetu66.com/2024/02/19/170835076078361368.png'
}, //
{ const loading = ref(false);
title: '智能监控',
description: '24 小时智能监控系统,实时监测设备运行状态,确保设施安全稳定运行...', //
image: 'https://img.shetu66.com/2024/02/19/170835076078361368.png' const selectConfig = ref({
}, show: true,
{ value: 'all',
title: '水处理系统', width: '142px',
description: '高效水处理系统,通过多级过滤和生物处理,实现水资源循环利用...', options: [
image: 'https://img.shetu66.com/2024/02/19/170835076078361368.png' { label: '全部', value: 'all' },
{ label: '鱼类增殖站', value: 'FB' },
{ label: '过鱼设施', value: 'FP' },
{ label: '低温水减缓设施', value: 'DW' }
]
});
//
const selectValue = ref('all');
//
const originalMediaData = ref<MediaItem[]>([]);
//
const renderMediaData = ref<MediaItem[]>([]);
// renderMediaData
const currentIndex = ref(1);
//
let timer: any = null;
//
const isHovering = ref(false);
//
const isTransitioning = ref(false);
// sttpCode
const dw = ['DW', 'DW_1', 'DW_2', 'DW_3', 'DW_4', 'DW_5', 'DW_6', 'DW_9'];
const fp = ['FP', 'FP_1', 'FP_2', 'FP_3', 'FP_4', 'FP_5'];
//
const initRenderData = () => {
const length = originalMediaData.value.length;
if (length === 0) {
renderMediaData.value = [];
return;
}
renderMediaData.value = [
originalMediaData.value[length - 1],
...originalMediaData.value,
originalMediaData.value[0]
];
currentIndex.value = 1;
};
//
const startAutoPlay = () => {
if (timer) clearInterval(timer);
timer = setInterval(() => {
if (!isHovering.value && !isTransitioning.value && originalMediaData.value.length > 0) {
nextSlide();
} }
]); }, 4000);
};
// //
const nextSlide = () => {
currentIndex.value++;
setTimeout(() => {
checkSeamlessJump();
}, 500);
};
//
const checkSeamlessJump = () => {
const realLength = originalMediaData.value.length;
if (currentIndex.value >= realLength + 1) {
isTransitioning.value = true;
currentIndex.value = 1;
requestAnimationFrame(() => {
requestAnimationFrame(() => {
isTransitioning.value = false;
});
});
}
};
//
const handleMouseEnter = () => {
isHovering.value = true;
};
//
const handleMouseLeave = () => {
isHovering.value = false;
};
//
const currentDescription = computed(() => {
const realIndex = getCurrentRealIndex();
return originalMediaData.value[realIndex]?.description || '';
});
//
const getCurrentRealIndex = () => {
const realLength = originalMediaData.value.length;
let realIndex = currentIndex.value - 1;
if (realIndex < 0) realIndex = realLength - 1;
if (realIndex >= realLength) realIndex = 0;
return realIndex;
};
//
const goToSlide = (targetIndex: number) => {
if (isTransitioning.value) return;
currentIndex.value = targetIndex + 1;
};
//
const handleItemClick = () => {
currentItem.value = originalMediaData.value.map((item: any) => ({
url: item.image || '',
description: item.description || '',
title: item.title || ''
}));
modalVisible.value = true;
};
//
const handlePanelChange = (payload: any) => {
if (payload.select !== undefined && payload.select !== selectValue.value) {
selectValue.value = payload.select;
getData();
}
};
//
const getData = async () => {
loading.value = true;
try {
// sttpCode
let sttpCodes: string[] = ['FB', ...dw, ...fp];
if (selectValue.value === 'FB') {
sttpCodes = ['FB'];
} else if (selectValue.value === 'DW') {
sttpCodes = [...dw];
} else if (selectValue.value === 'FP') {
sttpCodes = [...fp];
}
const filters: any[] = [
{
field: 'sttpCode',
operator: 'in',
dataType: 'string',
value: sttpCodes
},
{
logic: 'and',
filters: [
{ field: 'logo', dataType: 'string', operator: 'isnotnull' },
{ field: 'introduce', dataType: 'string', operator: 'isnotnull' }
]
}
];
//
if (baseid.value && baseid.value !== 'all') {
filters.push({
field: 'baseId',
operator: 'eq',
dataType: 'string',
value: baseid.value
});
}
const params = {
filter: {
logic: 'and',
filters: filters
},
select: ['introduce', 'logo', 'stnm', 'precis']
};
const res = await getMsstbprptKendoList(params);
if (res?.data?.data && Array.isArray(res.data.data)) {
const baseUrl = import.meta.env.VITE_APP_ATTACHMENT_URL || '';
originalMediaData.value = res.data.data
.filter((item: any) => item.logo || item.introduce)
.map((item: any) => ({
image: item.logo ? baseUrl + '?' + item.logo + '&view=jpg' : '',
title: item.stnm || '',
description: item.introduce || ''
}));
} else {
originalMediaData.value = [];
}
initRenderData();
} catch (error) {
console.error('获取设施介绍数据失败:', error);
originalMediaData.value = [];
initRenderData();
} finally {
loading.value = false;
}
};
//
watch(
() => JidiSelectEventStore.selectedItem,
(newVal) => {
if (newVal && newVal.wbsCode) {
baseid.value = newVal.wbsCode;
getData();
}
},
{ deep: true, immediate: true }
);
//
onMounted(() => { onMounted(() => {
// startAutoPlay();
});
//
onUnmounted(() => {
if (timer) clearInterval(timer);
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.carousel-wrapper { .container {
width: 414px; width: 100%;
:deep(.slick-slide) { height: 228px;
position: relative;
text-align: center; overflow: hidden;
height: 250px;
line-height: 160px;
background: #364d79;
overflow: hidden;
.carousel-track {
display: flex;
width: 100%;
height: 100%;
transition: transform 0.5s ease-in-out;
&.no-transition {
transition: none;
} }
:deep() { .carousel-item {
.ant-carousel .slick-dots li { min-width: 100%;
width: 5px !important; height: 100%;
height: 5px !important; position: relative;
border-radius: 50% !important; flex-shrink: 0;
background-color: #888e95; cursor: pointer;
} img {
.ant-carousel .slick-dots li button{
width: 5px !important;
height: 5px !important;
border-radius: 50% !important;
background-color: #888e95;
}
.ant-carousel .slick-dots li.slick-active{
background-color: #005293 !important;
}
.ant-carousel .slick-dots li.slick-active button{
background-color: #005293 !important;
}
.ant-carousel .slick-dots li :hover {
width: 5px !important;
height: 5px !important;
border-radius: 50% !important;
background-color: #ffffffcc;
}
.ant-carousel .slick-dots li button :hover{
width: 5px !important;
height: 5px !important;
border-radius: 50% !important;
background-color: #ffffffcc;
}
}
.description-container {
height: 44px;
width: 100%; width: 100%;
margin-top: 6px; height: 100%;
line-height: 22px; object-fit: cover;
overflow: hidden; }
text-overflow: ellipsis;
word-break: break-all;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
text-indent: 0em;
}
.text {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
height: 28px;
line-height: 28px;
background: rgba(0, 0, 0, 0.5);
color: #fff;
padding-left: 12px;
font-size: 14px;
}
}
}
.pagination-dots-fixed {
position: absolute;
bottom: 10px;
right: 10px;
display: flex;
gap: 6px;
z-index: 10;
.dot {
width: 5px;
height: 5px;
border-radius: 50%;
background-color: #d8d8d8;
cursor: pointer;
transition: background-color 0.3s ease;
&.active {
background-color: #005293;
}
&:hover {
opacity: 0.8;
}
}
}
} }
</style>
.description-text {
font-size: 14px;
line-height: 1.5;
transition: all 0.3s ease;
margin-top: 12px;
min-height: 44px;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
text-overflow: ellipsis;
word-break: break-word;
}
.detail-container {
width: 100%;
height: 100%;
}
</style>

View File

@ -31,7 +31,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted, onUnmounted, computed, reactive,watch } from 'vue'; import { ref, onMounted, onUnmounted, computed, reactive,watch } from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue'; import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { msstbprptGetKendoList } from '@/api/yldc'; import { VDmsstbprptGetKendoList } from '@/api/yldc';
import LiveVideoBox from '@/views/shiPinJianKong/components/LiveVideoBox.vue'; import LiveVideoBox from '@/views/shiPinJianKong/components/LiveVideoBox.vue';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
// 便 // 便
@ -84,7 +84,7 @@ const getVideoSelect = async () => {
}, },
select: ['stcd', 'stnm', 'url'] select: ['stcd', 'stnm', 'url']
}; };
let res = await msstbprptGetKendoList(params); let res = await VDmsstbprptGetKendoList(params);
let resData = res.data.data; //stnm stcd url let resData = res.data.data; //stnm stcd url
select.value.options = resData.map(item => { select.value.options = resData.map(item => {
return { return {

View File

@ -0,0 +1,390 @@
<template>
<div class="huanbao-two-layers-container">
<!-- 搜索表单 -->
<div class="search-form">
<a-space size="middle">
<div>所属基地:</div>
<a-select
v-model:value="searchData.baseid"
placeholder="请选择基地"
style="width: 200px"
show-search
:filter-option="filterOption"
:options="baseOptions"
@change="handleBaseChange"
/>
<div>类型:</div>
<a-select
v-model:value="searchData.type"
placeholder="请选择类型"
style="width: 200px"
:options="typeOptions"
@change="handleTypeChange"
/>
<div>建设状态:</div>
<a-select
v-model:value="searchData.bldstt"
placeholder="请选择状态"
style="width: 150px"
:options="bldsttOptions"
@change="handleBldsttChange"
/>
<a-input
v-model:value="searchData.search"
placeholder="搜索名称/电站"
style="width: 200px"
allow-clear
@press-enter="handleSearch"
/>
<a-button type="primary" @click="handleSearch">查询</a-button>
<a-tooltip title="重置">
<a-button @click="handleReset">重置</a-button>
</a-tooltip>
</a-space>
</div>
<!-- 数据表格 -->
<div class="table-wrapper">
<BasicTable
ref="tableRef"
:columns="columns"
:scroll-y="500"
:list-url="envOpdGetKendoListCust"
:search-params="tableSearchParams"
:transform-data="customTransform"
row-key="stcd"
>
<template #stnm="{ record }">
<a
v-if="record.stnm && record.stnm !== '-'"
@click="handleViewDetail(record, 'DW')"
class="text_hocer"
>{{ record.stnm }}</a
>
</template>
<template #ennm="{ record }">
<a
v-if="record.ennm && record.ennm !== '-'"
@click="handleViewDetail(record, 'ENG')"
class="text_hocer"
>{{ record.ennm }}</a
>
</template>
</BasicTable>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, onMounted } from 'vue';
import BasicTable from '@/components/BasicTable/index.vue';
import { envOpdGetKendoListCust, getBaseList } from '@/api/home';
import { useModelStore } from '@/store/modules/model';
const modelStore = useModelStore();
// ==================== Props ====================
const props = defineProps<{
data?: any;
currentJidiInfo?: any;
res?: any;
}>();
// ==================== ====================
const tableRef = ref();
const baseList = ref<any[]>([]);
//
const searchData = ref<any>({
baseid: props.currentJidiInfo?.wbsCode || 'all',
type: props.data?.type || '',
bldstt: props.res?.bldstt || '',
hydrodtin: props.res?.hydrodtin || '',
search: ''
});
//
const baseOptions = computed(() => {
const options = [];
baseList.value.forEach(item => {
options.push({
label: item.wbsName || item.basename,
value: item.wbsCode || item.baseid
});
});
return options;
});
//
const typeOptions = [
{ label: '全部', value: '' },
{ label: '鱼类增殖站', value: 'FB' },
{ label: '过鱼设施', value: 'FP' },
{ label: '珍稀植物园', value: 'VP' },
{ label: '动物救助站', value: 'VA' },
{ label: '低温水减缓设施', value: 'DW' },
{ label: '鱼类栖息地', value: 'FH' },
{ label: '生态流量泄放设施', value: 'EQ' }
];
//
const bldsttOptions = [
{ label: '全部', value: '' },
{ label: '未建', value: '0' },
{ label: '在建', value: '1' },
{ label: '已建', value: '2' }
];
// ==================== ====================
const columns = [
{
title: '名称',
key: 'stnm',
dataIndex: 'stnm',
width: 150
},
{
title: '建设情况',
key: 'bldsttCcodeName',
dataIndex: 'bldsttCcodeName',
width: 120
},
{
title: '类型',
key: 'sttpName',
dataIndex: 'sttpName',
width: 120
},
{
title: '接入日期',
key: 'dtinTm',
dataIndex: 'dtinTm',
width: 120
},
{
title: '关联电站',
key: 'ennm',
dataIndex: 'ennm',
width: 150
},
{
title: '关联基地',
key: 'baseName',
dataIndex: 'baseName',
width: 150
}
];
// ==================== ====================
const tableSearchParams = computed(() => {
return {
sort: [
{ field: 'baseStepSort', dir: 'asc' },
{ field: 'dtin', dir: 'desc' },
{ field: 'rvcdStepSort', dir: 'asc' },
{ field: 'rstcdStepSort', dir: 'asc' },
{ field: 'siteStepSort', dir: 'asc' }
],
select: [
'stnm',
'bldsttCcodeName',
'sttpName',
'dtinTm',
'ennm',
'baseName',
'stcd',
'sttpCode'
],
group: [],
groupResultFlat: false
};
});
//
const customTransform = (res: any) => {
return {
records: res?.data?.data || [],
total: res?.data?.total || 0
};
};
// ==================== ====================
const buildSearchFilter = () => {
const filters: any[] = [];
if (searchData.value.baseid && searchData.value.baseid !== 'all') {
filters.push({
field: 'baseId',
operator: 'eq',
value: searchData.value.baseid
});
}
if (searchData.value.type) {
const operator = searchData.value.type === 'EQ' ? 'contains' : 'eq';
filters.push({
field: 'sttpCode',
operator: operator,
value: searchData.value.type
});
}
if (searchData.value.bldstt !== undefined && searchData.value.bldstt !== '') {
filters.push({
field: 'bldsttCcode',
operator: 'eq',
value: searchData.value.bldstt
});
}
if (
searchData.value.hydrodtin !== undefined &&
searchData.value.hydrodtin !== ''
) {
filters.push({
field: 'dtin',
operator: 'eq',
value: searchData.value.hydrodtin
});
}
if (searchData.value.search) {
filters.push({
logic: 'or',
filters: [
{
field: 'baseName',
operator: 'contains',
value: searchData.value.search
},
{ field: 'stnm', operator: 'contains', value: searchData.value.search },
{ field: 'ennm', operator: 'contains', value: searchData.value.search }
]
});
}
return {
logic: 'and',
filters: filters.filter(
f => f.value !== undefined && f.value !== null && f.value !== ''
)
};
};
// ==================== ====================
const fetchBaseList = async () => {
try {
const params = {
filter: {
logic: 'and',
filters: [
{
field: 'wbsType',
operator: 'eq',
dataType: 'string',
value: 'PSB'
},
{ field: 'treeLevel', operator: 'eq', dataType: 'string', value: '1' }
]
},
sort: [{ field: 'orderIndex', dir: 'asc' }]
};
const res = await getBaseList(params);
if (res?.data?.data) {
baseList.value = res.data.data;
}
} catch (error) {
console.error('获取基地列表失败:', error);
}
};
// ==================== ====================
const filterOption = (input: string, option: any) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const handleBaseChange = () => {
handleSearch();
};
const handleTypeChange = () => {
handleSearch();
};
const handleBldsttChange = () => {
handleSearch();
};
const handleSearch = () => {
const filter = buildSearchFilter();
tableRef.value?.getList(filter);
};
const handleReset = () => {
searchData.value = {
baseid: props.currentJidiInfo?.wbsCode || 'all',
type: props.data?.type || '',
bldstt: '',
hydrodtin: '',
search: ''
};
const filter = buildSearchFilter();
tableRef.value?.reset();
tableRef.value?.getList(filter);
};
const handleViewDetail = (record: any, type: any) => {
console.log('查看详情:', record);
if (type == 'ENG') {
modelStore.modalVisible = true;
modelStore.params = record;
modelStore.params.sttp = 'ENG';
modelStore.title = record.ennm;
modelStore.params.stcd = record.stcd;
} else {
console.log('查看详情:', record);
modelStore.modalVisible = true;
modelStore.params = record;
modelStore.params.sttp = record.sttpCode;
// debugger
modelStore.title = record.stnm;
modelStore.params.stcd = record.stcd;
}
// TODO:
};
// ==================== ====================
onMounted(() => {
fetchBaseList();
handleSearch();
});
</script>
<style scoped lang="scss">
.huanbao-two-layers-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background-color: #ffffff;
box-sizing: border-box;
.search-form {
margin-bottom: 16px;
border-radius: 4px;
}
.table-wrapper {
flex: 1;
overflow: hidden;
}
}
.text_hocer {
color: #2f6b98;
}
.text_hocer:hover {
color: #40a9ff;
}
</style>

View File

@ -1,131 +1,210 @@
<!-- SidePanelItem.vue --> <!-- SidePanelItem.vue -->
<template> <template>
<SidePanelItem title="环保设施情况"> <SidePanelItem title="环保设施情况">
<div class="facility-grid" > <a-spin :spinning="loading">
<div v-for="facility in facilities" :key="facility.name" class="facility-card"> <div class="facility-grid" v-if="facilities.length > 0">
<div style="width: 60px;height: 62px;display: flex;align-items: center;justify-content: center;"> <div
<div class="facility-icon"> v-for="facility in facilities"
<i style="color: #fff;" :class="facility.icon" type="icon-shengtailiuliang2"></i> :key="facility.type"
</div> class="facility-card"
</div> @click="handleCardClick(facility)"
>
<div class="facility-info"> <div style="width: 60px;height: 62px;display: flex;align-items: center;justify-content: center;">
<div class="facility-name">{{ facility.name }}</div> <div class="facility-icon">
<div style="font-size: 16px;"> <span class="facility-count">{{ facility.count }}</span><span></span></div> <i style="color: #fff;" :class="facility.icon"></i>
</div>
</div>
</div> </div>
</SidePanelItem> </div>
<div class="facility-info">
<div class="facility-name">{{ facility.name }}</div>
<div style="font-size: 16px;">
<span class="facility-count">{{ facility.nowNum + facility.buildNum }}</span><span></span>
</div>
</div>
</div>
</div>
<a-empty v-else />
</a-spin>
<!-- 二级弹框 -->
<a-modal
v-model:open="modalVisible"
title="环保设施情况"
width="1536px"
:footer="null"
>
<HuanbaoModTwoLayers
v-if="modalVisible"
:data="modalData"
:currentJidiInfo="currentJidiInfo"
:res="modalRes"
/>
</a-modal>
</SidePanelItem>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted } from 'vue'; import { ref, watch } from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue'; import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { environmentalProtectionConstruction } from '@/api/home';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import HuanbaoModTwoLayers from './TwoLayers/HuanbaoModTwoLayers.vue';
// 便 // 便
defineOptions({ defineOptions({
name: 'huanbaoMod' name: 'huanbaoMod'
}); });
// store
const JidiSelectEventStore = useJidiSelectEventStore();
const baseid = ref('');
const currentJidiInfo = ref<any>(null);
//
const facilityList = [
{ name: '生态流量泄放设施', icon: 'icon iconfont icon-shengtailiuliang2', type: 'EQ', accessNum: 0, buildNum: 0, nowNum: 0, totalNum: 1 },
{ name: '低温水减缓设施', icon: 'icon iconfont icon-diwenshuijianhuan', type: 'DW', accessNum: 0, buildNum: 0, nowNum: 0, totalNum: 1 },
{ name: '栖息地', icon: 'icon iconfont icon-qixidi', type: 'FH', accessNum: 0, buildNum: 0, totalNum: 1, nowNum: 0 },
{ name: '过鱼设施', icon: 'icon iconfont icon-guoyusheshi', type: 'FP', accessNum: 0, buildNum: 0, nowNum: 0, totalNum: 1 },
{ name: '鱼类增殖站', icon: 'icon iconfont icon-yuleizengzhizhan', type: 'FB', accessNum: 0, buildNum: 0, nowNum: 0, totalNum: 1 },
{ name: '珍稀植物园', icon: 'icon iconfont icon-zhenxizhiwuyuan', type: 'VP', accessNum: 0, buildNum: 0, totalNum: 1, nowNum: 0 },
{ name: '动物救助站', icon: 'icon iconfont icon-dongwujiuzhuzhan', type: 'VA', accessNum: 0, buildNum: 0, totalNum: 1, nowNum: 0 }
];
// //
const facilities = ref([ const facilities = ref<any[]>([]);
{ const loading = ref(false);
name: '生态流量泄放设施',
count: 145,
icon: 'icon iconfont icon-shengtailiuliang2'
},
{
name: '低温水减缓设施',
count: 24,
icon: 'icon iconfont icon-diwenshuijianhuan'
},
{
name: '栖息地',
count: 142,
icon: 'icon iconfont icon-qixidi'
},
{
name: '过鱼设施',
count: 60,
icon: 'icon iconfont icon-guoyusheshi'
},
{
name: '鱼类增殖站',
count: 69,
icon: 'icon iconfont icon-yuleizengzhizhan'
},
{
name: '珍稀植物园',
count: 41,
icon: 'icon iconfont icon-zhenxizhiwuyuan'
},
{
name: '动物救助站',
count: 4,
icon: 'icon iconfont icon-dongwujiuzhuzhan'
}
]);
//
onMounted(() => {
//
const modalVisible = ref(false);
const modalData = ref<any>({});
const modalRes = ref({
bldstt: '',
hydrodtin: '1'
}); });
//
const getData = async () => {
if (!baseid.value) return;
loading.value = true;
try {
// const params = { baseId: baseid.value, '1': '1' };
const params ={
"filter": {
"logic": "and",
"filters": [
{
"field": "1",
"operator": "eq",
"dataType": "string",
"value": "1"
},
baseid.value !='all'?{
"field": "baseId",
"operator": "eq",
"dataType": "string",
"value": "01"
}:null
].filter(Boolean)
}
}
const res = await environmentalProtectionConstruction(params);
if (res?.data?.data) {
const list = [...facilityList];
list.forEach((item) => {
const found = res.data.data.find((el: any) => item.type === el.repCode);
if (found) {
item.nowNum = found.count || 0;
}
});
facilities.value = list;
} else {
facilities.value = [];
}
} catch (error) {
console.error('获取环保设施数据失败:', error);
facilities.value = [];
} finally {
loading.value = false;
}
};
//
const handleCardClick = (facility: any) => {
modalData.value = facility;
modalRes.value = {
bldstt: '',
hydrodtin: ''
};
modalVisible.value = true;
};
//
watch(
() => JidiSelectEventStore.selectedItem,
(newVal) => {
if (newVal && newVal.wbsCode) {
baseid.value = newVal.wbsCode;
currentJidiInfo.value = newVal;
getData();
}
},
{ deep: true, immediate: true }
);
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.facility-grid { .facility-grid {
width: 406px; width: 406px;
flex-flow: wrap; flex-flow: wrap;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji; font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;
} }
.facility-card { .facility-card {
width: 200px; width: 200px;
height: 64px; height: 64px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
margin: 4px 0px; margin: 4px 0px;
background: #fff; background: #fff;
border: 1px solid #e8e8e8; border: 1px solid #e8e8e8;
border-radius: 2px; border-radius: 2px;
transition: all 0.3s; transition: all 0.3s;
cursor: pointer; cursor: pointer;
box-sizing: border-box; box-sizing: border-box;
} }
.facility-icon { .facility-icon {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 40px; width: 40px;
height: 40px; height: 40px;
// margin-right: 8px; background: #2f6b98;
background: #2f6b98; border-radius: 50%;
border-radius: 50%;
.anticon { .anticon {
font-size: 24px; font-size: 24px;
color: #fff; color: #fff;
} }
} }
.facility-info { .facility-info {
flex: 1; flex: 1;
} }
.facility-name { .facility-name {
font-size: 16px; font-size: 16px;
color: #333; color: #333;
// margin-bottom: 4px;
// font-weight: 500;
} }
.facility-count { .facility-count {
font-size: 18px; font-size: 18px;
color: #2f6b98; color: #2f6b98;
// font-weight: 600;
} }
</style> </style>

View File

@ -0,0 +1,591 @@
<template>
<div class="huanbao-ej-container">
<!-- Tab切换 -->
<a-tabs v-model:activeKey="tabIndex" @change="handleTabChange">
<a-tab-pane
v-for="tab in tabs"
:key="String(tab.orderInx)"
:tab="tab.name"
/>
</a-tabs>
<!-- 搜索表单 -->
<div class="search-form">
<a-space size="middle">
<div>所属基地:</div>
<a-select
v-model:value="searchData.baseId"
placeholder="请选择所属基地"
style="width: 200px"
show-search
:filter-option="filterOption"
:options="jiDiList"
@change="handleBaseChange"
/>
<a-input
v-if="tabIndex !== '7'"
v-model:value="searchData.stnm"
placeholder="请输入测站名称"
style="width: 200px"
allow-clear
/>
<a-button type="primary" @click="handleSearch">查询</a-button>
<a-tooltip title="重置">
<a-button @click="handleReset">重置</a-button>
</a-tooltip>
</a-space>
</div>
<!-- 列表 -->
<BasicTable
ref="tableRef"
:scrollY="400"
:columns="columns"
:list-url="vmsstbprptGetKendoList"
:search-params="searchParams"
:transform-data="customTransform"
>
<template #coenvwState="{ column, record }">
<a-tag :color="record.coenvwState > 0 ? 'green' : '#999'">
{{ record.coenvwState > 0 ? '在线' : '离线' }}
</a-tag>
</template>
<template #dvtp="{ column, record }">
{{ dvtpText(record.dvtp) }}
</template>
<template #stindxForEng="{ column, record }">
{{ record.dvtp == 2 ? '生态流量' : '出库流量' }}
</template>
<template #action="{ column, record }">
<a @click="handleViewDetail(record, 'detail')" class="text-link">
查看详情
</a>
</template>
</BasicTable>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, onMounted } from 'vue';
import { vmsstbprptGetKendoList } from '@/api/home';
import BasicTable from '@/components/BasicTable/index.vue';
import { useModelStore } from '@/store/modules/model';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
const JidiSelectEventStore = useJidiSelectEventStore();
// ==================== Props ====================
const props = defineProps<{
baseId?: string;
tabs?: any[];
activeKey?: string | number;
}>();
// ==================== ====================
const tabIndex = ref(String(props.activeKey ?? ''));
const searchData = ref<any>({
baseId: props.baseId || 'all',
stnm: null
});
const modelStore = useModelStore();
const tableRef = ref();
// ==================== ====================
const jiDiList: any = ref([]);
// ==================== ====================
const columns = computed(() => {
// (tabIndex=7)
if (tabIndex.value === '7') {
return [
{
key: 'baseName',
title: '所属基地',
dataIndex: 'baseName',
width: '150px',
merge: true
},
{
key: 'stnm',
title: '电站名称',
dataIndex: 'stnm',
width: '176px',
},
{
key: 'dvtp',
title: '开发方式',
dataIndex: 'dvtp',
width: '120px',
slots: { customRender: 'dvtp' }
},
{
key: 'stindx',
title: '生态流量站类型',
dataIndex: 'stindx',
slots: { customRender: 'stindxForEng' }
},
{
key: 'jcdt',
title: '建成时间',
dataIndex: 'jcdt',
width: '150px',
sort: true
},
{
key: 'coenvwState',
title: '监测状态',
dataIndex: 'coenvwState',
width: '120px',
slots: { customRender: 'coenvwState' }
},
{
title: '操作',
key: 'action',
width: 100,
align: 'center' as const,
fixed: 'right' as const,
slots: { customRender: 'action' }
}
];
}
//
const baseColumns = [
{
key: 'baseName',
title: '所属基地',
dataIndex: 'baseName',
width: '150px',
merge: true
},
{
key: 'stnm',
title: '测站名称',
dataIndex: 'stnm',
width: '176px',
},
{
key: 'ennm',
title: '电站',
dataIndex: 'ennm',
width: '150px',
slots: { customRender: 'ennm' }
},
{
key: 'jcdt',
title: '建成时间',
dataIndex: 'jcdt',
width: '150px',
sort: true
},
{
key: 'stindx',
title: '监测指标',
dataIndex: 'stindx',
width: '150px',
}
];
// (tabIndex=4)
if (tabIndex.value !== '4') {
baseColumns.push({
key: 'coenvwState',
title: '监测状态',
dataIndex: 'coenvwState',
width: '120px',
slots: { customRender: 'coenvwState' }
} as any);
}
baseColumns.push({
title: '操作',
key: 'action',
width: 100,
align: 'center' as const,
fixed: 'right' as const,
slots: { customRender: 'action' }
} as any);
return baseColumns;
});
// ==================== ====================
const searchParams = computed(() => {
return {
sort: [
{
field: 'baseStepSort',
dir: 'asc'
},
{
field: 'hbrvcd',
dir: 'asc'
},
{
field: 'rstcdStepSort',
dir: 'asc'
},
{
field: 'siteStepSort',
dir: 'asc'
}
],
group: [],
select: [
'baseName',
'stnm',
'ennm',
'jcdt',
'stindx',
'coenvwState',
'sttpCode',
'stcd',
'rstcd',
'stCode',
'stName',
'dvtp'
],
groupResultFlat: false
};
});
// ==================== ====================
const handleTabChange = (key: string) => {
tabIndex.value = key;
handleSearch();
};
const filterOption = (input: string, option: any) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const handleBaseChange = () => {
handleSearch();
};
const dvtpText = (dvtp: number) => {
if (dvtp === 2) return '引水式';
if (dvtp === 3) return '混合式';
return '坝后式';
};
const handleSearch = () => {
let filters: any[] = [];
if (searchData.value.baseId !== 'all') {
filters.push({
field: 'baseId',
operator: 'eq',
value: searchData.value.baseId
});
}
if (searchData.value.stnm) {
filters.push({
field: 'stnm',
operator: 'contains',
value: searchData.value.stnm
});
}
// tabIndex
switch (tabIndex.value) {
case '1': //
filters.push(
{ field: 'mway', operator: 'eq', dataType: 'string', value: 2 },
{
field: 'sttpFullPath',
operator: 'contains',
dataType: 'string',
value: 'ENV,ENVM,WT'
}
);
break;
case '2': //
filters.push(
{ field: 'mway', operator: 'eq', dataType: 'string', value: 2 },
{
field: 'sttpFullPath',
operator: 'contains',
dataType: 'string',
value: 'ENV,ENVM,WQ'
},
{ field: 'dtinType', operator: 'eq', dataType: 'string', value: 1 }
);
break;
case '9': //
filters.push(
{ field: 'mway', operator: 'eq', dataType: 'string', value: 2 },
{ field: 'sttpCode', operator: 'eq', dataType: 'string', value: 'WQ' },
{ field: 'dtinType', operator: 'eq', dataType: 'string', value: 0 }
);
break;
case '10': //
filters.push(
{ field: 'mway', operator: 'eq', dataType: 'string', value: 2 },
{
field: 'sttpCode',
operator: 'eq',
dataType: 'string',
value: 'WQFB'
},
{ field: 'dtinType', operator: 'eq', dataType: 'string', value: 0 }
);
break;
case '4': //
filters.push(
{ field: 'mway', operator: 'eq', dataType: 'string', value: 2 },
{
field: 'sttpFullPath',
operator: 'contains',
dataType: 'string',
value: 'MM'
}
);
break;
case '5': //
filters.push(
{
logic: 'or',
filters: [
{
field: 'sttpFullPath',
operator: 'contains',
dataType: 'string',
value: 'ST,ZQ'
},
{
field: 'sttpFullPath',
operator: 'contains',
dataType: 'string',
value: 'ST,ZZ'
}
]
},
{ field: 'mway', operator: 'eq', dataType: 'string', value: 2 },
{ field: 'sttpCode', operator: 'in', value: ['ZZ', 'ZQ'] },
{ field: 'dtinType', operator: 'eq', dataType: 'string', value: 1 }
);
break;
case '6': //
filters.push(
{
logic: 'or',
filters: [
{
field: 'sttpFullPath',
operator: 'contains',
dataType: 'string',
value: 'ST,ZQ'
},
{
field: 'sttpFullPath',
operator: 'contains',
dataType: 'string',
value: 'ST,ZZ'
}
]
},
{ field: 'sttpCode', operator: 'in', value: ['ZZ', 'ZQ'] },
{ field: 'mway', operator: 'eq', dataType: 'string', value: 2 },
{ field: 'dtinType', operator: 'eq', dataType: 'string', value: 0 }
);
break;
case '7': //
filters.push(
{
field: 'runState',
operator: 'eq',
value: 4
},
{ field: 'sttpCode', operator: 'eq', dataType: 'string', value: 'ENG' },
{ field: 'DTIN', operator: 'eq', dataType: 'string', value: 1 },
{ field: 'bldsttCcode', operator: 'eq', dataType: 'string', value: 2 }
);
break;
case '8': //
filters.push(
{
field: 'sttpFullPath',
operator: 'contains',
dataType: 'string',
value: 'VD,VD'
},
{ field: 'dtin', operator: 'eq', dataType: 'string', value: 1 }
);
break;
case '11': //
filters.push({
field: 'sttpCode',
operator: 'eq',
dataType: 'string',
value: 'FH'
});
break;
}
let filter = {
logic: 'and',
filters: filters
};
tableRef.value?.getList(filter);
};
const handleReset = () => {
searchData.value = {
baseId: 'all',
stnm: null
};
handleSearch();
};
const customTransform = (res: any) => {
return {
records: res?.data?.data || [],
total: res?.data?.total || 0
};
};
// sttpCode
const getSttpCode = (sttpCode: string) => {
const codeMap: Record<string, string> = {
DW: 'DW',
DW_1: 'DW',
DW_2: 'DW',
DW_3: 'DW',
DW_4: 'DW',
DW_5: 'DW',
DW_6: 'DW',
DW_9: 'DW',
EQS: 'EQS',
EQ: 'EQ',
EQ_1: 'EQ',
EQ_2: 'EQ',
EQ_3: 'EQ',
EQ_4: 'EQ',
EQ_5: 'EQ',
EQ_6: 'EQ',
EQ_7: 'EQ',
FB: 'EQ',
FPC: 'FP',
'FPC,': 'FP',
FP: 'FP',
FP_1: 'FP',
FP_2: 'FP',
FP_3: 'FP',
FP_4: 'FP',
FP_5: 'FP',
FH: 'FH',
'FH,': 'FH',
SG: 'SG',
'SG,': 'SG',
TE: 'TE',
'TE,': 'TE',
VA: 'VA',
'VA,': 'VA',
VP: 'VP',
'VP,': 'VP',
WE: 'WE',
'WE,': 'WE',
WQ: 'WQ',
'WQ,': 'WQ',
WQH: 'WQ',
WT: 'WT',
'WT,': 'WT',
WTRV: 'WT',
'WTRV,': 'WT',
WTVT: 'WT',
'WTVT,': 'WT'
};
return codeMap[sttpCode] || '';
};
//
const handleViewDetail = (record: any, type: string) => {
if (type === 'dz') {
modelStore.modalVisible = true;
modelStore.params.sttp = 'ENG';
modelStore.title = record.ennm;
modelStore.params.stcd = record.rstcd;
} else {
const sttpCode = record.sttpCode || '';
if (sttpCode === 'MM') {
modelStore.modalVisible = true;
modelStore.params.sttp = 'MM';
modelStore.title = record.stnm;
modelStore.params.stcd = record.stcd;
} else if (sttpCode === 'ENG') {
modelStore.modalVisible = true;
modelStore.params.sttp = getSttpCode(sttpCode) || sttpCode;
modelStore.params.eqtp = 'QEC';
modelStore.params.stcd = record.stcd;
modelStore.title = record.stnm;
} else if (sttpCode.includes('VD')) {
modelStore.modalVisible = true;
modelStore.params.sttp = 'VD';
modelStore.params.stcd = record.stcd;
modelStore.title = record.stnm;
} else if (sttpCode.includes('WT')) {
modelStore.modalVisible = true;
modelStore.params.sttp = getSttpCode(sttpCode) || sttpCode;
modelStore.params.stcd = record.stcd;
modelStore.title = record.stnm;
modelStore.params.enfc =
sttpCode === 'WTVT' || sttpCode === 'WTVT,' ? '1' : '0';
} else {
modelStore.modalVisible = true;
modelStore.params.sttp = sttpCode;
modelStore.params.stcd = record.stcd;
modelStore.title = record.stnm;
}
}
};
// ==================== ====================
onMounted(() => {
JidiSelectEventStore.jidiData?.forEach((element: any) => {
jiDiList.value.push({
label: element.wbsName,
value: element.wbsCode
});
});
handleSearch();
});
</script>
<style scoped lang="scss">
.huanbao-ej-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background-color: #ffffff;
box-sizing: border-box;
.search-form {
margin-bottom: 16px;
border-radius: 4px;
}
:deep(.ant-table-wrapper) {
flex: 1;
overflow: hidden;
}
}
.text-link {
color: #2f6b98;
&:hover {
color: #40a9ff;
}
}
</style>

View File

@ -1,144 +1,223 @@
<!-- SidePanelItem.vue -->
<template> <template>
<SidePanelItem title="环保自动监测工作开展情况"> <SidePanelItem title="环保自动监测工作开展情况">
<div class="facility-grid" > <a-spin :spinning="loading">
<div v-for="facility in facilities" :key="facility.name" class="facility-card"> <div class="facility-grid">
<div style="width: 60px;height: 62px;display: flex;align-items: center;justify-content: center;"> <div
<div class="facility-icon"> v-for="facility in facilities"
<img style="width: 18px;height: 14px;" :src="facility.icon "> :key="facility.orderInx"
</div> class="facility-card"
</div> @click="handleFacilityClick(facility)"
>
<div class="facility-info"> <div
<div class="facility-name">{{ facility.name }}</div> style="
<div style="font-size: 16px;"> <span class="facility-count">{{ facility.count }}</span><span></span></div> width: 60px;
</div> height: 62px;
</div> display: flex;
align-items: center;
justify-content: center;
"
>
<div class="facility-icon">
<img style="width: 18px; height: 14px" :src="facility.icon" />
</div> </div>
</SidePanelItem> </div>
<div class="facility-info">
<div class="facility-name">{{ facility.name }}</div>
<div style="font-size: 16px">
<span class="facility-count">{{ facility.count }}</span>
<span>{{ facility.unit || '个' }}</span>
</div>
</div>
</div>
</div>
</a-spin>
</SidePanelItem>
<!-- 弹框 -->
<a-modal
v-model:open="modalVisible"
title="环保自动监测工作开展情况"
:footer="null"
width="1536px"
@cancel="handleCloseModal"
>
<HuanbaozidongjianceEJ
v-if="modalVisible && currentFacility"
:activeKey="currentFacility.orderInx"
:tabs="facilities"
:baseId="baseid"
/>
</a-modal>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted } from 'vue'; import { ref, onMounted, watch } from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue'; import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { baseEvnmAutoMonitorGetKendoListCust } from '@/api/home';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import HuanbaozidongjianceEJ from './huanbaozidongjianceEJ/index.vue';
// SVG
import svg_guojiashuiwenzhan from '@/assets/svg/guojiashuiwenzhan.svg';
import svg_guojiashuizhizhan from '@/assets/svg/guojiashuizhizhan.svg';
import svg_qixiangzhan from '@/assets/svg/qixiangzhan.svg';
import svg_zijianshuiwenzhan from '@/assets/svg/zijianshuiwenzhan.svg';
import svg_shipinjiankongshebei from '@/assets/svg/shipinjiankongshebei.svg';
import svg_diwenshuijianhuan from '@/assets/svg/diwenshuijianhuan.svg';
import svg_liuliangjiancezhan from '@/assets/svg/liuliangjiancezhan.svg';
import svg_shuizhijiancezhan from '@/assets/svg/shuizhijiancezhan.svg';
import svg_zengzhizhanshuizhizhan from '@/assets/svg/zengzhizhanshuizhizhan.svg';
import svg_qixidi from '@/assets/svg/qixidi.svg';
// 便
defineOptions({ defineOptions({
name: 'huanbaoMod' name: 'huanbaoMod'
}); });
// interface IFacility {
const facilities = ref([ name: string;
{ count: number | string;
"name": "生态流量", orderInx: number;
"count": 452 icon: string;
,"icon": "data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIyMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTEwMDEuNTIzIDgzOS4zNTVjLTE4LjEyNi04LjQ5OS0zOS4zMjQuMTU0LTQ3LjM2MyAxOS4zNTQtLjE0MS4zMzktLjI3OC42OC0uNDA5IDEuMDI0LTI4LjY3NCA3Mi4zNDQtMTA3LjMyIDEwNi4zNC0xNzUuNjI1IDc1LjkyOGExMzguNTUzIDEzOC41NTMgMCAwIDEtNzIuMzQ5LTc3LjgyM2MtNy42OC0xOS44MTQtMjguOTI5LTI5LjQzOS00Ny43NzItMjEuNTU1YTM2LjY2NSAzNi42NjUgMCAwIDAtMTYuODk3IDE0Ljc5N2MtMS42ODkgMi40NTgtMy40ODIgNS41ODEtNS4yMjIgOC42MDEtMjAuOTQxIDUyLjY4NC02OS41ODQgODYuOTg3LTEyMy40NDkgODcuMDM5LTUzLjU1OCAwLTEwMS4zMy0zMy45OTctMTIyLjg4Ni04NS4xOTVhMzguOTE0IDM4LjkxNCAwIDAgMC0yMS41MDUtMjUuODU2Yy0xOC43OTItNy44ODUtNDAuMDkxIDEuNjktNDcuNzcyIDIxLjUwNC0yMC4zMjcgNTQuMDY2LTY5LjY4NyA4OS40OTUtMTI0LjU3NSA4OS41NDctNTUuMTk3LS4wNTItMTA0LjgxMi0zNS43MzctMTI1LjI5Mi05MC4xMTEtNy40MjUtMTkuNzExLTI4LjMxNi0yOS41NDEtNDcuMTA3LTIyLjIyLTE4LjYzOCA3Ljg4NS0yNy45NTcgMzAuMDU0LTIwLjk5MyA1MC4wMjEgNDEuOTg2IDExMy4wOTkgMTYyLjUxNyAxNjguNzUyIDI2OS4yNzMgMTI0LjI2YTIwOC40MzUgMjA4LjQzNSAwIDAgMCA4Mi40MzYtNjIuNTY1Yzc0LjE5MyA5Mi43NzMgMjA1LjMyMiAxMDQuMTkgMjkyLjc3NiAyNS40OTdhMjE0LjQ2IDIxNC40NiAwIDAgMCAyNC41NzctMjYuMTExYzczLjYzIDkyLjk3NyAyMDQuNDUyIDEwNS4wNiAyOTIuMTYxIDI2Ljk4MiAyNS4yNDMtMjIuNDI1IDQ1LjA1OS01MC45NDMgNTcuODA4LTgzLjA5NiA3LjQzNC0xOS4yOS0xLjE4Ny00MS4wNTUtMTkuODE1LTUwLjAyMiIgZmlsbD0iI2ZmZiIvPjxwYXRoIGQ9Ik0xMDAxLjUyMyA2NDcuMzU5Yy0xOC4xMjYtOC40OTktMzkuMzI0LjE1NC00Ny4zNjMgMTkuMzU0LS4xNDEuMzM5LS4yNzguNjgtLjQwOSAxLjAyNC0yOC42NzQgNzIuMzQ0LTEwNy4zMiAxMDYuMzQtMTc1LjYyNSA3NS45MjhhMTM4LjU1MyAxMzguNTUzIDAgMCAxLTcyLjM0OS03Ny44MjNjLTcuNjgtMTkuODE0LTI4LjkyOS0yOS40MzktNDcuNzcyLTIxLjU1NWEzNi42NjUgMzYuNjY1IDAgMCAwLTE2Ljg5NyAxNC43OTdjLTEuNjg5IDIuNDU4LTMuNDgyIDUuNTgxLTUuMjIyIDguNjAxLTIwLjk0MSA1Mi42ODQtNjkuNTg0IDg2Ljk4Ny0xMjMuNDQ5IDg3LjAzOS01My41NTggMC0xMDEuMzMtMzMuOTk3LTEyMi44ODYtODUuMTk1YTM4LjkxNCAzOC45MTQgMCAwIDAtMjEuNTA1LTI1Ljg1NmMtMTguNzkyLTcuODg1LTQwLjA5MSAxLjY5LTQ3Ljc3MiAyMS41MDQtMjAuMzI3IDU0LjA2Ni02OS42ODcgODkuNDk1LTEyNC41NzUgODkuNTQ3LTU1LjE5Ny0uMDUyLTEwNC44MTItMzUuNzM3LTEyNS4yOTItOTAuMTExLTcuNDI1LTE5LjcxMS0yOC4zMTYtMjkuNTQxLTQ3LjEwNy0yMi4yMi0xOC42MzggNy44ODUtMjcuOTU3IDMwLjA1NC0yMC45OTMgNTAuMDIxIDQxLjk4NiAxMTMuMDk5IDE2Mi41MTcgMTY4Ljc1MiAyNjkuMjczIDEyNC4yNmEyMDguNDM1IDIwOC40MzUgMCAwIDAgODIuNDM2LTYyLjU2NWM3NC4xOTMgOTIuNzczIDIwNS4zMjIgMTA0LjE5IDI5Mi43NzYgMjUuNDk3YTIxNC40NiAyMTQuNDYgMCAwIDAgMjQuNTc3LTI2LjExMWM3My42MyA5Mi45NzcgMjA0LjQ1MiAxMDUuMDYgMjkyLjE2MSAyNi45ODIgMjUuMjQzLTIyLjQyNSA0NS4wNTktNTAuOTQzIDU3LjgwOC04My4wOTYgNy40MzQtMTkuMjktMS4xODctNDEuMDU1LTE5LjgxNS01MC4wMjIiIGZpbGw9IiNmZmYiLz48cGF0aCBkPSJNNDg2LjA2NyAwYzYuOTY0IDAgMTMuODI1IDIuOTE4IDE4LjYzOCA4LjA4OWwxOC42MzggMjAuNjM0IDIxLjYwNyAyNS40NDUgMTIuOTAzIDE1LjgyMUw1NzkgOTcuMTI0bDE0Ljg0OSAyMC4xMjIgMTUuMjA3IDIxLjUwMyAxNS4yNTggMjIuNjNhODk3LjgzNCA4OTcuODM0IDAgMCAxIDIzLjI0NiAzNy41OGwxMi4wODQtMTYuMTI4IDUwLjY5LTY1Ljg0MSA1MC42OSA2NS43OWMxNS4yNTkgMTkuNzEyIDI5LjY5OCAzOS45MzUgNDMuMzE4IDYwLjk3OCA0My4yNjYgNjcuMDcxIDY3LjA3NiAxMjUuNTkxIDY3LjA3NiAxNzQuNTg5LS4xNTQgOTAuMjEyLTcxLjg4OSAxNjQuMjQ2LTE2MS4xODYgMTY0LjI0Ni0yMS4xOTggMC00Mi4wODktNC4yNS02MS40NDMtMTIuMzlsLTEuOTk3IDIuMTVhMjMwLjY2IDIzMC42NiAwIDAgMS01Ni4xNjkgNDEuNzI3IDIyMC4zNDggMjIwLjM0OCAwIDAgMS04OC43ODUgMjUuMzk1bC0xNS42NjkuNTEyYTIyNS4xNCAyMjUuMTQgMCAwIDEtMTYyLjgyMi02OS42MzEgMjQwLjYyIDI0MC42MiAwIDAgMS02Ny4zODMtMTY4LjI0YzAtNzEuMDY0IDM1Ljk5NS0xNTkuMjc5IDEwNi45MS0yNjIuMzQzbDcuNjgxLTExLjA1OSAxNS4zMDktMjEuMTQ1IDE0Ljc5OC0xOS42MDkgMTQuMDI5LTE3LjkyIDE4Ljk0NS0yMy4yOTUgMTUuNjY4LTE4LjQzMkw0NjcuNDMgOC4xOTJhMjUuNjA1IDI1LjYwNSAwIDAgMSAxMy40NjYtNy42OEw0ODYuMDY3IDBabS4zMDcgODMuNDU0LTMuNTg0IDQuMzUyYTExOTguMTA0IDExOTguMTA0IDAgMCAwLTY3LjE3NyA4OC4zMThjLTY0LjI2IDkzLjM4Ny05NS42NDYgMTcwLjMzOS05NS42NDYgMjI2LjA0NCAwIDQ2Ljk0OSAxNy41NjMgOTAuNzI0IDQ5LjM1OSAxMjMuNjQ1IDMxLjQ4OSAzMi41MTEgNzIuNzA4IDUwLjE3NSAxMTYuODQzIDUwLjE3NSAyNi40MjEgMCA1MS4yNTUtNi4xNDQgNzQuNjU0LTE4LjUzNCAxMi4yODktNi40NTEgMjMuODYxLTE0LjY0MyAzNC40MDktMjQuMjY4QTE2Ni4wMyAxNjYuMDMgMCAwIDEgNTQ5LjIgNDE4LjI5NWMwLTQ0LjY0NSAyMC45OTMtOTkuMzI2IDU4LjI2OS0xNjAuMTVsLTkuNTI0LTE3LjFhMTAyNi42MDMgMTAyNi42MDMgMCAwIDAtMTA2Ljg2LTE1Mi4wNjFsLTQuNzExLTUuNTNabTIyNC4wMTIgMTM4LjM5MS0xMy45NzkgMTguNjM2Yy03LjUyNyAxMC4zNDMtMTUuNzcgMjIuMTE4LTI0LjAxNCAzNC43NjUtMzguMTQ2IDU4LjUyLTU5LjE4OSAxMDkuNDEyLTU5LjE4OSAxNDMuMDQ5IDAgMzUuOTQyIDE4LjczOSA2OS4zMjQgNDkgODcuMTQxIDE0LjQ5IDguNjUzIDMxLjE4MiAxMy4xNTggNDguMDI4IDEzLjE1OCA1My41MDYgMCA5Ny4wOC00NS4wMDQgOTcuMTMxLTEwMC4zNSAwLTMzLjc5MS0xOS42NjItODIuMTc0LTU2LjgzNC0xMzkuNzczbC04LjYwMi0xMy4xMDctOC41NTEtMTIuMzM5LTE1LjkyNC0yMS45MTMtNy4wNjYtOS4yNjdaIiBmaWxsPSIjZmZmIi8+PC9zdmc+" unit?: string | null;
}, }
{
"name": "水温监测", // orderInx SVG
"count": 140 const iconMap: Record<number, string> = {
,"icon": "data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDExMjUgMTAyNCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIyMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTMwLjgzOCA4MzIuOTM5YzE5LjE4Mi00LjA5NiAzOS4wOTQgNS42MzIgNDYuNTc2IDIzLjcwNmw0LjA1IDguOTA4YzI0LjUyNSA0OS4zMDYgNzYuMjc3IDgxLjE1MiAxMzMuNTk1IDgxLjIwNGwxMC4wMTQtLjMwOGM1Ni4yNTEtMy43MzcgMTA1Ljc1MS0zOC4xOTUgMTI2Ljg0Ni04OS4xODlsMi40MTgtNC43NjNjOS4zODEtMTYuNTY0IDMxLjExNi0yMy44NTUgNTAuMDY0LTE2Ljc5M2w1LjU2OCAyLjcxNGM4Ljk4OCA1LjM5NiAxNS40NDYgMTMuNjQ3IDE4LjExMyAyMy4xNDJsNC41IDguODU4YzI1LjMxMyA0Ni4yMzMgNzUuMDM5IDc2LjMzOSAxMzAuNDQ1IDc2LjMzOSA1OS4xNzctLjA1MiAxMTIuNjE1LTM0LjM1NiAxMzUuNTY2LTg3LjA0bDIuOTI1LTQuNTA1IDIuODY5LTQuMDk3YzQuMzI1LTYuNTk3IDEwLjgxOS0xMS43OTEgMTguNTYyLTE0Ljg0OGw1LjIzMi0xLjUzNWMxOS45NTQtNC40NDMgNDAuMzY2IDUuNTc2IDQ3LjI1IDIzLjE5M2w0LjMzMiA5LjM2OWMxNS4xNTMgMzAuMzMxIDQxLjg3MyA1NC42MzMgNzUuMjA4IDY4LjQwMyA3NC45ODIgMzAuNDEzIDE2MS4zODQtMy41ODMgMTkyLjk0LTc1Ljk4bC4xNjktLjUxMmM5LjA1Ni0xOS42NjEgMzIuMzQzLTI4LjMxMyA1Mi4zMTMtMTkuODE0bDUuMjMxIDIuNzEzYzE2LjkzNSAxMC4zNDcgMjMuNzcxIDI5Ljk3MSAxNi40ODEgNDcuMzA5LTEzLjc2NCAzMS44MjUtMzUuNTEyIDYwLjI4MS02My41MDcgODMuMDk2LTk2LjM1OCA3OC4wOC0yNDAuMDc4IDY1Ljk5Ny0zMjAuOTY3LTI2Ljk4MmwtOC40MzggOS4yMTdhMjI1LjQ0MSAyMjUuNDQxIDAgMCAxLTE4LjU2MyAxNi44OTZjLTk2LjEzMyA3OC42OTQtMjQwLjE5MSA2Ny4yNzYtMzIxLjY5OS0yNS40OThsLTkuNDUgMTAuMTM3Yy0yMi40NTMgMjIuNjc4LTUwLjEzMSA0MC41NjItODEuMDU3IDUyLjM3OC0xMTcuMjg0IDQ0LjQ5Mi0yNDkuNzU1LTExLjE2Mi0yOTUuODgtMTI0LjI2MmwtMS41NzUtNS40NzhjLTQuMjkyLTE4LjI4NSA1Ljk4NS0zNi44MjMgMjQuNjkzLTQ0LjU0NFpNNTQ0Ljk3MS4wMjNjOTEuMTI3LTEuNDM0IDE2Ni44OTcgNjMuNDM2IDE3My43MDQgMTQ2LjY4NmwuNDUgOS4zMnYxNzUuMzU5YzkgNi42NTUgMTcuNDM3IDEzLjk3NyAyNS4xNDMgMjEuOTY0bDguMzI2IDkuMjE2YzkxLjI5NCAxMDEuMzc2IDc5Ljk4OCAyNTAuNTcxLTIzLjUxNCAzMzkuMDQ0bC0xMS4xOTQgOS4wNjNjLTExMi4yMDQgODcuMjY5LTI4MS4zNzUgNzMuMjAyLTM3NC4zNS0zMS4xMjktOTEuNjg4LTEwMS42ODMtODAuNTUtMjUxLjQ5MyAyMy4xNzctMzQwLjYzMmwxMC4wMTItOC4xOTJWMTU2LjAyOUMzNzguMzU2IDcwLjUyNSA0NTIuNjYzIDEuNTU5IDU0NC45MTYuMDIzWm0xLjIzOSA2My45OTljLTUxLjI0NS44NzEtOTMuNTQ3IDM3LjU4MS05OC42NjUgODQuMTIybC0uNTA3IDcuODg1djIwNC4xODNsLTI0LjYzNyAxOS4xNDljLTgzLjgxNCA2NS4yMjktOTQuODQgMTgxLjYwNi0yNC41MjUgMjU5LjU4MyA2NS4xNzcgNzMuNTQyIDE4Mi43NTUgODYuNjQ3IDI2NS41MDMgMjkuNTkzbDEwLjE4Mi03LjUyNmM4MC40MzktNjIuMjU5IDkzLjY1OC0xNzIuMDgzIDMxLjgzOC0yNDkuMzQybC05LjMzOC0xMC45MDZhMTIyLjE5NSAxMjIuMTk1IDAgMCAwLTEzLjUtMTMuNTE3bC03LjQ4MS01Ljk5LTI2LjI3LTE5LjJWMTU3LjEwNGMtLjk1Ni00OS45Mi00Mi43NS04OS44MDUtOTQuMzg5LTkyLjg3N2wtOC4yMTEtLjIwNVptMS41NzQgMTI4IDUuMjg4LjM1OGMxNy4yMTIgMi4zNTUgMzAuMzc1IDE1Ljg3MiAzMC40MzEgMzIuMTU0djIxMi4wMThjMzAuMzc2IDkuNjI1IDU0LjA1OCAzMS40MzcgNjQuMzUxIDU5LjEzNWwyLjUzMiA3LjU3N2MxNC4wODEgNDguNzY4LTE1LjI3IDk5LjIxNy02Ny41MDIgMTE2LjAxOWwtOC41NSAyLjI1M2MtNzkuNzA3IDE3LjQxMy0xNTAuMjM0LTUwLjI0LTEyNi45NDktMTIxLjc3NiA5LjQ4My0yOS4xMzMgMzMuNDI3LTUyLjUzMiA2NC42NzktNjMuMjA4VjIyNC41ODRjLjAzMi0xNy45NTIgMTUuOTk2LTMyLjUwNiAzNS43Mi0zMi41NjJaIiBmaWxsPSIjZmZmIi8+PC9zdmc+" 1: svg_diwenshuijianhuan, //
}, 2: svg_guojiashuizhizhan, //
{ 4: svg_qixiangzhan, //
"name": "水文监测", 5: svg_guojiashuiwenzhan, //
"count": 21 6: svg_zijianshuiwenzhan, //
,"icon": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJNMCAwaDE2djE2SDB6Ii8+PHBhdGggZD0iTTkuOTcyIDEyLjc2YzEuMTA0IDAgMS42ODYuMTU3IDIuMi4yOTMuNDgxLjEyOC44OTQuMjQgMS43ODYuMjRWMTVjLTEuMSAwLTEuNjg1LS4xNTQtMi4yLS4yOTMtLjQ4LS4xMjgtLjg5NC0uMjQtMS43ODYtLjI0cy0xLjMwNi4xMTItMS43ODYuMjRjLS41MTQuMTM2LTEuMDk4LjI5My0yLjIuMjkzLTEuMTAxIDAtMS42ODYtLjE1NC0yLjItLjI5My0uNDgxLS4xMjgtLjg5NS0uMjQtMS43ODYtLjI0di0xLjcwOWMxLjEgMCAxLjY4NS4xNTUgMi4yLjI5NC40OC4xMjguODk0LjI0IDEuNzg2LjI0czEuMzA2LS4xMTIgMS43ODctLjI0Yy41MTQtLjEzNiAxLjA5OC0uMjk0IDIuMi0uMjk0di4wMDFabS4wMjYtMi42OTVjMS4xMDIgMCAxLjY4NS4xNTggMi4yLjI5My40OC4xMjkuODk1LjI0IDEuNzg3LjI0djEuNzA4Yy0xLjEwMiAwLTEuNjg2LS4xNTUtMi4yLS4yOTMtLjQ4MS0uMTI5LS44OTUtLjI0LTEuNzg2LS4yNC0uODkyIDAtMS4zMDYuMTExLTEuNzg3LjI0LS41MTUuMTM1LTEuMDk5LjI5My0yLjIuMjkzLTEuMTAxIDAtMS42ODUtLjE1NS0yLjItLjI5My0uNDgtLjEyOS0uODk1LS4yNC0xLjc4Ny0uMjR2LTEuNzA3YzEuMTAyIDAgMS42ODYuMTU0IDIuMi4yOTIuNDgyLjEyOS44OTUuMjQgMS43ODcuMjQuODkyIDAgMS4zMDUtLjExMSAxLjc4Ni0uMjQuNTE1LS4xMzUgMS4xLS4yOTMgMi4yLS4yOTNaTTE0IDF2Ny44NDloLTEuNjU0VjIuNzA4SDMuNjY1djYuMTRIMi4wMVYxSDE0Wk04Ljg4NCA0LjEyNHY0LjcyNUg3LjIzVjQuMTI0aDEuNjU1WiIgZmlsbD0iI0ZGRiIgZmlsbC1ydWxlPSJub256ZXJvIi8+PC9nPjwvc3ZnPg==" 7: svg_liuliangjiancezhan, //
}, 8: svg_shipinjiankongshebei, //
{ 9: svg_shuizhijiancezhan, //
"name": "河道水质监测", 10: svg_zengzhizhanshuizhizhan, //
"count": 56 11: svg_qixidi //
,"icon": "data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMjAwIiBoZWlnaHQ9IjIwMCI+PHBhdGggZD0ibTY2NS4yMTIgMCAuNTEyIDMwNy44MTRjMCAzMy41ODggNy44ODUgNjcuMTc1IDIyLjIyIDk3LjI4bDMyNC41MDYgNDYwLjY5OC43MTcgMi4wNDhjMTYuNDM1IDM0LjMwNCAxNC4zMzYgNzMuNTc0LTYuNDUxIDEwNS43MjhBMTE0LjMzIDExNC4zMyAwIDAgMSA5MTEuNjM4IDEwMjRoLTc5OS4xM2MtMzguNjA1IDAtNzQuMzQyLTE4Ljk0NC05NS4wNzgtNTEuMDk4YTEwNy40MTggMTA3LjQxOCAwIDAgMS02LjQ1Mi0xMDUuNzI4bDEuNDM0LTIuODE2IDMwNy4zNTQtNDU4LjU0N2MxNC4zMzYtMzAuODIyIDIyLjE3LTY0LjQxIDIyLjE3LTk3Ljk5N0wzNDEuNDIyIDBoMzIzLjc4OXptLTYzLjg0NiA2NGgtMTk1Ljg0bC40MSAyNDMuODE0YzAgMzYuNTU3LTcuMTY5IDczLjIxNi0yMC43ODggMTA3LjgyOGwtNy4zMjIgMTcuMS00Ljg2NCA4LjcwNEw2OC4xNyA4OTZsLTEuOTk3IDUuMTJhNDIuODAzIDQyLjgwMyAwIDAgMCAxLjg0MyAzMS4yODNsMy4yMjYgNS44MzdhNDcuNzE4IDQ3LjcxOCAwIDAgMCAzMy45OTcgMjEuMjQ4bDcuMjcuNTEyaDc5OS4xM2E0OS42NjQgNDkuNjY0IDAgMCAwIDQxLjI2Ny0yMS4wNDMgNDMuMDYgNDMuMDYgMCAwIDAgNS4wNjktMzcuMTJsLTIuMS01LjI3NC0zMjAuMjU2LTQ1NC42MDUtNS41My05LjM3YTI5My4zNzYgMjkzLjM3NiAwIDAgMS0yNy44NTItMTA4LjY0NmwtLjUxMi0xNi4wMjVMNjAxLjM2NiA2NHoiIGZpbGw9IiNmZmYiLz48cGF0aCBkPSJNMjU2LjA3MyAwaDUxMnY2NGgtNTEyek0zNjUuMjMxIDY4Ni40OWE4My45NjggODMuOTY4IDAgMCAxIDgzLjYxIDgzLjYxYzAgNDMuMDA3LTMzLjE3OCA3OC44NDctNzUuMTEgODMuMDk3bC04LjUuNDZhODMuOTY4IDgzLjk2OCAwIDAgMS04My41NTgtODMuNTU4YzAtNDMuMDA4IDMzLjEyNi03OC44NDggNzUuMDU5LTgzLjE0OWw4LjUtLjQ2em0yNDUuMDk1LTE4Ljg0MmM1MS41MDcgMCA5Mi45NzkgNDEuNDcyIDkyLjk3OSA5My4wMyAwIDQ4LjQ4Ny0zNi43MSA4OC4wNjQtODMuOTY4IDkyLjU3bC05LjAxMS40MWE5Mi43NzQgOTIuNzc0IDAgMCAxLTkzLjAzLTkyLjk4YzAtNDguNTM3IDM2Ljc2LTg4LjA2NCA4NC4wMTgtOTIuNjJsOS4wMTItLjQxek0zNjUuMjMgNzUwLjQ5YTE5Ljk2OCAxOS45NjggMCAwIDAtMTkuNTU4IDE5LjYxIDE5Ljk2OCAxOS45NjggMCAwIDAgMTkuNTU4IDE5LjU1OCAxOS45NjggMTkuOTY4IDAgMCAwIDE5LjYxLTE5LjU1OSAxOS45NjggMTkuOTY4IDAgMCAwLTE5LjYxLTE5LjYxem0yNDUuMDk1LTE4Ljg0MmEyOC43NzQgMjguNzc0IDAgMCAwLTI5LjAzIDI5LjAzYzAgMTYuMTggMTIuOCAyOC45OCAyOS4wMyAyOC45OCAxNi4xNzkgMCAyOC45NzktMTIuOCAyOC45NzktMjguOThhMjguNzc0IDI4Ljc3NCAwIDAgMC0yOC45OC0yOS4wM3pNNTAyLjI0MiA0MjEuOTM5YTExNi4zNzggMTE2LjM3OCAwIDAgMSAxMTYuMjI0IDExNi4yMjRjMCA2MC45MjgtNDcuNjE2IDExMS4wNTMtMTA2LjgwMyAxMTUuOTE3bC05LjQyLjM1OGExMTYuMzc4IDExNi4zNzggMCAwIDEtMTE2LjIyNS0xMTYuMjI0YzAtNjAuOTI4IDQ3LjA1My0xMTEuMDAxIDEwNi43MDEtMTE1Ljg2NWw5LjUyMy0uNDF6bTAgNjRjLTI4Ljc3NCAwLTUyLjIyNCAyMy41NTItNTIuMjI0IDUyLjIyNCAwIDI4Ljc3NSAyMy40NSA1Mi4yNzUgNTIuMjI0IDUyLjI3NSAyOC4zNjUgMCA1Mi4yMjQtMjMuNzU2IDUyLjIyNC01Mi4yMjQgMC0yOC43NzQtMjMuNS01Mi4yMjQtNTIuMjI0LTUyLjIyNHoiIGZpbGw9IiNmZmYiLz48L3N2Zz4=" };
},
{ const facilities = ref<IFacility[]>([]);
"name": "增殖站水质站", const loading = ref(false);
"count": 9 const JidiSelectEventStore = useJidiSelectEventStore();
,"icon": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNDgiIGhlaWdodD0iNDgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTI0IDBjMTIuODQgMCAyMy4yNSAxMC43NDUgMjMuMjUgMjRTMzYuODQgNDggMjQgNDggLjc1IDM3LjI1NS43NSAyNCAxMS4xNiAwIDI0IDBabS0uMDA1IDYuNjY4Yy05LjUwMSAwLTE3LjIwMiA3LjgyNC0xNy4yMDIgMTcuNDc2IDAgOC4zMjcgNS43MzIgMTUuMjg4IDEzLjQwNSAxNy4wNDVoNy41OTNjNy42NzMtMS43NTcgMTMuNDA2LTguNzE4IDEzLjQwNi0xNy4wNDUgMC05LjY1Mi03LjctMTcuNDc2LTE3LjIwMi0xNy40NzZabS4xOTggMS42OTNjOC40IDAgMTUuMjEgNi42NiAxNS4yMSAxNC44NzQgMCAuMDk4LS4wMDYuMTkzLS4wMDguMjloLS4wNDdjLS4wMDMtLjA1My0uMDEyLS4xMDUtLjAxNy0uMTU3LS4yNCA0LjI1Mi0zLjUwOSA3LjYyMS03LjUwNyA3LjYyMWE3LjAyNSA3LjAyNSAwIDAgMS0yLjU5My0uNDk1bC0uMTM2LjEwMmE4LjM5MSA4LjM5MSAwIDAgMC00LjYyMy0xLjM3IDguMzk5IDguMzk5IDAgMCAwLTQuMjMgMS4xMzMgNi44NzIgNi44NzIgMCAwIDEtMy45NTMgMS4yNjNjLTQuMDggMC03LjM4Ny0zLjYzOS03LjM4Ny04LjEyNSAwLS41NTUuMDUtMS4wOTcuMTQ3LTEuNjJDOS43NSAxNC4zIDE2LjI2IDguMzYgMjQuMTkzIDguMzZabS0uMTk1IDIuNzMxLS4wMDUuMTUzLS4wMDMtLjE1MmMtLjAwMi0uMDEtLjA2MS4wOS0uMTY1LjI3N2wtLjA4Ny4xNTVjLS4zNzUuNjgzLTEuMTIzIDIuMDc4LTEuODg1IDMuNTA2bC0uMjE2LjQwNWMtLjY2NiAxLjI1LTEuMzMgMi41MDItMS45OTQgMy43NTRhNS41MjIgNS41MjIgMCAwIDAtMS4wNTUgMy4yNTljMCAzLjAzMyAyLjQyIDUuNDkxIDUuNDA3IDUuNDkxIDIuOTg1IDAgNS40MDUtMi40NTggNS40MDUtNS40OTFhNS41MjcgNS41MjcgMCAwIDAtMS4wNTQtMy4yNTkgMTg2My4xNSAxODYzLjE1IDAgMCAwLTEuODg2LTMuNTUxbC0uNDMyLS44MWMtMS4wNC0xLjk1LTIuMDIzLTMuNzc3LTIuMDMtMy43MzdabTQuMDUyIDExLjM0MmMuMDAyLjA0OS4wMDYuMDk4LjAwNi4xNDcgMCAyLjE4Ny0xLjU0MiAzLjk2LTMuNDQ1IDMuOTYtMS4yMzggMC0yLjMyMy0uNzUtMi45My0xLjg3OS42ODMuNzI1IDEuNjE0IDEuMTcyIDIuNjQgMS4xNzIgMS44NjQgMCAzLjQxMS0xLjQ2NyAzLjcyOS0zLjRaIiBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9Im5vbnplcm8iLz48L3N2Zz4=" const baseid = ref('');
},
{ //
"name": "国家水质站", const modalVisible = ref(false);
"count": 1722 const currentFacility = ref<IFacility | null>(null);
,"icon": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTguMDEzIDEyLjc5OGMxLjE3NC4wMDIgMi4yOTYtLjQ0MyAzLjEwNC0xLjIyOS44My0uODA4IDEuMjkyLTEuODggMS4yODgtMi45OTQgMC0yLjMzNi0xLjcyLTQuNzM1LTQuMzktOC41NzUtMi42OCAzLjg0LTQuMzkyIDYuMjQtNC4zOTIgOC41NzUgMCAxLjEyMy40NjQgMi4yMDIgMS4yODggMi45OTQuODA4Ljc4NiAxLjkzIDEuMjMgMy4xMDMgMS4yMjloLS4wMDFaTTcuOTggMi43MmMuMzUzLjUyMy41NDYgMS4xMzMuNTYyIDEuNzU5IDAgMi4wOC0yLjIxNCAyLjQzLTIuMjE0IDEuMTVDNi4zNiA0LjggNy40NSAzLjQ5IDcuOTgyIDIuNzJ2LjAwMmgtLjAwMVptLjAzMyAxMy4yNzdjLTEuOTUyIDAtNC43My0uNDgtNi4wMTktMS44ODhhOC41ODQgOC41ODQgMCAwIDEgMS42ODctLjcwNGMuNzI2LjQ4IDIuMjEzLjk5MiA0LjMzMi45OTIgMi4xMTggMCAzLjYwNC0uNTEyIDQuMzY0LS45OTJhOC42NSA4LjY1IDAgMCAxIDEuNjkuNzA2QzEyLjc0NiAxNS41MiA5Ljk2OCAxNiA4LjAxNyAxNmwtLjAwMy0uMDAyWm01LjkxNy04Ljg2MmMuNTMtLjgzMyAxLjQ1NC0uNDUgMS45MjEtMS4yMTcuNTYzLS44OTYtLjU5Ni0xLjgyNC0xLjUyLTEuMDI0LS40OTkuNDU1LS41OTcgMS4zMTItLjQgMi4yNGwtLjAwMS4wMDFaTTEuNjY2IDQuODljLS44OTQtLjgzMi0yLjA4My4wOTYtMS41MiAxLjAyNC40OTQuNzY3IDEuMzg5LjM4NCAxLjkyIDEuMjE2LjIyOC0uOTIzLjEyOS0xLjc4MS0uNC0yLjIzNlY0Ljg5WiIgZmlsbD0iI0ZGRiIgZmlsbC1ydWxlPSJub256ZXJvIi8+PC9zdmc+"
}, const fetchData = () => {
{ let params = {
"name": "视频监控", filter: {
"count": 247 logic: 'and',
,"icon": "data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDExMzcgMTAyNCIgd2lkdGg9IjIwMCIgaGVpZ2h0PSIyMDAiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0ibTE0Ny43ODggMCA5NDcuNjYxIDI2My4wMDItNzUuMzE1IDk4LjA4NUwxMTM3IDM5Mi4zOTdsLTc4Ljc4MiAyOTQuNDgyLTIzOC43MzQtNjQuMDk5LTc1LjI1OCA5OC4xOTgtMzM5LjM0NC05NS4xMjR2MjA3LjYxMkg3My42NjdWMTAyNEgwVjY0Mi45ODloNzMuNjF2MTE0LjI1MmgyNTcuNzE5bC0uMDU3LTE1MS45OTVMOS45NDcgNTE1LjI0NSAxNDcuNzg4IDBaTTg1MS43NyAyNzQuMzg3IDYwNS4wNzggNjAyLjg1NWwxMTIuMjYyIDMxLjQyNCAyNTEuMTI1LTMyNy41TDg1MS43NyAyNzQuMzNaTTk3MCA0MjYuNDk2IDg2OS42MTggNTU3LjM3MWwxMzcuMTAyIDM2Ljc3NCAzOS4zOTEtMTQ3LjIxMi03Ni4xNjgtMjAuNDk0Wk0xOTguOTQ1IDkzLjE4OWwtOTguNTYzIDM2OC4zMTcgNDI4LjI0NCAxMTkuODg4IDI0Ni42OTItMzI4LjI5N0wxOTguOTQ1IDkzLjEzMloiIGZpbGw9IiNmZmYiLz48L3N2Zz4=" filters: [
}, {
{ field: 'showIds',
"name": "气象监测", operator: 'in',
"count": 74058 value: ['7', '1', '6', '9', '10', '2', '8', '4', '5']
,"icon": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJNMCAwaDE2djE2SDB6Ii8+PHBhdGggZD0iTTQuMTgzIDE2YS42NDIuNjQyIDAgMCAxLS42NC0uNjQ4LjY0Mi42NDIgMCAwIDEgLjY0LS42NDdINS41OXYtMS43N2E1LjkzIDUuOTMgMCAwIDEtMS43ODktMS4yNTRjLTIuNzUxLTIuNzgyLTEuODktNy4yNS0uNDU2LTguNjk2IDEuMTI3LTEuMTQgMy4xODEtLjUxNSA1LjA2Ni44NzdhLjI2LjI2IDAgMCAxIC4xMDIuMjVMOC4zNDYgNS4xOWwtLjEzLjA2YS4yNi4yNiAwIDAgMS0uMjc0LS4wNGMtMS41MDYtMS4yOS0zLjAwNy0xLjg0OC0zLjYzLTEuMjYtLjc2LjcxNi4wNzcgMi44NzQgMS44NzIgNC44MTggMS43OTQgMS45NDUgMy44NjQgMi45NCA0LjYyNSAyLjIyMi41ODctLjU1My4yMjItMS45NjctLjgwMS0zLjQ3N2wuMTIyLS4yMyAxLjE1NC0uMzc4YzEuMjA3IDEuOTA1IDEuNjM4IDQgLjU2IDUuMDktLjk0My45NTItMi45MzUgMS43MjItNC45NzMgMS4zNDF2MS4zN2gyLjQzMmEuNjQzLjY0MyAwIDAgMSAuNjQuNjQ3LjY0My42NDMgMCAwIDEtLjY0LjY0N2gtNS4xMlptMy4zMjMtOC4wMi0uMTQ0LS4xNDVhLjY5Mi42OTIgMCAwIDEgLjA1LTEuMDM5bDEuNTE2LTEuMjUzYS44NTkuODU5IDAgMCAxIC44NDgtLjEyNy43NzMuNzczIDAgMCAxLS4xNTUtLjQ2OS43NC43NCAwIDAgMSAuNzE2LS43NTguNzM5LjczOSAwIDAgMSAuNzE3Ljc1OC43MzcuNzM3IDAgMCAxLS43MTcuNzU3LjY4NS42ODUgMCAwIDEtLjQzNy0uMTU3Ljg4Ljg4IDAgMCAxLS4xMjYuODUybC0xLjI0IDEuNTNhLjY4NS42ODUgMCAwIDEtLjUzNS4yNjUuNjkuNjkgMCAwIDEtLjQ5My0uMjE0Wm02LjQ2LTIuMjhjMC0yLjU0LTEuOTQ4LTQuNjA3LTQuMzQzLTQuNjA3VjBDMTIuNTg4IDAgMTUgMi41NTcgMTUgNS42OTloLTEuMDMzWm0tMS44MjggMEEyLjczNSAyLjczNSAwIDAgMCAxMS40IDMuODFhMi40MjYgMi40MjYgMCAwIDAtMS43NzctLjc4M3YtMS4wOWMxLjk1OCAwIDMuNTUgMS42ODcgMy41NSAzLjc2MWgtMS4wMzVaIiBmaWxsPSIjRkZGIiBmaWxsLXJ1bGU9Im5vbnplcm8iLz48L2c+PC9zdmc+" },
}, baseid.value != 'all'
{ ? {
"name": "国家水文站", field: 'baseId',
"count": 1189 operator: 'eq',
,"icon": "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJNMCAwaDE2djE2SDB6Ii8+PHBhdGggZmlsbD0iI0ZGRiIgZmlsbC1ydWxlPSJub256ZXJvIiBkPSJNMyAxNCA4IDBsNSAxNHoiLz48L2c+PC9zdmc+" value: baseid.value
}
: null
].filter(Boolean)
} }
]); };
loading.value = true;
baseEvnmAutoMonitorGetKendoListCust(params)
.then((res: any) => {
const data = res?.data?.data || [];
facilities.value = data.map((item: any) => ({
name: item.sttpName,
count: item.cnt,
orderInx: item.orderInx,
icon: iconMap[item.orderInx] || '',
unit: item.unit || '个'
}));
})
.catch(() => {
facilities.value = [];
})
.finally(() => {
loading.value = false;
});
};
// //
onMounted(() => { const handleFacilityClick = (facility: IFacility) => {
currentFacility.value = facility;
modalVisible.value = true;
}); };
//
const handleCloseModal = () => {
modalVisible.value = false;
currentFacility.value = null;
};
//
watch(
() => JidiSelectEventStore.selectedItem,
newVal => {
if (newVal && newVal.wbsCode) {
baseid.value = newVal.wbsCode;
fetchData();
}
},
{ deep: true, immediate: true }
);
onMounted(() => {});
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.facility-grid { .facility-grid {
// width: 406px; flex-flow: wrap;
flex-flow: wrap; display: flex;
display: flex; justify-content: space-between;
justify-content: space-between; margin-top: -8px;
margin-top: -8px; font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji; Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji,
Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;
} }
.facility-card { .facility-card {
width: 200px; width: 200px;
height: 64px; height: 64px;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
margin: 4px 0px; margin: 4px 0px;
background: #fff; background: #fff;
border: 1px solid #e8e8e8; border: 1px solid #e8e8e8;
border-radius: 2px; border-radius: 2px;
transition: all 0.3s; transition: all 0.3s;
cursor: pointer; cursor: pointer;
box-sizing: border-box; box-sizing: border-box;
} }
.facility-icon { .facility-icon {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 40px; width: 40px;
height: 40px; height: 40px;
// margin-right: 8px; background: #2f6b98;
background: #2f6b98; border-radius: 50%;
border-radius: 50%;
.anticon {
font-size: 24px;
color: #fff;
}
} }
.facility-info { .facility-info {
flex: 1; flex: 1;
} }
.facility-name { .facility-name {
font-size: 16px; font-size: 16px;
color: #333; color: #333;
// margin-bottom: 4px;
// font-weight: 500;
} }
.facility-count { .facility-count {
font-size: 18px; font-size: 18px;
color: #2f6b98; color: #2f6b98;
// font-weight: 600;
} }
</style> </style>

View File

@ -2,8 +2,10 @@
<template> <template>
<div> <div>
<SidePanelItem title="基本情况介绍" :shrink="true"> <SidePanelItem title="基本情况介绍" :shrink="true">
<p v-if="title_text" class="basic_body1">{{ title_text }}</p> <a-spin :spinning="loading">
<div v-else class="zanwushujv"><a-empty /></div> <p v-if="title_text" class="basic_body1">{{ title_text }}</p>
<div v-else class="zanwushujv"><a-empty /></div>
</a-spin>
</SidePanelItem> </SidePanelItem>
</div> </div>
</template> </template>
@ -20,6 +22,7 @@ const JidiSelectEventStore = useJidiSelectEventStore();
defineOptions({ defineOptions({
name: "jidiInfoMod", name: "jidiInfoMod",
}); });
const loading = ref(false);
const initText = () => { const initText = () => {
const params = { const params = {
filter: { filter: {
@ -35,9 +38,12 @@ const initText = () => {
], ],
}, },
}; };
loading.value = true;
getBaseWbsb(params).then((res) => { getBaseWbsb(params).then((res) => {
console.log(res); console.log(res);
title_text.value = res.data.data[0].introduce; title_text.value = res.data.data[0].introduce;
}).finally(() => {
loading.value = false;
}); });
}; };
const title_text = ref(""); const title_text = ref("");

View File

@ -1,84 +1,158 @@
<!-- SidePanelItem.vue --> <!-- SidePanelItem.vue -->
<template> <template>
<SidePanelItem title="AI识别过鱼设施运行" :datetimePicker="datetimePicker"> <SidePanelItem title="AI识别过鱼设施运行" :datetimePicker="datetimePicker" @update-values="handlePanelChange">
<div class="facility-grid"> <a-spin :spinning="dataLoading" tip="加载中...">
<div v-for="facility in facilities" :key="facility.name" class="facility-card"> <div class="facility-grid">
<div style="width: 70px;height: 62px;display: flex;align-items: center;justify-content: center;"> <div v-for="facility in facilities" :key="facility.key" class="facility-card">
<div class="facility-icon"> <div style="width: 70px;height: 62px;display: flex;align-items: center;justify-content: center;">
<i style="color: #fff;" :class="facility.icon" type="icon-shengtailiuliang2"></i> <div class="facility-icon">
<i style="color: #fff;" :class="facility.icon" type="icon-shengtailiuliang2"></i>
</div>
</div> </div>
</div>
<div class="facility-info"> <div class="facility-info">
<div class="facility-name">{{ facility.name }}</div> <div class="facility-name">{{ facility.name }}</div>
<div style="font-size: 14px;"> <span class="facility-count">{{ facility.count }}</span> <div style="font-size: 14px;"> <span class="facility-count">{{ facility.count }}</span>
<span></span> <span></span>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </a-spin>
</SidePanelItem> </SidePanelItem>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue'; import { ref, computed, watch } from 'vue';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import SidePanelItem from '@/components/SidePanelItem/index.vue'; import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { getAiGyssList } from '@/api/zngj';
import dayjs from 'dayjs';
// 便 // 便
defineOptions({ defineOptions({
name: 'zengzhizhanjiansheyunxing' name: 'spdzwaijc'
}); });
const JidiSelectEventStore = useJidiSelectEventStore();
const baseid = ref('');
const dataLoading = ref(false);
const panelDetail = ref<any>({});
const lyName = computed(() => baseid.value === '02' ? '升鱼斗运行' : '升鱼机运行');
// ==================== ====================
const datetimePicker = ref({ const datetimePicker = ref({
show: true, show: true,
value: `${new Date().getFullYear() - 1}`, // value: dayjs().format('YYYY-MM'),
format: 'YYYY-MM', format: 'YYYY-MM',
picker: 'month' as const, picker: 'month' as const,
options: [] options: []
}); });
//
const facilities = ref([ // ==================== ====================
const facilities = computed(() => [
{ {
key: 'gys',
name: '赶鱼栅运行', name: '赶鱼栅运行',
count: "32", count: panelDetail.value?.fpGysCnt ?? 0,
icon: 'icon iconfont icon-ganyushan' icon: 'icon iconfont icon-ganyushan'
}, },
{ {
name: '升鱼斗运行', key: 'syj',
count: '66', name: lyName.value,
count: panelDetail.value?.fpSyjCnt ?? 0,
icon: 'icon iconfont icon-liuliangjiancezhan1' icon: 'icon iconfont icon-liuliangjiancezhan1'
}, },
{ {
key: 'agv',
name: 'AGV小车', name: 'AGV小车',
count: '0', count: panelDetail.value?.fpAgvCnt ?? 0,
icon: 'icon iconfont icon-agvxiaoche' icon: 'icon iconfont icon-agvxiaoche'
}, },
{ {
key: 'yych',
name: '运鱼车运行', name: '运鱼车运行',
count: '0', count: panelDetail.value?.fpYychCnt ?? 0,
icon: 'icon iconfont icon-yunyuche' icon: 'icon iconfont icon-yunyuche'
}, },
{ {
key: 'yyc',
name: '运鱼船出港', name: '运鱼船出港',
count: '32', count: panelDetail.value?.fpYycCnt ?? 0,
icon: 'icon iconfont icon-yunyuchuan' icon: 'icon iconfont icon-yunyuchuan'
}, },
{ {
key: 'ydh',
name: '鱼道放流', name: '鱼道放流',
count: '0', count: panelDetail.value?.fpYdhCnt ?? 0,
icon: 'icon iconfont icon-yudaofangliu' icon: 'icon iconfont icon-yudaofangliu'
} }
]); ]);
// // ==================== ====================
onMounted(() => { const handlePanelChange = (data: any) => {
// console.log('当前所有控件状态:', data);
if (data.datetime) {
datetimePicker.value.value = data.datetime;
}
getCardData();
};
}); // ==================== ====================
const getCardData = async () => {
if (!datetimePicker.value.value || !baseid.value) return;
// dataLoading.value = true;
onUnmounted(() => {
}); try {
const params = {
filter: {
logic: 'and',
filters: [
baseid.value !== 'all' ? {
field: 'baseId',
operator: 'eq',
dataType: 'string',
value: baseid.value
} : null,
{
field: 'startTime',
operator: 'gte',
dataType: 'date',
value: dayjs(datetimePicker.value.value).startOf('month').format('YYYY-MM-DD 00:00:00')
},
{
field: 'endTime',
operator: 'lte',
dataType: 'date',
value: dayjs(datetimePicker.value.value).endOf('month').format('YYYY-MM-DD 23:59:59')
}
].filter(Boolean)
}
};
const res = await getAiGyssList(params);
panelDetail.value = res?.data ?? {};
} catch (error) {
console.error('获取统计数据失败:', error);
panelDetail.value = {};
} finally {
dataLoading.value = false;
}
};
// ==================== ====================
watch(
() => JidiSelectEventStore.selectedItem,
async newVal => {
if (newVal && newVal.wbsCode) {
baseid.value = newVal.wbsCode;
getCardData();
}
},
{ deep: true, immediate: true }
);
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -111,7 +185,6 @@ onUnmounted(() => {
justify-content: center; justify-content: center;
width: 40px; width: 40px;
height: 40px; height: 40px;
// margin-right: 8px;
background: rgb(47, 107, 152); background: rgb(47, 107, 152);
border-radius: 50%; border-radius: 50%;
@ -128,13 +201,14 @@ onUnmounted(() => {
.facility-name { .facility-name {
font-size: 16px; font-size: 16px;
color: #333; color: #333;
// margin-bottom: 4px;
// font-weight: 500;
} }
.facility-count { .facility-count {
font-size: 18px; font-size: 18px;
color: #2f6b98; color: #2f6b98;
// font-weight: 600;
} }
</style>
:deep(.ant-spin-nested-loading) {
min-height: 72px;
}
</style>

View File

@ -0,0 +1,289 @@
<template>
<div class="modal-content">
<!-- 搜索表单 -->
<a-form layout="inline" class="search-form" @finish="handleSearch">
<a-form-item label="所属基地">
<a-select
v-model:value="searchForm.baseId"
placeholder="请选择基地"
style="width: 180px"
allow-clear
show-search
:filter-option="filterOption"
:options="baseOptions"
/>
</a-form-item>
<a-form-item label="监测数据状态">
<a-select
v-model:value="searchForm.warnState"
placeholder="请选择状态"
style="width: 150px"
allow-clear
:options="warnStateOptions"
/>
</a-form-item>
<a-form-item label="测站名称">
<a-input
v-model:value="searchForm.stnm"
placeholder="请输入测站名称"
style="width: 180px"
allow-clear
/>
</a-form-item>
<a-form-item>
<a-button type="primary" @click="handleSearch">查询</a-button>
<!-- <a-button style="margin-left: 8px" @click="handleReset">重置</a-button> -->
<a-tooltip title="导出(暂未实现)">
<a-button style="margin-left: 8px">导出</a-button>
</a-tooltip>
</a-form-item>
</a-form>
<!-- 表格 -->
<div class="table-wrapper">
<BasicTable
ref="tableRef"
:columns="columns"
:scroll-y="420"
:list-url="getStllGaojingDetail"
:search-params="tableSearchParams"
:transform-data="customTransform"
>
<template #action="{ record }">
<a-button
v-if="record.warnState === 2"
type="link"
size="small"
@click="opentan(record)"
>
查看详情
</a-button>
<span v-else style="color: #999">查看详情</span>
</template>
</BasicTable>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, reactive, watch,onMounted } from 'vue';
import BasicTable from '@/components/BasicTable/index.vue';
import { getStllGaojingDetail } from '@/api/zngj';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import { useModelStore } from '@/store/modules/model';
defineOptions({
name: 'ModeGaoJing'
});
const modelStore = useModelStore();
interface Props {
baseId: string;
warnState: string;
warnType: string;
sttpCode: string;
}
const props = withDefaults(defineProps<Props>(), {
baseId: '',
warnState: '',
warnType: 'QEC',
sttpCode: 'ENG'
});
const JidiSelectEventStore = useJidiSelectEventStore();
const tableRef = ref();
//
const baseOptions = computed(() => {
return JidiSelectEventStore.jidiData.map((item: any) => ({
label: item.wbsName,
value: item.wbsCode
}));
});
//
const warnStateOptions = [
{ label: '全部', value: '' },
{ label: '正常', value: '1' },
{ label: '告警', value: '2' },
{ label: '无数据', value: '0' }
];
//
const searchForm = reactive({
baseId: props.baseId || '',
warnState: props.warnState || '',
stnm: ''
});
// props
watch(
() => [props.baseId, props.warnState],
([newBaseId, newWarnState]) => {
searchForm.baseId = newBaseId;
searchForm.warnState = newWarnState;
handleSearch();
}
);
//
const columns = [
{
title: '电站名称',
key: 'ennm',
dataIndex: 'ennm',
width: '150px',
customRender: ({ text, record }: any) => {
return text || record.stnm || '-';
}
},
{
title: '测站名称',
key: 'stnm',
dataIndex: 'stnm',
width: '150px'
},
{
title: '所属基地',
key: 'baseName',
dataIndex: 'baseName',
width: '150px'
},
{
title: '监测数据状态',
key: 'warnstateName',
dataIndex: 'warnstateName',
width: '120px'
},
{
title: '操作',
key: 'action',
width: '100px',
slots: { customRender: 'action' }
}
];
//
const tableSearchParams = computed(() => {
return {
sort: [
{ field: 'baseStepSort', dir: 'asc' },
{ field: 'rvcdStepSort', dir: 'asc' },
{ field: 'rstcdStepSort', dir: 'asc' },
{ field: 'siteStepSort', dir: 'asc' },
{ field: 'stnm', dir: 'asc' }
],
group: [],
select: [],
groupResultFlat: false
};
});
//
const customTransform = (res: any) => {
return {
records: res?.data?.data || [],
total: res?.data?.total || 0
};
};
// Select
const filterOption = (input: string, option: any) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
//
const handleSearch = () => {
const filters: any[] = [];
//
if (searchForm.baseId && searchForm.baseId !== 'all') {
filters.push({
field: 'baseId',
operator: 'eq',
dataType: 'string',
value: searchForm.baseId
});
}
//
filters.push({
field: 'sttpCode',
operator: 'eq',
dataType: 'string',
value: props.sttpCode
});
//
if (searchForm.warnState !== undefined && searchForm.warnState !== '') {
filters.push({
field: 'warnState',
operator: 'eq',
dataType: 'string',
value: searchForm.warnState
});
}
//
filters.push({
field: 'warnType',
operator: 'eq',
dataType: 'string',
value: props.warnType
});
//
if (searchForm.stnm) {
filters.push({
field: 'stnm',
operator: 'contains',
dataType: 'string',
value: searchForm.stnm
});
}
const filter = {
logic: 'and',
filters: filters
};
tableRef.value?.getList(filter);
};
//
const handleReset = () => {
searchForm.baseId = '';
searchForm.warnState = '';
searchForm.stnm = '';
handleSearch();
};
const opentan = (record: any) => {
modelStore.modalVisible = true;
modelStore.params.sttp = 'ENG';
modelStore.title = record.ennm;
modelStore.params.stcd = record.rstcd;
};
//
// handleSearch();
onMounted(() => {
handleSearch();
});
</script>
<style lang="scss" scoped>
.modal-content {
display: flex;
flex-direction: column;
// height: 100%;
.search-form {
margin-bottom: 16px;
padding-bottom: 16px;
border-bottom: 1px solid #f0f0f0;
}
.table-wrapper {
flex: 1;
}
}
</style>

View File

@ -2,49 +2,173 @@
<template> <template>
<div> <div>
<SidePanelItem title="生态流量低于限值告警情况"> <SidePanelItem title="生态流量低于限值告警情况">
<div class="body_box"> <a-spin :spinning="dataLoading" tip="加载中...">
<div class="box" v-for="(item, index) in data" :key="index"> <div class="body_box">
<div> <div class="box" v-for="(item, index) in data" :key="index" @click="handleBoxClick(item.warnState)" style="cursor: pointer;">
<div :class="item.icon" :style="{background:item.background}"></div> <div>
<div class="title_text">{{ item.name }}</div> <div :class="item.icon" :style="{background:item.background}"></div>
<div class="title_text">{{ item.name }}</div>
</div>
<div><span class="text_num">{{ item.num }}</span><span></span></div>
</div> </div>
<div><span class="text_num">{{ item.num }}</span><span></span></div>
</div> </div>
</div> </a-spin>
</SidePanelItem> </SidePanelItem>
<!-- 详情弹窗 -->
<a-modal
v-model:open="isModalOpen"
title="生态流量低于限值告警统计"
width="90%"
:body-style="{ height: '600px', padding: '16px' }"
:footer="null"
@cancel="handleModalClose"
>
<ModeGaoJing
:base-id="baseid"
:warn-state="currentWarnState"
warn-type="QEC"
sttp-code="ENG"
/>
</a-modal>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted, watch } from "vue"; import { ref, onMounted, watch } from "vue";
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import SidePanelItem from "@/components/SidePanelItem/index.vue"; import SidePanelItem from "@/components/SidePanelItem/index.vue";
import { getStllGaojingList } from '@/api/zngj';
import ModeGaoJing from './ModeGaoJing.vue';
// 便 // 便
defineOptions({ defineOptions({
name: "jidiInfoMod", name: "jidiInfoMod",
}); });
const JidiSelectEventStore = useJidiSelectEventStore();
const baseid = ref('');
const dataLoading = ref(false);
const isModalOpen = ref(false);
const currentWarnState = ref('');
const data = ref([ const data = ref([
{ {
name:'正常', name:'正常',
num:'447', num:'0',
icon:'iconfont icon-shuidianzhan1 zhuangji', icon:'iconfont icon-shuidianzhan1 zhuangji',
background:'#78c300', background:'#78c300',
warnState:'1',
}, },
{ {
name:'告警', name:'告警',
num:'0', num:'0',
icon:'iconfont icon-shuidianzhanGaojing shebeiZhengchang', icon:'iconfont icon-shuidianzhanGaojing shebeiZhengchang',
background:'#e55555', background:'#e55555',
warnState:'2',
}, },
{ {
name:'无数据', name:'无数据',
num:'6', num:'0',
icon:'iconfont icon-shuidianzhanWushujv shebeiLixian', icon:'iconfont icon-shuidianzhanWushujv shebeiLixian',
background:'#8d8d8d', background:'#8d8d8d',
warnState:'0',
}, },
]) ])
//
onMounted(() => { }); //
const handleBoxClick = (warnState: string) => {
currentWarnState.value = warnState;
isModalOpen.value = true;
};
//
const handleModalClose = () => {
isModalOpen.value = false;
};
// ==================== ====================
const getCardData = async () => {
if (!baseid.value) return;
dataLoading.value = true;
try {
const params = {
filter: {
logic: 'and',
filters: [
baseid.value !== 'all' ? {
field: 'base_Id',
operator: 'eq',
dataType: 'string',
value: baseid.value
} : null
].filter(Boolean)
}
};
const res = await getStllGaojingList(params);
const list = res?.data?.data || [];
// warnType === 'QEC'
const qecList = list.filter((item: any) => item.warnType === 'QEC');
// warnState
const result = {
normal: 0, // warnState = 1
abnormal: 0, // warnState = 2
noData: 0 // warnState = 0
};
qecList.forEach((item: any) => {
if (item.warnState === 0) result.noData = item.num;
else if (item.warnState === 1) result.normal = item.num;
else if (item.warnState === 2) result.abnormal = item.num;
});
//
data.value = [
{
name: '正常',
num: result.normal.toString(),
icon: 'iconfont icon-shuidianzhan1 zhuangji',
background: '#78c300',
warnState: '1'
},
{
name: '告警',
num: result.abnormal.toString(),
icon: 'iconfont icon-shuidianzhanGaojing shebeiZhengchang',
background: '#e55555',
warnState: '2'
},
{
name: '无数据',
num: result.noData.toString(),
icon: 'iconfont icon-shuidianzhanWushujv shebeiLixian',
background: '#8d8d8d',
warnState: '0'
}
];
} catch (error) {
console.error('获取生态流量告警数据失败:', error);
} finally {
dataLoading.value = false;
}
};
// ==================== ====================
watch(
() => JidiSelectEventStore.selectedItem,
async newVal => {
if (newVal && newVal.wbsCode) {
baseid.value = newVal.wbsCode;
getCardData();
}
},
{ deep: true, immediate: true }
);
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@ -0,0 +1,289 @@
<template>
<div class="modal-content">
<!-- 搜索表单 -->
<a-form layout="inline" class="search-form" @finish="handleSearch">
<a-form-item label="所属基地">
<a-select
v-model:value="searchForm.baseId"
placeholder="请选择基地"
style="width: 180px"
allow-clear
show-search
:filter-option="filterOption"
:options="baseOptions"
/>
</a-form-item>
<a-form-item label="监测数据状态">
<a-select
v-model:value="searchForm.warnState"
placeholder="请选择状态"
style="width: 150px"
allow-clear
:options="warnStateOptions"
/>
</a-form-item>
<a-form-item label="测站名称">
<a-input
v-model:value="searchForm.stnm"
placeholder="请输入测站名称"
style="width: 180px"
allow-clear
/>
</a-form-item>
<a-form-item>
<a-button type="primary" @click="handleSearch">查询</a-button>
</a-form-item>
</a-form>
<!-- 表格 -->
<div class="table-wrapper">
<BasicTable
ref="tableRef"
:columns="columns"
:scroll-y="420"
:list-url="getStllGaojingDetail"
:search-params="tableSearchParams"
:transform-data="customTransform"
>
<template #action="{ record }">
<a-button
v-if="record.warnState === 2"
type="link"
size="small"
@click="opentan(record)"
>
查看详情
</a-button>
<span v-else style="color: #999">查看详情</span>
</template>
</BasicTable>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, reactive, watch, onMounted } from 'vue';
import BasicTable from '@/components/BasicTable/index.vue';
import { getStllGaojingDetail } from '@/api/zngj';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import { useModelStore } from '@/store/modules/model';
defineOptions({
name: 'ModeGaoJing'
});
const modelStore = useModelStore();
interface Props {
baseId: string;
warnState: string;
dtinType: string;
}
const props = withDefaults(defineProps<Props>(), {
baseId: '',
warnState: '',
dtinType: '0'
});
const JidiSelectEventStore = useJidiSelectEventStore();
const tableRef = ref();
//
const baseOptions = computed(() => {
return JidiSelectEventStore.jidiData.map((item: any) => ({
label: item.wbsName,
value: item.wbsCode
}));
});
//
const warnStateOptions = [
{ label: '全部', value: '' },
{ label: '正常', value: '1' },
{ label: '告警', value: '2' },
{ label: '无数据', value: '0' }
];
//
const searchForm = reactive({
baseId: props.baseId || '',
warnState: props.warnState || '',
stnm: ''
});
// props
watch(
() => [props.baseId, props.warnState],
([newBaseId, newWarnState]) => {
searchForm.baseId = newBaseId;
searchForm.warnState = newWarnState;
handleSearch();
}
);
//
const columns = [
{
title: '电站名称',
key: 'ennm',
dataIndex: 'ennm',
width: '150px',
customRender: ({ text, record }: any) => {
return text || record.stnm || '-';
}
},
{
title: '测站名称',
key: 'stnm',
dataIndex: 'stnm',
width: '150px'
},
{
title: '所属基地',
key: 'baseName',
dataIndex: 'baseName',
width: '150px'
},
{
title: '监测数据状态',
key: 'warnstateName',
dataIndex: 'warnstateName',
width: '120px'
},
{
title: '操作',
key: 'action',
width: '100px',
slots: { customRender: 'action' }
}
];
//
const tableSearchParams = computed(() => {
return {
sort: [
{ field: 'baseStepSort', dir: 'asc' },
{ field: 'rvcdStepSort', dir: 'asc' },
{ field: 'rstcdStepSort', dir: 'asc' },
{ field: 'siteStepSort', dir: 'asc' },
{ field: 'stnm', dir: 'asc' }
],
group: [],
select: [],
groupResultFlat: false
};
});
//
const customTransform = (res: any) => {
return {
records: res?.data?.data || [],
total: res?.data?.total || 0
};
};
// Select
const filterOption = (input: string, option: any) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
//
const handleSearch = () => {
const filters: any[] = [];
//
if (searchForm.baseId && searchForm.baseId !== 'all') {
filters.push({
field: 'baseId',
operator: 'eq',
dataType: 'string',
value: searchForm.baseId
});
}
// WQ
filters.push({
field: 'sttpCode',
operator: 'in',
dataType: 'string',
value: ['WQ']
});
//
if (searchForm.warnState !== undefined && searchForm.warnState !== '') {
filters.push({
field: 'warnState',
operator: 'eq',
dataType: 'string',
value: searchForm.warnState
});
}
// dtinType
if (props.dtinType === '') {
filters.push({
field: 'dtinType',
operator: 'in',
dataType: 'number',
value: [0, 1]
});
} else {
filters.push({
field: 'dtinType',
operator: 'eq',
dataType: 'number',
value: Number(props.dtinType)
});
}
// mway 2
filters.push({
field: 'mway',
operator: 'eq',
dataType: 'number',
value: 2
});
//
if (searchForm.stnm) {
filters.push({
field: 'stnm',
operator: 'contains',
dataType: 'string',
value: searchForm.stnm
});
}
const filter = {
logic: 'and',
filters: filters
};
tableRef.value?.getList(filter);
};
const opentan = (record: any) => {
modelStore.modalVisible = true;
modelStore.params.sttp = 'ENG';
modelStore.title = record.ennm;
modelStore.params.stcd = record.rstcd;
};
onMounted(() => {
handleSearch();
});
</script>
<style lang="scss" scoped>
.modal-content {
display: flex;
flex-direction: column;
.search-form {
margin-bottom: 16px;
padding-bottom: 16px;
border-bottom: 1px solid #f0f0f0;
}
.table-wrapper {
flex: 1;
}
}
</style>

View File

@ -1,57 +1,236 @@
<!-- SidePanelItem.vue --> <!-- SidePanelItem.vue -->
<template> <template>
<div> <div>
<SidePanelItem title="水质监测数据告警情况" :select="select" > <SidePanelItem title="水质监测数据告警情况" :select="select" @update-values="handlePanelChange">
<div class="body_box"> <a-spin :spinning="dataLoading" tip="加载中...">
<div class="box" v-for="(item, index) in data" :key="index"> <div class="body_box">
<div> <div class="box" v-for="(item, index) in data" :key="index" @click="handleCardClick(item.warnState)" style="cursor: pointer;">
<div :class="item.icon" :style="{background:item.background}"></div> <div>
<div class="title_text">{{ item.name }}</div> <div :class="item.icon" :style="{background:item.background}"></div>
<div class="title_text">{{ item.name }}</div>
</div>
<div><span class="text_num">{{ item.num }}</span><span></span></div>
</div> </div>
<div><span class="text_num">{{ item.num }}</span><span></span></div>
</div> </div>
</div> </a-spin>
</SidePanelItem> </SidePanelItem>
<a-modal
v-model:open="modalVisible"
title="水质监测告警统计"
width="1536px"
:footer="null"
@cancel="handleModalClose"
>
<ModeGaoJing
v-if="modalVisible"
:baseId="baseid"
:warnState="currentWarnState"
:dtinType="defaultValue"
/>
</a-modal>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted, watch } from "vue"; import { ref, watch } from "vue";
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import SidePanelItem from "@/components/SidePanelItem/index.vue"; import SidePanelItem from "@/components/SidePanelItem/index.vue";
import { getShuizhiGaojingList } from '@/api/zngj';
import ModeGaoJing from './ModeGaoJing.vue';
// 便
defineOptions({ defineOptions({
name: "jidiInfoMod", name: "shuizhijianceshuju",
}); });
const JidiSelectEventStore = useJidiSelectEventStore();
const baseid = ref('');
const dataLoading = ref(false);
const defaultValue = ref<string>('0');
//
const modalVisible = ref(false);
const currentWarnState = ref('');
const handleCardClick = (warnState: string) => {
currentWarnState.value = warnState;
modalVisible.value = true;
};
const handleModalClose = () => {
modalVisible.value = false;
};
const select = ref({ const select = ref({
show: true, show: true,
value: undefined, value: '0',
options: [], options: [
picker: undefined, { label: '全部', value: '' },
format: undefined { label: '国家站', value: '1' },
{ label: '自建站', value: '0' },
],
width: '140px',
minWidth: '140px',
}); });
const data = ref([ const data = ref([
{ {
name:'正常', name: '正常',
num:'56', num: '0',
icon:'iconfont icon-shuidianzhan1 zhuangji', warnState: '1',
background:'#78c300', icon: 'iconfont icon-shuidianzhan1 zhuangji',
background: '#78c300',
}, },
{ {
name:'告警', name: '告警',
num:'0', num: '0',
icon:'iconfont icon-shuidianzhanGaojing shebeiZhengchang', warnState: '2',
background:'#e55555', icon: 'iconfont icon-shuidianzhanGaojing shebeiZhengchang',
background: '#e55555',
}, },
{ {
name:'无数据', name: '无数据',
num:'0', num: '0',
icon:'iconfont icon-shuidianzhanWushujv shebeiLixian', warnState: '0',
background:'#8d8d8d', icon: 'iconfont icon-shuidianzhanWushujv shebeiLixian',
background: '#8d8d8d',
}, },
]) ]);
//
onMounted(() => { }); const handlePanelChange = (payload: any) => {
if (payload.select !== undefined) {
defaultValue.value = payload.select;
select.value.value = payload.select;
}
getCardData();
};
const getCardData = async () => {
if (!baseid.value) return;
dataLoading.value = true;
try {
const filters: any[] = [
{
field: 'sttpCode',
operator: 'in',
dataType: 'string',
value: ['WQ'],
},
{
field: 'mway',
operator: 'eq',
dataType: 'number',
value: 2,
},
{
field: 'usfl',
operator: 'eq',
dataType: 'string',
value: '1',
},
baseid.value !='all'? {
field: 'baseId',
operator: 'eq',
dataType: 'string',
value: baseid.value,
}: null,
].filter(Boolean);
if (defaultValue.value === '') {
filters.push({
field: 'dtinType',
operator: 'in',
dataType: 'number',
value: [0, 1],
});
} else {
filters.push({
field: 'dtinType',
operator: 'eq',
dataType: 'number',
value: Number(defaultValue.value),
});
}
const params = {
filter: {
logic: 'and',
filters,
},
group: [
{
dir: 'desc',
field: 'warnState',
aggregates: [
{
field: 'stcd',
aggregate: 'count',
},
],
},
],
select: [],
};
const res = await getShuizhiGaojingList(params);
const list = res?.data?.data || [];
// debugger
const result = {
normal: 0,
abnormal: 0,
noData: 0,
};
list.forEach((item: any) => {
const warnState = item.items?.[0]?.WARNSTATE;
const count = item.items?.[0]?.COUNT_STCD ?? 0;
if (warnState == 0) result.noData = count;
else if (warnState == 1) result.normal = count;
else if (warnState == 2) result.abnormal = count;
});
data.value = [
{
name: '正常',
num: result.normal.toString(),
warnState: '1',
icon: 'iconfont icon-shuidianzhan1 zhuangji',
background: '#78c300',
},
{
name: '告警',
num: result.abnormal.toString(),
warnState: '2',
icon: 'iconfont icon-shuidianzhanGaojing shebeiZhengchang',
background: '#e55555',
},
{
name: '无数据',
num: result.noData.toString(),
warnState: '0',
icon: 'iconfont icon-shuidianzhanWushujv shebeiLixian',
background: '#8d8d8d',
},
];
} catch (error) {
console.error('获取水质监测告警数据失败:', error);
} finally {
dataLoading.value = false;
}
};
watch(
() => JidiSelectEventStore.selectedItem,
async newVal => {
if (newVal && newVal.wbsCode) {
baseid.value = newVal.wbsCode;
getCardData();
}
},
{ deep: true, immediate: true }
);
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@ -19,6 +19,7 @@
show-search show-search
:filter-option="filterOption" :filter-option="filterOption"
:options="rstcdOptions" :options="rstcdOptions"
allowClear
/> />
</a-form-item> </a-form-item>
@ -29,54 +30,61 @@
</a-form-item> </a-form-item>
</a-form> </a-form>
<!-- Tabs 标签页 --> <a-spin :spinning="bodyLoading">
<a-tabs <template v-if="tabList.length > 0">
v-if="tabList.length > 0" <!-- Tabs 标签页 -->
v-model:activeKey="ecoFlowType" <a-tabs
class="tab-style" v-model:activeKey="ecoFlowType"
@change="fetchTableData" class="tab-style"
> @change="fetchTableData"
<a-tab-pane v-for="item in tabList" :key="item.key" :tab="item.label" />
</a-tabs>
<div class="body_zhengti">
<div class="echarts">
<a-spin :spinning="dataLoading">
<div v-if="pieData.length > 0" ref="chartRef" class="pie-chart"></div>
<a-empty
v-if="!dataLoading && pieData.length === 0"
description="暂无数据"
/>
</a-spin>
</div>
<div class="table_1">
<BasicTable
ref="tableRef"
:columns="columns"
:scrollY="380"
:scrollX="100"
:list-url="vmsstbprptGetKendoList"
:search-params="searchParams"
:transform-data="customTransform"
> >
<template #stnm="{ record }"> <a-tab-pane v-for="item in tabList" :key="item.key" :tab="item.label" />
<a-button </a-tabs>
type="link" <div class="body_zhengti">
size="small" <div class="echarts">
@click="handleView(record, 'EQ')" <a-spin :spinning="dataLoading">
>{{ record.stnm }}</a-button <div v-if="pieData.length > 0" ref="chartRef" class="pie-chart"></div>
<a-empty
v-if="!dataLoading && pieData.length === 0"
description="暂无数据"
/>
</a-spin>
</div>
<div class="table_1">
<BasicTable
ref="tableRef"
:columns="columns"
:scrollY="380"
:scrollX="100"
:list-url="vmsstbprptGetKendoList"
:search-params="searchParams"
:transform-data="customTransform"
> >
</template> <template #stnm="{ record }">
<template #ennm="{ record }"> <a-button
<a-button type="link"
type="link" size="small"
size="small" @click="handleView(record, 'EQ')"
@click="handleView(record, 'ENG')" >{{ record.stnm }}</a-button
>{{ record.ennm }}</a-button >
> </template>
</template> <template #ennm="{ record }">
</BasicTable> <a-button
</div> type="link"
</div> size="small"
@click="handleView(record, 'ENG')"
>{{ record.ennm }}</a-button
>
</template>
</BasicTable>
</div>
</div>
</template>
<a-empty
v-else-if="!bodyLoading"
description="暂无数据"
/>
</a-spin>
</div> </div>
</template> </template>
@ -294,8 +302,6 @@ const searchParams = computed(() => {
}; };
}); });
;
const params = ref({ const params = ref({
qid: props.basicId || 'all', qid: props.basicId || 'all',
rstcd: '' rstcd: ''
@ -309,6 +315,7 @@ const activeETime = ref('');
const tabList = ref<any[]>([]); const tabList = ref<any[]>([]);
const ecoFlowType = ref<string>(props.sttpCodekey || ''); const ecoFlowType = ref<string>(props.sttpCodekey || '');
const loading = ref<boolean>(false); const loading = ref<boolean>(false);
const bodyLoading = ref<boolean>(false);
const jidiOptions = computed(() => { const jidiOptions = computed(() => {
return [ return [
@ -589,6 +596,7 @@ const customTransform = (res: any) => {
// Tab // Tab
const fetchTabList = async () => { const fetchTabList = async () => {
loading.value = true; loading.value = true;
bodyLoading.value = true;
try { try {
const { qid, rstcd } = params.value; const { qid, rstcd } = params.value;
let obj = { let obj = {
@ -644,6 +652,8 @@ const fetchTabList = async () => {
// ecoFlowType.value = tabList.value[0].key; // ecoFlowType.value = tabList.value[0].key;
// DOM
await nextTick();
// //
fetchPieData(); fetchPieData();
// //
@ -656,6 +666,7 @@ const fetchTabList = async () => {
tabList.value = []; tabList.value = [];
} finally { } finally {
loading.value = false; loading.value = false;
bodyLoading.value = false;
} }
}; };
const handleView = (record: any, type: 'ENG' | 'EQ') => { const handleView = (record: any, type: 'ENG' | 'EQ') => {
@ -731,6 +742,17 @@ watch(ecoFlowType, () => {
fetchPieData(); fetchPieData();
}); });
// tabList
watch(
() => tabList.value.length,
(newLen) => {
if (newLen === 0 && chartInstance) {
chartInstance.dispose();
chartInstance = null;
}
}
);
const handleSearch = () => { const handleSearch = () => {
// Tab // Tab
fetchTabList(); fetchTabList();

View File

@ -29,7 +29,7 @@
ref="tableRef" ref="tableRef"
:columns="columns" :columns="columns"
:scrollY="480" :scrollY="480"
:list-url="vmsstbprptGetKendoList" :list-url="vmsstbprptGetKendoList1"
:search-params="searchParams" :search-params="searchParams"
:transform-data="customTransform" :transform-data="customTransform"
> >
@ -59,7 +59,7 @@
<script lang="ts" setup> <script lang="ts" setup>
import { ref, computed, onMounted, onUnmounted, watch, nextTick, h } from 'vue'; import { ref, computed, onMounted, onUnmounted, watch, nextTick, h } from 'vue';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import { vmsstbprptGetKendoList } from '@/api/stll'; import { vmsstbprptGetKendoList1 } from '@/api/stll';
import BasicTable from '@/components/BasicTable/index.vue'; import BasicTable from '@/components/BasicTable/index.vue';
import { useModelStore } from '@/store/modules/model'; import { useModelStore } from '@/store/modules/model';
@ -275,7 +275,7 @@ const handleChange = async () => {
], ],
select: ['stcd', 'stnm'] select: ['stcd', 'stnm']
}; };
let res = await vmsstbprptGetKendoList(params); let res = await vmsstbprptGetKendoList1(params);
if (res?.data?.data) { if (res?.data?.data) {
let data = res.data.data; let data = res.data.data;
stcdOptions.value = data.map((item: any) => ({ stcdOptions.value = data.map((item: any) => ({

View File

@ -111,6 +111,7 @@ const props = defineProps<{
typeKey?: string; typeKey?: string;
time?: string; time?: string;
basicId?: string; basicId?: string;
dateArr?: any[];
}>(); }>();
const JidiSelectEventStore = useJidiSelectEventStore(); const JidiSelectEventStore = useJidiSelectEventStore();
@ -193,8 +194,11 @@ const searchParams = computed(() => {
sort: baseSort sort: baseSort
}; };
}); });
// // 使 dateArr使
const initDateRange = () => { const initDateRange = () => {
if (props.dateArr && props.dateArr.length === 2) {
return [dayjs(props.dateArr[0]), dayjs(props.dateArr[1])];
}
const today = dayjs(); const today = dayjs();
const lastMonthSameDay = today.subtract(1, 'month'); const lastMonthSameDay = today.subtract(1, 'month');
return [lastMonthSameDay, today]; return [lastMonthSameDay, today];

View File

@ -1,9 +1,9 @@
<!-- SidePanelItem.vue --> <!-- SidePanelItem.vue -->
<template> <template>
<div> <div>
<SidePanelItem title="生态流量达标情况" :click-action="{ show: true }"> <SidePanelItem title="生态流量达标情况" :click-action="{ show: true }">
<!-- 使用插槽自定义点击提示的内容 --> <!-- 使用插槽自定义点击提示的内容 -->
<template #click-action-content> <template #click-action-content>
<div v-if="titleData.cnt" style="max-width: 300px; line-height: 1.6"> <div v-if="titleData.cnt" style="max-width: 300px; line-height: 1.6">
<p> <p>
1统计电站范围接入过生态流量数据的电站 1统计电站范围接入过生态流量数据的电站
@ -77,6 +77,7 @@
:typeKey="selectedItem.key" :typeKey="selectedItem.key"
:time="mode" :time="mode"
:basicId="baseid" :basicId="baseid"
:dateArr="dateArr"
/> />
</a-modal> </a-modal>
@ -100,6 +101,7 @@ import {
evnmAutoMonitorGetKendoListCust evnmAutoMonitorGetKendoListCust
} from '@/api/stll'; } from '@/api/stll';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent'; import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import { useMapViewStore } from '@/modules/map/stores/map-view.store';
import STLLXFFS from './TwoLayer/ShengTaiLiuLiangDaBQKTwoLayer.vue'; import STLLXFFS from './TwoLayer/ShengTaiLiuLiangDaBQKTwoLayer.vue';
import ModalYkzhbzdjcgz from './TwoLayer/ModalYkzhbzdjcgz.vue'; import ModalYkzhbzdjcgz from './TwoLayer/ModalYkzhbzdjcgz.vue';
import HuanbaoZDJCGZKZ from '@/modules/huanbaozdjcgzkzQK/index.vue'; import HuanbaoZDJCGZKZ from '@/modules/huanbaozdjcgzkzQK/index.vue';
@ -108,7 +110,9 @@ defineOptions({
name: 'shengtaidabiaoMod' name: 'shengtaidabiaoMod'
}); });
const JidiSelectEventStore = useJidiSelectEventStore(); const JidiSelectEventStore = useJidiSelectEventStore();
const mapViewStore = useMapViewStore();
const baseid = ref(''); const baseid = ref('');
const dateArr = ref<any[]>([]);
const obj = { const obj = {
show: true, show: true,
value: value:
@ -119,15 +123,15 @@ const mode = ref('hour');
const dataArr: any = ref([ const dataArr: any = ref([
{ {
name: '生态环境部门要求', name: '生态环境部门要求',
qecCnt: '41', // qecCnt: '0', //
qecTCnt: '55', // qecTCnt: '0', //
type: 1, type: 1,
key: 'qecInterval' key: 'qecInterval'
}, },
{ {
name: '水利部门要求', name: '水利部门要求',
qecCnt: '41', // qecCnt: '0', //
qecTCnt: '55', // qecTCnt: '0', //
type: 2, type: 2,
key: 'mwrInterval' key: 'mwrInterval'
} }
@ -181,13 +185,7 @@ const setStyle = () => {
const dataChage = () => { const dataChage = () => {
getData(); getData();
}; };
const getData = async () => { const getdate = (offsetYears = 0) => {
// 00:00:00 23:59:59
const now = new Date();
const oneMonthAgo = new Date(now);
oneMonthAgo.setMonth(oneMonthAgo.getMonth() - 1);
// YYYY-MM-DD
const formatDate = (date: Date) => { const formatDate = (date: Date) => {
const year = date.getFullYear(); const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0'); const month = String(date.getMonth() + 1).padStart(2, '0');
@ -195,8 +193,35 @@ const getData = async () => {
return `${year}-${month}-${day}`; return `${year}-${month}-${day}`;
}; };
const startDate = `${formatDate(oneMonthAgo)} 00:00:00`; let startDate: string;
const endDate = `${formatDate(now)} 23:59:59`; let endDate: string;
if (dateArr.value && dateArr.value.length === 2) {
const start = new Date(dateArr.value[0]);
const end = new Date(dateArr.value[1]);
if (offsetYears !== 0) {
start.setFullYear(start.getFullYear() + offsetYears);
end.setFullYear(end.getFullYear() + offsetYears);
}
startDate = `${formatDate(start)} 00:00:00`;
endDate = `${formatDate(end)} 23:59:59`;
} else {
const now = new Date();
const oneMonthAgo = new Date(now);
oneMonthAgo.setMonth(oneMonthAgo.getMonth() - 1);
if (offsetYears !== 0) {
now.setFullYear(now.getFullYear() + offsetYears);
oneMonthAgo.setFullYear(oneMonthAgo.getFullYear() + offsetYears);
}
startDate = `${formatDate(oneMonthAgo)} 00:00:00`;
endDate = `${formatDate(now)} 23:59:59`;
}
return { startDate, endDate };
};
const getData = async () => {
const { startDate, endDate } = getdate(0);
let params = { let params = {
filter: { filter: {
@ -279,6 +304,17 @@ watch(
}, },
{ deep: true, immediate: true } { deep: true, immediate: true }
); );
watch(
() => mapViewStore.searchTimeRange,
(newVal) => {
dateArr.value = newVal;
getData();
},
{ deep: true }
);
// //
const titleData:any = ref({ cnt: 0 }) const titleData:any = ref({ cnt: 0 })
const getcont = async () => { const getcont = async () => {

View File

@ -0,0 +1,386 @@
<template>
<div class="stlldbqk_container">
<div class="stlldbqk_title">
<div>选择水电站:</div>
<a-select
v-model:value="from.baseId"
show-search
placeholder=" "
:options="jidiOptions"
:filter-option="filterOption"
@change="handleChange"
style="width: 200px; margin: 0px 10px"
></a-select>
<a-select
v-model:value="from.stcd"
show-search
placeholder="请选择电站"
:options="stcdOptions"
:filter-option="filterOption"
style="width: 200px"
></a-select>
<a-button type="primary" style="margin: 0px 10px" @click="Search()"
>搜索</a-button
>
<a-button @click="resetSearch()">重置</a-button>
</div>
<div class="table">
<BasicTable
ref="tableRef"
:columns="columns"
:scrollY="480"
:list-url="vmsstbprptGetKendoList1"
:search-params="searchParams"
:transform-data="customTransform"
>
<template #dvtp="{ record }">
{{
record.dvtp == 2 ? '引水式' : record.dvtp == 3 ? '混合式' : '坝后式'
}}
</template>
<template #stindx="{ record }">
{{ record.dvtp == 2 ? '生态流量' : '出库流量' }}
</template>
<template #coenvwState="{ column, record }">
<a-tag :color="record.coenvwState > 0 ? 'success' : ''">
{{ record.coenvwState > 0 ? '在线' : '离线' }}
</a-tag>
</template>
<template #action="{ column, record }">
<a-button type="link" size="small" @click="handleView(record)"
>查看详情</a-button
>
</template>
</BasicTable>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, onMounted, onUnmounted, watch, nextTick, h } from 'vue';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import { vmsstbprptGetKendoList1 } from '@/api/stll';
import BasicTable from '@/components/BasicTable/index.vue';
import { useModelStore } from '@/store/modules/model';
const modelStore = useModelStore();
const props = defineProps<{
baseId?: any;
titleData?: any;
}>();
const tableRef = ref();
const columns = ref([
{
title: '所属基地',
key: 'baseName',
dataIndex: 'baseName',
merge: true, //
visible: true
},
{
title: '电站名称',
key: 'stnm',
dataIndex: 'stnm',
visible: true
},
{
title: '开发方式',
key: 'dvtp',
dataIndex: 'dvtp',
visible: true,
slots: { customRender: 'dvtp' }
},
{
title: '生态流量站类型',
key: 'stindx',
dataIndex: 'stindx',
visible: true,
slots: { customRender: 'stindx' }
},
{
title: '建成时间',
key: 'jcdt',
dataIndex: 'jcdt',
visible: true,
sort: true,
customRender: ({ record }: any) => {
const date = record.jcdt;
if (!date) return '-';
if (typeof date === 'string' && /^\d{4}-\d{2}-\d{2}$/.test(date)) {
return date;
}
if (typeof date === 'string' && date.includes(' ')) {
return date.split(' ')[0];
}
return date;
}
},
{
title: '监测状态',
key: 'coenvwState',
dataIndex: 'coenvwState',
visible: true,
slots: { customRender: 'coenvwState' }
},
{
title: '操作',
key: 'action',
width: 120,
slots: { customRender: 'action' }
}
]);
const sort = {
sort: [
{
field: 'baseStepSort',
dir: 'asc'
},
{
field: 'hbrvcd',
dir: 'asc'
},
{
field: 'rstcdStepSort',
dir: 'asc'
},
{
field: 'siteStepSort',
dir: 'asc'
}
],
group: [],
select: [
'baseName',
'stnm',
'ennm',
'jcdt',
'stindx',
'coenvwState',
'sttpCode',
'stcd',
'rstcd',
'stCode',
'stName',
'dvtp'
],
groupResultFlat: false
};
const JidiSelectEventStore = useJidiSelectEventStore();
// JidiSelectEventStore.jidiData
let jidiOptions = computed(() => {
return [
...JidiSelectEventStore.jidiData.map((item: any) => ({
value: item.wbsCode,
label: item.wbsName
}))
];
});
const from = ref({
baseId: props.baseId || 'all',
stcd: ''
});
//
const searchParams = computed(() => {
let baseSort;
//
baseSort = [
{ field: 'baseStepSort', dir: 'asc' },
{ field: 'hbrvcd', dir: 'asc' },
{ field: 'rstcdStepSort', dir: 'asc' },
{ field: 'siteStepSort', dir: 'asc' }
];
return {
sort: baseSort,
group: [],
select: [
'baseName',
'stnm',
'ennm',
'jcdt',
'stindx',
'coenvwState',
'sttpCode',
'stcd',
'rstcd',
'stCode',
'stName',
'dvtp'
],
groupResultFlat: false
};
});
// props.baseId from.value.baseId
watch(
() => props.baseId,
newBaseId => {
//
if (newBaseId && newBaseId !== from.value.baseId) {
from.value.baseId = newBaseId;
from.value.stcd = ''; //
// DOM
nextTick(() => {
handleChange(); //
Search(); //
});
}
},
{ immediate: false }
);
const filterOption = (input: string, option: any) => {
return option.value.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
const stcdOptions = ref([]);
const handleChange = async () => {
try {
let params = {
filter: {
logic: 'and',
filters: [
from.value.baseId != 'all'
? {
field: 'baseId',
operator: 'contains',
dataType: 'string',
value: from.value.baseId
}
: null,
{
field: 'sttpCode',
operator: 'eq',
dataType: 'string',
value: 'ENG'
}
].filter(Boolean)
},
sort: [
{
field: 'baseId',
dir: 'asc'
},
{
field: 'rvcdStepSort',
dir: 'asc'
},
{
field: 'rstcdStepSort',
dir: 'asc'
},
{
field: 'siteStepSort',
dir: 'asc'
}
],
select: ['stcd', 'stnm']
};
let res = await vmsstbprptGetKendoList1(params);
if (res?.data?.data) {
let data = res.data.data;
stcdOptions.value = data.map((item: any) => ({
value: item.stcd,
label: item.stnm
}));
} else {
stcdOptions.value = [];
}
} catch (error) {
console.error('获取电站列表失败:', error);
stcdOptions.value = [];
}
};
const Search = () => {
let filters = [
from.value.stcd
? {
field: 'stcd',
operator: 'eq',
value: from.value.stcd
}
: null,
from.value.baseId != 'all'
? {
field: 'baseId',
operator: 'eq',
value: from.value.baseId
}
: null,
{
field: 'runState',
operator: 'eq',
value: 4
},
{
field: 'sttpCode',
operator: 'eq',
dataType: 'string',
value: props.titleData?.sttpCode || 'ENG'
},
{
field: 'DTIN',
operator: 'eq',
dataType: 'string',
value: 1
},
{
field: 'bldsttCcode',
operator: 'eq',
dataType: 'string',
value: 2
}
].filter(Boolean);
const filter = {
logic: 'and',
filters
};
tableRef.value?.getList(filter);
};
const resetSearch = () => {
from.value = {
baseId: 'all',
stcd: ''
};
Search();
};
//
const customTransform = (res: any) => {
return {
records: res?.data?.data || [],
total: res?.data?.total || 0
};
};
const handleView = (record: any) => {
modelStore.modalVisible = true;
modelStore.params.sttp = 'ENG';
modelStore.title = record.stnm;
modelStore.params.stcd = record.stcd;
modelStore.params.eqtp = 'QGC';
modelStore.filter.stllgzlx = 'qecInterval';
modelStore.filter.stllTmType = 'day';
};
onMounted(() => {
handleChange();
Search();
});
onUnmounted(() => {});
</script>
<style scoped lang="scss">
.stlldbqk_container {
width: 100%;
.stlldbqk_title {
width: 100%;
display: flex;
align-items: center;
margin-bottom: 10px;
}
.table {
width: 100%;
height: 560px;
}
}
</style>

View File

@ -0,0 +1,939 @@
<template>
<div class="stlldbqk-container">
<!-- 搜索表单 -->
<a-form layout="inline" class="search-form">
<a-form-item label="基地选择">
<a-select
v-model:value="params.qid"
placeholder="请选择基地"
style="width: 200px"
show-search
:filter-option="filterOption"
:options="jidiOptions"
/>
</a-form-item>
<a-form-item label="规则类型">
<a-select
v-model:value="params.key"
placeholder="请选择规则类型"
style="width: 180px"
:options="ruleTypeOptions"
/>
</a-form-item>
<a-form-item label="时间维度">
<a-select
v-model:value="params.timeType"
placeholder="请选择时间维度"
style="width: 120px"
:options="timeTypeOptions"
/>
</a-form-item>
<a-form-item label="日期范围">
<a-range-picker
v-model:value="dateRange"
:allow-clear="false"
format="YYYY-MM-DD"
style="width: 260px"
:presets="DateSetting.RangeButton.days1"
/>
</a-form-item>
<a-form-item>
<a-space>
<a-button type="primary" @click="handleSearch">查询</a-button>
</a-space>
</a-form-item>
</a-form>
<!-- Tabs 标签页 -->
<a-tabs
v-if="tabList.length > 0"
v-model:activeKey="ecoFlowType"
class="tab-style"
@change="fetchTableData"
>
<a-tab-pane v-for="item in tabList" :key="item.key" :tab="item.label" />
</a-tabs>
<!-- 空状态 -->
<div v-if="!loading && tabList.length === 0" class="empty-state">
<a-empty description="暂无数据" />
</div>
<div v-show="tabList.length > 0" class="body_zhengti">
<div class="echarts">
<a-spin :spinning="dataLoading">
<div v-if="pieData.length > 0" ref="chartRef" class="pie-chart"></div>
<a-empty
v-if="!dataLoading && pieData.length === 0"
description="暂无数据"
/>
</a-spin>
</div>
<div class="table1">
<BasicTable
ref="tableRef"
:columns="columns"
:scrollY="400"
:list-url="
activeTimeType == 'day' ? dayGetKendoListCust : hourGetKendoListCust
"
:search-params="searchParams"
:transform-data="customTransform"
>
<template #ennm="{ column, record }">
<a-button type="link" size="small" @click="handleView(record)">{{
record.ennm
}}</a-button>
</template>
</BasicTable>
</div>
</div>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue';
import * as echarts from 'echarts';
import type { EChartsOption } from 'echarts';
import dayjs from 'dayjs';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import { dayGetKendoListCust, hourGetKendoListCust } from '@/api/stll';
import BasicTable from '@/components/BasicTable/index.vue';
import { useModelStore } from '@/store/modules/model';
import { DateSetting } from '@/utils/enumeration';
const modelStore = useModelStore();
const props = defineProps<{
options?: any[];
typeKey?: string;
time?: string;
basicId?: string;
dateArr?: any[];
}>();
const JidiSelectEventStore = useJidiSelectEventStore();
const columns = [
{
key: 'ennm',
title: '电站名称',
dataIndex: 'ennm',
slots: { customRender: 'action' }
},
{
key: 'baseName',
title: '所属基地',
dataIndex: 'baseName'
},
{
key: 'addvcdName',
title: '行政区',
dataIndex: 'addvcdName'
},
{
key: 'hbrvcdName',
title: '所在河段',
dataIndex: 'hbrvcdName',
width: '400px'
},
{
key: 'qecRate',
title: `生态流量达标率(%)`,
dataIndex: 'qecRate',
sort: true, //
width: '160px',
customRender: ({ text }: any) => {
if (text === null || text === undefined || text === '' || text === '-')
return '-';
return Number(text).toFixed(2);
}
}
];
const tableRef = ref();
const sort1 = ref([
{
field: 'baseStepSort',
dir: 'asc'
},
{
field: 'rvcdStepSort',
dir: 'asc'
},
{
field: 'siteStepSort',
dir: 'asc'
},
{
field: 'avqRate',
dir: 'desc'
}
]);
const sort2 = ref([
{
field: 'baseStepSort',
dir: 'asc'
},
{
field: 'rvcdStepSort',
dir: 'asc'
},
{
field: 'siteStepSort',
dir: 'asc'
}
]);
//
const searchParams = computed(() => {
let baseSort;
baseSort = params.value.key ? sort1.value : sort2.value;
return {
sort: baseSort
};
});
// 使 dateArr使
const initDateRange = () => {
if (props.dateArr && props.dateArr.length === 2) {
return [dayjs(props.dateArr[0]), dayjs(props.dateArr[1])];
}
const today = dayjs();
const lastMonthSameDay = today.subtract(1, 'month');
return [lastMonthSameDay, today];
};
const dateRange = ref(initDateRange());
const params = ref({
qid: props.basicId || 'all',
key: props.typeKey || '',
timeType: props.time || 'day',
sTime: '',
eTime: ''
});
// 使 timeTypekey handleView
const activeTimeType = ref(props.time || 'day');
const activeKey = ref(props.typeKey || '');
const activeSTime = ref('');
const activeETime = ref('');
// Tab
const tabList = ref<any[]>([]);
const ecoFlowType = ref<string>('');
const loading = ref<boolean>(false);
const timeTypeOptions = [
{ label: '逐时', value: 'hour' },
{ label: '日', value: 'day' }
];
const jidiOptions = computed(() => {
return [
...JidiSelectEventStore.jidiData.map((item: any) => ({
value: item.wbsCode,
label: item.wbsName
}))
];
});
const ruleTypeOptions = computed(() => {
return (
props.options?.map((el: any) => ({
label: el.name,
value: el.key
})) || []
);
});
const filterOption = (input: string, option: any) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
// ==================== ====================
const chartRef = ref<HTMLDivElement | null>(null);
let chartInstance: echarts.ECharts | null = null;
const pieData = ref<any[]>([]); //
const dataLoading = ref<boolean>(false);
const pieCode = ref<string[]>([]); //
//
const themeecLists = [];
const jdColor = [
'#4b79ab',
'#78c300',
'#9556a4',
'#df91ab',
'#7399c6',
'#dbb629',
'#56c2e3',
'#f56a06',
'#cdba75',
'#76523b',
'#df75b6',
'#00a050',
'#f5a644',
'#4b79ab',
'#78c300',
'#9556a4',
'#df91ab',
'#7399c6',
'#dbb629',
'#56c2e3',
'#f56a06',
'#cdba75',
'#76523b',
'#df75b6',
'#00a050',
'#f5a644'
];
//
const fetchPieData = async () => {
if (!ecoFlowType.value || !params.value.sTime || !params.value.eTime) return;
dataLoading.value = true;
try {
const { sTime, eTime, qid, key, timeType } = params.value;
//
const filters = [
qid != 'all'
? {
field: 'baseId',
operator: 'eq',
dataType: 'string',
value: qid
}
: null,
{
field: 'dtin',
operator: 'eq',
dataType: 'string',
value: '1'
},
{
field: 'tm',
operator: 'gte',
dataType: 'date',
value: sTime
},
{
field: 'tm',
operator: 'lte',
dataType: 'date',
value: eTime
},
key
? {
field: key,
operator: 'eq',
dataType: 'string',
value: ecoFlowType.value
}
: null
].filter(Boolean);
// key
if (!key) {
filters.push(
{
field: 'qecInterval',
operator: 'eq',
dataType: 'string',
value: 'QEC_STLL_6_NOEQMN'
},
{
field: 'mwrInterval',
operator: 'eq',
dataType: 'string',
value: 'QEC_STLL_6_NOEQMN'
},
{
field: 'avqInterval',
operator: 'eq',
dataType: 'string',
value: 'QEC_STLL_6_NOEQMN'
}
);
}
let obj: any = {
filter: {
logic: 'and',
filters: filters
},
group: [
qid !== 'all' ? { dir: 'asc', field: 'rvcdStepSort' } : null,
qid === 'all' ? { dir: 'asc', field: 'baseStepSort' } : null,
{
dir: 'asc',
field: qid === 'all' ? 'baseId' : 'hbrvcd'
},
qid !== 'all'
? { dir: 'asc', field: 'hbrvcdName' }
: { dir: 'asc', field: 'baseName' }
].filter(Boolean),
groupResultFlat: true
};
// TODO: API
// const res = timeType == 'day'
// ? await shengTaiLiuLiang.STLLTabsDay(obj)
// : await shengTaiLiuLiang.STLLTabsHour(obj);
let res =
timeType == 'day'
? await dayGetKendoListCust(obj)
: await hourGetKendoListCust(obj);
if (res?.data?.data) {
const dataSource = res.data.data.map((el: any) => ({
id: qid === 'all' ? el.baseId : el.hbrvcd,
name: qid === 'all' ? el.baseName || el.key : el.hbrvcdName,
value: qid === 'all' ? el.count_baseId : el.count_hbrvcd,
key: qid === 'all' ? el.baseId : el.hbrvcd
}));
pieData.value = dataSource;
pieCode.value = []; //
// DOM
await nextTick();
initOrUpdateChart();
} else {
pieData.value = [];
}
} catch (error) {
console.error('获取饼图数据失败:', error);
pieData.value = [];
} finally {
dataLoading.value = false;
}
};
//
const initOrUpdateChart = () => {
if (!chartRef.value) return;
//
if (!chartInstance) {
chartInstance = echarts.init(chartRef.value);
//
chartInstance.on('legendselectchanged', handleLegendSelectChanged);
}
updateChart();
};
//
const updateChart = () => {
if (!chartInstance) return;
const total =
pieData.value.reduce((pre: number, cur: any) => pre + cur.value, 0) || 0;
//
const colors = pieData.value.map((item: any, index: number) => {
const matched = themeecLists.find((i: any) => i.name === item.name);
return matched?.color || jdColor[index % jdColor.length];
});
const option: EChartsOption = {
color: colors,
tooltip: {
trigger: 'item',
formatter: '{b}: {c} (座) ({d}%)'
},
legend: {
orient: 'vertical',
right: 20,
top: 80,
type: 'scroll',
textStyle: {
width: 100, //
overflow: 'truncate', //
ellipsis: '...' //
}
},
title: [
{
text: total.toString(),
left: '34%',
top: '44%',
textAlign: 'center',
textStyle: {
fontSize: 24,
fontWeight: 'bold',
color: '#333'
}
},
{
text: '电站总数量',
left: '34%',
top: '51%',
textAlign: 'center',
textStyle: {
fontSize: 14,
color: '#666'
}
},
{
text: '(座)',
left: '34%',
top: '55%',
textAlign: 'center',
textStyle: {
fontSize: 12,
color: '#999'
}
}
],
series: [
{
name: '电站总数量',
type: 'pie',
radius: ['31%', '40%'],
center: ['35%', '50%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: true,
formatter: function (params) {
const maxLen = 8; //
let name = params.name;
if (name.length > maxLen) {
return name.substring(0, maxLen) + '...';
}
return name;
}
},
emphasis: {
label: {
show: true,
fontSize: 14,
fontWeight: 'bold'
}
},
data: pieData.value
}
]
};
chartInstance.setOption(option, true);
};
//
const handleLegendSelectChanged = (params: any) => {
const selected = params.selected;
const trueRivers = Object.keys(selected).filter(key => selected[key]);
const allFalse = Object.values(selected).every(value => value === false);
const selectedKeys = pieData.value
.filter((item: any) => trueRivers.includes(item.name))
.map((item: any) => item.key);
pieCode.value = allFalse ? ['0'] : selectedKeys;
//
fetchTableData();
};
//
const customTransform = (res: any) => {
return {
records: res?.data?.data || [],
total: res?.data?.total || 0
};
};
// Tab
const fetchTabList = async () => {
if (!params.value.sTime || !params.value.eTime) return;
loading.value = true;
try {
const { sTime, eTime, qid, key, timeType } = params.value;
//
const filters = [
qid != 'all'
? {
field: 'baseId',
operator: 'eq',
dataType: 'string',
value: qid
}
: null,
{
field: 'dtin',
operator: 'eq',
dataType: 'string',
value: '1'
},
{
field: 'tm',
operator: 'gte',
dataType: 'date',
value: sTime
},
{
field: 'tm',
operator: 'lte',
dataType: 'date',
value: eTime
}
].filter(Boolean);
// key
if (!key) {
filters.push(
{
field: 'qecInterval',
operator: 'eq',
dataType: 'string',
value: 'QEC_STLL_6_NOEQMN'
},
{
field: 'mwrInterval',
operator: 'eq',
dataType: 'string',
value: 'QEC_STLL_6_NOEQMN'
},
{
field: 'avqInterval',
operator: 'eq',
dataType: 'string',
value: 'QEC_STLL_6_NOEQMN'
}
);
}
let obj: any = {
filter: {
logic: 'and',
filters: filters
},
group: key
? [
{
dir: 'asc',
field: key
}
]
: [
{
dir: 'asc',
field: 'baseStepSort'
},
{
dir: 'asc',
field: 'baseId'
},
{
dir: 'asc',
field: 'baseName'
}
]
};
// key groupResultFlat
if (!key) {
obj.groupResultFlat = true;
}
// TODO: API
let res =
timeType == 'day'
? await dayGetKendoListCust(obj)
: await hourGetKendoListCust(obj);
// const res = timeType == 'day'
// ? await shengTaiLiuLiang.STLLTabsDay(par, group) dayGetKendoListCust,hourGetKendoListCust
// : await shengTaiLiuLiang.STLLTabsHour(par, group);
// API
// const res = {
// data: [
// {
// type: 1,
// qecCnt: 14,
// qecTCnt: 50,
// code: 'QEC_STLL_1_DY95',
// desc: '_:>=95%',
// typeName: '',
// key: 'QEC_STLL_1_DY95',
// keyName: '',
// count: 14
// },
// {
// type: 2,
// qecCnt: 13,
// qecTCnt: 71,
// code: 'QEC_STLL_2_DY95',
// desc: '_:>=95%',
// typeName: '',
// key: 'QEC_STLL_2_DY95',
// keyName: '',
// count: 13
// }
// ]
// };
if (res?.data?.data?.length > 0) {
const resData = res.data.data;
if (key) {
// ""
tabList.value = resData
.map((el: any) => ({
...el,
value: el.key,
label: `${el.keyName || el.typeName}(${el.count || el.qecCnt}座)`
}))
.filter((el: any) => el.key !== 'QEC_STLL_6_NOEQMN');
// ecoFlowType
const found = resData.find(
(el: any) => el.items?.[0] === ecoFlowType.value
);
// 使
ecoFlowType.value = found ? ecoFlowType.value : resData[0]?.key;
} else {
// ""
tabList.value = [
{
key: 'QEC_STLL_6_NOEQMN',
value: 'QEC_STLL_6_NOEQMN',
label: `无生态流量要求(${resData?.length}座)`
}
];
ecoFlowType.value = 'QEC_STLL_6_NOEQMN';
}
//
fetchPieData();
//
fetchTableData();
} else {
tabList.value = [];
}
} catch (error) {
console.error('获取 Tab 列表失败:', error);
tabList.value = [];
} finally {
loading.value = false;
}
};
const handleView = (record: any) => {
modelStore.modalVisible = true;
modelStore.params.sttp = 'ENGJJ';
modelStore.title = record.ennm;
modelStore.params.stcd = record.stcd;
modelStore.params.eqtp = record.eqtp;
modelStore.filter.stllgzlx = activeKey.value;
modelStore.filter.stllTmType = activeTimeType.value;
modelStore.filter.rangeTm = [activeSTime.value, activeETime.value];
};
//table
const fetchTableData = async () => {
//
const { sTime, eTime, qid, key, timeType } = params.value;
const filters: any[] = [
qid != 'all'
? {
field: 'baseId',
operator: 'eq',
dataType: 'string',
value: qid
}
: null,
{
field: 'tm',
operator: 'gte',
dataType: 'date',
value: sTime
},
{
field: 'tm',
operator: 'lte',
dataType: 'date',
value: eTime
},
{
field: 'dtin',
operator: 'eq',
dataType: 'string',
value: '1'
},
key
? {
field: key,
operator: 'eq',
dataType: 'string',
value: ecoFlowType.value
}
: null
].filter(Boolean);
if (!key) {
filters.push(
{
field: 'qecInterval',
operator: 'eq',
dataType: 'string',
value: 'QEC_STLL_6_NOEQMN'
},
{
field: 'mwrInterval',
operator: 'eq',
dataType: 'string',
value: 'QEC_STLL_6_NOEQMN'
},
{
field: 'avqInterval',
operator: 'eq',
dataType: 'string',
value: 'QEC_STLL_6_NOEQMN'
}
);
}
//
if (pieCode.value.length > 0) {
if (qid === 'all') {
filters.push({
field: 'baseId',
operator: 'in',
dataType: 'string',
value: pieCode.value
});
} else {
filters.push({
field: 'hbrvcd',
operator: 'in',
dataType: 'string',
value: pieCode.value
});
}
}
const filter = {
logic: 'and',
filters
};
tableRef.value?.getList(filter);
};
// ecoFlowType
watch(ecoFlowType, () => {
fetchPieData();
});
const handleSearch = () => {
// params
if (dateRange.value && dateRange.value.length === 2) {
params.value.sTime = dateRange.value[0].format('YYYY-MM-DD 00:00:00');
params.value.eTime = dateRange.value[1].format('YYYY-MM-DD 23:59:59');
}
// 使 timeTypekey
activeTimeType.value = params.value.timeType;
activeKey.value = params.value.key;
activeSTime.value = params.value.sTime;
activeETime.value = params.value.eTime;
// Tab
fetchTabList();
};
onMounted(() => {
//
if (dateRange.value && dateRange.value.length === 2) {
params.value.sTime = dateRange.value[0].format('YYYY-MM-DD 00:00:00');
params.value.eTime = dateRange.value[1].format('YYYY-MM-DD 23:59:59');
activeTimeType.value = params.value.timeType;
activeKey.value = params.value.key;
activeSTime.value = params.value.sTime;
activeETime.value = params.value.eTime;
fetchTabList();
}
//
window.addEventListener('resize', handleResize);
});
onUnmounted(() => {
//
if (chartInstance) {
chartInstance.dispose();
chartInstance = null;
}
window.removeEventListener('resize', handleResize);
});
//
const handleResize = () => {
chartInstance?.resize();
};
</script>
<style scoped lang="scss">
.stlldbqk-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background-color: #ffffff;
box-sizing: border-box;
// padding: 16px;
}
.body_zhengti {
width: 100%;
display: flex;
justify-content: space-between;
flex: 1;
.echarts {
width: 35%;
height: 482px;
position: relative;
.pie-chart {
width: 100%;
height: 100%;
}
:deep(.ant-spin-nested-loading) {
width: 100%;
height: 100%;
}
:deep(.ant-spin-container) {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
}
.table1 {
width: 65%;
height: 482px;
}
}
.empty-state {
width: 100%;
height: 582px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
</style>

View File

@ -0,0 +1,439 @@
<!-- SidePanelItem.vue -->
<template>
<div>
<SidePanelItem title="生态流量达标情况" :click-action="{ show: true }">
<!-- 使用插槽自定义点击提示的内容 -->
<template #click-action-content>
<div v-if="titleData.cnt" style="max-width: 300px; line-height: 1.6">
<p>
1统计电站范围接入过生态流量数据的电站
<!-- <span
style="color: #5989ad; cursor: pointer; "
@click.stop="handleStationClick()"
>
({{titleData.cnt}})
</span> -->
</p>
<p>2当来水不足时生态流量不小于入库流量判定为达标</p>
<p>395%座数表示统计电站范围内时段达标率大于等于95%的电站数量</p>
</div>
</template>
<div class="body_topOne">
<a-radio-group v-model:value="mode" @change="dataChage">
<a-radio-button value="hour">逐时</a-radio-button>
<a-radio-button value="day"></a-radio-button>
</a-radio-group>
<div class="title_text">95%座数/总座数</div>
</div>
<a-spin :spinning="spinning">
<div>
<div v-for="el in datalist" @click="handleBarClick(el)">
<div :key="el.key">
<div class="boy_one">
<div style="flex: 1; white-space: nowrap; margin-right: 5px">
{{ el.name }}
</div>
<img style="flex: 1" src="@/assets/components/fgx.svg" alt="" />
</div>
<div class="body_zhu">
<div class="body_biao">
<div v-for="value in allArr">
<div :key="value" class="nei_body">
<div
v-if="
value <
(el?.key == null
? 1
: el.qecTCnt == 0
? 0
: el.qecCnt / el.qecTCnt) *
20
"
class="little_body"
:style="{ backgroundColor: el.color }"
></div>
</div>
</div>
</div>
<div class="body_text">{{ el.qecCnt }}/{{ el.qecTCnt }}</div>
</div>
</div>
</div>
</div>
</a-spin>
</SidePanelItem>
<!-- 自定义弹框 -->
<a-modal
v-model:open="modalVisible"
:title="'生态流量达标情况'"
width="1536px"
:footer="null"
>
<STLLXFFS
v-if="modalVisible"
:options="list"
:typeKey="selectedItem.key"
:time="mode"
:basicId="baseid"
:dateArr="dateArr"
/>
</a-modal>
<!-- 环保自动监测工作开展情况弹框 -->
<a-modal
v-model:open="huanbaoModalVisible"
:title="'环保自动监测工作开展情况'"
width="1536px"
:footer="null"
>
<ModalYkzhbzdjcgz v-if="huanbaoModalVisible" :baseId="baseid" :titleData = titleData />
</a-modal>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, watch } from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue';
import {
qgcetQgcStaticData,
evnmAutoMonitorGetKendoListCust
} from '@/api/stll';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import { useMapViewStore } from '@/modules/map/stores/map-view.store';
import STLLXFFS from './TwoLayer/ShengTaiLiuLiangDaBQKTwoLayer.vue';
import ModalYkzhbzdjcgz from './TwoLayer/ModalYkzhbzdjcgz.vue';
import HuanbaoZDJCGZKZ from '@/modules/huanbaozdjcgzkzQK/index.vue';
// 便
defineOptions({
name: 'shengtaidabiaoMod'
});
const JidiSelectEventStore = useJidiSelectEventStore();
const mapViewStore = useMapViewStore();
const baseid = ref('');
const dateArr = ref<any[]>([]);
const obj = {
show: true,
value:
'1、统计电站范围接入过生态流量数据的电站,2、当来水不足时生态流量不小于入库流量判定为达标,3、“≥95%座数”表示统计电站范围内时段达标率大于等于95%的电站数量'
};
const mode = ref('hour');
const dataArr: any = ref([
{
name: '生态环境部门要求',
qecCnt: '0', //
qecTCnt: '0', //
type: 1,
key: 'qecInterval'
},
// {
// name: '',
// qecCnt: '0', //
// qecTCnt: '0', //
// type: 2,
// key: 'mwrInterval'
// }
]);
const list: any = ref([
{ name: '生态环境部门要求', type: 1, color: '#77C300', key: 'qecInterval' },
// { name: '', type: 2, color: '#56C3E3', key: 'mwrInterval' },
// { name: ' 10%', type: 3, color: '#F76B01', key: 'avqInterval' },
// { name: '', type: 4, color: '#B4B4B4', key: null }
]);
const datalist: any = ref([]);
const allArr: any = ref(Array.from({ length: 20 }, (_, i) => i));
const spinning = ref(false);
const modalVisible = ref(false);
const modalTitle = ref('');
const selectedItem = ref<any>(null);
const huanbaoModalVisible = ref(false);
//
const handleStationClick = () => {
huanbaoModalVisible.value = true;
};
//
const handleBarClick = (item: any) => {
selectedItem.value = item;
// modalTitle.value = `${item.name} - `;
modalVisible.value = true;
};
// type list dataArr
const setStyle = () => {
if (dataArr.value.length == 0) {
return false;
}
dataArr.value.forEach((item: any) => {
// list type
const matched = list.value.find(
(listItem: any) => listItem.type === item.type
);
if (matched) {
// dataArr
datalist.value.push({
...matched,
...item
});
}
});
console.log(datalist.value);
};
const dataChage = () => {
getData();
};
const getdate = (offsetYears = 0) => {
const formatDate = (date: Date) => {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
};
let startDate: string;
let endDate: string;
if (dateArr.value && dateArr.value.length === 2) {
const start = new Date(dateArr.value[0]);
const end = new Date(dateArr.value[1]);
if (offsetYears !== 0) {
start.setFullYear(start.getFullYear() + offsetYears);
end.setFullYear(end.getFullYear() + offsetYears);
}
startDate = `${formatDate(start)} 00:00:00`;
endDate = `${formatDate(end)} 23:59:59`;
} else {
const now = new Date();
const oneMonthAgo = new Date(now);
oneMonthAgo.setMonth(oneMonthAgo.getMonth() - 1);
if (offsetYears !== 0) {
now.setFullYear(now.getFullYear() + offsetYears);
oneMonthAgo.setFullYear(oneMonthAgo.getFullYear() + offsetYears);
}
startDate = `${formatDate(oneMonthAgo)} 00:00:00`;
endDate = `${formatDate(now)} 23:59:59`;
}
return { startDate, endDate };
};
const getData = async () => {
const { startDate, endDate } = getdate(0);
let params = {
filter: {
logic: 'and',
filters: [
baseid.value != 'all'
? {
field: 'baseId',
operator: 'eq',
dataType: 'string',
value: baseid.value
}
: null,
{
field: 'dtin',
operator: 'eq',
dataType: 'string',
value: '1'
},
{
field: 'type',
operator: 'eq',
dataType: 'string',
value: mode.value
},
{
field: 'tm',
operator: 'gte',
dataType: 'date',
value: startDate
},
{
field: 'tm',
operator: 'lte',
dataType: 'date',
value: endDate
}
].filter(Boolean)
}
};
spinning.value = true;
try {
let res = await qgcetQgcStaticData(params);
// API
if (res.data && res.data.list) {
const apiList = res.data.list;
//
// 使type: 1 type: 2
if (apiList && apiList.length > 0) {
dataArr.value = apiList.slice(0, 2).map((item: any) => ({
// name: item.typeName || item.desc,
qecCnt: item.qecCnt,
qecTCnt: item.qecTCnt,
type: item.type
}));
//
datalist.value = [];
setStyle();
} else {
//
dataArr.value = [];
datalist.value = [];
}
}
} catch (error) {
console.error('获取生态流量达标数据失败:', error);
} finally {
spinning.value = false;
}
};
watch(
() => JidiSelectEventStore.selectedItem,
newVal => {
if (newVal && newVal.wbsCode) {
baseid.value = newVal.wbsCode;
getData();
}
},
{ deep: true, immediate: true }
);
watch(
() => mapViewStore.searchTimeRange,
(newVal) => {
dateArr.value = newVal;
getData();
},
{ deep: true }
);
//
const titleData:any = ref({ cnt: 0 })
const getcont = async () => {
let params = {
"filter": {
"logic": "and",
"filters": [
{
"field": "showIds",
"operator": "in",
"value": [
"7"
]
}
]
}
}
let res = await evnmAutoMonitorGetKendoListCust(params);
// [
// {
// "cnt": 452,
// "orderInx": 7,
// "orderInxName": "",
// "sttpFullPath": "ENG",
// "sttpCode": "ENG",
// "sttpName": ""
// }
// ]
let list = res?.data?.data[0];
if (list) {
titleData.value = list
}
//
};
//
onMounted(() => {
setStyle();
getcont()
});
</script>
<style lang="scss" scoped>
.body_topOne {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
.title_text {
font-size: 16px;
}
}
.boy_one {
display: flex;
align-items: center;
margin: 5px 0px;
}
.body_zhu {
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
transition: all 0.3s ease;
.body_biao {
width: 100%;
height: 52px;
border: 1px solid #ccdae7;
border-radius: 2px;
display: flex;
padding: 5px 1px;
overflow: hidden;
.nei_body {
width: 12px;
height: 100%;
border: 1px solid #ccdae7;
padding: 2px;
margin-left: 4px;
.little_body {
width: 100%;
height: 100%;
}
}
}
.body_text {
display: flex;
flex-direction: column;
width: 90px;
height: 100%;
justify-content: space-around;
margin-left: 6px;
align-items: center;
font-size: 18px;
font-weight: 500;
}
}
.ant-radio-group {
// border: 3px solid #2f6b98 !important;
// border-radius: 10px !important;
.ant-radio-button-wrapper-checked {
border: 1px solid #2f6b98 !important;
background-color: #2f6b98 !important;
color: #fff !important;
}
.ant-radio-button-wrapper {
border: 2px solid #2f6b98 !important;
}
.ant-radio-button-wrapper-checked :before {
background-color: #2f6b98 !important;
}
}
</style>

View File

@ -15,7 +15,7 @@
<!-- <a-form-item label=" "> --> <!-- <a-form-item label=" "> -->
<a-input <a-input
v-model:value="params.ennm" v-model:value="params.ennm"
placeholder=" " placeholder="请输入电站名称"
style="width: 200px; margin-right: 15px" style="width: 200px; margin-right: 15px"
/> />
<!-- </a-form-item> --> <!-- </a-form-item> -->
@ -104,7 +104,7 @@ import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import BasicTable from '@/components/BasicTable/index.vue'; import BasicTable from '@/components/BasicTable/index.vue';
import { useModelStore } from '@/store/modules/model'; import { useModelStore } from '@/store/modules/model';
import { import {
vmsstbprptGetKendoList, vmsstbprptGetKendoList1,
intervalGetKendoListCust, intervalGetKendoListCust,
eqqecRateCount, eqqecRateCount,
eqGetKendoListCust eqGetKendoListCust
@ -442,7 +442,8 @@ const fetchPieData = async () => {
}; };
// TODO: API - // TODO: API -
const res = await vmsstbprptGetKendoList(obj); const res = await vmsstbprptGetKendoList1(obj);
// debugger
if (res?.data?.data) { if (res?.data?.data) {
const dataSource = res.data.data.map((el: any) => ({ const dataSource = res.data.data.map((el: any) => ({
id: isAllBase ? el.baseId : el.hbrvcd, id: isAllBase ? el.baseId : el.hbrvcd,
@ -561,12 +562,7 @@ const updateChart = () => {
label: { label: {
show: true, show: true,
formatter: function (params) { formatter: function (params) {
const maxLen = 8; // return params.value + '座';
let name = params.name;
if (name.length > maxLen) {
return name.substring(0, maxLen) + '...';
}
return name;
} }
}, },
emphasis: { emphasis: {

View File

@ -0,0 +1,796 @@
<template>
<div class="stlldbqk-container">
<!-- 搜索表单 -->
<a-form layout="inline" class="search-form">
<a-form-item label="基地选择">
<a-select
v-model:value="params.qid"
placeholder="请选择基地"
style="width: 200px"
show-search
:filter-option="filterOption"
:options="jidiOptions"
/>
</a-form-item>
<!-- <a-form-item label=" "> -->
<a-input
v-model:value="params.ennm"
placeholder="请输入电站名称"
style="width: 200px; margin-right: 15px"
/>
<!-- </a-form-item> -->
<a-form-item label="日期范围">
<a-range-picker
v-model:value="dateRange"
:allow-clear="false"
format="YYYY-MM-DD"
style="width: 360px"
/>
</a-form-item>
<a-form-item>
<a-space>
<a-button type="primary" @click="handleSearch">查询</a-button>
</a-space>
</a-form-item>
</a-form>
<!-- Tabs 选择器仅在 type === 'left' 时显示 -->
<a-spin :spinning="tabsLoading" tip="加载中...">
<a-tabs
v-if="props.type === 'left' && tabOptions.length > 0"
v-model:activeKey="activeTab"
@change="handleTabChange"
class="stll-tabs"
>
<a-tab-pane
v-for="item in tabOptions"
:key="item.qecPerformance"
:tab="`${item.qecPerformanceName} (${
item.qecRate !== null &&
item.qecRate !== undefined &&
item.qecRate !== ''
? Number(item.qecRate).toFixed(2) + '%'
: '-%'
})`"
/>
</a-tabs>
<div class="body_zhengti">
<div class="echarts">
<a-spin :spinning="dataLoading">
<div
v-show="pieData.length > 0"
ref="chartRef"
class="pie-chart"
></div>
<a-empty
v-show="!dataLoading && pieData.length === 0"
description="暂无数据"
/>
</a-spin>
</div>
<div class="table">
<BasicTable
ref="tableRef"
:columns="columns"
:scrollY="'450px'"
:list-url="
props.type == 'top'
? intervalGetKendoListCust
: eqGetKendoListCust
"
:search-params="searchParams"
:transform-data="customTransform"
>
<template #ennm="{ column, record }">
<a-button type="link" size="small" @click="handleView(record)">{{
record.ennm
}}</a-button>
</template>
</BasicTable>
</div>
</div>
</a-spin>
</div>
</template>
<script lang="ts" setup>
import { ref, computed, onMounted, onUnmounted, nextTick, watch } from 'vue';
import * as echarts from 'echarts';
import type { EChartsOption } from 'echarts';
import dayjs from 'dayjs';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import BasicTable from '@/components/BasicTable/index.vue';
import { useModelStore } from '@/store/modules/model';
import {
vmsstbprptGetKendoList1,
intervalGetKendoListCust,
eqqecRateCount,
eqGetKendoListCust
} from '@/api/stll';
const modelStore = useModelStore();
const props = defineProps<{
type?: string;
basicId?: string;
qecPerformance?: any;
dateArr?: string[];
}>();
const JidiSelectEventStore = useJidiSelectEventStore();
const columns = [
props.type == 'left'
? {
key: 'baseName',
title: '所属基地',
dataIndex: 'baseName',
sort: true //
}
: null,
{
key: 'ennm',
title: '电站名称',
dataIndex: 'ennm',
slots: { customRender: 'action' },
sort: true //
},
{
key: 'addvcdName',
title: '行政区',
dataIndex: 'addvcdName',
sort: true //
},
{
key: 'hbrvcdName',
title: '所在河段',
dataIndex: 'hbrvcdName',
width: '300px'
},
{
key: 'qecRate',
title: `生态流量达标率(%)`,
dataIndex: 'qecRate',
sort: true, //
width: '160px',
customRender: ({ text }: any) => {
if (text === null || text === undefined || text === '' || text === '-')
return '-';
return Number(text).toFixed(2);
}
},
{
key: 'beforeQecRate',
title: '去年同期达标率(%)',
dataIndex: 'beforeQecRate',
width: '160px',
sort: true, //
customRender: ({ text }: any) => {
if (text === null || text === undefined || text === '' || text === '-')
return '-';
return Number(text).toFixed(2);
}
}
].filter(Boolean);
const tableRef = ref();
const defaultSort = ref([
{
field: 'baseId',
dir: 'asc'
},
{
field: 'rvcdStepSort',
dir: 'asc'
},
{
field: 'siteStepSort',
dir: 'asc'
},
{
field: 'qecRate',
dir: 'asc'
}
]);
//
const searchParams = computed(() => {
let baseSort;
//
// 使
baseSort = defaultSort.value;
return {
sort: baseSort
};
});
// dateArr
const initDateRange = () => {
// dateArr使
if (props.dateArr && props.dateArr.length === 2) {
return [dayjs(props.dateArr[0]), dayjs(props.dateArr[1])];
}
// 使""
const today = dayjs();
const lastMonthSameDay = today.subtract(1, 'month');
return [lastMonthSameDay, today];
};
const dateRange = ref(initDateRange());
// dateArr
watch(
() => props.dateArr,
newVal => {
if (newVal && newVal.length === 2) {
dateRange.value = [dayjs(newVal[0]), dayjs(newVal[1])];
}
},
{ deep: true }
);
const params = ref({
qid: props.basicId || 'all',
ennm: '',
sTime: '',
eTime: ''
});
const jidiOptions = computed(() => {
return [
...JidiSelectEventStore.jidiData.map((item: any) => ({
value: item.wbsCode,
label: item.wbsName
}))
];
});
const filterOption = (input: string, option: any) => {
return option.label.toLowerCase().indexOf(input.toLowerCase()) >= 0;
};
// ==================== Tabs ====================
const activeTab = ref<string>(props.qecPerformance || ''); // tab key
const tabOptions = ref<any[]>([]); // tabs
const tabsLoading = ref<boolean>(false); // tabs
// Tabs
const fetchTabOptions = async () => {
if (props.type !== 'left') return;
tabsLoading.value = true;
try {
const res = await eqqecRateCount({
filter: {
logic: 'and',
filters: [
params.value.qid !== 'all'
? {
field: 'baseId',
operator: 'eq',
dataType: 'string',
value: params.value.qid
}
: null,
{
field: 'type',
operator: 'eq',
dataType: 'string',
value: 'DAY'
},
{
field: 'RGCP_CODE',
operator: 'in',
dataType: 'string',
value: ['1']
},
{
field: 'tm',
operator: 'gte',
dataType: 'date',
value:
params.value.sTime ||
dayjs().subtract(1, 'month').format('YYYY-MM-DD 00:00:00')
},
{
field: 'tm',
operator: 'lte',
dataType: 'date',
value: params.value.eTime || dayjs().format('YYYY-MM-DD 23:59:59')
}
].filter(Boolean)
},
group: [{ dir: 'asc', field: 'qecPerformance' }]
});
if (res?.data?.data && res.data.data.length > 0) {
tabOptions.value = res.data.data;
//
activeTab.value = props.qecPerformance || res.data.data[0].qecPerformance;
} else {
tabOptions.value = [];
activeTab.value = '';
}
} catch (error) {
console.error('获取tabs选项失败:', error);
tabOptions.value = [];
activeTab.value = '';
} finally {
tabsLoading.value = false;
}
};
// Tab
const handleTabChange = (key: string) => {
activeTab.value = key;
//
fetchPieData();
fetchTableData();
};
// ==================== ====================
const chartRef = ref<HTMLDivElement | null>(null);
let chartInstance: echarts.ECharts | null = null;
const pieData = ref<any[]>([]); //
const dataLoading = ref<boolean>(false);
const pieCode = ref<string[]>([]); //
//
const themeecLists = [];
const jdColor = [
'#4b79ab',
'#78c300',
'#9556a4',
'#df91ab',
'#7399c6',
'#dbb629',
'#56c2e3',
'#f56a06',
'#cdba75',
'#76523b',
'#df75b6',
'#00a050',
'#f5a644',
'#4b79ab',
'#78c300',
'#9556a4',
'#df91ab',
'#7399c6',
'#dbb629',
'#56c2e3',
'#f56a06',
'#cdba75',
'#76523b',
'#df75b6',
'#00a050',
'#f5a644'
];
//
const fetchPieData = async () => {
if (!params.value.sTime || !params.value.eTime) return;
const isAllBase = params.value.qid === 'all';
dataLoading.value = true;
try {
const { sTime, eTime, qid, ennm } = params.value;
let obj = {
filter: {
logic: 'and',
filters: [
{
field: 'sttpCode',
operator: 'eq',
dataType: 'string',
value: 'ENG'
},
{
field: 'prsc',
operator: 'in',
dataType: 'string',
value: [1, 2, 3]
},
qid != 'all'
? {
field: 'baseId',
operator: 'eq',
dataType: 'string',
value: qid
}
: null,
{
field: 'bldstt',
operator: 'in',
dataType: 'string',
value: [1, 10, 11]
},
props.type != 'left'
? {
field: 'dtinEnv',
operator: 'in',
dataType: 'string',
value: [1, 2]
}
: {
field: 'RGCP_CODE',
operator: 'in',
dataType: 'string',
value: [activeTab.value]
}
].filter(Boolean)
},
group: [
isAllBase
? { dir: 'asc', field: 'baseStepSort' }
: { dir: 'asc', field: 'rvcdStepSort' },
{
dir: 'asc',
field: isAllBase ? 'baseId' : 'hbrvcd'
},
{
dir: 'asc',
field: isAllBase ? 'baseName' : 'hbrvcdName'
}
],
groupResultFlat: true
};
// TODO: API -
const res = await vmsstbprptGetKendoList1(obj);
// debugger
if (res?.data?.data) {
const dataSource = res.data.data.map((el: any) => ({
id: isAllBase ? el.baseId : el.hbrvcd,
name: isAllBase ? el.baseName : el.hbrvcdName,
value: isAllBase ? el.count_baseId : el.count_hbrvcd,
key: isAllBase ? el.baseId : el.hbrvcd
}));
pieData.value = dataSource;
pieCode.value = []; //
// DOM
await nextTick();
initOrUpdateChart();
} else {
pieData.value = [];
}
} catch (error) {
console.error('获取饼图数据失败:', error);
pieData.value = [];
} finally {
dataLoading.value = false;
}
};
//
const initOrUpdateChart = () => {
if (!chartRef.value) return;
//
if (!chartInstance) {
chartInstance = echarts.init(chartRef.value);
//
chartInstance.on('legendselectchanged', handleLegendSelectChanged);
}
updateChart();
};
//
const updateChart = () => {
if (!chartInstance) return;
const total =
pieData.value.reduce((pre: number, cur: any) => pre + cur.value, 0) || 0;
//
const colors = pieData.value.map((item: any, index: number) => {
const matched = themeecLists.find((i: any) => i.name === item.name);
return matched?.color || jdColor[index % jdColor.length];
});
const option: EChartsOption = {
color: colors,
tooltip: {
trigger: 'item',
formatter: '{b}: {c} (座) ({d}%)'
},
legend: {
orient: 'vertical',
right: 20,
top: 80,
type: 'scroll',
textStyle: {
width: 100, //
overflow: 'truncate', //
ellipsis: '...' //
}
},
title: [
{
text: total.toString(),
left: '34%',
top: '44%',
textAlign: 'center',
textStyle: {
fontSize: 24,
fontWeight: 'bold',
color: '#333'
}
},
{
text: '电站总数量',
left: '34%',
top: '51%',
textAlign: 'center',
textStyle: {
fontSize: 14,
color: '#666'
}
},
{
text: '(座)',
left: '34%',
top: '55%',
textAlign: 'center',
textStyle: {
fontSize: 12,
color: '#999'
}
}
],
series: [
{
name: '电站总数量',
type: 'pie',
radius: ['31%', '40%'],
center: ['35%', '50%'],
avoidLabelOverlap: false,
itemStyle: {
borderRadius: 10,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: true,
formatter: function (params) {
return params.value + '座';
}
},
emphasis: {
label: {
show: true,
fontSize: 14,
fontWeight: 'bold'
}
},
data: pieData.value
}
]
};
chartInstance.setOption(option, true);
};
//
const handleLegendSelectChanged = (params: any) => {
const selected = params.selected;
const trueRivers = Object.keys(selected).filter(key => selected[key]);
const allFalse = Object.values(selected).every(value => value === false);
const selectedKeys = pieData.value
.filter((item: any) => trueRivers.includes(item.name))
.map((item: any) => item.key);
pieCode.value = allFalse ? ['0'] : selectedKeys;
//
fetchTableData();
};
//
const customTransform = (res: any) => {
return {
records: res?.data?.data || [],
total: res?.data?.total || 0
};
};
const handleView = (record: any) => {
modelStore.modalVisible = true;
modelStore.params.sttp = 'ENGJJ';
modelStore.title = record.ennm;
modelStore.params.stcd = record.stcd;
modelStore.params.eqtp = record.eqtp;
};
//
const fetchTableData = async () => {
const { sTime, eTime, qid, ennm } = params.value;
// TODO: -
const filters = [
qid != 'all'
? {
field: 'baseId',
operator: 'eq',
dataType: 'string',
value: qid
}
: null,
{
field: 'dtinEnv',
operator: 'in',
dataType: 'string',
value: [1, 2]
},
{
field: 'tm',
operator: 'gte',
dataType: 'date',
value: sTime
},
{
field: 'tm',
operator: 'lte',
dataType: 'date',
value: eTime
},
ennm
? {
field: 'ennm',
operator: 'contains',
dataType: 'string',
value: ennm
}
: null,
props.type == 'left'
? {
field: 'rgcpCode',
operator: 'eq',
dataType: 'string',
value: activeTab.value
}
: null,
props.type == 'left'
? {
field: 'type',
operator: 'eq',
dataType: 'string',
value: 'DAY'
}
: null
].filter(Boolean);
const filter = {
logic: 'and',
filters
};
tableRef.value?.getList(filter);
};
const handleSearch = () => {
// params
if (dateRange.value && dateRange.value.length === 2) {
params.value.sTime = dateRange.value[0].format('YYYY-MM-DD 00:00:00');
params.value.eTime = dateRange.value[1].format('YYYY-MM-DD 23:59:59');
}
// type === 'left' tabs
if (props.type === 'left') {
fetchTabOptions().then(() => {
// tabs
fetchPieData();
fetchTableData();
});
} else {
//
fetchPieData();
fetchTableData();
}
};
onMounted(() => {
//
if (dateRange.value && dateRange.value.length === 2) {
params.value.sTime = dateRange.value[0].format('YYYY-MM-DD 00:00:00');
params.value.eTime = dateRange.value[1].format('YYYY-MM-DD 23:59:59');
// type === 'left' tabs
if (props.type === 'left') {
fetchTabOptions().then(() => {
// tabs
console.log(JidiSelectEventStore.jidiData);
fetchPieData();
fetchTableData();
});
} else {
//
console.log(JidiSelectEventStore.jidiData);
fetchPieData();
fetchTableData();
}
}
//
window.addEventListener('resize', handleResize);
});
onUnmounted(() => {
//
if (chartInstance) {
chartInstance.dispose();
chartInstance = null;
}
window.removeEventListener('resize', handleResize);
});
//
const handleResize = () => {
chartInstance?.resize();
};
</script>
<style scoped lang="scss">
.stlldbqk-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background-color: #ffffff;
box-sizing: border-box;
// padding: 16px;
}
.stll-tabs {
margin-top: 16px;
margin-bottom: 16px;
:deep(.ant-tabs-nav) {
margin-bottom: 0;
}
}
.body_zhengti {
width: 100%;
display: flex;
justify-content: space-between;
flex: 1;
margin-top: 25px;
.echarts {
width: 35%;
height: 482px;
position: relative;
.pie-chart {
width: 100%;
height: 100%;
}
:deep(.ant-spin-nested-loading) {
width: 100%;
height: 100%;
}
:deep(.ant-spin-container) {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
}
.table {
width: 65%;
height: 482px;
}
}
</style>

View File

@ -0,0 +1,675 @@
<template>
<div>
<SidePanelItem title="生态流量达标情况" :click-action="{ show: true }">
<!-- 使用插槽自定义点击提示的内容 -->
<!-- 1时间2026-05-11 2026-06-11
-->
<template #click-action-content>
<div v-if="titleData.cnt" style="max-width: 300px; line-height: 1.6">
<p>
1时间{{ getdate().startDate1 }} {{ getdate().endDate1 }}
</p>
<p>
2范围接入过生态流量数据的电站
<!-- <span
style="color: #5989ad; cursor: pointer"
@click.stop="handleStationClick()"
>
({{ titleData.cnt }}) </span
> -->
</p>
<p>3达标判定按环评批复或报告中对生态流量限值有明确要求的评判</p>
</div>
</template>
<div class="body_topOne">
<a-radio-group v-model:value="mode" @change="getEcharts()">
<a-radio-button value="top">按基地</a-radio-button>
<a-radio-button value="left">按调节性能</a-radio-button>
</a-radio-group>
</div>
<a-spin :spinning="spinning">
<div ref="chartRef" class="chart-container"></div>
</a-spin>
</SidePanelItem>
</div>
<!-- 环保自动监测工作开展情况弹框 -->
<a-modal
v-model:open="huanbaoModalVisible"
:title="'环保自动监测工作开展情况'"
width="1536px"
:footer="null"
>
<ModalYkzhbzdjcgz v-if="huanbaoModalVisible" :titleData="titleData" />
</a-modal>
<!-- 生态流量达标率详情弹框 -->
<a-modal
v-model:open="detailModalVisible"
:title="detailModalTitle"
width="1536px"
:footer="null"
>
<STLLXFFS
v-if="detailModalVisible"
:type="mode"
:basicId="detailData[0]?.baseId"
:qecPerformance="detailData[0].qecPerformance"
:date-arr="dateArr"
/>
</a-modal>
</template>
<script lang="ts" setup>
import { ref, onMounted, watch } from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue';
import * as echarts from 'echarts';
import { eqqecRateCount, evnmAutoMonitorGetKendoListCust } from '@/api/stll';
import ModalYkzhbzdjcgz from '../shengtaidabiaoMod/TwoLayer/ModalYkzhbzdjcgz.vue';
import STLLXFFS from './TwoLayer/STLLXFFS.vue'
import { useMapViewStore } from '@/modules/map/stores/map-view.store';
// 便
defineOptions({
name: 'shengtaidabiaoMod'
});
const mode = ref('top');
const spinning = ref(false);
const chartRef = ref<HTMLElement | null>(null);
let chartInstance: echarts.ECharts | null = null;
const mapViewStore = useMapViewStore();
//
let dateArr = ref<any[]>([]);
const chartData = ref<{
categories: string[];
currentData: number[];
lastYearData: number[];
baseIds: (string | number)[];
qecPerformances: (string | number)[];
}>({
categories: [],
currentData: [],
lastYearData: [],
baseIds: [],
qecPerformances: []
});
const huanbaoModalVisible = ref(false);
//
const handleStationClick = () => {
huanbaoModalVisible.value = true;
};
//
const loadData = async () => {
spinning.value = true;
try {
//
await getEcharts();
// DOM
setTimeout(() => {
initChart();
spinning.value = false;
}, 50);
} catch (error) {
console.error('数据加载失败:', error);
spinning.value = false;
}
};
//
const initChart = () => {
if (!chartRef.value) {
console.error('图表容器未渲染');
return;
}
//
const containerHeight = chartRef.value.offsetHeight;
if (!containerHeight || containerHeight === 0) {
console.warn('容器高度为 0延迟重试');
setTimeout(() => initChart(), 50);
return;
}
//
if (chartInstance) {
chartInstance.dispose();
}
chartInstance = echarts.init(chartRef.value);
// 使
const data = chartData.value;
const isHorizontal = mode.value === 'top';
const option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
},
formatter: function (params: any) {
let result = params[0].name + '<br/>';
params.forEach((param: any) => {
const percentage = param.value.toFixed(2) + '%';
result +=
param.marker +
param.seriesName +
'&nbsp;&nbsp;<b>' +
percentage +
'</b><br/>';
});
return result;
}
},
legend: {
data: ['当前', '去年同期']
},
grid: { left: 10, right: 10, bottom: 20, top: 40, containLabel: true },
dataZoom: [
{
type: 'inside',
// (mode='top'): X
// (mode='left'): XY
[isHorizontal ? 'xAxisIndex' : 'xAxisIndex']: 0,
filterMode: 'empty',
zoomOnMouseWheel: true,
moveOnMouseMove: false,
moveOnMouseWheel: true,
start: 0,
end: 100,
minValueSpan: 0,
maxValueSpan: isHorizontal ? 20 : 5
}
],
xAxis: isHorizontal
? {
type: 'value',
min: 80,
max: 100,
splitLine: {
show: true,
lineStyle: {
color: '#E8E8E8',
type: 'solid'
}
},
axisLabel: {
color: '#666',
formatter: '{value}'
}
}
: {
type: 'category',
data: data.categories,
axisLabel: {
color: '#666',
fontSize: 12,
interval: 0,
rotate: 0,
margin: 10
},
axisLine: {
show: true,
lineStyle: {
color: '#666'
}
},
axisTick: {
show: true,
lineStyle: {
color: '#666'
}
},
splitLine: {
show: false
}
},
yAxis: isHorizontal
? {
type: 'category',
data: data.categories,
inverse: true,
axisLabel: {
color: '#666',
fontSize: 12,
interval: 0,
rotate: 45,
margin: 10
},
axisLine: {
show: true,
lineStyle: {
color: '#666'
}
},
axisTick: {
show: true,
lineStyle: {
color: '#666'
}
},
splitLine: {
show: false
}
}
: {
type: 'value',
min: 0,
max: 100,
splitLine: {
show: true,
lineStyle: {
color: '#E8E8E8',
type: 'solid'
}
},
axisLabel: {
color: '#666',
formatter: '{value}'
}
},
series: [
{
name: '当前',
type: 'bar',
data: data.currentData,
itemStyle: {
color: '#5470C6'
},
barWidth: isHorizontal ? 8 : 8
// barGap: '30%'
},
{
name: '去年同期',
type: 'bar',
data: data.lastYearData,
itemStyle: {
color: '#91CC75'
},
barWidth: isHorizontal ? 8 : 8
// barGap: '30%'
}
]
};
chartInstance.setOption(option);
//
chartInstance.off('click');
chartInstance.on('click', (params: any) => {
handleChartClick(params);
});
//
setTimeout(() => {
chartInstance?.resize();
}, 0);
};
//
const handleChartClick = (params: any) => {
const categoryName = params.name;
const currentIndex = params.dataIndex;
//
//
detailModalTitle.value =
mode.value === 'top'
? `生态流量达标率(按基地统计) `
: `生态流量达标率(按调节性能统计)`;
//
const baseId = mode.value === 'top' ? chartData.value.baseIds[currentIndex] : undefined;
const qecPerformance = mode.value === 'left' ? chartData.value.qecPerformances[currentIndex] : undefined;
//
const currentItem = {
baseId: baseId,
baseName: mode.value === 'top' ? categoryName :'',
qecPerformance: qecPerformance,
qecPerformanceName: mode.value === 'left' ? categoryName : '',
qecRate: chartData.value.currentData[currentIndex],
beforeQecRate: chartData.value.lastYearData[currentIndex]
};
detailData.value = [currentItem];
detailModalVisible.value = true;
};
const getdate = (offsetYears = 0) => {
const formatDate = (date: Date) => {
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
};
let startDate: string;
let endDate: string;
let startDate1: string;
let endDate1: string;
// dateArr.value 使
if (dateArr.value && dateArr.value.length === 2) {
const start = new Date(dateArr.value[0]);
const end = new Date(dateArr.value[1]);
// offsetYears 0
if (offsetYears !== 0) {
start.setFullYear(start.getFullYear() + offsetYears);
end.setFullYear(end.getFullYear() + offsetYears);
}
startDate = `${formatDate(start)} 00:00:00`;
endDate = `${formatDate(end)} 23:59:59`;
//
startDate1 = formatDate(start);
endDate1 = formatDate(end);
// debugger
} else {
// 使""
const now = new Date();
const oneMonthAgo = new Date(now);
oneMonthAgo.setMonth(oneMonthAgo.getMonth() - 1);
// offsetYears 0
if (offsetYears !== 0) {
now.setFullYear(now.getFullYear() + offsetYears);
oneMonthAgo.setFullYear(oneMonthAgo.getFullYear() + offsetYears);
}
startDate = `${formatDate(oneMonthAgo)} 00:00:00`;
endDate = `${formatDate(now)} 23:59:59`;
startDate1 = formatDate(oneMonthAgo);
endDate1 = formatDate(now);
}
return { startDate, endDate, startDate1, endDate1 };
};
const getEcharts = async () => {
//
const currentDateRange = getdate(0);
//
const lastYearDateRange = getdate(-1);
// filter
const baseFilter = {
logic: 'and',
filters: [
mode.value == 'top'
? {
field: 'dtinEnv',
operator: 'in',
dataType: 'string',
value: [1, 2]
}
: {
field: 'type',
operator: 'eq',
dataType: 'string',
value: 'DAY'
}
]
};
// params
const currentParams = {
filter: {
...baseFilter,
filters: [
...baseFilter.filters,
{
field: 'tm',
operator: 'gte',
dataType: 'date',
value: currentDateRange.startDate
},
{
field: 'tm',
operator: 'lte',
dataType: 'date',
value: currentDateRange.endDate
}
]
},
group:
mode.value == 'top'
? [
{ dir: 'asc', field: 'basestepsort' },
{ dir: 'asc', field: 'baseId' },
{ dir: 'asc', field: 'baseName' }
]
: [{ dir: 'asc', field: 'qecPerformance' }]
};
// params
const lastYearParams = {
filter: {
...baseFilter,
filters: [
...baseFilter.filters,
{
field: 'tm',
operator: 'gte',
dataType: 'date',
value: lastYearDateRange.startDate
},
{
field: 'tm',
operator: 'lte',
dataType: 'date',
value: lastYearDateRange.endDate
}
]
},
group: currentParams.group
};
try {
// API
const [currentRes, lastYearRes]: [any, any] = await Promise.all([
eqqecRateCount(currentParams),
eqqecRateCount(lastYearParams)
]);
//
const currentApiData = (currentRes && currentRes.data && currentRes.data.data) ? currentRes.data.data : [];
//
const lastYearApiData = (lastYearRes && lastYearRes.data && lastYearRes.data) ? lastYearRes.data.data : [];
// mode
if (mode.value === 'top') {
// baseId
const uniqueMap = new Map();
currentApiData.forEach((item: any) => {
if (!uniqueMap.has(item.baseId)) {
uniqueMap.set(item.baseId, item);
}
});
const uniqueData = Array.from(uniqueMap.values());
// baseId
const lastYearMap = new Map();
lastYearApiData.forEach((item: any) => {
if (!lastYearMap.has(item.baseId)) {
lastYearMap.set(item.baseId, item.qecRate);
}
});
chartData.value = {
categories: uniqueData.map((item: any) => item.baseName || ''),
currentData: uniqueData.map((item: any) =>
item.qecRate != null ? Number(item.qecRate) : 0
),
lastYearData: uniqueData.map((item: any) => {
const lastYearRate = lastYearMap.get(item.baseId);
return lastYearRate != null ? Number(lastYearRate) : 0;
}),
baseIds: uniqueData.map((item: any) => item.baseId),
qecPerformances: []
};
} else {
//
// qecPerformance
const lastYearMap = new Map();
lastYearApiData.forEach((item: any) => {
if (!lastYearMap.has(item.qecPerformance)) {
lastYearMap.set(item.qecPerformance, item.qecRate);
}
});
chartData.value = {
categories: currentApiData.map((item: any) => item.qecPerformanceName || ''),
currentData: currentApiData.map((item: any) =>
item.qecRate != null ? Number(item.qecRate) : 0
),
lastYearData: currentApiData.map((item: any) => {
const lastYearRate = lastYearMap.get(item.qecPerformance);
return lastYearRate != null ? Number(lastYearRate) : 0;
}),
baseIds: [],
qecPerformances: currentApiData.map((item: any) => item.qecPerformance || '')
};
}
} catch (error) {
console.error('API 调用失败:', error);
// 使
chartData.value = {
categories: [],
currentData: [],
lastYearData: [],
baseIds: [],
qecPerformances: []
};
}
};
//
const titleData: any = ref({ cnt: 0 });
const getcont = async () => {
let params = {
filter: {
logic: 'and',
filters: [
{
field: 'showIds',
operator: 'in',
value: ['7']
}
]
}
};
let res = await evnmAutoMonitorGetKendoListCust(params);
// [
// {
// "cnt": 452,
// "orderInx": 7,
// "orderInxName": "",
// "sttpFullPath": "ENG",
// "sttpCode": "ENG",
// "sttpName": ""
// }
// ]
let list = res?.data?.data[0];
if (list) {
titleData.value = list;
}
//
};
//
onMounted(() => {
loadData();
getcont();
//
window.addEventListener('resize', () => {
chartInstance?.resize();
});
});
watch(
() => mapViewStore.searchTimeRange,
(newVal, oldVal) => {
console.log('时间范围变化:', oldVal, '->', newVal);
dateArr.value = newVal
// debugger
loadData();
//
},
{ deep: true }
);
//
const detailModalVisible = ref(false);
const detailModalTitle = ref('');
const detailData = ref<any[]>([]);
const detailColumns = ref([
{
title: mode.value === 'top' ? '基地名称' : '调节性能',
dataIndex: mode.value === 'top' ? 'baseName' : 'qecPerformanceName',
key: mode.value === 'top' ? 'baseName' : 'qecPerformanceName',
width: 150,
fixed: 'left'
},
{
title: '当前达标率',
dataIndex: 'qecRate',
key: 'qecRate',
width: 120,
align: 'right'
},
{
title: '去年同期达标率',
dataIndex: 'beforeQecRate',
key: 'beforeQecRate',
width: 150,
align: 'right'
}
]);
// mode
watch(mode, () => {
loadData();
});
</script>
<style lang="scss" scoped>
.body_topOne {
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 16px;
.title_text {
font-size: 16px;
}
}
.ant-radio-group {
.ant-radio-button-wrapper-checked {
border: 1px solid #2f6b98 !important;
background-color: #2f6b98 !important;
color: #fff !important;
}
.ant-radio-button-wrapper {
border: 2px solid #2f6b98 !important;
}
.ant-radio-button-wrapper-checked :before {
background-color: #2f6b98 !important;
}
}
.chart-container {
width: 100%;
height: 449px;
// padding: 10px;
}
.detail-content {
padding: 16px 0;
}
</style>

View File

@ -1,196 +1,495 @@
<!-- SidePanelItem.vue --> <!-- 水生生态调查 -->
<template> <template>
<SidePanelItem title="水生生态调查" :select="select" :datetimePicker="datetimePicker"> <SidePanelItem
<div ref="chartRef" class="echarts-container"></div> title="水生生态调查"
</SidePanelItem> :moreSelect="moreSelect"
:select="select"
@update-values="handlePanelChange"
>
<a-spin :spinning="dataLoading" tip="加载中..." class="spin-wrapper">
<div
v-show="chartData.length > 0 && select.options.length > 0"
ref="chartRef"
class="chart-container"
></div>
<a-empty
v-show="
!dataLoading &&
(chartData.length === 0 || select.options.length === 0)
"
:description="select.options.length === 0 ? '暂无数据' : '暂无数据'"
class="empty-placeholder"
/>
</a-spin>
</SidePanelItem>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted, onUnmounted, nextTick } from 'vue'; import { ref, watch, onMounted, onUnmounted, nextTick } from 'vue';
import * as echarts from 'echarts'; import * as echarts from 'echarts';
import type { EChartsOption } from 'echarts'; import type { EChartsOption } from 'echarts';
import SidePanelItem from '@/components/SidePanelItem/index.vue'; import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import { wbsbGetKendoList, getDftYear, getFishListStat } from '@/api/stdc';
import moment from 'moment';
//
defineOptions({ defineOptions({
name: 'shuiShengShengTaiDiaoCha' name: 'shuiShengShengTaiDiaoCha'
}); });
// ==================== ==================== // ==================== Store ====================
const JidiSelectEventStore = useJidiSelectEventStore();
// ==================== ====================
const baseid = ref('');
const isInitializing = ref(false);
const dataLoading = ref(false);
// ==================== ====================
const moreSelect = ref({
show: true,
value: undefined as string | undefined,
options: [] as any[]
});
const select = ref({
show: true,
value: undefined as string | undefined,
options: [] as any[],
picker: undefined,
format: undefined,
width: '120px'
});
const yearOptions = ref<Record<string, any[]>>({});
// ==================== ====================
const chartRef = ref<HTMLDivElement>(); const chartRef = ref<HTMLDivElement>();
let chartInstance: any = null; let chartInstance: any = null;
let resizeObserver: ResizeObserver | null = null;
const chartData = ref<any[]>([]);
// // ==================== ====================
const select = ref({
show: true,
value: undefined,
options: [],
picker: undefined,
format: undefined
});
//
const datetimePicker = ref({
show: true,
value: '2020',
format: 'YYYY',
picker: 'year' as const,
options: []
});
// ==================== ====================
const mockData = [
{ name: '鱼类', value: 320 },
{ name: '底栖动物', value: 280 },
{ name: '浮游植物', value: 250 },
{ name: '浮游动物', value: 220 },
{ name: '水生植物', value: 190 },
{ name: '两栖类', value: 150 },
{ name: '爬行类', value: 120 },
{ name: '鸟类', value: 100 },
{ name: '哺乳类', value: 80 },
{ name: '其他', value: 60 }
];
//
const totalValue = mockData.reduce((sum, item) => sum + item.value, 0);
// ==================== ====================
const initChart = () => { const initChart = () => {
if (!chartRef.value) return; if (!chartRef.value) return;
// if (chartInstance) {
const rect = chartRef.value.getBoundingClientRect(); chartInstance.dispose();
if (rect.width === 0 || rect.height === 0) { }
console.warn('图表容器尺寸为0稍后重试...');
setTimeout(() => initChart(), 50); chartInstance = echarts.init(chartRef.value);
return; updateChart();
};
const updateChart = () => {
// DOM
if (!chartInstance && chartRef.value) { chartInstance = echarts.init(chartRef.value);
}
if (!chartInstance) return;
const totalValue = chartData.value.reduce(
(sum: number, item: any) => sum + (item.fcnt || 0),
0
);
const option: EChartsOption = {
color: [
'#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de',
'#3ba272', '#fc8452', '#9a60b4', '#ea7ccc', '#8dd3a7'
],
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(0, 0, 0, 0.5)',
borderColor: 'transparent',
textStyle: { color: '#ffffff' },
formatter: '{b}: {c} ({d}%)'
},
legend: {
type: 'scroll',
orient: 'horizontal',
bottom: '5%',
data: chartData.value.map((item: any) => item.name),
icon: 'rect',
itemWidth: 14,
itemHeight: 14,
textStyle: { fontSize: 12, height: 8 },
pageTextStyle: { color: '#333' },
pageIconColor: '#2F6B98',
pageIconInactiveColor: '#aaa'
},
title: [
{
text: `(类)`,
top: '42%',
textAlign: 'center',
left: '50%',
textStyle: { color: '#333', fontSize: 13, fontWeight: 500 }
},
{
text: totalValue.toString(),
left: 'center',
top: '32%',
textStyle: { color: '#2F6B98', fontSize: 24 }
}
],
series: [
{
name: '生态类别',
type: 'pie',
radius: ['35%', '65%'],
center: ['50%', '40%'],
avoidLabelOverlap: false,
label: {
show: true,
position: 'outside',
formatter: '{b}: {c}'
},
labelLine: { show: true, length: 8, length2: 10 },
emphasis: {
label: { show: true, fontSize: 14, fontWeight: 'bold' }
},
data: chartData.value.map((item: any) => ({
name: item.name,
value: item.fcnt || 0
}))
}
]
};
chartInstance.setOption(option);
nextTick(() => {
chartInstance.resize();
});
};
const handleResize = () => {
if (chartInstance) {
chartInstance.resize();
}
};
// ==================== ====================
const getYearData = async () => {
try {
const filter: any = {};
if (baseid.value && baseid.value !== 'all') {
filter.baseId = baseid.value;
} }
// const params = {
chartInstance = echarts.init(chartRef.value); filter,
group: [{ dir: 'des', field: 'yr' }]
//
const option: EChartsOption = {
color: [
'#5470c6', '#91cc75', '#fac858', '#ee6666', '#73c0de',
'#3ba272', '#fc8452', '#9a60b4', '#ea7ccc', '#8dd3a7'
],
tooltip: {
trigger: 'item',
backgroundColor: 'rgba(0, 0, 0, 0.5)',
borderColor: 'transparent',
textStyle: {
color: '#ffffff'
},
formatter: '{b}: {c} ({d}%)'
},
legend: {
type: 'scroll',
orient: 'horizontal',
bottom: '5%',
data: mockData.map(item => item.name),
icon: 'rect',
itemWidth: 14,
itemHeight: 14,
textStyle: {
fontSize: 12,
height: 8
},
pageTextStyle: {
color: '#333'
},
pageIconColor: '#2F6B98',
pageIconInactiveColor: '#aaa'
},
title: [
{
text: `(类)`,
top: '42%',
textAlign: 'center',
left: '50%',
textStyle: {
color: '#333',
fontSize: 13,
fontWeight: 500
}
},
{
text: totalValue.toString(),
left: 'center',
top: '32%',
textStyle: {
color: '#2F6B98',
fontSize: 24
}
}
],
series: [
{
name: '生态类别',
type: 'pie',
radius: ['35%', '65%'],
center: ['50%', '40%'],
avoidLabelOverlap: false,
label: {
show: true,
position: 'outside',
formatter: '{b}: {c}'
},
labelLine: {
show: true,
length: 8,
length2: 10
},
emphasis: {
label: {
show: true,
fontSize: 14,
fontWeight: 'bold'
}
},
data: mockData
}
]
}; };
// const res = await getDftYear(params);
chartInstance.setOption(option); // debugger
const data = res?.data?.data?.[0] || {};
if (Object.keys(data).length > 0) {
const objYear: Record<string, any[]> = {};
const allYears: any[] = [];
Object.keys(data).forEach(key => {
objYear[key] = data[key].map((item: any) => ({
label: String(item),
value: String(item)
}));
allYears.push(...data[key]);
});
yearOptions.value = objYear;
const uniqueYears = [...new Set(allYears)].sort(
(a: any, b: any) => Number(b) - Number(a)
);
const latestYear = uniqueYears[0];
const firstWbsCode = Object.keys(data)[0];
select.value.options = objYear[firstWbsCode] || [];
select.value.value = latestYear
? String(latestYear)
: moment().format('YYYY');
} else {
yearOptions.value = {};
select.value.options = [];
select.value.value = moment().format('YYYY');
}
} catch (error) {
console.error('获取年份数据失败:', error);
select.value.options = [];
select.value.value = moment().format('YYYY');
}
}; };
// ==================== resize ==================== const updateYearOptionsByBase = async (wbsCode: string) => {
const handleResize = () => { const options = yearOptions.value[wbsCode];
if (chartInstance) { if (options) {
chartInstance.resize(); select.value.options = options;
} await nextTick();
select.value.value = options[0]?.value || '';
} else {
select.value.options = [];
await nextTick();
select.value.value = '';
}
}; };
const getMoreSelectData = async () => {
if (!baseid.value) return;
isInitializing.value = true;
try {
const params = {
filter: {
logic: 'and',
filters: [
{
field: 'wbsType',
operator: 'eq',
value: 'PSB_RVCD'
},
baseid.value !== 'all'
? {
field: 'objid',
operator: 'eq',
value: baseid.value
}
: null
].filter(Boolean)
},
group: [
{ dir: 'asc', field: 'orderIndex' },
{ dir: 'asc', field: 'wbsCode' },
{ dir: 'asc', field: 'wbsName' },
{ dir: 'asc', field: 'objid' }
],
groupResultFlat: true
};
const res = await wbsbGetKendoList(params);
const data = res?.data?.data || [];
// debugger
if (data.length > 0) {
const treeData = buildTreeData(data);
const filteredData = filterSelectOptions(treeData);
moreSelect.value.options = filteredData;
moreSelect.value.value = treeData?.[0]?.children?.[0]?.value;
await getYearData();
if (moreSelect.value.value) {
await updateYearOptionsByBase(moreSelect.value.value);
}
await getChartData();
} else {
moreSelect.value.options = [];
moreSelect.value.value = undefined;
await getYearData();
}
} catch (error) {
console.error('获取树形选择器数据失败:', error);
moreSelect.value.options = [];
moreSelect.value.value = undefined;
} finally {
isInitializing.value = false;
}
};
/**
* 获取图表数据
* 根据当前选中的流域(hbrvcd)调用 getFishListStat API
*/
const getChartData = async () => {
if (!moreSelect.value.value) return;
dataLoading.value = true;
try {
const params = {
filter: {
logic: 'and',
filters: [
{
field: 'hbrvcd',
operator: 'eq',
dataType: 'string',
value: moreSelect.value.value
}
]
}
};
const res = await getFishListStat(params);
// debugger
chartData.value = res?.data?.data || [];
nextTick(() => {
updateChart();
});
} catch (error) {
console.error('获取图表数据失败:', error);
chartData.value = [];
nextTick(() => {
updateChart();
});
} finally {
dataLoading.value = false;
}
};
// ==================== ====================
const buildTreeData = (data: any[]) => {
if (!data || data.length === 0) return [];
const jiDiListMap: Record<string, string> = {};
JidiSelectEventStore.jidiData.forEach((item: any) => {
jiDiListMap[item.wbsCode] = item.wbsName;
});
const dataMapNameMap: Record<string, any[]> = {};
data.forEach(item => {
const objId = item.objid || item.objId;
if (!dataMapNameMap[objId]) {
dataMapNameMap[objId] = [];
}
const exists = dataMapNameMap[objId].some(
existing => existing.wbsCode === item.wbsCode
);
if (!exists) {
dataMapNameMap[objId].push(item);
}
});
const treeData = Object.keys(dataMapNameMap).map(objId => ({
title: jiDiListMap[objId] || '---',
value: objId,
selectable: false,
children: dataMapNameMap[objId].map((item: any) => ({
title: item.wbsName,
value: item.wbsCode
}))
}));
treeData.sort((a, b) => {
const numA = Number(a.value);
const numB = Number(b.value);
const aIsNum = !isNaN(numA);
const bIsNum = !isNaN(numB);
if (aIsNum && bIsNum) return numA - numB;
if (aIsNum) return -1;
if (bIsNum) return 1;
return a.value.localeCompare(b.value);
});
return treeData;
};
const filterSelectOptions = (options: any[]) => {
if (options?.length === 1 && options?.[0]?.children?.length === 1) {
return options[0].children;
}
return options;
};
// ==================== ====================
const handlePanelChange = async (data: any) => {
if (isInitializing.value) return;
if (
data.moreSelect !== undefined &&
data.moreSelect !== moreSelect.value.value
) {
moreSelect.value.value = data.moreSelect;
await updateYearOptionsByBase(data.moreSelect);
return;
}
if (data.select !== undefined && data.select !== select.value.value) {
select.value.value = data.select;
await getChartData();
}
};
// ==================== Watch ====================
watch(
() => JidiSelectEventStore.selectedItem,
async newVal => {
if (newVal && newVal.wbsCode) {
baseid.value = newVal.wbsCode;
await getMoreSelectData();
}
},
{ deep: true, immediate: true }
);
// ==================== ==================== // ==================== ====================
//
onMounted(() => { onMounted(() => {
nextTick(() => { nextTick(() => {
setTimeout(() => { setTimeout(() => {
initChart(); initChart();
window.addEventListener('resize', handleResize); window.addEventListener('resize', handleResize);
}, 50);
}); if (chartRef.value) {
resizeObserver = new ResizeObserver(() => {
if (chartInstance) {
chartInstance.resize();
}
});
resizeObserver.observe(chartRef.value);
}
}, 50);
});
}); });
//
onUnmounted(() => { onUnmounted(() => {
window.removeEventListener('resize', handleResize); window.removeEventListener('resize', handleResize);
if (chartInstance) {
chartInstance.dispose(); if (resizeObserver) {
chartInstance = null; resizeObserver.disconnect();
} resizeObserver = null;
}
if (chartInstance) {
chartInstance.dispose();
chartInstance = null;
}
}); });
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.echarts-container { .spin-wrapper {
width: 100%; width: 100%;
height: 270px; display: block;
min-height: 270px;
} }
</style>
.chart-container {
width: 100%;
height: 270px;
min-height: 270px;
}
.empty-placeholder {
width: 100%;
min-height: 270px;
display: flex;
background: #fff;
flex-direction: column;
justify-content: center;
align-items: center;
}
:deep(.ant-empty-description) {
text-indent: 0em !important;
}
:deep(.ant-spin-container) {
width: 100%;
}
</style>

View File

@ -2,209 +2,207 @@
<template> <template>
<div class="data-table-container"> <div class="data-table-container">
<a-table :columns="columns" :data-source="tableData" :pagination="false" size="middle" :customRow="customRow" <a-table :columns="columns" :data-source="tableData" :pagination="false" size="middle" :customRow="customRow"
bordered class="custom-table"> :loading="dataLoading" bordered class="custom-table">
</a-table> </a-table>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted } from 'vue'; import { ref, watch } from 'vue';
import type { ColumnsType } from 'ant-design-vue/es/table/interface'; import { getVmsstbprptKendoList } from '@/api/home';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
//
defineOptions({ defineOptions({
name: 'DataTable' name: 'DataTable'
}); });
// const emit = defineEmits<{
const columns: ColumnsType = [ (e: 'row-click', record: any): void;
}>();
const JidiSelectEventStore = useJidiSelectEventStore();
const baseid = ref('');
const dataLoading = ref(false);
const tableData = ref<any[]>([]);
const columns = ref([
{ {
title: '基地名称', title: '基地名称',
dataIndex: 'name', dataIndex: 'name',
key: 'name', key: 'name',
fixed: 'left', fixed: 'left' as const,
width: 114.19, width: 114.19,
align: 'left' align: 'left' as const
}, },
{ {
title: '装机容量(万kW)', title: '装机容量(万kW)',
key: 'capacity', key: 'capacity',
align: 'center', align: 'center' as const,
children: [ children: [
{ {
title: '总计', title: '总计',
dataIndex: 'total', dataIndex: 'total',
key: 'total', key: 'total',
width: 76.64, width: 76.64,
align: 'center' align: 'center' as const
}, },
{ {
title: '已建', title: '已建',
dataIndex: 'built', dataIndex: 'buildinstall',
key: 'built', key: 'buildinstall',
width: 76.64, width: 76.64,
align: 'center' align: 'center' as const
}, },
{ {
title: '在建', title: '在建',
dataIndex: 'building', dataIndex: 'ubuildinstall',
key: 'building', key: 'ubuildinstall',
width: 68.25, width: 68.25,
align: 'center' align: 'center' as const
}, },
{ {
title: '未建', title: '未建',
dataIndex: 'unbuilt', dataIndex: 'nbuildinstall',
key: 'unbuilt', key: 'nbuildinstall',
// width: 76, align: 'center' as const
align: 'center' }
},
] ]
} }
];
//
const tableData = ref([
{
key: '1',
name: '金沙江干流',
total: '7952.00',
built: '6370.00',
building: '902.00',
unbuilt: '680.00'
},
{
key: '2',
name: '雅砻江干流',
total: '2773.65',
built: '1920.00',
building: '492.00',
unbuilt: '361.65'
},
{
key: '3',
name: '大渡河干流',
total: '2689.65',
built: '1925.65',
building: '534.00',
unbuilt: '230.00'
},
{
key: '4',
name: '乌江干流',
total: '1181.36',
built: '1133.36',
building: '48.00',
unbuilt: '0.00'
},
{
key: '5',
name: '长江上游干流',
total: '3212.65',
built: '2523.65',
building: '0.00',
unbuilt: '689.00'
},
{
key: '6',
name: '湘西',
total: '1054.32',
built: '959.30',
building: '38.52',
unbuilt: '56.65'
},
{
key: '7',
name: '黄河上游干流',
total: '2794.59',
built: '1749.89',
building: '0.00',
unbuilt: '1044.65'
},
{
key: '8',
name: '黄河中游干流',
total: '835.65',
built: '401.65',
building: '0.00',
unbuilt: '434.00'
},
{
key: '9',
name: '南盘江 - 红水河',
total: '1271.00',
built: '1271.00',
building: '0.00',
unbuilt: '0.00'
},
{
key: '10',
name: '东北',
total: '1331.95',
built: '749.05',
building: '0.00',
unbuilt: '582.90'
},
{
key: '11',
name: '澜沧江干流',
total: '2535.00',
built: '2275.00',
building: '260.00',
unbuilt: '0.00'
},
{
key: '12',
name: '怒江干流',
total: '3138.00',
built: '0.00',
building: '102.00',
unbuilt: '3036.00'
},
{
key: '13',
name: '闽浙赣',
total: '962.08',
built: '920.68',
building: '0.00',
unbuilt: '41.40'
},
{
key: '14',
name: '其他',
total: '7460.57',
built: '7273.27',
building: '121.90',
unbuilt: '65.40'
},
{
key: '15',
name: '总计',
total: '7460.57',
built: '7273.27',
building: '121.90',
unbuilt: '65.40'
}
]); ]);
// const getData = async () => {
const customRow = (_record: any, index: number) => { if (!baseid.value) return;
const filters: any[] = [
{ field: 'sttpCode', operator: 'eq', dataType: 'string', value: 'ENG' },
{ field: 'bldsttCcode', operator: 'isnotnull' },
{ field: 'prsc', operator: 'in', dataType: 'string', value: ['1', '2', '3'] }
];
if (baseid.value !== 'all') {
filters.unshift({ field: 'baseId', operator: 'eq', dataType: 'string', value: baseid.value });
}
const aggregates = [{ field: 'ttpwr', aggregate: 'sum' }];
const group: any[] = [];
if (baseid.value !== 'all') {
group.push({ dir: 'asc', field: 'rvcdStepSort' });
} else {
group.push({ dir: 'asc', field: 'baseStepSort' });
}
group.push(
{ dir: 'asc', field: baseid.value === 'all' ? 'baseId' : 'hbrvcd' },
{ dir: 'asc', field: baseid.value === 'all' ? 'baseName' : 'hbrvcdName', aggregates },
{ dir: 'desc', field: 'bldsttCcode', aggregates }
);
const params = {
filter: { logic: 'and', filters },
group
};
try {
dataLoading.value = true;
const res = await getVmsstbprptKendoList(params);
const resData = res?.data?.data;
if (resData && Array.isArray(resData)) {
let newList: any = {};
let keyList: any[] = [];
const list = resData.flatMap((item: any) => {
const key = baseid.value === 'all' ? item.items[0].key : item.key;
keyList.push(key);
const { BASENAME, HBRVCDNAME } = baseid.value === 'all'
? item?.items?.[0]?.items?.[0]?.items[0]?.items?.[0]
: item?.items?.[0]?.items?.[0]?.items[0]?.items[0];
return item.items.map((outItem: any) => {
const itmeData = baseid.value === 'all' ? outItem.items?.[0]?.items : outItem.items[0]?.items;
const nbuildinstall = itmeData.find((x: any) => x.items[0]?.BLDSTTCCODE == '0')?.items[0]?.SUM_TTPWR * 0.1 || 0;
const ubuildinstall = itmeData.find((x: any) => x.items[0]?.BLDSTTCCODE == '1')?.items[0]?.SUM_TTPWR * 0.1 || 0;
const buildinstall = itmeData.find((x: any) => x.items[0]?.BLDSTTCCODE == '2')?.items[0]?.SUM_TTPWR * 0.1 || 0;
const total = nbuildinstall + ubuildinstall + buildinstall;
return {
key,
nbuildinstall: nbuildinstall?.toFixed(2),
ubuildinstall: ubuildinstall?.toFixed(2),
buildinstall: buildinstall?.toFixed(2),
total: total?.toFixed(2),
name: BASENAME || HBRVCDNAME,
bldsttCcode: outItem.key
};
});
});
const result = { total: 0, buildinstall: 0, ubuildinstall: 0, nbuildinstall: 0 };
list.forEach((e: any) => {
result.total += Number(e.total) * 100;
result.buildinstall += Number(e.buildinstall) * 100;
result.ubuildinstall += Number(e.ubuildinstall) * 100;
result.nbuildinstall += Number(e.nbuildinstall) * 100;
if (newList[e.key]) {
const { total, nbuildinstall, ubuildinstall, buildinstall } = newList[e.key];
newList[e.key] = {
...e,
total: Number(total) + Number(e.total),
nbuildinstall: Number(nbuildinstall) + Number(e.nbuildinstall),
ubuildinstall: Number(ubuildinstall) + Number(e.ubuildinstall),
buildinstall: Number(buildinstall) + Number(e.buildinstall)
};
} else {
newList[e.key] = e;
}
});
const { total, buildinstall, ubuildinstall, nbuildinstall } = result;
const arr: any[] = keyList.map((key) => newList[key]);
tableData.value = [
...arr,
{
name: '总计',
total: (total / 100)?.toFixed(2),
buildinstall: (buildinstall / 100)?.toFixed(2),
ubuildinstall: (ubuildinstall / 100)?.toFixed(2),
nbuildinstall: (nbuildinstall / 100)?.toFixed(2)
}
];
} else {
tableData.value = [];
}
} catch (error) {
console.error('DataTable getData error:', error);
tableData.value = [];
} finally {
dataLoading.value = false;
}
};
const customRow = (record: any, index: number) => {
return { return {
style: { style: {
backgroundColor: index % 2 === 1 ? '#fafafa' : '#ffffff' backgroundColor: index % 2 === 1 ? '#fafafa' : '#ffffff'
},
onClick: () => {
if (record.name !== '总计') {
emit('row-click', record);
}
} }
}; };
}; };
// watch(
onMounted(() => { () => JidiSelectEventStore.selectedItem,
newVal => {
}); if (newVal && newVal.wbsCode) {
baseid.value = newVal.wbsCode;
getData();
}
},
{ deep: true, immediate: true }
);
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.data-table-container { .data-table-container {
// padding: 0;
background: #fff; background: #fff;
padding: 16px 0px; padding: 16px 0px;
width: 100%; width: 100%;
@ -213,7 +211,6 @@ onMounted(() => {
.custom-table { .custom-table {
:deep(.ant-table) { :deep(.ant-table) {
font-size: 14px; font-size: 14px;
// border: 1px solid #d5e2ed;
border-top: 1px solid #d5e2ed; border-top: 1px solid #d5e2ed;
.ant-table-thead { .ant-table-thead {
@ -221,8 +218,6 @@ onMounted(() => {
>th { >th {
background-color: #e5eff8 !important; background-color: #e5eff8 !important;
color: #2f6b98; color: #2f6b98;
// font-weight: 600;
// border: 1px solid #d5e2ed!important;
padding: 0px 6px; padding: 0px 6px;
text-align: center; text-align: center;
font-weight: 600; font-weight: 600;
@ -249,7 +244,6 @@ onMounted(() => {
.ant-table-tbody { .ant-table-tbody {
>tr { >tr {
>td { >td {
// border: 1px solid #d5e2ed;
padding: 0px 6px !important; padding: 0px 6px !important;
text-align: center; text-align: center;
overflow-wrap: break-word; overflow-wrap: break-word;
@ -257,7 +251,6 @@ onMounted(() => {
&:first-child { &:first-child {
text-align: left; text-align: left;
// font-weight: 500;
} }
} }
@ -267,7 +260,6 @@ onMounted(() => {
} }
} }
// footer
.ant-table-footer::before { .ant-table-footer::before {
display: none; display: none;
} }
@ -295,6 +287,5 @@ onMounted(() => {
.ant-table-wrapper .ant-table-thead>tr>th { .ant-table-wrapper .ant-table-thead>tr>th {
border-bottom: 1px solid #d5e2ed00 !important; border-bottom: 1px solid #d5e2ed00 !important;
} }
} }
</style> </style>

View File

@ -0,0 +1,439 @@
<!-- HuanJingSJJRQK.vue -->
<template>
<div class="huanjing-sjjrqk">
<a-tabs v-model:activeKey="activeTab" @change="handleTabChange">
<a-tab-pane key="notAccess" tab="大中型已建在建电站" />
<a-tab-pane key="partAccess" tab="已接入电站运行数据" />
<a-tab-pane key="isAccess" tab="已开展全过程监测工作" />
</a-tabs>
<div class="content-wrapper">
<!-- 左侧饼图 -->
<div class="chart-section">
<div ref="chartContainer" class="chart-container"></div>
</div>
<!-- 右侧表格 -->
<div class="table-section">
<a-table
:columns="columns"
:data-source="tableData"
:pagination="false"
size="middle"
:customRow="customRow"
:loading="tableLoading"
class="custom-table"
/>
</div>
</div>
<!-- 详情弹窗 -->
<a-modal
v-model:open="detailModalVisible"
:title="detailModalTitle"
width="1200px"
:footer="null"
:destroy-on-close="true"
>
<component
v-if="detailModalVisible && detailComponent"
:is="detailComponent"
v-bind="detailProps"
/>
</a-modal>
</div>
</template>
<script lang="ts" setup>
import { ref, onMounted, onUnmounted, watch, shallowRef } from 'vue';
import * as echarts from 'echarts';
import { getVmsstbprptKendoList } from '@/api/home';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
defineOptions({
name: 'HuanJingSJJRQK'
});
const props = defineProps<{
dataDimensionVal: string;
name: string;
}>();
const JidiSelectEventStore = useJidiSelectEventStore();
const activeTab = ref(props.name || 'notAccess');
const chartContainer = ref<HTMLDivElement | null>(null);
let chartInstance: echarts.ECharts | null = null;
const tableLoading = ref(false);
const tableData = ref<any[]>([]);
const chartFilter = ref<string>('');
//
const detailModalVisible = ref(false);
const detailModalTitle = ref('');
const detailComponent = shallowRef<any>(null);
const detailProps = ref<any>({});
//
const columns = ref([
{
title: '电站名称',
dataIndex: 'stnm',
key: 'stnm',
align: 'left'
},
{
title: '接入状态',
dataIndex: 'accessStatus',
key: 'accessStatus',
align: 'center'
},
{
title: '操作',
key: 'action',
align: 'center',
width: 120
}
]);
//
const customRow = (record: any) => {
return {
onClick: () => {
handleRowClick(record);
}
};
};
//
const handleRowClick = async (record: any) => {
// Tab
if (activeTab.value === 'notAccess') {
// -
detailModalTitle.value = '电站详情';
//
// 使
detailComponent.value = null;
detailProps.value = {
stcd: record.stcd,
stnm: record.stnm
};
detailModalVisible.value = true;
} else if (activeTab.value === 'partAccess') {
//
detailModalTitle.value = '运行数据详情';
detailComponent.value = null;
detailProps.value = {
stcd: record.stcd,
stnm: record.stnm
};
detailModalVisible.value = true;
} else if (activeTab.value === 'isAccess') {
//
detailModalTitle.value = '监测数据详情';
detailComponent.value = null;
detailProps.value = {
stcd: record.stcd,
stnm: record.stnm
};
detailModalVisible.value = true;
}
};
//
const getData = async () => {
if (!props.dataDimensionVal) return;
const baseFilters: any[] = [
{ field: 'sttpCode', operator: 'eq', dataType: 'string', value: 'ENG' },
{ field: 'bldsttCcode', operator: 'in', dataType: 'string', value: ['1', '2'] }
];
if (props.dataDimensionVal !== 'all') {
baseFilters.unshift({ field: 'baseId', operator: 'eq', dataType: 'string', value: props.dataDimensionVal });
}
let params: any = {};
if (activeTab.value === 'notAccess') {
//
params = {
filter: {
logic: 'and',
filters: [
...baseFilters,
{ field: 'prsc', operator: 'in', dataType: 'string', value: ['1', '2', '3'] }
]
}
};
} else if (activeTab.value === 'partAccess') {
//
params = {
filter: {
logic: 'and',
filters: [
...baseFilters,
{ field: 'runState', operator: 'eq', dataType: 'number', value: 4 },
{ field: 'dtin', operator: 'eq', dataType: 'number', value: 1 }
]
}
};
} else if (activeTab.value === 'isAccess') {
//
params = {
filter: {
logic: 'and',
filters: [
...baseFilters,
{ field: 'prsc', operator: 'in', dataType: 'string', value: ['1', '2', '3'] },
{ field: 'dtinEnv', operator: 'in', dataType: 'string', value: ['2'] }
]
}
};
}
try {
tableLoading.value = true;
const res = await getVmsstbprptKendoList(params);
const resData = res?.data?.data || [];
//
tableData.value = resData.map((item: any) => ({
key: item.stcd,
stcd: item.stcd,
stnm: item.stnm,
accessStatus: getAccessStatus(item),
...item
}));
//
updateChart(resData);
} catch (error) {
console.error('HuanJingSJJRQK getData error:', error);
} finally {
tableLoading.value = false;
}
};
//
const getAccessStatus = (item: any) => {
if (activeTab.value === 'notAccess') {
return '已建在建';
} else if (activeTab.value === 'partAccess') {
return '已接入';
} else if (activeTab.value === 'isAccess') {
return '已监测';
}
return '-';
};
//
const updateChart = (data: any[]) => {
if (!chartInstance) return;
//
const statusMap: Record<string, number> = {};
data.forEach((item: any) => {
const status = item.bldsttCcode === '1' ? '在建' : '已建';
statusMap[status] = (statusMap[status] || 0) + 1;
});
const chartData = Object.entries(statusMap).map(([name, value]) => ({
name,
value
}));
const option = {
tooltip: {
trigger: 'item',
formatter: '{b}: {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 'left',
top: 'center'
},
color: ['#78c300', '#2196F3'],
series: [
{
name: '电站数量',
type: 'pie',
radius: ['40%', '70%'],
center: ['60%', '50%'],
data: chartData,
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
label: {
show: true,
formatter: '{b}: {c}'
}
}
]
};
chartInstance.setOption(option, true);
//
chartInstance.off('click');
chartInstance.on('click', (params: any) => {
chartFilter.value = params.name;
filterTableByChart(params.name);
});
};
//
const filterTableByChart = (status: string) => {
//
//
console.log('筛选状态:', status);
};
//
const initChart = () => {
if (!chartContainer.value) return;
chartInstance = echarts.init(chartContainer.value);
const option = {
tooltip: {
trigger: 'item',
formatter: '{b}: {c} ({d}%)'
},
legend: {
orient: 'vertical',
left: 'left',
top: 'center'
},
color: ['#78c300', '#2196F3'],
series: [
{
name: '电站数量',
type: 'pie',
radius: ['40%', '70%'],
center: ['60%', '50%'],
data: [],
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
},
label: {
show: true,
formatter: '{b}: {c}'
}
}
]
};
chartInstance.setOption(option);
};
// Tab
const handleTabChange = (key: string) => {
activeTab.value = key;
chartFilter.value = '';
getData();
};
onMounted(() => {
if (chartContainer.value) {
initChart();
}
getData();
});
onUnmounted(() => {
if (chartInstance) {
chartInstance.dispose();
chartInstance = null;
}
});
// props
watch(
() => props.dataDimensionVal,
() => {
getData();
}
);
//
const handleResize = () => {
if (chartInstance) {
chartInstance.resize();
}
};
onMounted(() => {
window.addEventListener('resize', handleResize);
});
onUnmounted(() => {
window.removeEventListener('resize', handleResize);
});
</script>
<style lang="scss" scoped>
.huanjing-sjjrqk {
padding: 20px;
.content-wrapper {
display: flex;
gap: 20px;
margin-top: 20px;
.chart-section {
flex: 0 0 400px;
.chart-container {
width: 100%;
height: 400px;
}
}
.table-section {
flex: 1;
}
}
.custom-table {
:deep(.ant-table) {
font-size: 13px;
border: 1px solid #e8e8e8;
.ant-table-thead {
> tr {
> th {
background-color: #e5eff8 !important;
color: #2f6b98;
font-weight: 600;
border: 1px solid #e8e8e8 !important;
padding: 6px 8px;
text-align: center;
}
}
}
.ant-table-tbody {
> tr {
> td {
border: 1px solid #e8e8e8;
padding: 6px 8px;
text-align: center;
}
&:hover {
background-color: #e6f7ff !important;
}
}
}
}
}
}
</style>

View File

@ -9,18 +9,50 @@
<div>水电开发情况</div> <div>水电开发情况</div>
<div style="color: #757575;font-size: 12px;line-height: 16px;">图释数量/装机容量</div> <div style="color: #757575;font-size: 12px;line-height: 16px;">图释数量/装机容量</div>
<div> <div>
<DevelopStatusChart /> <DevelopStatusChart @chart-click="handleChartClick" />
</div> </div>
</div> </div>
<!-- style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center" }} --> <!-- style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center" }} -->
<div style="flex: 1;display: flex; flex-direction: column; align-items: center;"> <div style="flex: 1;display: flex; flex-direction: column; align-items: center;">
<EngEnvironmentData /> <EngEnvironmentData @item-click="handleEnvItemClick" />
</div> </div>
</div> </div>
<DataTable /> <DataTable @row-click="handleRowClick" />
</div> </div>
<!-- <div v-else class="zanwushujv"> <a-empty /></div> --> <!-- <div v-else class="zanwushujv"> <a-empty /></div> -->
</SidePanelItem> </SidePanelItem>
<!-- 水电开发情况弹窗 -->
<a-modal
v-model:open="shuidianModalVisible"
:title="shuidianModalTitle"
width="1536px"
:footer="null"
:destroy-on-close="true"
>
<ShuiDianKaiFQKTwoLayer
v-if="shuidianModalVisible"
:defaultJidiInfo="shuidianModalProps.defaultJidiInfo"
:seriesName="shuidianModalProps.seriesName"
:stateName="shuidianModalProps.stateName"
:defaultTab="shuidianModalProps.defaultTab"
/>
</a-modal>
<!-- 环境监测数据接入情况弹窗 -->
<a-modal
v-model:open="huanjingModalVisible"
:title="huanjingModalTitle"
width="1536px"
:footer="null"
:destroy-on-close="true"
>
<HuanJingSJJRQK
v-if="huanjingModalVisible"
:dataDimensionVal="huanjingModalProps.dataDimensionVal"
:name="huanjingModalProps.name"
/>
</a-modal>
</div> </div>
</template> </template>
@ -30,15 +62,75 @@ import SidePanelItem from '@/components/SidePanelItem/index.vue';
import DevelopStatusChart from "@/components/developStatusChart/index.vue" import DevelopStatusChart from "@/components/developStatusChart/index.vue"
import EngEnvironmentData from "@/components/engEnvironmentData/index.vue" import EngEnvironmentData from "@/components/engEnvironmentData/index.vue"
import DataTable from "./DataTable.vue" import DataTable from "./DataTable.vue"
import ShuiDianKaiFQKTwoLayer from "./TwoLayer/ShuiDianKaiFQKTwoLayer.vue"
import HuanJingSJJRQK from "./TwoLayer/HuanJingSJJRQK.vue"
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
// 便 // 便
defineOptions({ defineOptions({
name: 'shuidianhuangjingjieruMod' name: 'shuidianhuangjingjieruMod'
}); });
const JidiSelectEventStore = useJidiSelectEventStore();
const prompt = ref({ const prompt = ref({
show: true, show: true,
value: '统计大中型已建,在建水电站', value: '统计大中型已建,在建水电站',
}) })
//
const shuidianModalVisible = ref(false);
const shuidianModalTitle = ref('水电开发情况');
const shuidianModalProps = ref<any>({});
//
const huanjingModalVisible = ref(false);
const huanjingModalTitle = ref('环境监测数据接入情况');
const huanjingModalProps = ref<any>({});
// DataTable
const handleRowClick = (record: any) => {
const currentJidiInfo = JidiSelectEventStore.selectedItem;
shuidianModalProps.value = {
defaultJidiInfo: {
baseid: currentJidiInfo?.wbsCode || 'all',
basename: currentJidiInfo?.wbsName || '全部基地'
},
seriesName: currentJidiInfo?.wbsCode === 'other' ? '数量(座)' : '装机容量(万kW)',
stateName: record.bldsttCcode === '0' ? '未建' : record.bldsttCcode === '1' ? '在建' : '已建',
defaultTab: record.bldsttCcode === '0' ? '未建' : record.bldsttCcode === '1' ? '在建' : '已建'
};
shuidianModalTitle.value = '水电开发情况';
shuidianModalVisible.value = true;
};
// DevelopStatusChart
const handleChartClick = (params: any) => {
const currentJidiInfo = JidiSelectEventStore.selectedItem;
shuidianModalProps.value = {
defaultJidiInfo: {
baseid: currentJidiInfo?.wbsCode || 'all',
basename: currentJidiInfo?.wbsName || '全部基地'
},
seriesName: params.seriesName,
stateName: params.name,
defaultTab: params.name
};
shuidianModalTitle.value = '水电开发情况';
shuidianModalVisible.value = true;
};
// EngEnvironmentData
const handleEnvItemClick = (params: any) => {
const currentJidiInfo = JidiSelectEventStore.selectedItem;
huanjingModalProps.value = {
dataDimensionVal: currentJidiInfo?.wbsCode || 'all',
name: params.name
};
huanjingModalTitle.value = '环境监测数据接入情况';
huanjingModalVisible.value = true;
};
// //
onMounted(() => { onMounted(() => {

View File

@ -264,11 +264,12 @@ const getDcpcOptions = async () => {
]; ];
const res = await getWeStaticsSecond( { filter: params, group }); const res = await getWeStaticsSecond( { filter: params, group });
// debugger
if (res?.data?.data?.length) { if (res?.data?.data?.length) {
const options = res.data.data.map((item: any) => ({ const options = res.data.data.map((item: any) => ({
label: item.dcpc, label: item.key,
value: item.dcpc value: item.key
})); }));
dcpcOptions.value = [{ label: '全部', value: '' }, ...options]; dcpcOptions.value = [{ label: '全部', value: '' }, ...options];
} else { } else {

View File

@ -0,0 +1,614 @@
<template>
<div>
<SidePanelItem
title="生态流量沿程变化"
:iconmap="iconmap"
:select="select"
:datetimePicker="datetimePicker"
@update-values="handlePanelChange"
>
<!-- 加载状态 -->
<div v-if="dataLoading" class="chart-loading">
<a-spin tip="加载中..." />
</div>
<!-- 无数据提示 -->
<a-empty
v-if="!chartData.length && !dataLoading"
description="暂无数据"
class="chart-empty"
/>
<!-- 图表容器使用 display 控制避免 v-if 销毁 DOM-->
<div
ref="chartRef"
class="chart-container"
:style="{
display: chartData.length && !dataLoading ? 'block' : 'none'
}"
></div>
</SidePanelItem>
</div>
</template>
<script lang="ts" setup>
import { ref, watch, nextTick, onBeforeUnmount } from 'vue';
import SidePanelItem from '@/components/SidePanelItem/index.vue';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
// import { wbsbGetKendoList } from '@/api/sz';
import * as echarts from 'echarts';
import dayjs from 'dayjs';
// TODO: API
import { qgcHourVGetKendoListCust, wbsbGetKendoList } from '@/api/stll';
import { useModelStore } from '@/store/modules/model';
//
defineOptions({
name: 'StllyanchengChangeMod'
});
// ==================== ====================
//
const iconmap = ref({
show: true,
value:
'入库流量是基于库容曲线和水量平衡的推算值,非实测数据。出库流量是基于机组出力特征曲线和闸门开度的推算值,非实测数据。',
icon: 'iconfont icon-time'
});
//
const datetimePicker = ref({
show: true,
value: dayjs().format('YYYY-MM-DD HH:mm'), //
format: 'YYYY-MM-DD HH:mm',
picker: 'date',
timeFormat: 'HH:mm',
options: []
});
//
const select = ref({
show: true,
value: '',
options: [],
picker: undefined,
format: undefined
});
const modelStore = useModelStore();
//
const wbsCode = ref(''); //
const selectData = ref(''); //
const chartData = ref<any[]>([]); //
const dataLoading = ref(false); //
const latestTime = ref(''); //
const hasTimeData = ref(false); //
//
const chartRef = ref<HTMLElement | null>(null);
let chartInstance: echarts.ECharts | null = null;
//
const modalVisible = ref(false);
const modalData = ref<any>({
stcd: '',
stnm: '',
titleName: ''
});
// Store
const JidiSelectEventStore = useJidiSelectEventStore();
// ==================== ====================
/**
* 获取河段列表
*/
const getSelect = async () => {
if (!wbsCode.value) {
console.warn('wbsCode 为空,无法获取河段数据');
return;
}
let params = {
filter: {
logic: 'and',
filters: [
{
field: 'objId',
operator: 'eq',
value: wbsCode.value
},
{
field: 'wbsType',
operator: 'eq',
value: 'PSB_RVCD'
}
]
},
group: [
{
dir: 'asc',
field: 'orderIndex'
},
{
dir: 'asc',
field: 'wbsCode'
},
{
dir: 'asc',
field: 'wbsName'
},
{
dir: 'asc',
field: 'objid'
}
],
groupResultFlat: 'true'
};
try {
let res = await wbsbGetKendoList(params);
//
let data;
if (res && res.data && res.data.data) {
if (Array.isArray(res.data.data)) {
data = res.data.data;
} else if (res.data.data.data && Array.isArray(res.data.data.data)) {
data = res.data.data.data;
} else {
console.warn('无法解析河段数据:', res);
return;
}
} else {
console.warn('未获取到河段数据');
return;
}
if (data && data.length > 0) {
// ;
select.value.value = data[0].wbsCode;
selectData.value = data[0].wbsCode; //
select.value.options = data.map(item => ({
value: item.wbsCode,
label: item.wbsName
}));
//
await loadChartData();
} else {
console.warn('河段数据为空');
select.value.value = '';
select.value.options = [];
}
} catch (error) {
console.error('获取河段数据失败:', error);
}
};
/**
* 获取生态流量数据预留 API 位置
*/
const getList = async (rvcd: string, sDate: string) => {
// TODO: API
// React
// - baseId: JidiSelectEventStore.selectedItem
// - rvcd:
// - tm: 1
const currentTime = dayjs(sDate);
const startTime = currentTime.subtract(1, 'month');
let params = {
filter: {
logic: 'and',
filters: [
{
field: 'baseId',
operator: 'eq',
dataType: 'string',
value: wbsCode.value
},
{
field: 'rvcd',
operator: 'eq',
dataType: 'string',
value: rvcd
},
{
field: 'tm',
operator: 'gte',
dataType: 'date',
value: startTime.format('YYYY-MM-DD HH:mm:ss')
},
{
field: 'tm',
operator: 'lte',
dataType: 'date',
value: currentTime.format('YYYY-MM-DD HH:mm:ss')
}
]
},
sort: [
{
field: 'sort',
dir: 'asc'
}
]
};
// TODO: API FAA
const res = await qgcHourVGetKendoListCust(params);
//
if (!res || !res.data || !res.data.data || !Array.isArray(res.data.data)) {
console.warn('未获取到有效的生态流量数据:', res);
return [];
}
//
return res.data.data.map((item: any) => ({
TM: dayjs(item.tm).format('YYYY-MM-DD H时'),
stnm: item.stnm,
stcd: item.stcd,
qec: item.qec, //
qecLimit: item.qecLimit, //
qi: item.qi //
}));
};
/**
* 加载图表数据
*/
const loadChartData = async () => {
if (!selectData.value || !datetimePicker.value.value) {
return;
}
dataLoading.value = true;
try {
const data = await getList(selectData.value, datetimePicker.value.value);
if (data && data.length > 0) {
chartData.value = data;
hasTimeData.value = true;
//
if (data[0]?.TM) {
latestTime.value = data[0].TM;
}
//
await nextTick();
initChart();
} else {
chartData.value = [];
hasTimeData.value = false;
latestTime.value = '';
//
if (chartInstance) {
chartInstance.clear();
}
}
} catch (error) {
console.error('加载图表数据失败:', error);
chartData.value = [];
} finally {
dataLoading.value = false;
}
};
/**
* 初始化 ECharts 图表
*/
const initChart = () => {
if (!chartRef.value) {
console.warn('图表容器未准备好');
return;
}
//
if (chartInstance) {
chartInstance.dispose();
}
//
chartInstance = echarts.init(chartRef.value);
//
const xData: string[] = [];
const inData: (number | string)[] = []; //
const outData: (number | string)[] = []; //
const limitData: (number | string)[] = []; //
let hasValidData = false; //
chartData.value.forEach(item => {
xData.push(item.stnm);
const qecValue = item.qec ?? '-';
const qiValue = item.qi ?? '-';
const qecLimitValue = item.qecLimit ?? '-';
outData.push(qecValue);
inData.push(qiValue);
limitData.push(qecLimitValue);
//
if (qecValue !== '-' || qiValue !== '-' || qecLimitValue !== '-') {
hasValidData = true;
}
});
//
if (!hasValidData && chartData.value.length > 0) {
chartData.value = [];
if (chartInstance) {
chartInstance.clear();
}
return;
}
//
const option: echarts.EChartsOption = {
tooltip: {
trigger: 'axis',
confine: true,
formatter: function (params: any) {
const datum = chartData.value.find(
(el: any) => el.stnm === params[0].name
);
const unit = 'm³/s'; // TODO:
const content = params
.map((item: any) => {
const value = item.value ?? '-';
return `<div>${item.marker}${item.seriesName}: &nbsp;&nbsp;&nbsp;&nbsp;<span style="float:right">${value} ${unit}</span></div>`;
})
.join('');
return `<h3 style="color:white">${params[0].name}<br/>${
datum?.TM || ''
}</h3>${content}`;
},
axisPointer: {
type: 'line'
}
},
legend: {
data: ['入库流量', '生态流量', '环评要求限值'],
icon: 'roundRect',
top: 10
},
grid: {
left: 10,
right: 10,
bottom: 10,
top: 70,
containLabel: true
},
xAxis: {
type: 'category',
data: xData,
axisLine: {
lineStyle: {
color: '#505050'
}
},
splitLine: {
show: true,
lineStyle: {
color: '#8f8f8f',
type: 'solid'
}
},
axisLabel: {
interval: xData.length > 12 ? 2 : 0,
rotate: 0,
formatter: (value: string, index: number) => {
const shortValue =
value.substring(0, 6) + (value.length > 6 ? '...' : '');
if (index % 2 !== 0) {
return `{a|${shortValue}}`;
} else {
return `\n{b|}${shortValue}`;
}
},
rich: {
a: {
height: 20,
align: 'center'
},
b: {
height: 30,
align: 'center'
}
}
}
},
yAxis: {
type: 'value',
name: '流量(m³/s)', // TODO:
minInterval: 1,
axisLine: {
lineStyle: {
color: '#505050'
}
},
splitLine: {
show: true,
lineStyle: {
color: '#8f8f8f',
type: 'solid'
}
}
},
dataZoom: [
{
type: 'inside',
xAxisIndex: 0,
start: 0,
end: 100,
zoomOnMouseWheel: true,
moveOnMouseMove: true
}
],
series: [
{
name: '入库流量',
data: inData,
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 6,
connectNulls: true,
color: '#5470c6' // TODO:
},
{
name: '生态流量',
data: outData,
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 6,
connectNulls: true,
color: '#91cc75' // TODO:
},
{
name: '环评要求限值',
data: limitData,
type: 'bar',
barMaxWidth: 10,
color: '#fac858' // TODO:
}
]
};
chartInstance.setOption(option);
//
chartInstance.on('click', handleChartClick);
//
window.addEventListener('resize', handleResize);
};
/**
* 图表点击事件
*/
const handleChartClick = (params: any) => {
const datum = chartData.value.find((item: any) => item.stnm === params.name);
if (datum) {
const currentTime = dayjs(datetimePicker.value.value);
const startTime = currentTime.subtract(1, 'month');
modalVisible.value = true;
modelStore.modalVisible = true;
modelStore.params.sttp = 'ENGJJ';
modelStore.title = datum.stnm;
modelStore.params.stcd = datum.stcd;
modelStore.params.eqtp = 'QEC';
modelStore.filter.rangeTm = [startTime, currentTime];
modelStore.filter.stllgzlx = 'qecInterval';
modelStore.filter.stllTmType = 'day';
}
};
/**
* 窗口大小改变时重新调整图表
*/
const handleResize = () => {
if (chartInstance) {
chartInstance.resize();
}
};
/**
* 弹窗取消事件
*/
const handleModalCancel = () => {
modalVisible.value = false;
modalData.value = {
stcd: '',
stnm: '',
titleName: ''
};
};
/**
* 面板数据变化处理
*/
const handlePanelChange = async (data: any) => {
console.log('当前所有控件状态:', data);
//
if (data.select) {
select.value.value = data.select;
selectData.value = data.select;
}
if (data.datetime) {
datetimePicker.value.value = data.datetime;
}
//
if (data.select || data.datetime) {
await loadChartData();
}
};
// ==================== ====================
//
watch(
() => JidiSelectEventStore.selectedItem,
newVal => {
console.log('流域切换:', newVal);
if (newVal?.wbsCode) {
wbsCode.value = newVal.wbsCode;
getSelect();
}
},
{ deep: true, immediate: true }
);
//
onBeforeUnmount(() => {
if (chartInstance) {
chartInstance.dispose();
chartInstance = null;
}
window.removeEventListener('resize', handleResize);
});
</script>
<style lang="scss" scoped>
.chart-loading {
display: flex;
justify-content: center;
align-items: center;
height: 424px;
}
.chart-empty {
display: flex;
align-items: center;
height: 424px;
flex-direction: column;
/* align-content: center; */
justify-content: center;
text-align: center !important;
:deep(.ant-empty-description) {
text-align: center !important;
text-indent: 0;
width: 100%;
}
}
.chart-container {
width: 406px;
height: 424px;
}
.time-tip {
text-align: right;
font-size: 12px;
color: #8e8e8e;
padding: 8px 0;
margin-top: 4px;
}
</style>

File diff suppressed because it is too large Load Diff

View File

@ -1,65 +1,188 @@
<!-- SidePanelItem.vue --> <!-- SidePanelItem.vue -->
<template> <template>
<SidePanelItem title="AI识别大坝环境" :datetimePicker="datetimePicker"> <SidePanelItem title="AI识别大坝环境" :datetimePicker="datetimePicker" @update-values="handlePanelChange">
<div class="facility-grid"> <a-spin :spinning="dataLoading" tip="加载中...">
<div v-for="facility in facilities" :key="facility.name" class="facility-card"> <div class="facility-grid">
<div style="width: 70px;height: 62px;display: flex;align-items: center;justify-content: center;"> <div
<div class="facility-icon"> v-for="(facility, idx) in facilities"
<i style="color: #fff;" :class="facility.icon" type="icon-shengtailiuliang2"></i> :key="facility.name"
class="facility-card"
@click="handleCardClick(String(idx + 1))"
>
<div style="width: 70px;height: 62px;display: flex;align-items: center;justify-content: center;">
<div class="facility-icon">
<i style="color: #fff;" :class="facility.icon" type="icon-shengtailiuliang2"></i>
</div>
</div> </div>
</div>
<div class="facility-info"> <div class="facility-info">
<div class="facility-name">{{ facility.name }}</div> <div class="facility-name">{{ facility.name }}</div>
<div style="font-size: 14px;"> <span class="facility-count">{{ facility.count }}</span> <div style="font-size: 14px;"> <span class="facility-count">{{ facility.count }}</span>
<span></span> <span></span>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> </a-spin>
</SidePanelItem> </SidePanelItem>
<!-- AI识别大坝环境详情弹框 -->
<a-modal
v-model:open="modalVisible"
title="AI识别大坝环境"
width="1536px"
:footer="null"
@cancel="handleModalClose"
>
<AISBTK
v-if="modalVisible"
:month="datetimePicker.value"
:tab-idx="currentTabIdx"
:baseid="baseid"
/>
</a-modal>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue'; import { ref, watch } from 'vue';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import SidePanelItem from '@/components/SidePanelItem/index.vue'; import SidePanelItem from '@/components/SidePanelItem/index.vue';
import AISBTK from './AISBTK.vue';
import { getAisbdbyxList } from '@/api/zngj';
import dayjs from 'dayjs';
// 便 // 便
defineOptions({ defineOptions({
name: 'zengzhizhanjiansheyunxing' name: 'aisbdbyx'
}); });
const JidiSelectEventStore = useJidiSelectEventStore();
const baseid = ref('');
const dataLoading = ref(false);
// ==================== ====================
const modalVisible = ref(false);
const currentTabIdx = ref('1');
// ==================== ====================
const datetimePicker = ref({ const datetimePicker = ref({
show: true, show: true,
value: `${new Date().getFullYear() - 1}`, // value: dayjs().format('YYYY-MM'),
format: 'YYYY-MM', format: 'YYYY-MM',
picker: 'month' as const, picker: 'month' as const,
options: [] options: []
}); });
//
// ==================== ====================
const facilities = ref([ const facilities = ref([
{ {
name: '漂浮物识别', name: '漂浮物识别',
count: "34", count: 0,
icon: 'icon iconfont icon-piaofuwu' icon: 'icon iconfont icon-piaofuwu'
}, },
{ {
name: '叠梁门运行识别', name: '叠梁门运行识别',
count: '0', count: 0,
icon: 'icon iconfont icon-dieliangmen1' icon: 'icon iconfont icon-dieliangmen1'
}, },
]); ]);
// // ==================== ====================
onMounted(() => { const handlePanelChange = (data: any) => {
// console.log('当前所有控件状态:', data);
if (data.datetime) {
datetimePicker.value.value = data.datetime;
}
getCardData();
};
}); const handleCardClick = (tabIdx: string) => {
currentTabIdx.value = tabIdx;
modalVisible.value = true;
};
// const handleModalClose = () => {
onUnmounted(() => { modalVisible.value = false;
};
}); // ==================== ====================
const getCardData = async () => {
if (!datetimePicker.value.value || !baseid.value) return;
dataLoading.value = true;
try {
const params = {
filter: {
logic: 'and',
filters: [
baseid.value !== 'all' ? {
field: 'baseId',
operator: 'eq',
dataType: 'string',
value: baseid.value
} : null,
{
field: 'startTime',
operator: 'gte',
dataType: 'date',
value: dayjs(datetimePicker.value.value).startOf('month').format('YYYY-MM-DD 00:00:00')
},
{
field: 'endTime',
operator: 'lte',
dataType: 'date',
value: dayjs(datetimePicker.value.value).endOf('month').format('YYYY-MM-DD 23:59:59')
}
].filter(Boolean)
}
};
const res = await getAisbdbyxList(params);
const data = res?.data ?? {};
facilities.value = [
{
name: '漂浮物识别',
count: data?.pfwCnt ?? 0,
icon: 'icon iconfont icon-piaofuwu'
},
{
name: '叠梁门运行识别',
count: data?.dlmCnt ?? 0,
icon: 'icon iconfont icon-dieliangmen1'
}
];
} catch (error) {
console.error('获取统计数据失败:', error);
facilities.value = [
{
name: '漂浮物识别',
count: 0,
icon: 'icon iconfont icon-piaofuwu'
},
{
name: '叠梁门运行识别',
count: 0,
icon: 'icon iconfont icon-dieliangmen1'
}
];
} finally {
dataLoading.value = false;
}
};
// ==================== ====================
watch(
() => JidiSelectEventStore.selectedItem,
async newVal => {
if (newVal && newVal.wbsCode) {
baseid.value = newVal.wbsCode;
getCardData();
}
},
{ deep: true, immediate: true }
);
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@ -118,4 +241,8 @@ onUnmounted(() => {
color: #2f6b98; color: #2f6b98;
// font-weight: 600; // font-weight: 600;
} }
</style>
:deep(.ant-spin-nested-loading) {
min-height: 72px;
}
</style>

View File

@ -1,2 +1,6 @@
declare module 'jsencrypt' declare module 'jsencrypt'
declare module 'sortablejs' declare module 'sortablejs'
declare module '*.svg' {
const content: string
export default content
}

View File

@ -1,5 +1,5 @@
import { defineStore } from 'pinia'; import { defineStore } from 'pinia';
import { ref, onMounted } from 'vue'; import { ref, onMounted,nextTick } from 'vue';
import { wbsbGetKendoList } from '@/api/select'; import { wbsbGetKendoList } from '@/api/select';
export const useJidiSelectEventStore = defineStore('jidiSelectEvent', () => { export const useJidiSelectEventStore = defineStore('jidiSelectEvent', () => {
const jidiData: any = ref([ const jidiData: any = ref([
@ -12,7 +12,9 @@ export const useJidiSelectEventStore = defineStore('jidiSelectEvent', () => {
const loading = ref(false); const loading = ref(false);
const selectedItem = ref(jidiData.value[0]); const selectedItem = ref(jidiData.value[0]);
const updataJidiData = (index: any) => { const updataJidiData = (index: any) => {
console.log(index); if(jidiData.value.length == 1){
return
}
selectedItem.value = jidiData.value[index]; selectedItem.value = jidiData.value[index];
jidiData.value.forEach((item: any) => { jidiData.value.forEach((item: any) => {
item.selected = false; item.selected = false;

View File

@ -34,7 +34,7 @@ service.interceptors.request.use(
config.headers._sysid = '10EC2E0B-AEA9-4757-83A2-201BA1BC54E9'; config.headers._sysid = '10EC2E0B-AEA9-4757-83A2-201BA1BC54E9';
config.headers.authorization = config.headers.authorization =
'bearer cb68557d-2861-497d-b708-6b73ae68ba95'; 'bearer 85eef719-84d2-4de0-b57f-72b2c261f9c8';
config.baseURL = '/'; config.baseURL = '/';
} else { } else {
const user = useUserStoreHook(); const user = useUserStoreHook();

View File

@ -54,7 +54,7 @@ const onMouseUp = () => {
watch( watch(
() => JidiSelectEventStore.selectedItem, () => JidiSelectEventStore.selectedItem,
newVal => { newVal => {
if (newVal && newVal.wbsCode) { if (newVal && newVal.wbsCode) {
baseid.value = newVal.wbsCode; baseid.value = newVal.wbsCode;
if (newVal.wbsCode == '07') { if (newVal.wbsCode == '07') {
uiStore.setDrawerOpen(true); uiStore.setDrawerOpen(true);
@ -65,8 +65,17 @@ watch(
}, },
{ deep: true, immediate: true } { deep: true, immediate: true }
); );
watch(
() => JidiSelectEventStore.jidiData,
(newData) => {
if (newData.length > 1) {
JidiSelectEventStore.updataJidiData(11);
}
},
{ immediate: true }
);
onMounted(() => { onMounted(() => {
JidiSelectEventStore.updataJidiData(11); // JidiSelectEventStore.updataJidiData(11);
}); });
</script> </script>
@ -82,7 +91,7 @@ onMounted(() => {
<FishVideo /> <FishVideo />
</RightDrawer> </RightDrawer>
</div> </div>
<div class="fixedP" ref="fixedPRef"> <div class="fixedP" ref="fixedPRef" v-if="baseid == '07'">
<div class="zhuai" @mousedown="onMouseDown"></div> <div class="zhuai" @mousedown="onMouseDown"></div>
<SurveyQingKuang /> <SurveyQingKuang />
<FishChangeTu /> <FishChangeTu />
@ -100,13 +109,14 @@ onMounted(() => {
padding: 0px 16px; padding: 0px 16px;
border: 2px solid rgb(197, 214, 226); border: 2px solid rgb(197, 214, 226);
box-shadow: rgb(229, 237, 243) 0px 0px 3px 6px; box-shadow: rgb(229, 237, 243) 0px 0px 3px 6px;
background-color: rgba(255, 255, 255, 0.411);
.zhuai { .zhuai {
width: 100%; width: 100%;
height: 16px; height: 16px;
cursor: grab; cursor: grab;
cursor: grab; cursor: grab;
user-select: none; user-select: none;
background-color: rgba(0, 0, 0, 0.5); // background-color: rgba(0, 0, 0, 0.5);
} }
.zhuai:active { .zhuai:active {
cursor: grabbing; cursor: grabbing;

View File

@ -1,11 +1,21 @@
<script setup lang="ts"> <script setup lang="ts">
import JidiSelectorMod from "@/modules/jidiSelectorMod.vue"; import { ref, computed } from 'vue';
import RightDrawer from "@/components/RightDrawer/index.vue"; import JidiSelectorMod from '@/modules/jidiSelectorMod.vue';
import SSSTJCQKTT from "@/modules/shuishengshengtaijiance/index.vue" import RightDrawer from '@/components/RightDrawer/index.vue';
import SSSTDCQK from "@/modules/shuiShengShengTaiDiaoCha/index.vue" // import SSSTJCQKTT from '@/modules/shuishengshengtaijiance/index.vue';
// import SSSTJCQKTT from "@/modules/shuishengshengtaijiance" import SSSTDCQK from '@/modules/shuiShengShengTaiDiaoCha/index.vue'; //
import AlongFishMod from "@/modules/alongFishMod/index.vue" //沿 import AlongFishMod from '@/modules/alongFishMod/index.vue'; //沿
import SSSTDCDB from './shuiShengShengTaiDiaoCha/SSSTDCDB.vue';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
const JidiSelectEventStore = useJidiSelectEventStore();
const modalVisible = ref(false);
const currentItem = computed(() => JidiSelectEventStore.selectedItem);
const handleOpenModal = () => {
modalVisible.value = true;
};
</script> </script>
<template> <template>
@ -17,9 +27,58 @@ import AlongFishMod from "@/modules/alongFishMod/index.vue" //沿程鱼类变
<RightDrawer> <RightDrawer>
<SSSTJCQKTT /> <SSSTJCQKTT />
<SSSTDCQK /> <SSSTDCQK />
<AlongFishMod /> <AlongFishMod />
</RightDrawer> </RightDrawer>
</div> </div>
<div class="center">
<div class="center_bottom" @click="handleOpenModal">
<a-tooltip placement="top">
<template #title>
<span>水生生态调查对比</span>
</template>
<i class="icon iconfont icon-contrast"></i>
</a-tooltip>
</div>
</div>
<!-- 水生生态调查对比弹窗 -->
<a-modal
v-model:open="modalVisible"
title="水生生态调查对比"
width="1536px"
:footer="null"
destroy-on-close
>
<SSSTDCDB v-if="modalVisible" :current-item="currentItem" />
</a-modal>
</div> </div>
</template> </template>
<style scoped lang="scss"></style> <style scoped lang="scss">
.center {
position: fixed;
bottom: 10px;
left: 50%;
transform: translate(-50%, 0);
z-index: 999;
.center_bottom {
width: 48px;
height: 32px;
background: #005293;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
pointer-events: all;
i {
font-size: 16px;
color: #fff;
}
i:hover {
color: #40a9ff;
}
}
.center_bottom:hover {
border: 1px solid #40a9ff;
}
}
</style>

View File

@ -0,0 +1,441 @@
<script setup lang="ts">
import {
ref,
reactive,
watch,
onMounted,
onBeforeUnmount,
nextTick
} from 'vue';
import * as echarts from 'echarts';
import type { ECharts } from 'echarts';
import { getFishtKendoList, getCompareBar } from '@/api/stdc';
import BasicTable from '@/components/BasicTable/index.vue';
const props = defineProps<{
currentItem: any;
}>();
// ==================== ====================
const weLis = ref<any[]>([]);
const pcList = ref<any[]>([]);
const searchParam = reactive({
dcpc: '',
dcpcCompare: '',
stcd: ''
});
// ==================== ====================
const chartRef = ref<HTMLElement | null>(null);
let chartInstance: ECharts | null = null;
const chartList = ref<any[]>([]);
const chartLoading = ref(true);
// ==================== ====================
const tabLoading = ref(false);
const tableRef = ref();
const column = ref([
{
key: 'ftp',
title: '鱼种类',
dataIndex: 'ftp',
fixed: 'left' as const,
width: 150,
ellipsis: true
},
{
key: 'genus',
title: '科属',
dataIndex: 'genus',
fixed: 'left' as const,
width: 150,
ellipsis: true
},
{
key: 'fcnt',
title: '第一批次',
dataIndex: 'fcnt',
width: 150,
ellipsis: true
},
{
key: 'fcnt2',
title: '对比批次',
dataIndex: 'fcnt2',
width: 150,
ellipsis: true
}
]);
// ==================== ====================
const buildTableFilter = () => {
const filters: any[] = [];
if (searchParam.stcd) {
filters.push({ field: 'stcd', operator: 'eq', value: searchParam.stcd });
}
if (searchParam.dcpc) {
filters.push({ field: 'dcpc', operator: 'eq', value: searchParam.dcpc });
}
if (searchParam.dcpcCompare) {
filters.push({
field: 'dcpc2',
operator: 'eq',
value: searchParam.dcpcCompare
});
}
//
column.value[2].title = searchParam.dcpc || '第一批次';
column.value[3].title = searchParam.dcpcCompare || '对比批次';
return {
logic: 'and',
filters
};
};
// ==================== ====================
const fetchPcData = async () => {
const baseid = props.currentItem?.wbsCode || props.currentItem?.baseid;
const params = {
filter: {
filters:
baseid === 'all'
? []
: [
{
field: 'baseId',
operator: 'eq',
value: baseid
}
]
},
group: [
{ dir: 'asc', field: 'stcd' },
{ dir: 'asc', field: 'stnm' },
{ dir: 'asc', field: 'dcpc' }
]
};
const res = await getFishtKendoList(params);
if (res?.data?.data?.length) {
const options: any[] = [];
res.data.data.forEach((el: any) => {
if (el?.items?.[0]?.items?.length > 1) {
options.push({
label: el?.items?.[0]?.key,
value: el?.key,
dcpc: el?.items?.[0]?.items?.map((item: any) => ({
label: item.key,
value: item.key
}))
});
}
});
weLis.value = options;
pcList.value = options?.[0]?.dcpc ?? [];
searchParam.stcd = options[0]?.value || '';
searchParam.dcpc = options[0]?.dcpc?.[0]?.value || '';
searchParam.dcpcCompare = options[0]?.dcpc?.[1]?.value || '';
tabLoading.value = true;
} else {
weLis.value = [];
pcList.value = [];
tabLoading.value = true;
}
};
// ==================== ====================
const handleStcdChange = (stcd: string) => {
if (!stcd) return;
const found = weLis.value.find((el: any) => el.value === stcd);
if (found) {
pcList.value = found.dcpc;
searchParam.stcd = found.value;
searchParam.dcpc = found.dcpc?.[0]?.value || '';
searchParam.dcpcCompare = found.dcpc?.[1]?.value || '';
}
};
// ==================== ====================
const fetchChartData = async () => {
chartLoading.value = true;
try {
const params = {
filter: {
logic: 'and',
filters: [
{
field: 'stcd',
operator: 'eq',
dataType: 'string',
value: searchParam.stcd
},
{
field: 'dcpc',
operator: 'eq',
dataType: 'string',
value: searchParam.dcpc
},
{
field: 'dcpc2',
operator: 'eq',
dataType: 'string',
value: searchParam.dcpcCompare
}
]
}
};
const res: any = await getCompareBar(params);
// debugger
if (res?.data?.data?.[0]?.dataSource) {
chartList.value = res.data.data[0].dataSource;
} else {
chartList.value = [];
}
} catch (error) {
console.error('获取图表数据失败:', error);
chartList.value = [];
} finally {
chartLoading.value = false;
}
};
// ==================== ====================
const initChart = () => {
if (!chartRef.value) return;
if (!chartInstance) {
chartInstance = echarts.init(chartRef.value);
}
if (!chartList.value || chartList.value.length < 1) {
chartInstance.setOption({
title: { text: '', subtext: '' },
tooltip: { trigger: 'axis' },
xAxis: { type: 'category', data: [] },
yAxis: { type: 'value' },
series: []
});
return;
}
const option = {
title: { text: '', subtext: '' },
tooltip: {
trigger: 'axis',
axisPointer: { type: 'shadow' }
},
legend: {
data: [searchParam.dcpc, searchParam.dcpcCompare],
left: 'center',
show: true,
itemWidth: 12,
itemHeight: 8,
textStyle: { fontSize: 14 }
},
grid: {
top: '20%',
left: '5%',
right: 0,
bottom: 0,
containLabel: true
},
xAxis: {
type: 'category',
axisLabel: { rotate: 45 },
axisTick: { show: false },
data: chartList.value.map((e: any) => e.ftp)
},
yAxis: {
type: 'value',
name: '数量(尾)'
},
series: [
{
name: searchParam.dcpc,
type: 'bar',
barWidth: 5,
stack: 'dcpc',
data: chartList.value.map((e: any) => e.fcnt)
},
{
name: searchParam.dcpcCompare,
type: 'bar',
barWidth: 5,
stack: 'dcpcCompare',
data: chartList.value.map((e: any) => e.fcnt2)
}
]
};
chartInstance.setOption(option, true);
};
// ==================== ====================
const customTransform = (res: any) => {
return {
records: res?.data?.data?.[0].dataSource || [],
total: res?.data?.total || 0
};
};
// ==================== ====================
const refreshTable = () => {
const filter = buildTableFilter();
tableRef.value?.getList(filter);
};
// ==================== ====================
const handleSearch = () => {
fetchChartData();
nextTick(() => {
initChart();
refreshTable();
});
};
// ==================== ====================
watch(
() => [searchParam.dcpc, searchParam.dcpcCompare],
() => {
fetchChartData();
nextTick(() => {
initChart();
});
}
);
// ==================== ====================
watch(
() => chartList.value,
() => {
nextTick(() => {
initChart();
});
}
);
// ==================== resize ====================
const handleResize = () => {
chartInstance?.resize();
};
// ==================== ====================
onMounted(async () => {
await fetchPcData();
await nextTick();
fetchChartData();
await nextTick();
initChart();
await nextTick();
refreshTable();
window.addEventListener('resize', handleResize);
});
onBeforeUnmount(() => {
window.removeEventListener('resize', handleResize);
chartInstance?.dispose();
chartInstance = null;
});
</script>
<template>
<div class="ssstdcdb-page">
<!-- 搜索表单 -->
<div class="search-form">
<a-form-item label="调查断面">
<a-select
v-model:value="searchParam.stcd"
placeholder="请选择调查断面"
style="width: 200px; margin-right: 12px"
:options="weLis"
@change="handleStcdChange"
/>
</a-form-item>
<a-form-item label="调查批次">
<a-select
v-model:value="searchParam.dcpc"
placeholder="请选择调查批次"
style="width: 200px; margin-right: 12px"
:options="pcList"
/>
</a-form-item>
<a-form-item label="对比批次">
<a-select
v-model:value="searchParam.dcpcCompare"
placeholder="请选择对比批次"
style="width: 200px; margin-right: 12px"
:options="pcList"
/>
</a-form-item>
<a-button type="primary" @click="handleSearch">查询</a-button>
</div>
<!-- 图表 + 表格 -->
<div class="content-area">
<!-- 图表 -->
<div class="chart-section">
<a-spin :spinning="chartLoading">
<div ref="chartRef" class="chart-container" style="height: 500px"></div>
<a-empty
v-if="!chartLoading && chartList.length === 0"
class="chart-empty"
description="暂无数据"
/>
</a-spin>
</div>
<!-- 表格 -->
<BasicTable
ref="tableRef"
:columns="column"
:scroll-y="400"
:scroll-x="300"
:list-url="tabLoading ? getCompareBar : undefined"
:search-params="{ sort: [] }"
:transform-data="customTransform"
/>
</div>
</div>
</template>
<style scoped lang="scss">
.ssstdcdb-page {
// padding: 16px;
.search-form {
padding: 16px 0;
display: flex;
}
.content-area {
display: flex;
gap: 16px;
.chart-section {
width: 40%;
height: 500px;
position: relative;
}
.chart-empty {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 1;
}
.table-section {
width: 60%;
height: 500px;
}
}
}
</style>

View File

@ -0,0 +1,36 @@
<script setup lang="ts">
import JidiSelectorMod from '@/modules/jidiSelectorMod.vue';
import RightDrawer from '@/components/RightDrawer/index.vue';
import ShengtaidabiaoMod from '@/modules/shengtaidabiaoModJZ/index.vue'; // -
import ShengtaidabiaoTwoMod from '@/modules/shengtaidabiaoTwoModJJ/index.vue';
import StllyanchengChangeMod from '@/modules/stllyanchengChangeModJJ/index.vue' // -沿
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
import { ref, onMounted, watch } from 'vue';
const JidiSelectEventStore = useJidiSelectEventStore();
const baseid = ref('');
watch(
() => JidiSelectEventStore.selectedItem,
newVal => {
if (newVal && newVal.wbsCode) {
baseid.value = newVal.wbsCode;
}
},
{ deep: true, immediate: true }
);
</script>
<template>
<div class="moduleContent">
<div class="leftContent">
<JidiSelectorMod />
</div>
<div class="rightContent">
<RightDrawer>
<ShengtaidabiaoMod />
<ShengtaidabiaoTwoMod v-if="baseid == 'all'" />
<StllyanchengChangeMod v-if="baseid != 'all'" />
</RightDrawer>
</div>
</div>
</template>
<style scoped lang="scss"></style>