地图锚点图层图例添加,以及放大显示功能添加

This commit is contained in:
扈兆增 2026-06-01 08:42:06 +08:00
parent 9e669a57f8
commit 4573c92030
42 changed files with 8663 additions and 10984 deletions

View File

@ -7,12 +7,12 @@ VITE_APP_TITLE = '水电水利建设项目全过程环境管理信息平台'
VITE_APP_PORT = 3000
VITE_APP_BASE_API = '/dev-api'
# 本地环境
# VITE_APP_BASE_URL = 'http://localhost:8093'
VITE_APP_BASE_URL = 'http://localhost:8093'
# 测试环境
# VITE_APP_BASE_URL = 'http://172.16.21.142:8096'
# VITE_APP_BASE_URL = 'http://172.16.21.142:8096'
# 汤伟
VITE_APP_BASE_URL = 'http://10.84.121.21:8093'
# VITE_APP_BASE_URL = 'http://10.84.121.21:8093'
# VITE_APP_BASE_URL = 'http://192.168.1.162:8093'
# 测试环境线上
@ -25,4 +25,7 @@ VITE_APP_TEST_ONLINE_URL = 'https://211.99.26.225:12122'
VITE_APP_BASE_API_URL = 'http://10.84.121.21:8093'
## 开发环境预览 图片视频地址
VITE_APP_PREVIEW_URL = 'https://211.99.26.225:12125'
# 地图服务地址
VITE_APP_MAP_URL = 'https://211.99.26.225:18085'
# ?menu=systemManageMenu&page=disposeManage

Binary file not shown.

View File

@ -96,7 +96,7 @@ export function getStationList(params:any): AxiosPromise<any[]> {
* @param phone
* @param type 1- 2-
*/
export function sendSmsCode(phone: string, type: number = 1): AxiosPromise<any> {
export function sendSmsCode(phone: string, type = 1): AxiosPromise<any> {
return request({
url: '/sms/sendCode',
method: 'post',
@ -110,7 +110,7 @@ export function sendSmsCode(phone: string, type: number = 1): AxiosPromise<any>
* @param code
* @param type 1- 2-
*/
export function verifySmsCode(phone: string, code: string, type: number = 1): AxiosPromise<any> {
export function verifySmsCode(phone: string, code: string, type = 1): AxiosPromise<any> {
return request({
url: '/sms/verifyCode',
method: 'post',

21
frontend/src/api/map.ts Normal file
View File

@ -0,0 +1,21 @@
import request from '@/utils/request';
// 获取图例列表
export function getModuleMapLegendList(params?: { moduleId?: string }) {
const url = params?.moduleId
? `/api/wmp-sys-server/mapLegend/getModuleMapLegendList?moduleId=${params.moduleId}`
: '/api/wmp-sys-server/mapLegend/getModuleMapLegendList';
return request({
url,
method: 'get'
});
}
// 获取地图配置列表
export function getMapList(data: any) {
return request({
url: '/api/wmp-sys-server/mapmodule/getMapData',
method: 'post',
data
});
}

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="23px" viewBox="0 0 20 23" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>map-dongwujiuzhuzhanZWeijian</title>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="图例备份-4" transform="translate(-513.000000, -134.000000)" fill-rule="nonzero">
<g id="编组-9" transform="translate(511.000000, 73.000000)">
<g id="编组" transform="translate(0.000000, 60.000000)">
<g id="ExtinctionSquadGreen" transform="translate(2.000000, 1.000000)">
<path d="M10,0 C15.5228475,0 20,4.48367994 20,10.0145795 C20,14.5981513 16.9251889,18.4625155 12.7285722,19.6518192 C12.0801126,20.2555114 11.512719,20.9434728 11.0416667,21.6982555 L10.4241725,22.6876865 C10.2779707,22.9219506 9.96954214,22.993339 9.73527812,22.8471372 C9.67067972,22.806822 9.6161427,22.7522849 9.57582748,22.6876865 L8.95833333,21.6982555 C8.48728096,20.9434728 7.91988742,20.2555114 7.27176537,19.6511428 C3.07481109,18.4625155 0,14.5981513 0,10.0145795 C0,4.48367994 4.4771525,0 10,0 Z" id="路径" fill="#C1C1C1"></path>
<path d="M10,1 C5.02976365,1 1,5.03563882 1,10.0145795 C1,13.9819459 3.58136776,17.4404602 7.28412666,18.6110508 L7.77691051,18.7548749 L7.95375471,18.9197807 C8.56499354,19.489756 9.11007499,20.1266528 9.57875348,20.8184146 L9.80667838,21.1688117 L10,21.478 L10.1933216,21.1688117 C10.6366411,20.4584664 11.1579737,19.8014467 11.7470472,19.210064 L12.0471815,18.9198993 L12.2237777,18.7554947 L12.4559139,18.6897083 C16.2972752,17.6010825 19,14.0740888 19,10.0145795 C19,5.03563882 14.9702364,1 10,1 Z" id="路径" fill="#ABABAB"></path>
<g id="编组" transform="translate(4.000000, 3.000000)" fill="#FFFFFF">
<g id="路径" transform="translate(0.000000, 0.750000)">
<polygon points="10.875 4.5 10.875 11.25 1.125 11.25 1.125 4.5 1.875 4.5 1.875 10.5 10.125 10.5 10.125 4.5"></polygon>
<path d="M5.99949383,4.96447889 C6.67450486,4.35550941 7.69047373,4.34769678 8.37336406,4.92716844 L8.49146602,5.03674798 C9.14571049,5.70005088 9.16747093,6.74976529 8.56371984,7.43930899 L8.47321526,7.53528448 L6.39365573,9.594412 C6.19192974,9.79215339 5.87920854,9.80771639 5.66059081,9.64219611 L5.59803369,9.58710862 L3.50898437,7.51703373 C2.82358027,6.82214497 2.83161245,5.70390133 3.5257724,5.01849209 C4.20606465,4.34914721 5.29073738,4.32506093 5.99949383,4.96447889 Z M7.94691339,5.55282003 C7.57613564,5.18761167 6.9994374,5.15126266 6.58749808,5.45179201 L6.50188227,5.52135038 L5.99949201,5.97458791 L5.49710338,5.52134857 C5.08326332,5.14799497 4.44938056,5.1619074 4.05272796,5.55217536 C3.67961282,5.92058695 3.65089103,6.50579436 3.96642977,6.90431163 L4.03931446,6.98670364 L5.99925,8.92875 L7.94682981,7.00103888 C8.32016884,6.63319265 8.34924559,6.04776046 8.0339059,5.64936394 L7.96106138,5.5670035 L7.94691339,5.55282003 Z"></path>
<polygon points="0 5.25 6 -4.61860726e-14 12 5.25 11.4921155 5.75788455 6 1.0156924 0.507884548 5.75788455"></polygon>
</g>
</g>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="23px" viewBox="0 0 20 23" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>map-dwsjhDieliangmenshiZWeijian</title>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="图例备份-4" transform="translate(-271.000000, -74.000000)">
<g id="map-dieliangmen" transform="translate(269.000000, 73.000000)">
<rect id="矩形" x="0" y="0" width="24" height="24"></rect>
<path d="M12,1 C17.5228475,1 22,5.48367994 22,11.0145795 C22,15.5981513 18.9251889,19.4625155 14.7285722,20.6518192 C14.0801126,21.2555114 13.512719,21.9434728 13.0416667,22.6982555 L12.4241725,23.6876865 C12.2779707,23.9219506 11.9695421,23.993339 11.7352781,23.8471372 C11.6706797,23.806822 11.6161427,23.7522849 11.5758275,23.6876865 L10.9583333,22.6982555 C10.487281,21.9434728 9.91988742,21.2555114 9.27176537,20.6511428 C5.07481109,19.4625155 2,15.5981513 2,11.0145795 C2,5.48367994 6.4771525,1 12,1 Z" id="路径" fill="#C1C1C1" fill-rule="nonzero"></path>
<path d="M12,2 C7.02976365,2 3,6.03563882 3,11.0145795 C3,14.9819459 5.58136776,18.4404602 9.28412666,19.6110508 L9.77691051,19.7548749 L9.95375471,19.9197807 C10.5649935,20.489756 11.110075,21.1266528 11.5787535,21.8184146 L11.8066784,22.1688117 L12,22.478 L12.1933216,22.1688117 C12.6366411,21.4584664 13.1579737,20.8014467 13.7470472,20.210064 L14.0471815,19.9198993 L14.2237777,19.7554947 L14.4559139,19.6897083 C18.2972752,18.6010825 21,15.0740888 21,11.0145795 C21,6.03563882 16.9702364,2 12,2 Z" id="路径" fill="#ABABAB" fill-rule="nonzero"></path>
<path d="M14.7811001,10.5551365 C14.5138652,10.5551365 14.2963802,10.766443 14.2963802,11.0291867 L14.2963802,11.8132457 C14.2963802,12.0745982 14.5138638,12.2872959 14.7811001,12.2872959 C15.048335,12.2872959 15.26582,12.0745996 15.26582,11.8132457 L15.26582,11.0291867 C15.26582,10.766443 15.0483364,10.5551365 14.7811001,10.5551365 Z M16.0845832,5.98146365 L11.1023479,5.02502315 C11.0184816,5.00834105 10.9331933,5 10.8479054,5 C10.218196,5 9.72494835,5.46570874 9.72494835,6.06209443 L9.72494835,6.30120489 L8.36176364,6.08989838 C8.28216159,6.07738681 8.20113819,6.07182609 8.12295707,6.07182609 C7.48329742,6.07182609 7,6.47219703 7,7.00324357 L7,14.999536 C7,15.5305825 7.48329742,15.9295637 8.12295707,15.9295637 C8.20113763,15.9295637 8.28073899,15.924003 8.36176364,15.9114914 L9.72636942,15.6987951 L9.72636942,15.9379056 C9.72636942,16.5329001 10.2196171,17 10.8493265,17 C10.9346144,17 11.0199022,16.9916589 11.1023465,16.976367 L16.0859987,16.0185368 C16.606255,15.9184442 17,15.4374428 17,14.9008358 L17,7.09916829 C16.9971571,6.56255988 16.6048326,6.08155937 16.0845762,5.98146731 L16.0845832,5.98146365 Z M8.24093928,15.1691309 C7.97512543,15.2094459 7.76474861,15.1010123 7.76474861,14.9981392 L7.76474861,7.000461 C7.76474861,6.897588 7.9765465,6.7877647 8.23951821,6.82946927 L9.72353006,7.06023828 L9.72353006,14.9383646 L8.24094901,15.1691336 L8.24093928,15.1691309 Z M16.2309965,14.896656 C16.2309965,15.0732082 16.0959574,15.2483707 15.9367529,15.2789542 L10.9531008,16.2367845 C10.9189856,16.2437354 10.883449,16.2465157 10.8479124,16.2465157 C10.6375355,16.2465157 10.491125,16.1186196 10.491125,15.9351158 L10.491125,6.06070476 C10.491125,5.84661731 10.7015018,5.7103812 10.9531008,5.75903608 L15.9381837,6.71686637 C16.0973881,6.74884037 16.2324273,6.92400215 16.2324273,7.09916461 L16.2324273,14.8966614 L16.2309965,14.896656 Z" id="形状" fill="#FFFFFF" fill-rule="nonzero" transform="translate(12.000000, 11.000000) rotate(-90.000000) translate(-12.000000, -11.000000) "></path>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="23px" viewBox="0 0 20 23" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>map-dwsjhGeshuimuqiangZWeijian</title>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="图例备份-4" transform="translate(-271.000000, -130.000000)">
<g id="编组-9备份-4" transform="translate(269.000000, 73.000000)">
<g id="map-geshuimuqiang" transform="translate(0.000000, 56.000000)">
<rect id="矩形" x="0" y="0" width="24" height="24"></rect>
<path d="M12,1 C17.5228475,1 22,5.48367994 22,11.0145795 C22,15.5981513 18.9251889,19.4625155 14.7285722,20.6518192 C14.0801126,21.2555114 13.512719,21.9434728 13.0416667,22.6982555 L12.4241725,23.6876865 C12.2779707,23.9219506 11.9695421,23.993339 11.7352781,23.8471372 C11.6706797,23.806822 11.6161427,23.7522849 11.5758275,23.6876865 L10.9583333,22.6982555 C10.487281,21.9434728 9.91988742,21.2555114 9.27176537,20.6511428 C5.07481109,19.4625155 2,15.5981513 2,11.0145795 C2,5.48367994 6.4771525,1 12,1 Z" id="路径" fill="#C1C1C1" fill-rule="nonzero"></path>
<path d="M12,2 C7.02976365,2 3,6.03563882 3,11.0145795 C3,14.9819459 5.58136776,18.4404602 9.28412666,19.6110508 L9.77691051,19.7548749 L9.95375471,19.9197807 C10.5649935,20.489756 11.110075,21.1266528 11.5787535,21.8184146 L11.8066784,22.1688117 L12,22.478 L12.1933216,22.1688117 C12.6366411,21.4584664 13.1579737,20.8014467 13.7470472,20.210064 L14.0471815,19.9198993 L14.2237777,19.7554947 L14.4559139,19.6897083 C18.2972752,18.6010825 21,15.0740888 21,11.0145795 C21,6.03563882 16.9702364,2 12,2 Z" id="路径" fill="#ABABAB" fill-rule="nonzero"></path>
<path d="M14.6829236,6 C14.8849788,6 15.0487771,6.16398891 15.0487771,6.36627918 L15.0487771,6.73255837 L16.6341461,6.73255837 C16.8225904,6.73256742 16.9802012,6.87588227 16.9982927,7.06367475 L17,7.09883755 L17,14.9011619 C17,15.1034522 16.8362017,15.2674411 16.6341465,15.2674411 L15.0487775,15.2674411 L15.0487775,15.6337203 C15.0487775,15.8223662 14.9056362,15.9801673 14.7180631,15.998289 L14.6829236,16 L7.36585352,16 C7.16379833,16 7,15.8360111 7,15.6337208 L7,6.3662797 C7,6.16398938 7.16379833,6 7.36585351,6 L14.6829236,6 Z M14.3170701,6.73255837 L7.73170701,6.73255837 L7.73170701,15.2674411 L14.3170701,15.2674411 L14.3170701,6.73255837 Z M16.2682926,7.46511674 L15.0487771,7.46511674 L15.0487771,14.5348827 L16.2682926,14.5348827 L16.2682926,7.46511674 Z M12.7785228,10.301827 C12.9365516,10.4045553 12.9908088,10.6106331 12.9038958,10.7779941 L12.8860909,10.8085174 L10.6299981,14.2881696 C10.5212801,14.4586817 10.2950798,14.5086731 10.124767,14.3998281 C9.96414932,14.2971801 9.90912496,14.0882916 9.99829146,13.9196933 L10.0163403,13.88917 L12.2724331,10.4095178 C12.3824826,10.2398641 12.6090663,10.1916492 12.7785228,10.301827 Z M11.8029138,8.10415051 C11.9609427,8.20688016 12.0151999,8.41295798 11.9282868,8.58031896 L11.910482,8.61084226 L9.65438916,12.0904945 C9.5456711,12.2610066 9.31947085,12.3109969 9.14915804,12.2021528 C8.98854035,12.0995048 8.93351598,11.8906163 9.02268249,11.7220169 L9.0407313,11.6914936 L11.2968241,8.2118413 C11.4068737,8.04218763 11.6334574,7.9939727 11.8029138,8.10415051 Z" id="形状结合" fill="#FFFFFF" fill-rule="nonzero"></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="23px" viewBox="0 0 20 23" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>map-dwsjhQianzhidangqiangZWeijian</title>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="图例备份-4" transform="translate(-271.000000, -102.000000)">
<g id="编组-9备份-4" transform="translate(269.000000, 73.000000)">
<g id="map-qianzhidangqiang" transform="translate(0.000000, 28.000000)">
<rect id="矩形" x="0" y="0" width="24" height="24"></rect>
<path d="M12,1 C17.5228475,1 22,5.48367994 22,11.0145795 C22,15.5981513 18.9251889,19.4625155 14.7285722,20.6518192 C14.0801126,21.2555114 13.512719,21.9434728 13.0416667,22.6982555 L12.4241725,23.6876865 C12.2779707,23.9219506 11.9695421,23.993339 11.7352781,23.8471372 C11.6706797,23.806822 11.6161427,23.7522849 11.5758275,23.6876865 L10.9583333,22.6982555 C10.487281,21.9434728 9.91988742,21.2555114 9.27176537,20.6511428 C5.07481109,19.4625155 2,15.5981513 2,11.0145795 C2,5.48367994 6.4771525,1 12,1 Z" id="路径" fill="#C1C1C1" fill-rule="nonzero"></path>
<path d="M12,2 C7.02976365,2 3,6.03563882 3,11.0145795 C3,14.9819459 5.58136776,18.4404602 9.28412666,19.6110508 L9.77691051,19.7548749 L9.95375471,19.9197807 C10.5649935,20.489756 11.110075,21.1266528 11.5787535,21.8184146 L11.8066784,22.1688117 L12,22.478 L12.1933216,22.1688117 C12.6366411,21.4584664 13.1579737,20.8014467 13.7470472,20.210064 L14.0471815,19.9198993 L14.2237777,19.7554947 L14.4559139,19.6897083 C18.2972752,18.6010825 21,15.0740888 21,11.0145795 C21,6.03563882 16.9702364,2 12,2 Z" id="路径" fill="#ABABAB" fill-rule="nonzero"></path>
<path d="M10.0519815,12.9205132 L7.7118534,12.9205132 L7.72330394,14.2987312 L10.0519828,14.2987312 L10.0519828,15 L7,15 L7,10.1469013 L10.0519815,10.1469013 L10.0519815,8.77366828 L7.72870375,8.77366828 L7.72870375,10.1469013 L7,10.1469013 L7,6 L17,6 L17,8.07937399 L16.29493,8.07937399 L16.29493,6.70579619 L13.9480371,6.70579619 L13.9480759,8.07937399 L17,8.07937399 L17,12.2262753 L16.29493,12.2262753 L16.3021599,10.8530423 L13.9480759,10.8530423 L13.9480759,12.2262753 L17,12.2262753 L17,15 L10.0519828,15 L10.0519815,12.9205132 Z M16.2817281,14.2936887 L16.2817281,12.932528 L10.770252,12.932528 L10.770252,14.2936887 L16.2817281,14.2936887 Z M13.2297466,12.2143147 L13.2297466,10.853154 L7.71827055,10.853154 L7.71827055,12.2143147 L13.2297466,12.2143147 Z M16.2817281,10.1467874 L16.2817281,8.78562666 L10.770252,8.78562666 L10.770252,10.1467874 L16.2817281,10.1467874 Z M13.2297466,8.06741336 L13.2297466,6.70625266 L7.71827055,6.70625266 L7.71827055,8.06741336 L13.2297466,8.06741336 Z" id="形状" fill="#FFFFFF" fill-rule="nonzero"></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.9 KiB

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="23px" viewBox="0 0 20 23" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>map-dwsjhQitaZWeijian</title>
<g id="页面-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="图例备份-4" transform="translate(-271.000000, -158.000000)">
<g id="编组-9备份-4" transform="translate(269.000000, 73.000000)">
<g id="map-dwsjhQita" transform="translate(0.000000, 84.000000)">
<rect id="矩形" x="0" y="0" width="24" height="24"></rect>
<path d="M12,1 C17.5228475,1 22,5.48367994 22,11.0145795 C22,15.5981513 18.9251889,19.4625155 14.7285722,20.6518192 C14.0801126,21.2555114 13.512719,21.9434728 13.0416667,22.6982555 L12.4241725,23.6876865 C12.2779707,23.9219506 11.9695421,23.993339 11.7352781,23.8471372 C11.6706797,23.806822 11.6161427,23.7522849 11.5758275,23.6876865 L10.9583333,22.6982555 C10.487281,21.9434728 9.91988742,21.2555114 9.27176537,20.6511428 C5.07481109,19.4625155 2,15.5981513 2,11.0145795 C2,5.48367994 6.4771525,1 12,1 Z" id="路径" fill="#C1C1C1" fill-rule="nonzero"></path>
<path d="M12,2 C7.02976365,2 3,6.03563882 3,11.0145795 C3,14.9819459 5.58136776,18.4404602 9.28412666,19.6110508 L9.77691051,19.7548749 L9.95375471,19.9197807 C10.5649935,20.489756 11.110075,21.1266528 11.5787535,21.8184146 L11.8066784,22.1688117 L12,22.478 L12.1933216,22.1688117 C12.6366411,21.4584664 13.1579737,20.8014467 13.7470472,20.210064 L14.0471815,19.9198993 L14.2237777,19.7554947 L14.4559139,19.6897083 C18.2972752,18.6010825 21,15.0740888 21,11.0145795 C21,6.03563882 16.9702364,2 12,2 Z" id="路径" fill="#ABABAB" fill-rule="nonzero"></path>
<path d="M17.3285024,6.28571322 L12.4556195,4.09751195 C12.1661029,3.96749602 11.8340457,3.96749602 11.5445304,4.09751195 L6.67164751,6.28571322 C6.263666,6.46887583 6,6.88024173 6,7.33364584 L6,13.6662796 C6,14.1196838 6.263666,14.5310496 6.67164751,14.7143621 L11.5443805,16.9025633 C11.6891381,16.9675712 11.8445316,17 11.9999251,17 C12.1553185,17 12.310712,16.967421 12.4554696,16.9025633 L17.3283525,14.7143621 C17.736334,14.5310484 18,14.1196825 18,13.6662796 L18,7.33364584 C18,6.88024173 17.736334,6.46887583 17.3283525,6.28556342 L17.3285024,6.28571322 Z M17.1138759,13.6662873 C17.1138759,13.7632736 17.0574498,13.8511015 16.9702998,13.8902871 L12.0975668,16.0784884 C12.0356754,16.1062631 11.9646253,16.1062631 11.9027342,16.0784884 L7.02985136,13.8902871 L7.02985138,13.8902871 C6.94259532,13.8510798 6.88627531,13.7632546 6.88627531,13.6662873 L6.88627531,7.33365346 C6.88627531,7.2366671 6.94270136,7.14883918 7.02985138,7.10965362 L11.9027342,4.92145235 C11.9646257,4.89367765 12.0356758,4.89367765 12.0975668,4.92145235 L16.9702998,7.10965362 C17.0575977,7.14883854 17.1138759,7.2368169 17.1138759,7.33365346 L17.1138759,13.6662873 L17.1138759,13.6662873 Z M9.17611666,10.4999704 L8.38497002,10.4999704 L8.38497002,10.4999703 C8.38497002,10.9440712 8.73917812,11.3040855 9.17611666,11.3040855 C9.61305521,11.3040855 9.9672633,10.9440712 9.9672633,10.4999703 C9.9672633,10.4999702 9.9672633,10.4999702 9.9672633,10.4999702 L9.9672633,10.4999702 C9.9672633,10.0558693 9.61305521,9.69585494 9.17611666,9.69585494 C8.73917812,9.69585494 8.38497002,10.0558693 8.38497002,10.4999702 L9.17611666,10.4999704 Z M12.0260792,10.4999704 L11.2349326,10.4999704 L11.2349326,10.4999705 C11.2349326,10.9440714 11.5891406,11.3040858 12.0260792,11.3040858 C12.4630177,11.3040858 12.8172258,10.9440714 12.8172258,10.4999705 L12.8172258,10.4999705 C12.8172258,10.0558695 12.4630177,9.69585518 12.0260792,9.69585518 C11.5891406,9.69585518 11.2349326,10.0558695 11.2349326,10.4999705 C11.2349326,10.4999705 11.2349326,10.4999705 11.2349326,10.4999705 L12.0260792,10.4999704 Z M14.8758918,10.4999704 L14.0847452,10.4999704 L14.0847452,10.5000713 C14.0847452,10.9441722 14.4389533,11.3041866 14.8758918,11.3041866 C15.3128304,11.3041866 15.6670385,10.9441722 15.6670385,10.5000713 C15.6670385,10.5000039 15.6670385,10.4999366 15.6670385,10.4998692 L15.6670385,10.4997682 C15.6670385,10.0556672 15.3128304,9.69565288 14.8758918,9.69565288 C14.4389533,9.69565288 14.0847452,10.0556672 14.0847452,10.4997682 C14.0847452,10.4998355 14.0847452,10.4999029 14.0847452,10.4999702 L14.8758918,10.4999704 Z" id="形状" fill="#FFFFFF" fill-rule="nonzero"></path>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>map-dxsdzYijian</title>
<defs>
<path d="M10,0 C15.5228475,0 20,4.4771525 20,10 C20,15.5228475 15.5228475,20 10,20 C4.4771525,20 0,15.5228475 0,10 C0,4.4771525 4.4771525,0 10,0 Z" id="path-1"></path>
</defs>
<g id="1-首页" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="1.1-首页-水电开发-全国" transform="translate(-158.000000, -812.000000)">
<g id="图例备份-4" transform="translate(16.000000, 737.000000)">
<g id="编组-9" transform="translate(142.000000, 74.000000)">
<g id="map-shuikudaxing-yijian" transform="translate(0.000000, 1.000000)">
<g id="路径" fill-rule="nonzero">
<use fill="#499934" xlink:href="#path-1"></use>
<use fill="#71B603" xlink:href="#path-1"></use>
<use fill="#78C300" xlink:href="#path-1"></use>
</g>
<path d="M10,1.66666667 C14.6023729,1.66666667 18.3333333,5.39762709 18.3333333,10 L18.3333333,10 L1.66666667,10 L1.67048694,9.74522729 C1.80514922,5.26072284 5.48285621,1.66666667 10,1.66666667 Z" id="形状结合" fill="#FFFFFF"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>map-dxsdzYijian</title>
<defs>
<path d="M10,0 C15.5228475,0 20,4.4771525 20,10 C20,15.5228475 15.5228475,20 10,20 C4.4771525,20 0,15.5228475 0,10 C0,4.4771525 4.4771525,0 10,0 Z" id="path-1"></path>
</defs>
<g id="1-首页" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="1.1-首页-水电开发-全国" transform="translate(-158.000000, -812.000000)">
<g id="图例备份-4" transform="translate(16.000000, 737.000000)">
<g id="编组-9" transform="translate(142.000000, 74.000000)">
<g id="map-shuikudaxing-yijian" transform="translate(0.000000, 1.000000)">
<g id="路径" fill-rule="nonzero">
<use fill="#6B8E23" xlink:href="#path-1"></use> <!-- 前两个调整为较深的橄榄绿 -->
<use fill="#9ACD32" xlink:href="#path-1"></use> <!-- 中间的黄绿色 -->
<use fill="#EECA47" xlink:href="#path-1"></use> <!-- 最后一个改为指定的黄橙色 -->
</g>
<path d="M10,1.66666667 C14.6023729,1.66666667 18.3333333,5.39762709 18.3333333,10 L18.3333333,10 L1.66666667,10 L1.67048694,9.74522729 C1.80514922,5.26072284 5.48285621,1.66666667 10,1.66666667 Z" id="形状结合" fill="#FFFFFF"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>map-dxsdzYijian</title>
<defs>
<path d="M10,0 C15.5228475,0 20,4.4771525 20,10 C20,15.5228475 15.5228475,20 10,20 C4.4771525,20 0,15.5228475 0,10 C0,4.4771525 4.4771525,0 10,0 Z" id="path-1"></path>
</defs>
<g id="1-首页" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="1.1-首页-水电开发-全国" transform="translate(-158.000000, -812.000000)">
<g id="图例备份-4" transform="translate(16.000000, 737.000000)">
<g id="编组-9" transform="translate(142.000000, 74.000000)">
<g id="map-shuikudaxing-yijian" transform="translate(0.000000, 1.000000)">
<g id="路径" fill-rule="nonzero">
<use fill="#C5862B" xlink:href="#path-1"></use> <!-- 前两个调整为较深的橄榄绿 -->
<use fill="#E69730" xlink:href="#path-1"></use> <!-- 中间的黄绿色 -->
<use fill="#F7A737" xlink:href="#path-1"></use> <!-- 最后一个改为指定的黄橙色 -->
</g>
<path d="M10,1.66666667 C14.6023729,1.66666667 18.3333333,5.39762709 18.3333333,10 L18.3333333,10 L1.66666667,10 L1.67048694,9.74522729 C1.80514922,5.26072284 5.48285621,1.66666667 10,1.66666667 Z" id="形状结合" fill="#FFFFFF"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="20px" viewBox="0 0 20 20" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>map-dxsdzYijian</title>
<defs>
<path d="M10,0 C15.5228475,0 20,4.4771525 20,10 C20,15.5228475 15.5228475,20 10,20 C4.4771525,20 0,15.5228475 0,10 C0,4.4771525 4.4771525,0 10,0 Z" id="path-1"></path>
</defs>
<g id="1-首页" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="1.1-首页-水电开发-全国" transform="translate(-158.000000, -812.000000)">
<g id="图例备份-4" transform="translate(16.000000, 737.000000)">
<g id="编组-9" transform="translate(142.000000, 74.000000)">
<g id="map-shuikudaxing-yijian" transform="translate(0.000000, 1.000000)">
<g id="路径" fill-rule="nonzero">
<use fill="#B24444" xlink:href="#path-1"></use> <!-- 前两个调整为较深的橄榄绿 -->
<use fill="#D44D4D" xlink:href="#path-1"></use> <!-- 中间的黄绿色 -->
<use fill="#E55555" xlink:href="#path-1"></use> <!-- 最后一个改为指定的黄橙色 -->
</g>
<path d="M10,1.66666667 C14.6023729,1.66666667 18.3333333,5.39762709 18.3333333,10 L18.3333333,10 L1.66666667,10 L1.67048694,9.74522729 C1.80514922,5.26072284 5.48285621,1.66666667 10,1.66666667 Z" id="形状结合" fill="#FFFFFF"></path>
</g>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -20,45 +20,81 @@
</div>
</template>
<script setup lang="ts">
import { ref, watch } from "vue";
import { useUiStore } from "@/store/modules/ui";
import shiliangImg from "@/assets/images/map-shiliangtu.png";
import dixingImg from "@/assets/images/map-dixingtu.png";
import yingxiangImg from "@/assets/images/map-yingxiangtu.png";
import nineSectionsShiliangImg from "@/assets/images/nineSections-shiliang.png";
import nineSectionsDixingImg from "@/assets/images/nineSections-dixing.png";
import nineSectionsYingxiangImg from "@/assets/images/nineSections-yingxiang.png";
import { ref, watch } from 'vue';
import { useUiStore } from '@/store/modules/ui';
import { useMapStore } from '@/store/modules/map';
import { layerConfig2Flat } from '@/components/gis/gisUtils';
import shiliangImg from '@/assets/images/map-shiliangtu.png';
import dixingImg from '@/assets/images/map-dixingtu.png';
import yingxiangImg from '@/assets/images/map-yingxiangtu.png';
import nineSectionsShiliangImg from '@/assets/images/nineSections-shiliang.png';
import nineSectionsDixingImg from '@/assets/images/nineSections-dixing.png';
import nineSectionsYingxiangImg from '@/assets/images/nineSections-yingxiang.png';
const props = defineProps({
map: {
type: Object,
default: () => {},
},
default: () => {}
}
});
const uiStore = useUiStore();
const mapStore = useMapStore();
const drawerOpen = ref(uiStore.drawerOpen);
// store drawerOpen
watch(
() => uiStore.drawerOpen,
(newVal) => {
newVal => {
drawerOpen.value = newVal;
}
);
const layers = [
{ key: "s_province_boundaries", name: "矢量", img: shiliangImg },
{ key: "BASEMAP-white", name: "地形", img: dixingImg },
{ key: "BASEMAP-img", name: "影像", img: yingxiangImg },
{ key: 's_province_boundaries', name: '矢量', img: shiliangImg },
{ key: 'BASEMAP-white', name: '地形', img: dixingImg },
{ key: 'BASEMAP-img', name: '影像', img: yingxiangImg }
];
const nineSectionsImg: any = {
s_province_boundaries: nineSectionsShiliangImg,
"BASEMAP-white": nineSectionsDixingImg,
"BASEMAP-img": nineSectionsYingxiangImg,
'BASEMAP-white': nineSectionsDixingImg,
'BASEMAP-img': nineSectionsYingxiangImg
};
const activeKey = ref(layers[0].key);
/**
* 判断图层管理中的基础底图customBaseLayer是否被选中
*/
const isCustomBaseLayerChecked = (): boolean => {
const layerConfig = layerConfig2Flat(mapStore.layerData);
const customBaseLayer = layerConfig.find(
(item: any) => item.key === 'customBaseLayer'
);
if (!customBaseLayer) {
return false;
}
//
const checkedKeys = mapStore.checkedLayerKeys;
if (checkedKeys.includes('customBaseLayer')) {
return true;
}
//
if (customBaseLayer.children && customBaseLayer.children.length > 0) {
return customBaseLayer.children.some((child: any) =>
checkedKeys.includes(child.key)
);
}
return false;
};
const handleSwitch = (key: string) => {
//
const customBaseLayerChecked = isCustomBaseLayerChecked();
activeKey.value = key;
props.map.baseLayerSwitcher(key);
props.map.baseLayerSwitcher(key, customBaseLayerChecked ? 1 : 0);
};
</script>

View File

@ -136,7 +136,7 @@ const getList = async (filter?: Record<string, any>) => {
const res = await props.listUrl(params);
let finalRecords: any[] = [];
let finalTotal: number = 0;
let finalTotal = 0;
if (props.transformData) {
const result = props.transformData(res);

View File

@ -1188,7 +1188,7 @@ const WATabs: Array<any> = [
const handleTabs = (modaldata: any) => {
console.log('modaldata', modaldata);
if (!modaldata?.sttp) return;
let sttp = modaldata?.sttp ? modaldata?.sttp.toUpperCase() : '';
const sttp = modaldata?.sttp ? modaldata?.sttp.toUpperCase() : '';
console.log('sttp', sttp);
switch (sttp) {
case 'ENG':

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,15 @@
// import { Session } from '@zebras/qgc-share/service/Session'
import domtoimage from 'dom-to-image'
import { offset2, drawDotImg2, drawDotImg1, offset1, drawDotImg3, offset3, drawDotImg5, offset5 } from '@/utils/GisUrlList'
import domtoimage from 'dom-to-image';
import {
offset2,
drawDotImg2,
drawDotImg1,
offset1,
drawDotImg3,
offset3,
drawDotImg5,
offset5
} from '@/utils/GisUrlList';
declare global {
interface Window {
__lyConfigs?: {
@ -10,14 +19,16 @@ declare global {
__mapMode?: string; // 建议同时声明代码中用到的其他全局变量
}
}
console.log(import.meta.env.VITE_APP_PREVIEW_URL);
/**
*
* @param {Number} height
*/
const A = 40487.57
const B = 0.00007096758
const C = 91610.74
const D = -40467.74
const A = 40487.57;
const B = 0.00007096758;
const C = 91610.74;
const D = -40467.74;
/**
*
@ -25,23 +36,23 @@ const D = -40467.74
* @returns nameEn为下标的图例数据
*/
export const legendData2Obj = (data: any[]) => {
const _tempData: any = {}
const _tempData: any = {};
const f = (_data: any[]) => {
_data.forEach((item) => {
_data.forEach(item => {
// childrenList有值表示这是一个分组
if (item?.childrenList && item.childrenList?.length > 0) {
f(item.childrenList)
f(item.childrenList);
} else {
if (item.nameEn.includes('_测试')) {
item.nameEn = item.nameEn.split('_测试')[0]
item.nameEn = item.nameEn.split('_测试')[0];
}
_tempData[item.nameEn] = item
}
})
}
f(data)
return _tempData
_tempData[item.nameEn] = item;
}
});
};
f(data);
return _tempData;
};
/**
* item中
@ -49,48 +60,83 @@ export const legendData2Obj = (data: any[]) => {
* @param index - item的索引
* @param labelType -
*/
export const appendOffsetPropties = (item: any, index: any, labelType: number = 2) => {
let drawDotImg = null
let offset = null
export const appendOffsetPropties = (
item: any,
index: any,
labelType = 2
) => {
let drawDotImg = null;
let offset = null;
if (labelType == 2) {
drawDotImg = drawDotImg1
offset = offset1
addItemProperty(item, index, drawDotImg, offset)
drawDotImg = drawDotImg1;
offset = offset1;
addItemProperty(item, index, drawDotImg, offset);
} else if (labelType == 3) {
drawDotImg = drawDotImg2
offset = offset2
addItemProperty(item, index, drawDotImg, offset)
drawDotImg = drawDotImg2;
offset = offset2;
addItemProperty(item, index, drawDotImg, offset);
} else if (labelType == 4) {
drawDotImg = drawDotImg3
offset = offset3
addItemProperty2(item, index, drawDotImg, offset)
drawDotImg = drawDotImg3;
offset = offset3;
addItemProperty2(item, index, drawDotImg, offset);
} else if (labelType == 5) {
drawDotImg = drawDotImg5
offset = offset5
addItemProperty2(item, index, drawDotImg, offset)
}
drawDotImg = drawDotImg5;
offset = offset5;
addItemProperty2(item, index, drawDotImg, offset);
}
};
const addItemProperty2 = (item: any, index: any, drawDotImg: any, offset: any) => {
if (!drawDotImg || !offset) return
item.icon_image = index % 2 !== 0 ? drawDotImg[item.anchoPointState]?.left || '' : drawDotImg[item.anchoPointState]?.right || ''
item.text_anchor = index % 2 !== 0 ? 'right' : 'left'
item.text_offset = offset[item.icon_image]?.text_offset ?? [-10, -1.8]
item.text_offset2 = offset[item.icon_image]?.text_offset2 ?? [-10, -1.8]
item.icon_offset = [offset[item.icon_image]?.icon_x ?? -200, offset[item.icon_image]?.icon_y ?? -50]
item.icon_offset2 = offset[item.icon_image]?.icon_offset2 ?? [-200, -50]
item.billboard_offset = [offset[item.icon_image]?.billboard_x ?? -80, offset[item.icon_image]?.billboard_y ?? -15]
item.label_offset = offset[item.icon_image]?.labelOffset ?? [100, 41]
}
const addItemProperty2 = (
item: any,
index: any,
drawDotImg: any,
offset: any
) => {
if (!drawDotImg || !offset) return;
item.icon_image =
index % 2 !== 0
? drawDotImg[item.anchoPointState]?.left || ''
: drawDotImg[item.anchoPointState]?.right || '';
item.text_anchor = index % 2 !== 0 ? 'right' : 'left';
item.text_offset = offset[item.icon_image]?.text_offset ?? [-10, -1.8];
item.text_offset2 = offset[item.icon_image]?.text_offset2 ?? [-10, -1.8];
item.icon_offset = [
offset[item.icon_image]?.icon_x ?? -200,
offset[item.icon_image]?.icon_y ?? -50
];
item.icon_offset2 = offset[item.icon_image]?.icon_offset2 ?? [-200, -50];
item.billboard_offset = [
offset[item.icon_image]?.billboard_x ?? -80,
offset[item.icon_image]?.billboard_y ?? -15
];
item.label_offset = offset[item.icon_image]?.labelOffset ?? [100, 41];
};
export const addItemProperty = (item: any, index: any, drawDotImg: any, offset: any) => {
if (!drawDotImg || !offset) return
item.icon_image = index % 2 !== 0 ? drawDotImg[item.anchoPointState]?.left || '' : drawDotImg[item.anchoPointState]?.right || ''
item.text_offset = [offset[item.icon_image]?.text_x ?? -10, offset[item.icon_image]?.text_y ?? -1.8]
item.icon_offset = [offset[item.icon_image]?.icon_x ?? -200, offset[item.icon_image]?.icon_y ?? -50]
item.billboard_offset = [offset[item.icon_image]?.billboard_x ?? -80, offset[item.icon_image]?.billboard_y ?? -15]
item.label_offset = offset[item.icon_image]?.labelOffset ?? [100, 41]
}
export const addItemProperty = (
item: any,
index: any,
drawDotImg: any,
offset: any
) => {
if (!drawDotImg || !offset) return;
item.icon_image =
index % 2 !== 0
? drawDotImg[item.anchoPointState]?.left || ''
: drawDotImg[item.anchoPointState]?.right || '';
item.text_offset = [
offset[item.icon_image]?.text_x ?? -10,
offset[item.icon_image]?.text_y ?? -1.8
];
item.icon_offset = [
offset[item.icon_image]?.icon_x ?? -200,
offset[item.icon_image]?.icon_y ?? -50
];
item.billboard_offset = [
offset[item.icon_image]?.billboard_x ?? -80,
offset[item.icon_image]?.billboard_y ?? -15
];
item.label_offset = offset[item.icon_image]?.labelOffset ?? [100, 41];
};
/**
* popName属性
@ -106,12 +152,13 @@ export const setPopName = (item: any) => {
item.popName = item?.ftp;
}
} else if (item.sttp === 'WE_FISH') {
item.popName = item.fishList?.[0]?.fishName + `(${item.fishList?.[0]?.ptypeName})`
item.popName1 = item.total + "尾"
item.popName =
item.fishList?.[0]?.fishName + `(${item.fishList?.[0]?.ptypeName})`;
item.popName1 = item.total + '尾';
} else {
item.popName = item.stnm || item.titleName;
}
}
};
/**
* key
@ -119,25 +166,25 @@ export const setPopName = (item: any) => {
* @returns key数组
*/
export const getCheckedLayerConfigs = (data: any[]): any[] => {
const rs: any[] = []
const rs: any[] = [];
const f = (arr: any[] = []) => {
let count = 0
let count = 0;
arr.forEach((item: any) => {
if (item?.children && item.children.length > 0) {
const childrenCount = f(item.children)
const childrenCount = f(item.children);
if (childrenCount) {
rs.push(item.key)
rs.push(item.key);
}
} else if (item.checked) {
count++
rs.push(item.key) // 对应图例的layerCode
}
})
return count
}
f(data)
return rs
count++;
rs.push(item.key); // 对应图例的layerCode
}
});
return count;
};
f(data);
return rs;
};
// type mapType = "" | "pointMap" | "gisLayer"
@ -147,77 +194,128 @@ export const getCheckedLayerConfigs = (data: any[]): any[] => {
* @returns
*/
export const layerConfig2Flat = (data: any): any[] => {
const rs: any[] = []
const rs: any[] = [];
const f = (arr: any[] = []) => {
arr.forEach((item: any) => {
const { type } = item
const { type } = item;
if (type) {
if (type == 'GISMap') {
if (item?.children && item.children.length > 0) {
f(item.children)
f(item.children);
} else {
rs.push(item)
rs.push(item);
}
} else if (type == 'pointMap') {
if (item.url || item.title === '国家水文站' || item.title === '自建水文站') {
rs.push(item)
if (
item.url ||
item.title === '国家水文站' ||
item.title === '自建水文站'
) {
rs.push(item);
} else if (item.children.length > 0) {
f(item.children)
f(item.children);
}
}
} else if (item.children.length > 0) {
f(item.children)
f(item.children);
}
})
});
};
f(data);
return rs;
};
/**
* URL
* @param layerConfigsArr -
* @param urlList - URL
* @returns
*/
export const replaceUrl = (layerConfigsArr: any[], urlList: any[]): any[] => {
const bDict: Record<string, any[]> = {};
// 构建 URL 映射字典
for (let i = 0; i < urlList.length; i++) {
const key = urlList[i].url;
const title = urlList[i].title;
const keyType = urlList[i].keyType;
if (!bDict[key]) bDict[key] = [];
if (!bDict[title]) bDict[title] = [];
if (!bDict[keyType]) bDict[keyType] = [];
bDict[key].push(urlList[i]);
bDict[title].push(urlList[i]);
if (bDict[keyType]) {
bDict[keyType].push(urlList[i]);
}
f(data)
return rs
}
// 替换图层配置中的 URL
for (let i = 0; i < layerConfigsArr.length; i++) {
const obj = layerConfigsArr[i];
const key = obj.url;
const title = obj.title;
const keyType = obj.key;
const bObjList = bDict[keyType] || bDict[title] || bDict[key];
if (bObjList && bObjList.length > 0) {
const bObj = bObjList[0];
obj.url = bObj.url;
obj.urlThd = bObj.url;
obj.params = bObj.params;
obj.orders = bObj.orders;
} else {
obj.url = '';
}
}
return layerConfigsArr;
};
/**
*
* @param config -
* @returns
*/
export const getMapConfig = () => {
// const mapBaseUrls = MemoryCache.get('mapBaseUrls') || {}
// const r = { ...config }
// const { urlType } = r
// const baseUrlObj = mapBaseUrls[urlType as string]
// if (baseUrlObj) {
// r.url = baseUrlObj.url + r.url // 'http://localhost:8088'
export const getMapConfig = (config: any) => {
const r = { ...config };
const baseUrlObj = import.meta.env.VITE_APP_MAP_URL;
if (baseUrlObj) {
r.url = baseUrlObj + r.url; // 'http://localhost:8088'
r.url_3d = baseUrlObj + r.url_3d;
// r.url = baseUrlObj.url + r.url //baseUrlObj.url
// r.url_3d = baseUrlObj.url + r.url_3d
// // r.url = baseUrlObj.url + r.url //baseUrlObj.url
// // r.url_3d = baseUrlObj.url + r.url_3d
// if (r.geojson_url) {
// r.geojson_url = baseUrlObj.url + r.geojson_url + `&token=${Session.getToken()?.accessToken}`
// }
// }
// return r
if (r.geojson_url) {
r.geojson_url = baseUrlObj + r.geojson_url;
}
}
return r;
};
/**
*
*/
export const resetMapElPos = () => {
const legend = document.querySelector('#qgc-legendtl') as HTMLElement // 图例
const legend = document.querySelector('#qgc-legendtl') as HTMLElement; // 图例
// const filter = document.querySelector('#map-filter-container') as HTMLElement // 全局表单
const controller = document.querySelector('#map-controller') as HTMLElement // 地图工具栏
const baselayer = document.querySelector('#map-baselayer') as HTMLElement // 底图模式切换
const controller = document.querySelector('#map-controller') as HTMLElement; // 地图工具栏
const baselayer = document.querySelector('#map-baselayer') as HTMLElement; // 底图模式切换
if (legend) {
legend.style.left = '0'
legend.style.bottom = '0'
legend.style.left = '0';
legend.style.bottom = '0';
}
if (controller) {
controller.style.right = '480px'
controller.style.bottom = '114px'
controller.style.right = '480px';
controller.style.bottom = '114px';
}
if (baselayer) {
baselayer.style.right = '480px'
baselayer.style.bottom = '20px'
}
baselayer.style.right = '480px';
baselayer.style.bottom = '20px';
}
};
/**
*
@ -225,7 +323,8 @@ export const resetMapElPos = () => {
* @param position -
* @returns
*/
const getListByPosition = (data: any, position: string) => data?.data?.filter((el: any) => el.position === position && el.code)
const getListByPosition = (data: any, position: string) =>
data?.data?.filter((el: any) => el.position === position && el.code);
/**
*
@ -233,118 +332,191 @@ const getListByPosition = (data: any, position: string) => data?.data?.filter((e
* @param data -
* @param offset -
*/
export const setMapLegendPos = (layoutType: string, data: any, offset: number = 456) => {
export const setMapLegendPos = (
layoutType: string,
data: any,
offset = 456
) => {
const menuStateString = localStorage.getItem('menuState'); //处理澜沧江左侧菜单状态
const menuState = menuStateString !== null ? JSON.parse(menuStateString) : true;
const _theme = localStorage.getItem("ly-theme") || window.__lyConfigs?.theme
const leftEle = document.querySelector('#page-layout-left') as HTMLElement
const rightEle = document.querySelector('#page-layout-right') as HTMLElement
const bottomEle = document.querySelector('#page-layout-bottom') as HTMLElement
const legend = document.querySelector('#qgc-legendtl') as HTMLElement // 图例
const filter = document.querySelector('#map-filter-container') as HTMLElement // 全局表单
const compassControl = document.querySelector('#map-compassControl') as HTMLElement // 全局表单
const controller = document.querySelector('#map-controller') as HTMLElement // 地图工具栏
const monitor = document.querySelector('#map-monitor') as HTMLElement // 地图工具栏
const baselayer = document.querySelector('#map-baselayer') as HTMLElement // 底图模式切换
const menuState =
menuStateString !== null ? JSON.parse(menuStateString) : true;
const _theme = localStorage.getItem('ly-theme') || window.__lyConfigs?.theme;
const leftEle = document.querySelector('#page-layout-left') as HTMLElement;
const rightEle = document.querySelector('#page-layout-right') as HTMLElement;
const bottomEle = document.querySelector(
'#page-layout-bottom'
) as HTMLElement;
const legend = document.querySelector('#qgc-legendtl') as HTMLElement; // 图例
const filter = document.querySelector('#map-filter-container') as HTMLElement; // 全局表单
const compassControl = document.querySelector(
'#map-compassControl'
) as HTMLElement; // 全局表单
const controller = document.querySelector('#map-controller') as HTMLElement; // 地图工具栏
const monitor = document.querySelector('#map-monitor') as HTMLElement; // 地图工具栏
const baselayer = document.querySelector('#map-baselayer') as HTMLElement; // 底图模式切换
// const vd = document.querySelector('#vd_operate') as HTMLElement // 底部视频
const left = ['layout1', 'layout2', 'layout3', 'layout4', 'layout6', 'layout7', 'layout8', 'layout9', 'layout10', 'layout11', 'layout14', 'layout15', 'layout16', 'layout17'] // 左侧布局
const right = ['layout1', 'layout2', 'layout3', 'layout4', 'layout5', 'layout6', 'layout8', 'layout10', 'layout11', 'layout15', 'layout16', 'layout17'] // 右侧布局
const bottom1 = ['layout1', 'layout6', 'layout8', 'layout9', 'layout10', 'layout16'] // 三行底部布局
const bottom2 = ['layout2', 'layout15'] // 四行底部布局
const w = `${offset}px`
const l = `${_theme === 'ly-8' ? menuState ? 643 : 510 : offset}px`
let b = `0px`
const le = ['layout17', 'layout10'].includes(layoutType) ? 0 : 1
const leftList = getListByPosition(data, 'left')
const rightList = getListByPosition(data, 'right')
const bottomList = getListByPosition(data, 'bottom')
let bottom = '0'
const left = [
'layout1',
'layout2',
'layout3',
'layout4',
'layout6',
'layout7',
'layout8',
'layout9',
'layout10',
'layout11',
'layout14',
'layout15',
'layout16',
'layout17'
]; // 左侧布局
const right = [
'layout1',
'layout2',
'layout3',
'layout4',
'layout5',
'layout6',
'layout8',
'layout10',
'layout11',
'layout15',
'layout16',
'layout17'
]; // 右侧布局
const bottom1 = [
'layout1',
'layout6',
'layout8',
'layout9',
'layout10',
'layout16'
]; // 三行底部布局
const bottom2 = ['layout2', 'layout15']; // 四行底部布局
const w = `${offset}px`;
const l = `${_theme === 'ly-8' ? (menuState ? 643 : 510) : offset}px`;
let b = `0px`;
const le = ['layout17', 'layout10'].includes(layoutType) ? 0 : 1;
const leftList = getListByPosition(data, 'left');
const rightList = getListByPosition(data, 'right');
const bottomList = getListByPosition(data, 'bottom');
let bottom = '0';
if (_theme === 'ly-8') {
if (window.__mapMode === '3D') {
b = `200px`
b = `200px`;
} else {
b = `${menuState ? 200 : 50}px`
b = `${menuState ? 200 : 50}px`;
}
}
if (bottomList?.length > 0) {
if (bottom1.includes(layoutType)) {
bottom = 'calc((100% - 16px) / 3 + 8px)'
bottom = 'calc((100% - 16px) / 3 + 8px)';
}
if (bottom2.includes(layoutType)) {
bottom = 'calc((100% - 24px) / 4 + 8px)'
bottom = 'calc((100% - 24px) / 4 + 8px)';
}
} else {
// 没有底部布局时,底部高度为
bottom = '28px'
bottom = '28px';
}
const rle = ['layout6'].includes(layoutType) || bottom != '28px' ? 0 : 1
const rle = ['layout6'].includes(layoutType) || bottom != '28px' ? 0 : 1;
const leftHide = leftEle?.classList?.contains('hide')
const rightHide = rightEle?.classList?.contains('hide')
const bottomHide = bottomEle?.classList?.contains('hide')
const leftHide = leftEle?.classList?.contains('hide');
const rightHide = rightEle?.classList?.contains('hide');
const bottomHide = bottomEle?.classList?.contains('hide');
if (legend) {
legend.style.left = !leftHide && left.includes(layoutType) && leftList?.length > le ? l : b
legend.style.bottom = bottomHide ? '0' : bottomList?.length > 0 ? bottom : '12px'
legend.style.left =
!leftHide && left.includes(layoutType) && leftList?.length > le ? l : b;
legend.style.bottom = bottomHide
? '0'
: bottomList?.length > 0
? bottom
: '12px';
}
if (filter) {
if (layoutType === 'layout10') {
filter.style.left = !leftHide && left.includes(layoutType) && leftList?.length > 1 ? l : b
filter.style.left =
!leftHide && left.includes(layoutType) && leftList?.length > 1 ? l : b;
} else {
filter.style.left = !leftHide && left.includes(layoutType) && leftList?.length > 0 && layoutType !== 'layout17' ? l : b
filter.style.left =
!leftHide &&
left.includes(layoutType) &&
leftList?.length > 0 &&
layoutType !== 'layout17'
? l
: b;
}
}
if (compassControl) {
if (layoutType === 'layout10') {
compassControl.style.left = !leftHide && left.includes(layoutType) && leftList?.length > 1 ? l : b
compassControl.style.left =
!leftHide && left.includes(layoutType) && leftList?.length > 1 ? l : b;
} else {
compassControl.style.left = !leftHide && left.includes(layoutType) && leftList?.length > 0 && layoutType !== 'layout17' ? l : b
compassControl.style.left =
!leftHide &&
left.includes(layoutType) &&
leftList?.length > 0 &&
layoutType !== 'layout17'
? l
: b;
}
}
if (controller) {
controller.style.right = !rightHide && right.includes(layoutType) && rightList?.length > rle ? w : '0'
controller.style.bottom = bottomHide ? '0' : bottom
controller.style.right =
!rightHide && right.includes(layoutType) && rightList?.length > rle
? w
: '0';
controller.style.bottom = bottomHide ? '0' : bottom;
}
if (monitor) {
monitor.style.right = !rightHide && right.includes(layoutType) && rightList?.length > rle ? w : '0'
monitor.style.right =
!rightHide && right.includes(layoutType) && rightList?.length > rle
? w
: '0';
// monitor.style.bottom = bottomHide ? '0' : bottom
}
if (baselayer) {
baselayer.style.right = !rightHide && right.includes(layoutType) && rightList?.length > rle ? `calc(${w} + 60px)` : '60px'
baselayer.style.bottom = bottomHide ? '0' : bottom
}
baselayer.style.right =
!rightHide && right.includes(layoutType) && rightList?.length > rle
? `calc(${w} + 60px)`
: '60px';
baselayer.style.bottom = bottomHide ? '0' : bottom;
}
};
export const altitudeToZoom = (height: number) => {
const lv = Math.round(D + (A - D) / (1 + Math.pow(Number(height) / C, B))) + 1
return lv > -1 ? lv : 0
}
const lv =
Math.round(D + (A - D) / (1 + Math.pow(Number(height) / C, B))) + 1;
return lv > -1 ? lv : 0;
};
/**
*
* @param {Number} zoom
*/
export const zoomToAltitude = (zoom: number) => {
return Math.round(C * Math.pow((A - D) / (zoom - D) - 1, 1 / B))
}
return Math.round(C * Math.pow((A - D) / (zoom - D) - 1, 1 / B));
};
export const mapOutPut = (imageUrl: string) => {
const canvas = document.createElement('canvas')
const downloadElement = document.createElement('a')
const mapElem = document.getElementById('mapContainer')
const canvas = document.createElement('canvas');
const downloadElement = document.createElement('a');
const mapElem = document.getElementById('mapContainer');
if (mapElem == null) {
return
return;
}
const context = canvas.getContext('2d')!
canvas.width = mapElem.offsetWidth
canvas.height = mapElem.offsetHeight
const image = new Image()
image.src = imageUrl
const context = canvas.getContext('2d')!;
canvas.width = mapElem.offsetWidth;
canvas.height = mapElem.offsetHeight;
const image = new Image();
image.src = imageUrl;
image.onload = () => {
context.drawImage(image, 0, 0)
const elem: any = document.getElementById('qgc-legendtl')
const l = elem?.style?.left === '' ? 0 : parseInt(elem?.style?.left)
context.drawImage(image, 0, 0);
const elem: any = document.getElementById('qgc-legendtl');
const l = elem?.style?.left === '' ? 0 : parseInt(elem?.style?.left);
if (elem) {
domtoimage
.toPng(elem, {
@ -353,23 +525,23 @@ export const mapOutPut = (imageUrl: string) => {
height: mapElem.offsetHeight - 20
})
.then((legendUrl: string) => {
const image = new Image()
image.src = legendUrl
image.width = elem.offsetWidth
const image = new Image();
image.src = legendUrl;
image.width = elem.offsetWidth;
image.onload = () => {
context.drawImage(image, 0, 0)
downloadElement.href = canvas.toDataURL('image/png')
downloadElement.download = '地图截图'
downloadElement.click()
}
context.drawImage(image, 0, 0);
downloadElement.href = canvas.toDataURL('image/png');
downloadElement.download = '地图截图';
downloadElement.click();
};
})
.catch((e: any) => {
console.log('e', e)
})
console.log('e', e);
});
} else {
downloadElement.href = canvas.toDataURL('image/png')
downloadElement.download = 'download'
downloadElement.click()
}
}
downloadElement.href = canvas.toDataURL('image/png');
downloadElement.download = 'download';
downloadElement.click();
}
};
};

View File

@ -8,7 +8,7 @@ import type { MapInterface, layer } from './map.d';
export class MapCesium implements MapInterface {
private viewer: Cesium.Viewer | null = null;
private containerId: string = '';
private containerId = '';
init(container: HTMLElement, rectangle?: any): Promise<any> {
return new Promise(async (resolve, reject) => {
@ -113,16 +113,19 @@ export class MapCesium implements MapInterface {
}
// ... 其他空实现方法保持不变 ...
jdPanelControlShowAndHidden(baseid: String, isAll: boolean): void {}
jdPanelControlShowAndHidden(baseid: string, isAll: boolean): void {}
mdLayerShowOrHidden(): void {}
addBaseDataLayer(layer: any): void {}
controlBaseLayerTreeShowAndHidden(
layerType: String,
key: String,
layerType: string,
key: string,
checked: boolean
): void {}
mdLayerTreeShowOrHidden(layerType: String, checked?: boolean): void {}
mdLayerTreeShowOrHidden(layerType: string, checked?: boolean): void {}
setLegendPointVisible(layerKey: string, anchoPointState: string, checked: boolean): void {}
addInitDataLayer(pointData: any[], layerType: any, mdoptions?: any): void {}
switchView(type: any): void {}
fitBounds(bounds: any): void {}
baseLayerSwitcher(key: string): void {}
addTertiarybasinLayer(
layer: layer,
@ -146,7 +149,7 @@ export class MapCesium implements MapInterface {
*
* @param fileName 'cesium_map.png'
*/
mapOutPut(fileName: string = 'cesium_map.png'): void {
mapOutPut(fileName = 'cesium_map.png'): void {
if (!this.viewer) {
console.warn('Viewer is not initialized.');
return;

View File

@ -47,36 +47,50 @@ export class MapClass implements MapClassInterface {
});
}
// 基地面板控制
jdPanelControlShowAndHidden(baseid: String, isAll: boolean): void {
jdPanelControlShowAndHidden(baseid: string, isAll: boolean): void {
this.service.jdPanelControlShowAndHidden(baseid, isAll);
}
mdLayerShowOrHidden(): void {
// layerType: String, key?: String, baseid: String, checked: boolean, isAll: boolean
// this.service.mdLayerShowOrHidden(layerType, key, baseid, checked, isAll)
mdLayerShowOrHidden(
layerType: string,
baseid: string,
key?: string,
checked?: boolean,
isAll?: boolean
): void {
this.service.mdLayerShowOrHidden(layerType, baseid, key, checked, isAll);
}
// 添加基础数据图层
addBaseDataLayer(layer: any): void {
return this.service.addBaseDataLayer(layer);
addBaseDataLayer(layer: any, isShow: boolean): void {
return this.service.addBaseDataLayer(layer, isShow);
}
// 基础图层显示影隐藏方法
controlBaseLayerTreeShowAndHidden(
layerType: String,
key: String,
layerType: string,
key: string,
checked: boolean
) {
this.service.controlBaseLayerTreeShowAndHidden(layerType, key, checked);
}
// 图层树控制描点数据显示隐藏方法
mdLayerTreeShowOrHidden(layerType: String, checked?: boolean) {
mdLayerTreeShowOrHidden(layerType: string, checked?: boolean) {
this.service.mdLayerTreeShowOrHidden(layerType, checked);
}
// 根据图例控制锚点显示隐藏
setLegendPointVisible(
layerKey: string,
anchoPointState: string,
checked: boolean
): void {
this.service.setLegendPointVisible(layerKey, anchoPointState, checked);
}
// 初始化加载描点数据
addInitDataLayer = (pointData: any[], layerType: any, mdoptions?: any) => {
return this.service.addInitDataLayer(pointData, layerType, mdoptions);
};
//切换底图
baseLayerSwitcher(key: string): void {
this.service.baseLayerSwitcher(key);
baseLayerSwitcher(key: string, checked: boolean): void {
this.service.baseLayerSwitcher(key, checked);
}
// 添加梯级流域图
@ -118,6 +132,10 @@ export class MapClass implements MapClassInterface {
mapOutPut() {
this.service.mapOutPut();
}
// 检查图层是否存在
hasLayer(layerKey: string): void {
return this.service.hasLayer(layerKey);
}
// 销毁地图
destroy(): void {
this.service.destroy();

View File

@ -82,13 +82,13 @@ export interface MapInterface {
*
* @param layer
*/
addBaseDataLayer(layer: any): void;
addBaseDataLayer(layer: any, isShow: boolean): void;
/**
*
* @param layer
*/
baseLayerSwitcher(key: string): void;
baseLayerSwitcher(key: string, checked: boolean): void;
/**
* 2D或者3D视图
@ -103,6 +103,12 @@ export interface MapInterface {
*/
zoomToggle(type: 'out' | 'in'): void;
/**
*
* @param layerKey key
* @returns
*/
hasLayer(layerKey: string): void;
/**
*
*/
@ -147,7 +153,7 @@ export interface MapInterface {
* @param baseid
* @param isAll
*/
jdPanelControlShowAndHidden(baseid: String, isAll: boolean): void;
jdPanelControlShowAndHidden(baseid: string, isAll: boolean): void;
/**
*
* @param layerType
@ -155,16 +161,22 @@ export interface MapInterface {
* @param checked
* @param isAll
*/
mdLayerShowOrHidden(): void;
// layerType: String, key?: String, baseid: String, checked: boolean, isAll: boolean
mdLayerShowOrHidden(
layerType: string,
baseid: string,
key?: string,
checked?: boolean,
isAll?: boolean
): void;
/**
*
* @param layerType
* @param checked
*/
controlBaseLayerTreeShowAndHidden(
layerType: String,
key: String,
layerType: string,
key: string,
checked: boolean
): void;
@ -173,7 +185,19 @@ export interface MapInterface {
* @param layerType
* @param checked
*/
mdLayerTreeShowOrHidden(layerType: String, checked?: boolean): void;
mdLayerTreeShowOrHidden(layerType: string, checked?: boolean): void;
/**
* anchoPointState
* @param layerKey key
* @param anchoPointState nameEn
* @param checked
*/
setLegendPointVisible(
layerKey: string,
anchoPointState: string,
checked: boolean
): void;
/**
*

View File

@ -13,6 +13,7 @@ import Icon from 'ol/style/Icon';
import Text from 'ol/style/Text';
import Circle from 'ol/style/Circle';
import RegularShape from 'ol/style/RegularShape';
import Cluster from 'ol/source/Cluster';
// import LayerGroup from 'ol/layer/Group';
// import OSM from 'ol/source/OSM';
@ -40,6 +41,10 @@ import {
import { unByKey } from 'ol/Observable';
import { MDOptions } from './map.class';
import { getIconPath } from '@/utils/index'; // ✅ 确保引入获取图标路径的工具函数
import { generatePopupHtml } from '@/utils/popupHtmlGenerator';
import { useModelStore } from '@/store/modules/model';
const modelStore = useModelStore();
// 定义与 leaflet 中相同的常量
const CENTER_positionCN = [114.17112499999996, 38]; // OpenLayers 使用 [lon, lat]
@ -74,7 +79,7 @@ export class MapOl implements MapInterface {
// ✅ 新增:声明用于存储 mask 事件监听器的引用,以便后续移除
private _maskPrerender: any = null;
private _maskPostrender: any = null;
private BASEID: string = '';
private BASEID = '';
// ✅ 新增:记录当前鼠标悬停的 Feature ID
private hoveredFeatureId: string | number | null = null;
// ✅ 新增:用于显示自定义内容的 Overlay
@ -147,68 +152,42 @@ export class MapOl implements MapInterface {
// 如果需要防抖处理,可以添加 debounce
console.log('当前缩放级别', this.view?.getZoom());
});
// 点击弹出弹框
this.map.on('click', evt => {
const pixel = evt.pixel;
// 使用共享方法检测要素
const { detectedFeature, isHitIcon } = this.detectFeatureAtPixel(pixel);
if (detectedFeature && isHitIcon) {
modelStore.modalVisible = true;
modelStore.params = detectedFeature.values_;
modelStore.title = detectedFeature.values_.titleName + ' 详情信息';
}
});
// ✅ 新增:监听鼠标移动,动态改变光标样式
let lastHoveredId: string | number | null = null;
let animationFrameId: number | null = null;
// pointermove
this.map.on('click', evt => {
this.map.on('pointermove', evt => {
const pixel = evt.pixel;
// 判断地图层级4.7 以上才进行 popup 显示
const zoom = this.map.getView().getZoom();
if (zoom !== undefined && zoom < 4.7) {
return;
}
// 取消之前的动画帧,确保只处理最新的一次移动
if (animationFrameId) {
cancelAnimationFrame(animationFrameId);
}
animationFrameId = requestAnimationFrame(() => {
let detectedFeature: Feature | undefined = undefined;
let isHitIcon: boolean = false; // 标记是否真正命中了图标区域
// 1. 获取当前视口下的所有点图层
const pointLayers = Array.from(this.pointLayerRegistry.values());
// 2. 遍历检测,但我们需要更精细的判断
this.map?.forEachFeatureAtPixel(
pixel,
(feature, layer) => {
// 只关心点图层
if (pointLayers.includes(layer)) {
detectedFeature = feature as Feature;
// ✅ 关键优化:判断是否命中图标区域
// OpenLayers 的 Icon 样式通常有 anchor [0.5, 0.5]
// 我们可以获取图标的尺寸,判断鼠标是否在图标矩形范围内
const style = (layer as VectorLayer).getStyle();
let iconSize = { width: 0, height: 0 };
// 尝试从样式中获取图标尺寸(如果样式是函数,可能需要调用它,这里简化处理,假设固定大小或从 feature 获取)
// 更通用的做法是:计算鼠标点到 Feature 坐标投影后的像素距离
const geom = feature.getGeometry();
if (geom && geom.getType() === 'Point') {
const coord = (geom as Point).getCoordinates();
const iconPixel = this.map?.getPixelFromCoordinate(coord);
if (iconPixel) {
// 计算鼠标像素与图标中心像素的距离
const dx = pixel[0] - iconPixel[0];
const dy = pixel[1] - iconPixel[1];
const distance = Math.sqrt(dx * dx + dy * dy);
// 假设图标大致大小为 30x30 或 40x40半径设为 15-20
// 你可以根据实际 icon 大小调整这个阈值,例如 15
const hitRadius = 15;
if (distance <= hitRadius) {
isHitIcon = true;
}
}
}
return true; // 找到第一个点图层要素即停止
}
return false;
},
{ hitTolerance: 0 } // 设置为 0完全依赖上面的距离计算
);
// 使用共享方法检测要素
const { detectedFeature, isHitIcon } =
this.detectFeatureAtPixel(pixel);
// 3. 根据是否命中图标来决定行为
const newHoveredId =
@ -261,6 +240,7 @@ export class MapOl implements MapInterface {
layerType: any,
mdoptions?: MDOptions
): void {
console.log('addInitDataLayer', pointData, layerType, mdoptions);
if (!this.map) return;
let dataArray: any[] = [];
@ -283,24 +263,26 @@ export class MapOl implements MapInterface {
let vectorLayer = this.pointLayerRegistry.get(targetLayerKey);
let vectorSource: VectorSource;
const shouldClear = mdoptions?.isRemove !== false;
// const shouldClear = mdoptions?.isRemove !== false;
if (!vectorLayer) {
vectorSource = new VectorSource();
vectorLayer = new VectorLayer({
source: vectorSource,
zIndex: 100, // 确保点在底图之上
// declutter: true,
// style: (feature: any) => this.createPointStyle(feature) // 使用动态样式函数
style: (feature: any) => this.createPointStyle1(feature) // 使用动态样式函数
// declutter: false,
// renderOrder: (a, b) =>
// (b.get('distance') || 0) - (a.get('distance') || 0),
style: (feature: any) => this.createPointStyle(feature) // 使用动态样式函数
// style: (feature: any) => this.createPointStyle1(feature) // 使用动态样式函数
});
this.pointLayerRegistry.set(targetLayerKey, vectorLayer);
this.map.addLayer(vectorLayer);
} else {
vectorSource = vectorLayer.getSource() as VectorSource;
if (shouldClear) {
vectorSource.clear();
}
// if (shouldClear) {
// vectorSource.clear();
// }
}
if (dataArray.length === 0) {
@ -315,7 +297,7 @@ export class MapOl implements MapInterface {
const features: Feature[] = [];
dataArray.forEach((item: any) => {
let { lgtd, lttd, stnm, iconCode, titleName, ennm } = item;
const { lgtd, lttd, stnm, iconCode, titleName, ennm } = item;
if (lgtd == null || lttd == null) {
return;
@ -336,11 +318,19 @@ export class MapOl implements MapInterface {
}
// 显示的文字优先使用 titleName其次 ennm最后 stnm
const labelText = titleName || ennm || stnm || '';
const labelText = titleName || stnm || ennm || '';
if (lgtd == null || lttd == null) return;
const lon = Number(lgtd);
const lat = Number(lttd);
if (isNaN(lon) || isNaN(lat) || !isFinite(lon) || !isFinite(lat)) return;
if (Math.abs(lon) > 180 || Math.abs(lat) > 90) return;
const coord = fromLonLat([lon, lat]);
if (!isFinite(coord[0]) || !isFinite(coord[1])) return;
const geometry = new Point(coord);
// 5. 创建 Feature
const feature = new Feature({
geometry: new Point(fromLonLat([lgtd, lttd])), // ✅ 关键:坐标转换 EPSG:4326 -> EPSG:3857
geometry: geometry, // ✅ 关键:坐标转换 EPSG:4326 -> EPSG:3857
...item, // 保留原始数据以便点击事件使用
_layerKey: targetLayerKey
});
@ -351,6 +341,8 @@ export class MapOl implements MapInterface {
// 将自定义属性绑定到 feature以便样式函数访问
feature.set('_iconUrl', iconUrl);
feature.set('_labelText', labelText);
feature.set('_legendVisible', true); // 默认显示
feature.set('_sttpMap', item.sttpMap); // 默认显示
if (item.popupHtml) {
feature.set('popupHtml', item.popupHtml);
}
@ -364,6 +356,7 @@ export class MapOl implements MapInterface {
}
console.log(`图层 [${targetLayerKey}] 描点加载完成`);
console.log(`图层 [${targetLayerKey}] 描点加载完成`);
}
/**
* Popup Overlay
@ -389,6 +382,67 @@ export class MapOl implements MapInterface {
this.map.addOverlay(this.popupOverlay);
}
}
/**
*
* @param pixel
* @returns
*/
private detectFeatureAtPixel(pixel: number[]): {
detectedFeature: Feature | undefined;
isHitIcon: boolean;
} {
let detectedFeature: Feature | undefined = undefined;
let isHitIcon = false;
// 1. 获取当前视口下的所有点图层
const pointLayers = Array.from(this.pointLayerRegistry.values());
// 2. 遍历检测,但我们需要更精细的判断
this.map?.forEachFeatureAtPixel(
pixel,
(feature, layer) => {
// 只关心点图层
if (pointLayers.includes(layer)) {
detectedFeature = feature as Feature;
// ✅ 关键优化:判断是否命中图标区域
// OpenLayers 的 Icon 样式通常有 anchor [0.5, 0.5]
// 我们可以获取图标的尺寸,判断鼠标是否在图标矩形范围内
const style = (layer as VectorLayer).getStyle();
const iconSize = { width: 0, height: 0 };
// 尝试从样式中获取图标尺寸(如果样式是函数,可能需要调用它,这里简化处理,假设固定大小或从 feature 获取)
// 更通用的做法是:计算鼠标点到 Feature 坐标投影后的像素距离
const geom = feature.getGeometry();
if (geom && geom.getType() === 'Point') {
const coord = (geom as Point).getCoordinates();
const iconPixel = this.map?.getPixelFromCoordinate(coord);
if (iconPixel) {
// 计算鼠标像素与图标中心像素的距离
const dx = pixel[0] - iconPixel[0];
const dy = pixel[1] - iconPixel[1];
const distance = Math.sqrt(dx * dx + dy * dy);
// 假设图标大致大小为 30x30 或 40x40半径设为 15-20
// 你可以根据实际 icon 大小调整这个阈值,例如 15
const hitRadius = 15;
if (distance <= hitRadius) {
isHitIcon = true;
}
}
}
return true; // 找到第一个点图层要素即停止
}
return false;
},
{ hitTolerance: 0 } // 设置为 0完全依赖上面的距离计算
);
return { detectedFeature, isHitIcon };
}
/**
* pointermove / Popup
* @param feature
@ -398,31 +452,22 @@ export class MapOl implements MapInterface {
if (!this.popupOverlay || !this.popupElement) return;
if (feature && coordinate) {
// 1. 获取数据
const props = feature.getProperties();
// 2. 生成内容 (这里假设父组件已经在 feature 上绑定了 popupHtml 或者我们在这里构建)
// 方案 A: 如果父组件传入了 HTML 字符串
const popupHtml = props.popupHtml || props.popup || '';
// 方案 B: 如果父组件希望动态更新 DOM (推荐,性能更好,支持交互)
// 我们可以触发一个事件,让 Vue 组件去更新这个 div 的内容
// 这里为了简单,直接演示如何填充内容
const popupHtml = props.popupHtml || generatePopupHtml(props);
if (popupHtml) {
this.popupElement.innerHTML = popupHtml;
this.popupOverlay.setPosition(coordinate);
this.popupElement.style.display = 'block';
} else {
// 如果没有预设 HTML可以显示默认文本
this.popupElement.innerHTML = `<div style="padding:5px; background:white; border-radius:4px;">${
props.stnm || props.titleName || '未知'
}</div>`;
this.popupOverlay.setPosition(coordinate);
this.popupElement.style.display = 'block';
// this.popupElement.innerHTML = `<div style="padding:5px; background:white; border-radius:4px;">${
// props.stnm || props.titleName || '未知'
// }</div>`;
// this.popupOverlay.setPosition(coordinate);
// this.popupElement.style.display = 'block';
}
} else {
// 隐藏
this.popupOverlay.setPosition(undefined);
this.popupElement.style.display = 'none';
}
@ -432,13 +477,26 @@ export class MapOl implements MapInterface {
*/
private createPointStyle(feature: Feature): Style {
const iconUrl = feature.get('_iconUrl') as string;
const sttpMap = feature.get('_sttpMap') as string;
const labelText = feature.get('_labelText') as string;
const legendVisible = feature.get('_legendVisible');
const regionVisible = feature.get('_regionVisible');
// 如果没图标,返回空样式
if (!iconUrl) {
return new Style();
}
// 如果图例设置为隐藏,返回空样式
if (legendVisible === false) {
return new Style();
}
// 如果区域外,返回空样式
if (regionVisible === false) {
return new Style();
}
// ✅ 1. 获取当前地图分辨率
// 注意如果样式函数在地图未完全初始化时调用view 可能为 null
// const currentResolution = this.view ? this.view.getResolution() : 1000;
@ -455,8 +513,26 @@ export class MapOl implements MapInterface {
// 限制最大和最小缩放,防止过大或过小
// let dynamicScale = baseScale * (baseResolution / (currentResolution || 1));
const currentZoom: any = this.view ? this.view.getZoom() : 4.5;
const distance = feature.get('distance'); // 你通过计算赋值的字段
// ✅ 分级过滤规则(根据实际业务调整阈值)
if (distance !== undefined && distance !== null) {
let minDistanceRequired = 0;
if (currentZoom <= 6) {
// 极远视图只显示最孤立的站点distance >= 50000000 或 1500000根据你的数据分布定
// 假设 50000000 和 1500000 属于高值都显示400000 和 50000 不显示
minDistanceRequired = 1500000; // 只显示 >=150万 的点
} else if (currentZoom <= 8) {
minDistanceRequired = 800000; // 显示 >=80万 的点
} else if (currentZoom <= 10.5) {
minDistanceRequired = 400000; // 显示 >=40万 的点
} else {
minDistanceRequired = 0; // 放大到14级以上显示所有点包括5万的
}
if (distance <= minDistanceRequired) {
return new Style(); // 不满足,隐藏
}
}
let dynamicScale = 0.7 + (currentZoom - 4.5) * 0.08;
// 限制范围:最小 0.5,最大 3.0 (可根据需求调整)
dynamicScale = Math.max(0.5, Math.min(3.0, dynamicScale));
@ -472,7 +548,8 @@ export class MapOl implements MapInterface {
src: iconUrl,
scale: dynamicScale,
anchor: [0.5, 0.5],
crossOrigin: 'anonymous'
crossOrigin: 'anonymous',
declutterMode: 'obstacle' // 图标参与碰撞,可被隐藏
})
// zIndex: zIndex // ✅ 设置样式的 zIndex
@ -574,7 +651,11 @@ export class MapOl implements MapInterface {
*
* @param layer
*/
addBaseDataLayer(layer: any, isCache: boolean = false): void {
addBaseDataLayer(
layer: any,
isShow: boolean,
isCache: boolean = false
): void {
if (!this.map) return;
console.log('OL addBaseDataLayer', layer);
@ -640,10 +721,12 @@ export class MapOl implements MapInterface {
if (layer.key === this.REGISTRY_KEY) {
!isCache ? wmtsLayer.setZIndex(-100) : wmtsLayer.setZIndex(-99);
} else {
wmtsLayer.setZIndex(-99);
wmtsLayer.setZIndex(-100);
}
console.log('基础图层', wmtsLayer);
wmtsLayer.type = 'layer';
// 5. 注册与添加
wmtsLayer.setVisible(isShow);
console.log('基础图层', wmtsLayer);
this.layerRegistry.set(layer.key, wmtsLayer);
this.map.addLayer(wmtsLayer);
layer._layer = wmtsLayer;
@ -656,7 +739,9 @@ export class MapOl implements MapInterface {
})
});
tileLayer.setZIndex(-100);
this.layerRegistry.set(this.REGISTRY_KEY, tileLayer);
tileLayer.setVisible(isShow);
tileLayer.type = 'layer';
this.layerRegistry.set(layer.key, tileLayer);
this.map.addLayer(tileLayer);
} else if (layer.type === 'vector') {
if (layer.key === 'hydropBase') {
@ -702,8 +787,9 @@ export class MapOl implements MapInterface {
console.log(`切换区域至: ${this.BASEID}`);
if (!isAll) {
// ✅ 情况 A: isAll == false -> 清空裁切
// ✅ 情况 A: isAll == false -> 清空裁切,显示所有锚点
this.clearMapMask();
this.showAllPoints();
return;
}
@ -713,6 +799,10 @@ export class MapOl implements MapInterface {
console.warn('未找到底图图层,无法应用遮罩');
return;
}
// ✅ 关键优化:在加载新区域数据前,先隐藏所有锚点,避免闪烁
this.hideAllPoints();
try {
const url =
this.hydropBaseConfig.geojson_url +
@ -723,7 +813,10 @@ export class MapOl implements MapInterface {
const geoJsonData = await this.loadGeoJsonData(url);
console.log('获取到的原始 GeoJSON:', geoJsonData);
// ✅ 新增:在应用遮罩前,先让地图视角聚焦到该区域
// ✅ 先根据区域边界过滤锚点(此时锚点还是隐藏的)
this.filterPointsByRegion(geoJsonData);
// ✅ 再让地图视角聚焦到该区域
this.fitViewToGeoJson(geoJsonData);
console.log('基础图层', baseLayer);
@ -733,8 +826,150 @@ export class MapOl implements MapInterface {
console.error('加载裁切数据失败:', error);
// 出错时也清空遮罩,保证用户体验
this.clearMapMask();
this.showAllPoints();
}
}
/**
*
*/
private hideAllPoints(): void {
this.pointLayerRegistry.forEach(layer => {
const vectorSource = layer.getSource() as VectorSource;
if (!vectorSource) return;
const features = vectorSource.getFeatures();
features.forEach((feature: Feature) => {
feature.set('_regionVisible', false);
feature.changed();
});
});
}
/**
*
*/
private showAllPoints(): void {
this.pointLayerRegistry.forEach(layer => {
const vectorSource = layer.getSource() as VectorSource;
if (!vectorSource) return;
const features = vectorSource.getFeatures();
features.forEach((feature: Feature) => {
feature.set('_regionVisible', true);
feature.changed();
});
});
}
/**
*
* 使线
*/
private filterPointsByRegion(geoJson: any): void {
// 解析 GeoJSON 获取区域多边形坐标
const regionCoords = this.extractPolygonCoords(geoJson);
if (!regionCoords || regionCoords.length === 0) {
console.warn('无法解析区域边界,显示所有锚点');
this.showAllPoints();
return;
}
// 遍历所有锚点图层
this.pointLayerRegistry.forEach(layer => {
const vectorSource = layer.getSource() as VectorSource;
if (!vectorSource) return;
const features = vectorSource.getFeatures();
features.forEach((feature: Feature) => {
const props = feature.getProperties();
const lon = props.lgtd;
const lat = props.lttd;
if (lon == null || lat == null) {
feature.set('_regionVisible', false);
feature.changed();
return;
}
// 判断点是否在区域内
const isInside = this.isPointInPolygon(lon, lat, regionCoords);
feature.set('_regionVisible', isInside);
feature.changed();
});
});
}
/**
* GeoJSON
*/
private extractPolygonCoords(geoJson: any): number[][][] {
if (!geoJson || !geoJson.features || geoJson.features.length === 0) {
return [];
}
const coords: number[][][] = [];
geoJson.features.forEach((feature: any) => {
const geometry = feature.geometry;
if (!geometry) return;
if (geometry.type === 'Polygon') {
// Polygon: [[[lon, lat], ...], ...]
coords.push(...geometry.coordinates);
} else if (geometry.type === 'MultiPolygon') {
// MultiPolygon: [[[[lon, lat], ...], ...], ...]
geometry.coordinates.forEach((polygon: number[][][]) => {
coords.push(...polygon);
});
}
});
return coords;
}
/**
* 线
* @param lon
* @param lat
* @param polygons [[[lon, lat], ...], ...]
*/
private isPointInPolygon(
lon: number,
lat: number,
polygons: number[][][]
): boolean {
for (const polygon of polygons) {
if (this.isPointInRing(lon, lat, polygon)) {
return true;
}
}
return false;
}
/**
* 线
*/
private isPointInRing(lon: number, lat: number, ring: number[][]): boolean {
let inside = false;
const n = ring.length;
for (let i = 0, j = n - 1; i < n; j = i++) {
const xi = ring[i][0];
const yi = ring[i][1];
const xj = ring[j][0];
const yj = ring[j][1];
const intersect =
yi > lat !== yj > lat &&
lon < ((xj - xi) * (lat - yi)) / (yj - yi) + xi;
if (intersect) {
inside = !inside;
}
}
return inside;
}
/**
*
* @param layerType (使 key)
@ -742,11 +977,12 @@ export class MapOl implements MapInterface {
* @param checked true false
*/
controlBaseLayerTreeShowAndHidden(
layerType: String,
key: String,
layerType: string,
key: string,
checked: boolean
): void {
if (!this.map) return;
console.log('controlBaseLayerTreeShowAndHidden', layerType, key, checked);
// 1. 确定查找的 Key优先使用传入的 key如果为空则尝试使用 layerType
const registryKey = key || layerType;
@ -759,11 +995,12 @@ export class MapOl implements MapInterface {
}
// 2. 从注册表中获取图层实例
const layerInstance = this.layerRegistry.get(registryKey as string);
console.log(layerInstance);
if (layerInstance) {
layerInstance.setVisible(checked);
// 3. 设置可见性
// OpenLayers 的 Layer.setVisible(boolean) 方法
layerInstance.setVisible(checked);
// layerInstance.setVisible(checked);
console.log(
`图层 [${registryKey}] 已设置为: ${checked ? '显示' : '隐藏'}`
@ -776,11 +1013,23 @@ export class MapOl implements MapInterface {
}
}
// 图层树控制描点数据显示隐藏方法
mdLayerTreeShowOrHidden(layerType: String, checked?: boolean): void {
const layerInstance: any = this.pointLayerRegistry.get(layerType as string);
mdLayerTreeShowOrHidden(layerType: string, checked?: boolean): void {
console.log('mdLayerTreeShowOrHidden', layerType, checked);
const layerInstance: any = this.pointLayerRegistry.get(layerType);
console.log('mdLayerTreeShowOrHidden', layerInstance);
if (layerInstance) {
layerInstance.setVisible(checked);
}
// this.service.mdLayerTreeShowOrHidden(layerType, checked)
}
hasLayer(layerType: string): void {
console.log('hasLayer', layerType);
const layerInstance: any = this.pointLayerRegistry.get(layerType);
console.log('hasLayer', layerInstance);
return this.pointLayerRegistry.has(layerType as string);
}
/**
*
* @param type 'out' , 'in'
@ -822,7 +1071,7 @@ export class MapOl implements MapInterface {
*
* @param key Key ( 's_province_boundaries', 'BASEMAP-white', 'BASEMAP-img')
*/
baseLayerSwitcher(key: string): void {
baseLayerSwitcher(key: string, checked: boolean): void {
if (!this.map || !this.view) return;
console.log('OL 切换底图 key:', key);
@ -836,12 +1085,42 @@ export class MapOl implements MapInterface {
// 2. 根据传入的业务 key 创建新的图层实例
if (key == 's_province_boundaries') {
this.addBaseDataLayer(this.baseLayerConfig);
this.addBaseDataLayer(this.baseLayerConfig, checked);
// 隐藏 BASEMAP-white 和 BASEMAP-img 图层(如果存在)
this.hideBaseMapLayers(['BASEMAP-white', 'BASEMAP-img']);
} else {
this.addBaseDataLayer(this.baseLayerConfig, true);
this.addBaseDataLayer(servers.BaseLayer[key]);
this.addBaseDataLayer(this.baseLayerConfig, checked, true);
this.addBaseDataLayer(servers.BaseLayer[key], 1);
// 显示 BASEMAP-white 和 BASEMAP-img 图层(如果存在)
this.showBaseMapLayers(['BASEMAP-white', 'BASEMAP-img']);
}
}
/**
*
* @param layerKeys key
*/
hideBaseMapLayers(layerKeys: string[]): void {
layerKeys.forEach(key => {
const layer = this.layerRegistry.get(key);
if (layer) {
layer.setVisible(false);
}
});
}
/**
*
* @param layerKeys key
*/
showBaseMapLayers(layerKeys: string[]): void {
layerKeys.forEach(key => {
const layer = this.layerRegistry.get(key);
if (layer) {
layer.setVisible(true);
}
});
}
/**
* (Vector Layer) - 使 GeoJSON
* @param layer
@ -1348,6 +1627,7 @@ export class MapOl implements MapInterface {
*/
private applyMapMask(rasterLayer: TileLayer, clipGeoJson: any): void {
if (!rasterLayer || !clipGeoJson) return;
console.log('地图遮罩开始');
// 1. 解析 GeoJSON 为 OL Features (EPSG:3857)
const features = new GeoJSON().readFeatures(clipGeoJson, {
@ -1596,8 +1876,96 @@ export class MapOl implements MapInterface {
const areaSqKm = areaSqMeters / 1000000;
return '面积:' + areaSqKm.toFixed(3) + 'km²';
}
// 图例和基地面板控制描点数据显示隐藏方法
/**
*
* @param layerType
* @param key
* @param baseid ID
* @param checked (/)
* @param isAll
*/
mdLayerShowOrHidden(
layerType: string,
baseid: string,
key?: string,
checked?: boolean,
isAll?: boolean
): void {
console.log('mdLayerShowOrHidden', layerType, key, baseid, checked, isAll);
// 确定查找的 Key优先使用传入的 key如果为空则尝试使用 layerType
const registryKey = key || layerType;
mdLayerShowOrHidden(): void {}
if (isAll) {
// 如果是全部操作,则对所有相应类型的图层进行处理
if (layerType === 'point') {
// 处理所有点图层
this.pointLayerRegistry.forEach((layer, key) => {
if (layer) {
layer.setVisible(checked);
}
});
} else {
// 处理其他类型的图层
this.layerRegistry.forEach((layer, key) => {
if (key.startsWith(layerType as string)) {
layer.setVisible(checked);
}
});
}
} else {
// 单独操作特定图层
let targetLayer = null;
// 先尝试在点图层注册表中查找
targetLayer = this.pointLayerRegistry.get(registryKey as string);
// 如果没找到,再在普通图层注册表中查找
if (!targetLayer) {
targetLayer = this.layerRegistry.get(registryKey as string);
}
// 如果指定了基地ID可以进一步筛选
if (targetLayer) {
targetLayer.setVisible(checked);
}
}
}
/**
* anchoPointState
* @param layerKey key
* @param anchoPointState nameEn
* @param checked
*/
setLegendPointVisible(
layerKey: string,
anchoPointState: string,
checked: boolean
): void {
const vectorLayer = this.pointLayerRegistry.get(layerKey);
if (!vectorLayer) return;
const vectorSource = vectorLayer.getSource() as VectorSource;
if (!vectorSource) return;
const features = vectorSource.getFeatures();
features.forEach((feature: Feature) => {
const props = feature.getProperties();
// 如果 anchoPointState 为空,隐藏所有锚点
if (!anchoPointState) {
feature.set('_legendVisible', false);
feature.changed();
} else if (props.anchoPointState === anchoPointState) {
// 根据 anchoPointState 匹配
// 设置 feature 的可见性
feature.set('_legendVisible', checked);
// 触发重新渲染
feature.changed();
}
// 不匹配的 feature 不做处理,保持原样
});
}
switchView(type): void {
console.log(type);

View File

@ -8,33 +8,33 @@
// import { Session } from '@zebras/qgc-share/service/Session'
export interface MapBaseUrlItem {
code: string
name: string
url: string
code: string;
name: string;
url: string;
}
export interface ServerConfigItem {
id?: string
key?: string
urlType: 'gisurl' | 'online'
url?: string
url_3d?: string
layers?: string
rasteropacity?: number
_layer?: string
imgUrl?: string
visible?: boolean
visibility?: boolean //?是否可以删除
minZoom?: number
maxZoom?: number
fillOpacity?: number
lineWidth?: number
[name: string]: any
id?: string;
key?: string;
urlType: 'gisurl' | 'online';
url?: string;
url_3d?: string;
layers?: string;
rasteropacity?: number;
_layer?: string;
imgUrl?: string;
visible?: boolean;
visibility?: boolean; //?是否可以删除
minZoom?: number;
maxZoom?: number;
fillOpacity?: number;
lineWidth?: number;
[name: string]: any;
}
const tdtToken = 'e90d56e5a09d1767899ad45846b0cefd' //企业版密钥勿换e650f138c4481cca888cd13094bb9026
const mapType = 'w' //c:天地图经纬度底图;w:天地图墨卡托底图
const URL_TerTDT = `https://t0.tianditu.gov.cn/ter_${mapType}/wmts?tk=${tdtToken}` //terMap
const tdtToken = 'e90d56e5a09d1767899ad45846b0cefd'; //企业版密钥勿换e650f138c4481cca888cd13094bb9026
const mapType = 'w'; //c:天地图经纬度底图;w:天地图墨卡托底图
const URL_TerTDT = `https://t0.tianditu.gov.cn/ter_${mapType}/wmts?tk=${tdtToken}`; //terMap
// const URL_TerLabelTDT = `http://t0.tianditu.gov.cn/cta_${mapType}/wmts?tk=${tdtToken}` //terLabel
// const URL_VecTDT = `http://t0.tianditu.com/vec_${mapType}/wmts?tk=${tdtToken}` //vecMap
// const URL_VecLableTDT = `http://t0.tianditu.com/cva_${mapType}/wmts?tk=${tdtToken}` //vecLabel
@ -44,10 +44,10 @@ const URL_TerTDT = `https://t0.tianditu.gov.cn/ter_${mapType}/wmts?tk=${tdtToken
// const znyMapUrl = "http://10.219.26.6:8050/" //中南院的测试地图环境
// const djjtMapUrl = "http://210.72.227.199:18084/" //中南院的测试地图环境
//TODO以后改成在系统管理里面配置地图可视化范围
export const location_map_maxlon = 126.8267
export const location_map_maxlat = 38.5769
export const location_map_minlon = 73.7443
export const location_map_minlat = 16.32
export const location_map_maxlon = 126.8267;
export const location_map_maxlat = 38.5769;
export const location_map_minlon = 73.7443;
export const location_map_minlat = 16.32;
// todo: 以后从接口获取数据
export const servers: Record<string, ServerConfigItem> | Record<string, any> = {
// 省(自治区)界
@ -120,15 +120,21 @@ export const servers: Record<string, ServerConfigItem> | Record<string, any> = {
// 基础图层
BaseLayer: {
'BASEMAP-img': {
key: 'BASEMAP-img',
type: 'raster-dem',
urlType: 'online',
url: 'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}' + `&token=`,
url_3d: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}' + `&token=`,
url:
'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}' +
`&token=`,
url_3d:
'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}' +
`&token=`,
_layer: 'img',
visible: false,
maxzoom: 20
},
'BASEMAP-white': {
key: 'BASEMAP-white',
urlType: 'online',
type: 'raster-dem',
url: `${URL_TerTDT}&SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=ter&STYLE=default&TILEMATRIXSET=${mapType}&TILEMATRIX={z}&TILEROW={y}&TILECOL={x}&FORMAT=tiles&token=
@ -402,7 +408,11 @@ export const servers: Record<string, ServerConfigItem> | Record<string, any> = {
'text-allow-overlap': false,
visibility: 'visible'
},
paint_text: { 'text-color': '#404040', 'text-halo-color': '#fff', 'text-halo-width': 2 },
paint_text: {
'text-color': '#404040',
'text-halo-color': '#fff',
'text-halo-width': 2
}
},
/**
@ -722,7 +732,7 @@ export const servers: Record<string, ServerConfigItem> | Record<string, any> = {
'line-opacity': 0
}
}
}
};
/**
* Gis图层配置

View File

@ -1,203 +0,0 @@
.map-tooltip {
height: auto;
color: rgba(255, 255, 255, 0.85);
text-align: center;
position: relative;
padding: 24px 0 25px;
// width: 279px;
width: 260px;
&::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 24px;
background: url(@/assets/images/mapTip/top@260.png) center no-repeat;
filter: opacity(75%);
}
&::before {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 25px;
background: url(@/assets/images/mapTip/bottom@260.png) center no-repeat;
filter: opacity(75%);
}
&-box {
padding: 0 12px;
&::before {
content: '';
position: absolute;
top: 24px;
bottom: 25px;
left: 0;
right: 0;
z-index: -1;
background: url(@/assets/images/mapTip/center@260.png) repeat-y;
filter: opacity(75%);
}
}
&-title {
font-size: 16px;
font-weight: 500;
}
&-list {
font-size: 14px;
line-height: 1.5;
> li {
display: flex;
text-align: left;
.__label {
flex: 0 0 100px;
width: 100px;
text-align: right;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.__warn {
color: #ff4d4f;
}
}
}
&-content {
margin-top: 10px;
border-top: 1px dashed #12aaeb;
padding: 10px 0;
margin: 10px 0 0;
&.__noborder {
border: none;
margin-top: 6px;
}
&.__small {
font-size: 12px;
}
}
&-sub {
margin: 0;
padding: 10px 0 0;
text-align: center;
}
&-sub1 {
text-align: center;
position: relative;
height: 1px;
border-bottom: 1px dashed #12aaeb;
margin-top: 16px;
.__content {
position: absolute;
top: -9px;
left: 50%;
transform: translateX(-50%);
background-color: rgb(88 110 134);
padding: 0 6px;
font-size: 12px;
border-radius: 3px;
white-space: nowrap;
}
}
&.map-tooltip-small {
width: 175px;
padding: 18px 0 18px;
&::after {
background-image: url(@/assets/images/mapTip/top@175.png);
height: 18px;
filter: opacity(75%);
}
&::before {
background-image: url(@/assets/images/mapTip/bottom@175.png);
height: 18px;
filter: opacity(75%);
}
.map-tooltip-box {
padding: 0 10px;
&::before {
content: '';
position: absolute;
top: 18px;
bottom: 18px;
left: 0;
right: 0;
z-index: -1;
background-image: url(@/assets/images/mapTip/center@175.png);
filter: opacity(75%);
}
}
.map-tooltip-list {
> li {
.__label {
flex: 0 0 80px;
width: 80px;
}
}
}
}
&.map-tooltip-middle {
width: 215px;
padding: 18px 0 18px;
&::after {
background-image: url(@/assets/images/mapTip/top@215.png);
height: 18px;
filter: opacity(75%);
}
&::before {
background-image: url(@/assets/images/mapTip/bottom@215.png);
height: 18px;
filter: opacity(75%);
}
.map-tooltip-box {
padding: 0 10px;
&::before {
content: '';
position: absolute;
top: 18px;
bottom: 18px;
left: 0;
right: 0;
z-index: -1;
background-image: url(@/assets/images/mapTip/center@215.png);
filter: opacity(75%);
}
}
.map-tooltip-list {
> li {
.__label {
flex: 0 0 110px;
width: 110px;
}
}
&.__list2 {
> li {
.__label {
flex: 0 0 90px;
width: 90px;
}
}
}
}
}
.map-waterQuality-subtitle {
margin-top: 10px;
border: 1px solid rgba(77, 129, 167);
border-bottom: none;
.map-waterQuality-leftType,
.map-waterQuality-rightType {
width: 50%;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +1,18 @@
<template>
<div class="layer-controller" :ref="componentRef">
<a-tooltip
placement="leftBottom"
trigger="click"
color="transparent"
:overlayInnerStyle="{ boxShadow: 'none' }"
:open="tooltipVisible"
@openChange="handleTooltipVisibleChange"
>
<template #title>
<div class="layers-tree">
<div class="layers-tree" :ref="tipRef">
<div class="layers-tree-title">图层管理</div>
<div class="layers-tree-content">
<a-Tree
<a-tree
checkable
:onCheck="onCheck"
:checkedKeys="checkedKeys"
@ -18,81 +21,245 @@
</div>
</div>
</template>
<div class="map-item">
<a-tooltip title="图层管理" placement="left">
<div class="map-item" @click="handleClick">
<i class="icon iconfont icon-layer"></i>
</div>
</a-tooltip>
</a-tooltip>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted, computed } from "vue";
import { useMapStore } from "@/store/modules/map";
import { useRoute } from "vue-router";
let route = useRoute();
const mapStore: any = useMapStore();
import { ref, onMounted, computed, watch, onUnmounted } from 'vue';
import { useMapStore } from '@/store/modules/map';
import { MapClass } from '@/components/gis/map.class';
import { layerConfig2Flat, getMapConfig } from '@/components/gis/gisUtils';
const mapStore = useMapStore();
const mapClass = MapClass.getInstance();
//
const layerConfigs = computed(() => mapStore.layerData);
const layerConfigs = computed(() => {
const convertCheckedToBoolean = (items: any[]) => {
return items.map(item => {
const newItem = { ...item };
// checked(0/1)(false/true)
if (typeof newItem.checkable === 'number') {
newItem.checkable = !!newItem.checkable;
}
//
if (newItem.children && Array.isArray(newItem.children)) {
newItem.children = convertCheckedToBoolean(newItem.children);
}
return newItem;
});
};
return convertCheckedToBoolean(mapStore.layerData);
});
//
const checkedKeys: any = ref([]);
const checkedKeys = ref<string[]>([]);
const tooltipVisible = ref(false);
const componentRef = ref<any | null>(null);
const tipRef = ref<any | null>(null);
// key
let baseLayersInited = false;
/**
* 广播图层配置变化
*/
const broadcast = (v: string[]) => {
console.log('broadcast 被调用,图层 keys:', v);
// 使 store
mapStore.updateLayerData(v);
};
/**
* 添加基础图层GISMap 类型
*/
const addBaseLayers = (configs: any[]) => {
//
const layerConfigsArr = layerConfig2Flat(configs);
layerConfigsArr.forEach((item: any) => {
//
if (item.type !== 'GISMap') {
return;
}
// paramJson config
if (!item.config && item.paramJson) {
try {
const jsonObj = JSON.parse(item.paramJson);
item.config = getMapConfig(jsonObj);
} catch {
item.config = null;
}
}
//
if (item.config) {
if (item.key === 'customBaseLayer') {
sessionStorage.setItem('customBaseLayer', JSON.stringify(item.config));
}
mapClass.addBaseDataLayer(item.config, item.checked === 1);
mapClass.controlBaseLayerTreeShowAndHidden(
item.key,
item.config?.id,
item.checked === 1
);
}
});
};
/**
* 获取初始选中的图层 key
*/
const getInitCheckedKeys = (data: any[] = []): string[] => {
const keys: string[] = [];
const f = (arr: any[] = []) => {
arr.forEach((item: any) => {
if (item.key && item.checked) {
keys.push(item.key);
}
if (item.children && item.children.length > 0) {
f(item.children);
}
});
};
f(data);
return keys;
};
const onCheck = (v: any, e: any) => {
//
const fData = layerConfigs.value?.filter((e: any) => e.key === "facilities")?.[0];
const fbData = layerConfigs.value?.filter((e: any) => e.key === "facilities_built")?.[0];
const fData = layerConfigs.value?.filter(
(item: any) => item.key === 'facilities'
)?.[0];
const fbData = layerConfigs.value?.filter(
(item: any) => item.key === 'facilities_built'
)?.[0];
const facilities_built_data =
(fbData && [fbData.key, ...fbData?.children?.map((e: any) => e.key)]) || [];
(fbData && [
fbData.key,
...fbData?.children?.map((item: any) => item.key)
]) ||
[];
const facilities_data =
(fData && [fData.key, ...fData?.children?.map((e: any) => e.key)]) || [];
(fData && [fData.key, ...fData?.children?.map((item: any) => item.key)]) ||
[];
let checkKeys = v;
if (e?.node.key === "rare_fish_point") {
checkKeys = v?.filter((item: any) => item !== "fish_along_point");
} else if (e?.node.key === "fish_along_point") {
checkKeys = v?.filter((item: any) => item !== "rare_fish_point");
// 沿
if (e?.node.key === 'rare_fish_point') {
checkKeys = v?.filter((item: any) => item !== 'fish_along_point');
} else if (e?.node.key === 'fish_along_point') {
checkKeys = v?.filter((item: any) => item !== 'rare_fish_point');
}
if (e.checked) {
if (e?.node.key === "stinfo_video_point" || e?.node.key == "stinfo") {
checkKeys = v?.filter((item: any) => item !== "stinfo_ai_video_point");
} else if (e?.node.key === "stinfo_ai_video_point") {
checkKeys = v?.filter(
(item: any) => item !== "stinfo_video_point" && item !== "stinfo"
// AI
if (e?.node.key === 'stinfo_video_point' || e?.node.key == 'stinfo') {
checkKeys = v?.filter((item: any) => item !== 'stinfo_ai_video_point');
} else if (e?.node.key === 'stinfo_ai_video_point') {
checkKeys = checkKeys.filter(
(item: any) => item !== 'stinfo_video_point' && item !== 'stinfo'
);
}
console.log(checkKeys, "res111");
//
if (
checkKeys.some((e: any) => facilities_data.includes(e)) &&
checkKeys.some((e: any) => facilities_built_data.includes(e))
checkKeys.some((item: any) => facilities_data.includes(item)) &&
checkKeys.some((item: any) => facilities_built_data.includes(item))
) {
if (
facilities_built_data.some((e: any) =>
e.includes(checkKeys[checkKeys.length - 1])
facilities_built_data.some((item: any) =>
item.includes(checkKeys[checkKeys.length - 1])
)
) {
checkKeys = checkKeys.filter((e: any) => !facilities_data.includes(e));
checkKeys = checkKeys.filter(
(item: any) => !facilities_data.includes(item)
);
} else if (
facilities_data.some((e: any) => e.includes(checkKeys[checkKeys.length - 1]))
facilities_data.some((item: any) =>
item.includes(checkKeys[checkKeys.length - 1])
)
) {
checkKeys = checkKeys.filter((e: any) => !facilities_built_data.includes(e));
checkKeys = checkKeys.filter(
(item: any) => !facilities_built_data.includes(item)
);
}
}
}
checkedKeys.value = checkKeys;
mapStore.updateLayerData(checkKeys);
broadcast(checkKeys);
};
const getCheckedKeys = () => {
const name = route.path.split("/")[2];
if (name === "shuiDianKaiFaZhuangKuang") {
checkedKeys.value = ["customBaseLayer","powerBaseStation", "eng", "eng_point"];
const handleClick = () => {
tooltipVisible.value = !tooltipVisible.value;
};
const handleTooltipVisibleChange = (visible: boolean) => {
tooltipVisible.value = visible;
};
// tooltip
const handleClickOutside = (event: MouseEvent) => {
if (
componentRef.value &&
!componentRef.value.contains(event.target as Node)
) {
if (tipRef.value && !tipRef.value.contains(event.target as Node)) {
tooltipVisible.value = false;
}
}
mapStore.updateLayerData(checkedKeys.value);
};
onMounted(() => {
getCheckedKeys();
// router.push({ name: 'map' })
//
document.addEventListener('click', handleClickOutside);
//
baseLayersInited = false;
});
onUnmounted(() => {
document.removeEventListener('click', handleClickOutside);
});
//
watch(
() => layerConfigs.value,
newVal => {
if (newVal && newVal.length > 0 && !baseLayersInited) {
addBaseLayers(newVal);
baseLayersInited = true;
const keys = getInitCheckedKeys(newVal);
checkedKeys.value = keys;
// loadAllLayerData updateLayerData GisView.vue
}
},
{ immediate: true }
);
// store checkedLayerKeys
watch(
() => mapStore.checkedLayerKeys,
newVal => {
if (newVal && newVal.length > 0) {
checkedKeys.value = newVal;
}
},
{ immediate: true, deep: true }
);
</script>
<style scoped lang="scss">
<style lang="scss">
.map-item {
height: 40px;
width: 40px;
@ -109,12 +276,21 @@ onMounted(() => {
color: #ffffff;
}
}
.ant-tooltip-inner {
height: auto !important;
max-height: 300px !important;
overflow: visible !important;
}
.layers-tree {
width: 230px;
max-height: 300px;
box-sizing: border-box;
box-shadow: 0 1px 2px #00000026;
background-color: #fff;
cursor: initial;
border: 1px solid #ccdae7;
display: flex;
flex-direction: column;
.layers-tree-title {
color: rgba(0, 0, 0, 0.85);
text-align: left;
@ -123,10 +299,12 @@ onMounted(() => {
line-height: 40px;
font-size: 16px;
border-bottom: 1px dotted #ccc;
flex-shrink: 0;
}
.layers-tree-content {
max-height: 300px;
flex: 1;
overflow-y: auto;
overflow-x: hidden;
}
}
</style>

View File

@ -8,7 +8,11 @@
:key="child.key"
>
<component v-if="child.component" :is="child.component" :map="map" />
<div v-else class="map-controller-item" @click="handleControllerClick(child)">
<div
v-else
class="map-controller-item"
@click="handleControllerClick(child)"
>
<i class="icon iconfont" :class="'icon-' + child.icon"></i>
</div>
</a-tooltip>
@ -16,10 +20,10 @@
</div>
</template>
<script setup lang="ts">
import { ref, watch, computed } from "vue";
import { useUiStore } from "@/store/modules/ui";
import Calculate from "./Calculate.vue";
import LayerController from "./LayerController.vue";
import { ref, watch, computed } from 'vue';
import { useUiStore } from '@/store/modules/ui';
import Calculate from './Calculate.vue';
import LayerController from './LayerController.vue';
const props = defineProps<{
map: any;
@ -34,7 +38,7 @@ const drawerOpen = ref(uiStore.drawerOpen);
// store drawerOpen
watch(
() => uiStore.drawerOpen,
(newVal) => {
newVal => {
drawerOpen.value = newVal;
}
);
@ -46,11 +50,11 @@ const controllers: any = computed(() => [
{
children: [
{
name: "全屏",
key: "fullScreen",
icon: isFullScreen.value ? "exitFullScreen" : "fullScreen",
},
],
name: '全屏',
key: 'fullScreen',
icon: isFullScreen.value ? 'exitFullScreen' : 'fullScreen'
}
]
},
{
@ -61,136 +65,150 @@ const controllers: any = computed(() => [
// icon: "iconGlobal",
// },
{
name: "放大",
key: "zoomIn",
icon: "zoomIn",
name: '放大',
key: 'zoomIn',
icon: 'zoomIn'
},
{
name: "缩小",
key: "zoomOut",
icon: "zoomOut",
},
],
name: '缩小',
key: 'zoomOut',
icon: 'zoomOut'
}
]
},
{
children: [
{
name: "3D",
key: "dim",
icon: uiStore.mapType === "2D" ? "a-3D" : "a-2D",
},
],
name: '3D',
key: 'dim',
icon: uiStore.mapType === '2D' ? 'a-3D' : 'a-2D'
}
]
},
{
children: [
{
name: "图层管理",
key: "layerController",
component: LayerController,
name: '图层管理',
key: 'layerController',
component: LayerController
}
]
},
],
},
uiStore.mapType === "2D"
uiStore.mapType === '2D'
? {
children: [
{
name: "测量工具",
key: "Calculate",
component: Calculate,
},
],
name: '测量工具',
key: 'Calculate',
component: Calculate
}
]
}
: {},
uiStore.mapType === "2D"
uiStore.mapType === '2D'
? {
children: [
{
name: "梯级",
key: "TJ",
icon: "tiji",
},
],
name: '梯级',
key: 'TJ',
icon: 'tiji'
}
]
}
: {},
uiStore.mapType === "3D"
uiStore.mapType === '3D'
? {
children: [
{
name: "电站倾斜摄影",
key: "OSBGController",
icon: "obliquePhotography",
},
],
name: '电站倾斜摄影',
key: 'OSBGController',
icon: 'obliquePhotography'
}
]
}
: {},
uiStore.mapType === "3D"
uiStore.mapType === '3D'
? {
children: [
{
name: "流域三维漫游",
key: "threedRoam",
icon: "roaming",
},
],
name: '流域三维漫游',
key: 'threedRoam',
icon: 'roaming'
}
]
}
: {},
{
children: [
{
name: "下载",
key: "screenShot",
icon: "downLoad",
},
],
},
name: '下载',
key: 'screenShot',
icon: 'downLoad'
}
]
}
]);
//
// const toggleFullScreen = () => {
// isFullScreen.value = !isFullScreen.value;
// //
// if (isFullScreen.value) {
// document.documentElement.requestFullscreen();
// } else {
// document.exitFullscreen();
// }
// };
const toggleFullScreen = () => {
if (!document.fullscreenElement) {
//
document.documentElement.requestFullscreen().catch(err => {
console.error('进入全屏失败:', err);
isFullScreen.value = false;
});
} else {
// 退
document.exitFullscreen().catch(err => {
console.error('退出全屏失败:', err);
isFullScreen.value = true;
});
}
};
//
document.addEventListener('fullscreenchange', () => {
isFullScreen.value = !!document.fullscreenElement;
});
//
const handleControllerClick = (item: any) => {
switch (item.key) {
case "fullScreen":
isFullScreen.value = !isFullScreen.value;
map.jdPanelControlShowAndHidden("01", false);
case 'fullScreen':
// map.jdPanelControlShowAndHidden("01", false);
// map.mdLayerTreeShowOrHidden('fp_point',!isFullScreen.value);
// map.controlBaseLayerTreeShowAndHidden('customBaseLayer','customBaseLayer',!isFullScreen.value);
// map.controlBaseLayerTreeShowAndHidden(
// 'customBaseLayer',
// 'customBaseLayer',
// !isFullScreen.value
// );
// map.controlBaseLayerTreeShowAndHidden('lcj_bhq','lcj_bhq',!isFullScreen.value);
// toggleFullScreen();
toggleFullScreen();
break;
case "zoomIn":
map.zoomToggle("in");
case 'zoomIn':
map.zoomToggle('in');
break;
case "zoomOut":
map.zoomToggle("out");
case 'zoomOut':
map.zoomToggle('out');
break;
case "dim":
uiStore.mapType = uiStore.mapType === "2D" ? "3D" : "2D";
if (uiStore.mapType === "2D") {
case 'dim':
uiStore.mapType = uiStore.mapType === '2D' ? '3D' : '2D';
if (uiStore.mapType === '2D') {
uiStore.drawerOpen = true;
} else {
uiStore.drawerOpen = false;
}
props.onClick("dim", uiStore.mapType);
props.onClick('dim', uiStore.mapType);
break;
case "rightDrawer":
case 'rightDrawer':
// 使
// GlobalEvents.get('rightDrawerState').set(!drawerOpen);
break;
//
case "screenShot":
case 'screenShot':
map.mapOutPut();
break;
case "TJ":
case 'TJ':
props.onClick(4, null);
// map.addTertiarybasinLayer(servers.Tertiarybasin, '#4DFFDD', '#92A0A5')
break;

View File

@ -10,9 +10,11 @@
placeholder="装机容量"
style="width: 120px"
>
<a-select-option v-for="item in siteRangePicker" :key="item.value">{{
item.label
}}</a-select-option>
<a-select-option
v-for="item in siteRangePicker"
:key="item.value"
>{{ item.label }}</a-select-option
>
</a-select>
</a-form-item>
</a-col>
@ -25,28 +27,40 @@
/>
</a-form-item>
</a-col>
<a-col>
<a-button @click="handleSearch">查询</a-button>
</a-col>
</a-row>
</a-form>
</div>
</div>
</template>
<script setup lang="ts">
import { ref } from "vue";
import { ref } from 'vue';
const props = defineProps({
map: {
type: Object,
default: () => ({})
}
});
const siteRangePicker = [
{ label: "0-10", value: "0-10" },
{ label: "10-20", value: "10-20" },
{ label: "20-30", value: "20-30" },
{ label: "30-40", value: "30-40" },
{ label: "40-50", value: "40-50" },
{ label: "50-60", value: "50-60" },
{ label: '0-10', value: '0-10' },
{ label: '10-20', value: '10-20' },
{ label: '20-30', value: '20-30' },
{ label: '30-40', value: '30-40' },
{ label: '40-50', value: '40-50' },
{ label: '50-60', value: '50-60' }
];
const formModel = ref({
siteRangePicker: [],
siteRangePicker: []
});
const rules = ref({
siteRangePicker: [{ required: true, message: "请选择装机容量" }],
siteRangePicker: [{ required: true, message: '请选择装机容量' }]
});
const handleSearch = () => {
props.map.flyTopanto([98.958315, 30.754818], 14);
};
</script>
<style lang="scss" scoped>

View File

@ -4,7 +4,12 @@
class="legendItem"
:class="{ gray: item.checked == 0, disabled: item.canBeChecked == 0 }"
>
<div class="legendIcon" :class="{ smallIcon: item.layerCode == 'eng_point' || item.layerCode == 'ef_point' }">
<div
class="legendIcon"
:class="{
smallIcon: item.layerCode == 'eng_point' || item.layerCode == 'ef_point'
}"
>
<img :src="getIconPath(item.icon)" alt="" />
</div>
<div class="legendIconTitle">
@ -14,7 +19,7 @@
</template>
<script setup lang="ts">
import { getIconPath } from "@/utils/index";
import { getIconPath } from '@/utils/index';
defineProps<{ item: any }>();
</script>
<style scoped lang="scss">
@ -40,7 +45,6 @@ defineProps<{ item: any }>();
width: 22px !important;
height: 22px !important;
text-align: center;
}
.legendIconTitle {
cursor: pointer;

View File

@ -3,22 +3,51 @@
<div class="legendTitle">
图例
<span class="legendBtn" @click="isOpen = !isOpen">
<i class="icon iconfont" :class="isOpen ? 'icon-fold' : 'icon-unFold'"></i>
<i
class="icon iconfont"
:class="isOpen ? 'icon-fold' : 'icon-unFold'"
></i>
</span>
</div>
<div class="legendContent" v-show="isOpen">
<a-spin :spinning="loadLegendData">
<div class="legendGroup" v-for="i in legendData">
<div class="groupTitle">{{ i.name }} {{ i.layerCode }}</div>
<div class="groupContent">
<a-spin :spinning="loadLegendData" tip="加载中...">
<div class="legendContainer">
<div
class="legendGroup"
v-for="i in legendData"
:key="i.name"
:class="{ envFac: i.name == '环保设施' }"
>
<div
class="groupTitle"
v-if="i.name != '环保设施'"
:class="{ gray: isGroupAllUnchecked(i) }"
@click="toggleGroup(i)"
>
{{ i.name }}
</div>
<div
class="groupContent"
:class="{ envFacBottom: hasEnvFac && i.name != '环保设施' }"
>
<template v-for="j in i.childrenList" :key="j.name">
<LegendItem v-if="j.layerCode" :item="j" @click="legendItemClick(j)" />
<LegendItem
v-if="j.layerCode"
:item="j"
@click="legendItemClick(j)"
/>
<div
v-else-if="j.childrenList && j.childrenList.length > 0"
class="legendGroup"
>
<div class="groupTitle">{{ j.name }}</div>
<div
class="groupTitle"
:class="{ gray: isGroupAllUnchecked(j) }"
@click="toggleGroup(j)"
>
{{ j.name }}
</div>
<div class="groupContent">
<LegendItem
v-for="item in j.childrenList"
@ -31,58 +60,176 @@
</template>
</div>
</div>
</div>
</a-spin>
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, watch } from "vue";
import { useMapStore } from "@/store/modules/map";
import LegendItem from "@/components/mapLegend/LegendItem.vue";
import { onMounted, ref, watch, computed } from 'vue';
import { useMapStore } from '@/store/modules/map';
import { useRoute } from 'vue-router';
import LegendItem from '@/components/mapLegend/LegendItem.vue';
import { MapClass } from '@/components/gis/map.class';
const mapStore: any = useMapStore();
//
const legendData = ref(mapStore.legendDataSelected);
const route = useRoute();
const mapClass = MapClass.getInstance();
// pageKey
const pageKey = computed(() => {
const path = route.path;
const parts = path.split('/');
if (parts.length >= 3) {
return parts[1] + '_' + parts[2];
}
return '';
});
// 使
const legendData = ref<any[]>([]);
const loadLegendData = ref(false);
// ""
const hasEnvFac = computed(() => {
return legendData.value.some((item: any) => item.name === '环保设施');
});
const legendItemClick = (item: any) => {
if (item.parentName == '环保设施') return;
if (item.canBeChecked == 0) {
return;
}
item.checked = item.checked == 0 ? 1 : 0;
const newChecked = item.checked == 0 ? 1 : 0;
item.checked = newChecked;
// store
if (item.nameEn) {
mapStore.updateLegendChecked(item.nameEn, newChecked);
}
// nameEn anchoPointState
if (item.nameEn && item.layerCode) {
const layerKey = item.layerCode;
//
const layerItem = mapStore.findLayerByKey(mapStore.layerData, layerKey);
console.log(`图例 ${item.nameEn} 控制图层:`, layerItem);
// alarm_range_ large_eng_built_
const nameEnToUse = item.nameEn.includes('alarm_range_')
? `large_eng_built_${item.nameEn}`
: item.nameEn;
if (layerItem) {
if (layerItem.type === 'pointMap') {
//
mapClass.setLegendPointVisible(layerKey, nameEnToUse, newChecked === 1);
} else if (layerItem.type === 'GISMap') {
// GIS
mapClass.controlBaseLayerTreeShowAndHidden(
layerKey,
layerItem.config?.id,
newChecked === 1
);
}
} else {
//
mapClass.setLegendPointVisible(layerKey, nameEnToUse, newChecked === 1);
}
}
};
//
watch(
() => mapStore.legendDataSelected,
(newValue) => {
// layerConfigs.value = newValue;
console.log(newValue);
newValue => {
console.log('图例数据更新:', newValue);
legendData.value = newValue;
// for (let i = 0; i < newValue.length; i++) {
// console.log(mapStore.layerData[i]);
// if (newValue[i].key != "-") {
// if (newValue[i].checked == 1) {
// if (newValue[i].children?.length > 0) {
// legendData.value.push(newValue[i]);
// }
// }
// }
// }
},
{ immediate: true, deep: true }
);
onMounted(() => {
// for (let i = 0; i < mapStore.layerData.length; i++) {
// console.log(mapStore.layerData[i]);
// if (mapStore.layerData[i].key != "-") {
// if (mapStore.layerData[i].checked == 1) {
// }
// }
// }
// console.log(layerConfigs.value)
// setTimeout(() => {
// data.value = 10;
// }, 1000);
// console.log(data.value);
});
watch(
() => mapStore.loading,
newValue => {
console.log('图例加载状态:', newValue);
loadLegendData.value = newValue;
},
{ immediate: true }
);
const isOpen = ref(true);
const getAllLeafItems = (group: any): any[] => {
const items: any[] = [];
if (!group.childrenList) return items;
group.childrenList.forEach((child: any) => {
if (child.layerCode) {
items.push(child);
} else if (child.childrenList && child.childrenList.length > 0) {
items.push(...getAllLeafItems(child));
}
});
return items;
};
const isGroupAllUnchecked = (group: any): boolean => {
const leafItems = getAllLeafItems(group);
if (leafItems.length === 0) return false;
return leafItems.every((item: any) => item.checked === 0);
};
const toggleGroup = (group: any) => {
const leafItems = getAllLeafItems(group);
if (leafItems.length === 0) return;
const hasAnyChecked = leafItems.some((item: any) => item.checked === 1);
const targetChecked = hasAnyChecked ? 0 : 1;
leafItems.forEach((item: any) => {
if (item.parentName === '环保设施') return;
if (item.canBeChecked === 0) return;
if (item.checked !== targetChecked) {
item.checked = targetChecked;
if (item.nameEn) {
mapStore.updateLegendChecked(item.nameEn, targetChecked);
}
if (item.nameEn && item.layerCode) {
const layerKey = item.layerCode;
const layerItem = mapStore.findLayerByKey(mapStore.layerData, layerKey);
const nameEnToUse = item.nameEn.includes('alarm_range_')
? `large_eng_built_${item.nameEn}`
: item.nameEn;
if (layerItem) {
if (layerItem.type === 'pointMap') {
mapClass.setLegendPointVisible(
layerKey,
nameEnToUse,
targetChecked === 1
);
} else if (layerItem.type === 'GISMap') {
mapClass.controlBaseLayerTreeShowAndHidden(
layerKey,
layerItem.config?.id,
targetChecked === 1
);
}
} else {
mapClass.setLegendPointVisible(
layerKey,
nameEnToUse,
targetChecked === 1
);
}
}
}
});
};
</script>
<style lang="scss" scoped>
@ -107,13 +254,48 @@ const isOpen = ref(true);
cursor: pointer;
}
}
.envFac {
position: absolute;
left: 0;
bottom: 0;
background-color: #ffffff;
border-top: 1px solid #eeeeee;
.groupContent {
padding: 0 !important;
:deep(.legendItem) {
cursor: none;
&:hover {
.legendIconTitle {
cursor: auto;
color: rgba(0, 0, 0, 0.85);
}
}
}
}
}
.envFacBottom {
padding-bottom: 80px !important;
}
.legendContent {
white-space: nowrap;
max-width: 450px;
max-height: 392px;
max-height: 450px;
overflow-x: scroll;
overflow-y: scroll;
border-top: 1px solid #eeeeee;
:deep(.ant-spin-nested-loading) {
min-height: 50px;
}
&::-webkit-scrollbar {
display: none;
}
.legendContainer {
position: relative;
min-height: 20px;
min-width: 30px;
overflow: auto;
padding-bottom: 8px;
}
.legendGroup {
display: inline-block;
vertical-align: top;
@ -138,4 +320,35 @@ const isOpen = ref(true);
}
}
}
.legendItem {
cursor: pointer;
margin-right: 10px;
padding: 4px 0;
min-height: 30px;
display: flex;
flex-direction: row;
.legendIcon {
width: 25px !important;
height: 25px !important;
text-align: center;
img {
max-width: 80%;
max-height: 80%;
vertical-align: middle;
display: inline-block;
}
}
.smallIcon {
width: 22px !important;
height: 22px !important;
text-align: center;
}
.legendIconTitle {
cursor: pointer;
flex: 1 1;
}
&:hover {
color: #2f6b98;
}
}
</style>

View File

@ -0,0 +1,260 @@
# 地图图层、图例和锚点加载逻辑
## 一、整体流程
```
GisView.vue (onMounted)
├─> 1. 获取图层配置 (mapStore.setLayerData)
├─> 2. 收集初始选中的图层 keys (collectCheckedKeys)
├─> 3. 加载所有锚点数据 (mapStore.loadAllLayerData)
│ │
│ ├─> 并行加载选中的图层数据 (优先)
│ ├─> 后台加载未选中的图层数据
│ └─> 数据缓存到 pointDataCache
└─> 4. 更新图例和图层显隐 (mapStore.updateLayerData)
├─> 更新图层 checked 状态
├─> 获取并排序图例数据 (getlegendData)
├─> 处理环保设施图例 (fp_point/eq_point 联动)
└─> 控制锚点显示/隐藏 (setLegendPointVisible)
```
## 二、核心组件和 Store
### 2.1 组件
- **GisView.vue**: 主视图,负责初始化加载流程
- **LayerController.vue**: 图层树控制器,处理图层勾选交互
- **mapLegend/index.vue**: 图例显示组件
### 2.2 Store (map.ts)
- `layerData`: 图层树配置数据
- `legendData`: 过滤排序后的图例数据
- `legendDataOriginal`: 原始图例数据
- `legendDataSelected`: 选中的图例数据
- `legendDataMap`: 图例数据映射 (nameEn -> 图例项)
- `pointDataCache`: 锚点数据缓存
- `checkedLayerKeys`: 选中的图层 key 列表
## 三、初始化加载流程 (GisView.vue)
### 3.1 获取图层配置
```typescript
const layerRes = await mapStore.getLayerConfig();
mapStore.setLayerData(limitedLayers); // 设置图层数据
```
### 3.2 收集初始选中的 keys
```typescript
const checkedKeys = collectCheckedKeys(limitedLayers);
```
### 3.3 加载锚点数据
```typescript
await mapStore.loadAllLayerData(limitedLayers, checkedKeys);
```
### 3.4 更新图例和图层显隐
```typescript
await mapStore.updateLayerData(checkedKeys, true); // isInit = true
```
## 四、锚点数据加载 (loadAllLayerData)
### 4.1 处理逻辑
1. 递归遍历所有图层配置
2. 区分**选中的图层**和**未选中的图层**
3. 选中的图层**优先加载**,阻塞等待
4. 未选中的图层**后台加载**,不阻塞 UI
### 4.2 数据缓存
- 所有加载的数据都会缓存到 `pointDataCache`
- 已缓存的数据不会重复加载
- 即使图层未选中,也会加载数据并缓存,只是隐藏不显示
### 4.3 加载完成后
1. 调用 `setSelectedLegendData()` 设置选中图例
2. 未选中图层继续后台加载,完成后打印日志
## 五、图层勾选流程 (LayerController.vue)
### 5.1 用户勾选图层
```
onCheck(v, e)
├─> 处理互斥逻辑
│ ├─> 珍稀鱼类 vs 沿程鱼类
│ ├─> 视频监控 vs AI视频监控
│ └─> 环保设施 vs 环保设施在建
├─> checkedKeys.value = checkKeys
└─> broadcast(checkKeys)
└─> mapStore.updateLayerData(v)
```
### 5.2 互斥图层处理
- `rare_fish_point``fish_along_point` 互斥
- `stinfo_video_point``stinfo_ai_video_point` 互斥
- `facilities``facilities_built` 互斥
## 六、图例数据更新 (updateLayerData)
### 6.1 处理流程
```typescript
updateLayerData(checkKeys, isInit = false)
├─> 处理互斥图层 (stinfo_video_point vs stinfo_ai_video_point)
├─> 更新图层 checked 状态 (递归遍历 layerData)
│ 记录 newlyChecked 和 newlyUnchecked
├─> 获取有效 keys (过滤掉 '-', 'customBaseLayer', 'powerBaseStation')
├─> 获取图例数据 (getlegendData)
│ 过滤掉 name === '地图' 的项
│ 递归匹配 layerCode
│ 去重 (根据 parent name)
├─> 处理环保设施图例联动
│ 勾选 fp_point 或 eq_point → 自动添加环保设施图例
│ 取消勾选 → 自动移除环保设施图例
├─> 按 orderIndex 排序
├─> 更新 legendDataSelected
└─> 控制锚点显示/隐藏
isInit = true: 处理所有图层
isInit = false: 只处理变化的图层
```
### 6.2 环保设施图例联动
```typescript
const triggerKeys = ['fp_point', 'eq_point'];
const hasTriggerLayer = triggerKeys.some(key => checkKeys.includes(key));
if (hasTriggerLayer) {
// 添加环保设施图例
} else {
// 移除环保设施图例
}
```
## 七、图例点击处理 (mapLegend)
### 7.1 单个图例项点击
```typescript
legendItemClick(item)
├─> 切换 item.checked (0 ↔ 1)
├─> 更新 legendDataMap
└─> 控制锚点显示/隐藏
pointMap 图层 → setLegendPointVisible
GISMap 图层 → controlBaseLayerTreeShowAndHidden
```
### 7.2 groupTitle 点击 (全选/取消全选)
```typescript
toggleGroup(group)
├─> 获取组内所有叶子节点 (getAllLeafItems)
├─> 判断是否有任何选中 → 决定目标是全选还是取消全选
└─> 遍历所有叶子节点,切换 checked 状态
跳过 parentName === '环保设施' 的项
跳过 canBeChecked === 0 的项
```
### 7.3 groupTitle 变灰判断
```typescript
isGroupAllUnchecked(group)
└─> 所有叶子节点 checked === 0 → 返回 true (变灰)
```
## 八、锚点显示/隐藏控制
### 8.1 pointMap 图层
```typescript
setLegendPointVisible(layerKey, nameEn, visible)
├─> 隐藏所有锚点 (setLegendPointVisible(key, '', false))
└─> 显示选中的锚点 (遍历 legendDatachecked === 1 的项)
```
### 8.2 GISMap 图层
```typescript
controlBaseLayerTreeShowAndHidden(layerKey, configId, visible)
```
## 九、关键数据结构
### 9.1 图层配置 (mapLayerVos)
```typescript
{
key: 'eng_point',
title: '水电站',
type: 'pointMap', // 或 'GISMap'
checked: 1, // 0: 未选中, 1: 选中
url: '/api/xxx',
params: {},
children: [] // 子图层
}
```
### 9.2 图例数据
```typescript
{
name: '已建',
nameEn: 'large_eng_built',
layerCode: 'eng_point',
icon: 'xxx.png',
checked: 1, // 0: 未选中, 1: 选中
canBeChecked: 1, // 0: 不可勾选, 1: 可勾选
childrenList: [] // 子图例
}
```
### 9.3 锚点数据
```typescript
{
stcd: 'xxx', // 站点编码
stnm: '三峡电站', // 站点名称
sttpMap: 'ENG', // 类型编码
anchoPointState: 'large_eng_built', // 状态
iconCode: 'xxx.png', // 图标编码
lng: 111.11, // 经度
lat: 33.33, // 纬度
}
```
## 十、加载时序图
```
时间轴
├─1─┤ setLayerData() - 设置图层配置
├─2─┤ loadAllLayerData() 开始
│ │
│ ├─3─┤ 选中图层数据请求 (阻塞)
│ │ │
│ │ └─4─┤ 数据返回,添加到地图,缓存
│ │
│ ├─5─┤ setSelectedLegendData() - 设置图例
│ │
│ └─6─┤ 未选中图层数据请求 (后台,不阻塞)
│ │
│ └─7─┤ 数据返回,添加到地图,缓存
└─8─┤ updateLayerData() - 更新图层显隐,控制锚点显示
```

View File

@ -43,8 +43,8 @@ function chartMax(
targetTickCount: number,
max: number,
min: number,
round: boolean = true,
base: number = 0
round = true,
base = 0
): { min: number; max: number; scale: number } {
const range = max - min;

View File

@ -1,13 +1,13 @@
<script setup lang="ts">
import { onMounted, ref } from "vue";
import { useJidiSelectEventStore } from "@/store/modules/jidiSelectEvent";
import { onMounted, ref } from 'vue';
import { useJidiSelectEventStore } from '@/store/modules/jidiSelectEvent';
const loading = ref(false);
const isOpen = ref(true);
const JidiSelectEventStore = useJidiSelectEventStore();
const jidiDataNum = ref(9);
const itemClick = (index: any) => {
useJidiSelectEventStore().updataJidiData(index);
JidiSelectEventStore.updataJidiData(index);
};
onMounted(() => {});
</script>
@ -32,7 +32,10 @@ onMounted(() => {});
<div
v-if="isOpen"
class="item"
v-for="(i, index) in JidiSelectEventStore.jidiData.slice(0, jidiDataNum)"
v-for="(i, index) in JidiSelectEventStore.jidiData.slice(
0,
jidiDataNum
)"
:class="{ selected: i.selected }"
@click="itemClick(index)"
>
@ -44,7 +47,7 @@ onMounted(() => {});
</div>
</template>
<style scoped lang="scss">
@use "@/styles/variables.module.scss" as *;
@use '@/styles/variables.module.scss' as *;
.jidiSelectorMod {
width: 175px;
max-height: 941px;

View File

@ -0,0 +1,449 @@
import moment from 'moment';
export const urlList = [
{
url: '/wmp-eng-server/eng/point/GetKendoListCust',
title: '常规水电',
params: {
anchoPointState: [{ field: 'anchoPointState', operator: 'isnotnull' }]
},
orders:
'{"baseId":"asc","rvcdStepSort":"asc","siteStepSort":"asc","ennm":"asc"}'
},
{
url: '/wmp-env-server/sw/getFacilityPointList/GetKendoListCust',
title: '低温水减缓设施',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-eng-server/eng/eq/interval/GetKendoListCust',
title: '生态流量达标率',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] },
orders:
'{"baseId":"asc","rvcdStepSort":"asc","siteStepSort":"asc","ennm":"asc"}'
},
{
url: '/wmp-env-server/env/wq/anchorPoint/reach/GetKendoListCust',
title: '实际水质',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/env/wq/anchorPoint/reach/GetKendoListCust',
title: '目标水质',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/env/wq/anchorPoint/GetKendoListCust',
title: '自建站',
params: {
dtinType: [{ field: 'dtinType', operator: 'eq', value: '0' }],
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
},
orders: '{"siteStepSort":"asc"}'
},
{
url: '/wmp-env-server/env/wq/anchorPoint/GetKendoListCust',
title: '国家站',
params: {
dtinType: [{ field: 'dtinType', operator: 'eq', value: '1' }],
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/wq/anchorPoint/GetKendoListCust',
title: '人工站',
params: {
dtinType: [{ field: 'dtinType', operator: 'eq', value: '2' }],
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/wq/anchorPoint/GetKendoListCust',
title: '栖息地水质站',
params: {
fhstcd: [{ field: 'fhstcd', operator: 'isnotnull' }],
fhFlag: [{ field: 'fhFlag', operator: 'eq', value: '1' }],
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fp/point/qgc/GetKendoListCust',
title: '过鱼设施',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-eng-server/eng/eq/eqds/GetKendoListCust',
title: '生态流量泄放设施',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/fb/point/GetKendoListCust',
title: '鱼类增殖站',
params: {
sttp: [{ field: 'sttp', operator: 'eq', value: 'FB' }],
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fhvap/GetKendoListCust',
title: '珍稀植物园',
params: { sttpCode: 'VP', lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/env/fhvap/GetKendoListCust',
title: '动物救助站',
params: { sttpCode: 'VA', lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/fb/point/GetKendoListCust',
title: '人工产卵场',
params: { sttp: 'SG', lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/sw/getEngTempPointList/GetKendoListCust',
title: '水温监测断面',
keyType: 'wt_point',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/sw/getEngTempPointList/GetKendoListCust',
title: '自建水温站',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }], flag: '0' }
},
{
url: '/wmp-env-server/sw/getEngTempPointList/GetKendoListCust',
title: '人工水温站',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }], flag: '2' }
},
{
url: '/wmp-env-server/sw/getEngTempPointList/GetKendoListCust',
title: '栖息地水温站',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
fhstcd: [{ field: 'fhstcd', operator: 'isnotnull' }],
fhFlag: '1'
}
},
{
url: '/wmp-env-server/env/fhvap/GetKendoListCust',
title: '栖息地',
params: { sttpCode: 'FH', lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/env/fhvap/fhPoint/GetKendoListCust',
title: '水质监测站',
params: { sttpCode: 'WQ', lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/env/fhvap/fhPoint/GetKendoListCust',
title: '水温监测站',
params: {
sttpCode: 'WTRV',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fhvap/fhPoint/GetKendoListCust',
title: '流量监测站',
params: { sttpCode: 'ZQ', lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/env/fhvap/fhPoint/GetKendoListCust',
title: '视频监控',
params: { sttpCode: 'VD', lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/env/vd/aiPoint/GetKendoListCust',
title: 'AI视频监控站',
params: { sttpCode: 'AIVD' }
},
{
url: '/wmp-env-server/env/fh/vdpoint/GetKendoListCust',
title: '水电站监控视频',
keyType: 'video_fbfm_point',
params: {
sttp: 'VD_FBFM',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fh/vdpoint/GetKendoListCust',
title: '生态流量监测断面视频',
keyType: 'video_eqs_point',
params: {
sttp: 'VD_EQS',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fh/vdpoint/GetKendoListCust',
title: '水质站运行视频',
keyType: 'video_wq_point',
params: {
sttp: 'VD_WQ',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fh/vdpoint/GetKendoListCust',
title: '过鱼设施视频',
keyType: 'video_fp_point',
params: {
sttp: 'VD_FP',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fh/vdpoint/GetKendoListCust',
title: '鱼类增殖站视频',
keyType: 'video_fb_point',
params: {
sttp: 'VD_FB',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fh/vdpoint/GetKendoListCust',
title: '栖息地视频',
keyType: 'video_fh_point',
params: {
sttp: 'VD_FH',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fh/vdpoint/GetKendoListCust',
title: '低温水减缓设施视频',
keyType: 'video_dw_point',
params: {
sttp: 'VD_DW',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fh/vdpoint/GetKendoListCust',
title: '动物救助站视频',
keyType: 'video_va_point',
params: {
sttp: 'VD_VA',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fh/vdpoint/GetKendoListCust',
title: '珍稀植物园视频',
keyType: 'video_vp_point',
params: {
sttp: 'VD_VP',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/we/point/qgc/GetKendoListCust',
title: '水生生态调查断面',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] },
orders: '{"siteStepSort":"asc"}'
},
{
url: '/wmp-env-server/env/we/fishPoint/qgc/GetKendoListCust',
title: '鱼类分布',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-eng-server/eng/alarmPoint/GetKendoListCust',
title: '水电站告警情况',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/fb/point/discharge/GetKendoListCust',
title: '水电站',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/env/fh/zqpoint/GetKendoListCust',
title: '国家水文站',
params: { dtinType: 1, lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/env/fh/zqpoint/GetKendoListCust',
title: '自建水文站',
params: { dtinType: 0, lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/env/wq/anchorPoint/GetKendoListCust',
title: '增殖站水质站',
params: {
dtinType: 0,
sttpCode: 'WQFB',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/fh/vdpoint/GetKendoListCust',
title: '视频监控站',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/env/wb/point/GetKendoListCust',
title: '气象站',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
},
{
url: '/wmp-env-server/sw/getEngTempPointList/getLastData',
title: '水温站点',
params: {
logic: 'and',
filters: []
}
},
{
url: '/wmp-env-server/env/wq/anchorPoint/GetKendoListCust',
title: '水质站点',
params: {
logic: 'and',
filters: [
{
field: 'lgtd',
operator: 'isnotnull',
dataType: 'string'
},
{
field: 'orderIndex',
operator: 'isnotnull',
dataType: 'string'
}
]
},
orders: '{"orderIndex":"asc"}'
},
{
url: '/wmp-env-server/env/warn/stcd/point/GetKendoListCust',
title: '水质告警',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
sttpCode: [{ field: 'sttpCode', operator: 'eq', value: 'WQ' }]
}
},
{
url: '/wmp-env-server/env/warn/stcd/point/GetKendoListCust',
title: '水温告警',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
sttpCode: [{ field: 'sttpCode', operator: 'eq', value: 'WTRV' }]
}
},
{
url: '/wmp-env-server/env/warn/stcd/point/GetKendoListCust',
title: '水位告警',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
sttpCode: [{ field: 'sttpCode', operator: 'eq', value: 'ENG' }]
}
},
{
url: '/wmp-env-server/env/warn/stcd/operatePoint/GetKendoListCust',
title: '环保设施告警',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
yr: moment().format('YYYY')
}
},
{
url: '/wmp-env-server/env/fp/point/built/GetKendoListCust',
title: '在建过鱼设施-地图锚点',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
bldsttCcode: [{ field: 'bldsttCcode', operator: 'eq', value: '1' }]
}
},
{
url: '/wmp-env-server/env/fb/point/built/GetKendoListCust',
title: '在建鱼类增殖站',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
sttpCode: [{ field: 'sttpCode', operator: 'eq', value: 'FB' }],
bldsttCcode: [{ field: 'bldsttCcode', operator: 'eq', value: '1' }]
}
},
{
url: '/wmp-env-server/env/fb/point/built/GetKendoListCust',
title: '在建人工产卵场',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
sttpCode: [{ field: 'sttpCode', operator: 'eq', value: 'SG' }],
bldsttCcode: [{ field: 'bldsttCcode', operator: 'eq', value: '1' }]
}
},
{
url: '/wmp-env-server/env/fhvap/built/GetKendoListCust',
title: '珍稀植物园-在建',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
sttpCode: [{ field: 'sttpCode', operator: 'eq', value: 'VP' }],
bldsttCcode: [{ field: 'bldsttCcode', operator: 'eq', value: '1' }]
}
},
{
url: '/wmp-env-server/env/fhvap/built/GetKendoListCust',
title: '动物救助站-在建',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
sttpCode: [{ field: 'sttpCode', operator: 'eq', value: 'VA' }],
bldsttCcode: [{ field: 'bldsttCcode', operator: 'eq', value: '1' }]
}
},
{
url: '/wmp-env-server/eng/eq/eqds/built/GetKendoListCust',
title: '在建生态流量泄放设施',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
BLDSTT_CCODE: [{ field: 'BLDSTT_CCODE', operator: 'eq', value: '1' }]
}
},
{
url: '/wmp-env-server/env/we/fishList/point/GetKendoList',
title: '鱼类沿程',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/env/wva/point/GetKendoListCust',
title: '野生动物监测',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }],
sttpCode: [{ field: 'sttpCode', operator: 'eq', value: 'WVA' }]
}
},
{
url: '/wmp-env-server/env/we/fishList/point/GetNativeRareFish',
title: '土著珍稀鱼类',
params: {
rare: '1',
specOrigin: '1',
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/te/tet/point/GetTerrestrialAnimal',
title: '陆生动物分布',
params: {
lgtd: [{ field: 'lgtd', operator: 'isnotnull' }]
}
},
{
url: '/wmp-env-server/sdFprdR/point/getFprdPointList',
title: '鱼类调查装置',
params: { lgtd: [{ field: 'lgtd', operator: 'isnotnull' }] }
}
];

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,7 @@
@use 'src/styles/ant-design-vue' as permission;
@use './sidebar' as sidebar;
@use './tailwind' as tailwind;
@use './popup-styles' as popup;
@import './iconfont/iconfont.css';
html,

View File

@ -0,0 +1,422 @@
// Popup 相关样式 - 用于 map.ol.ts generatePopupHtml 生成的 HTML
.iconDiv {
background: rgba(0, 0, 0, 0.6);
color: #fff;
border-radius: 4px;
padding: 5px;
font-size: 12px;
&.smallfont {
font-size: 10px;
}
}
.iconDivContent {
display: flex;
justify-content: space-between;
}
.iconDivTitle {
width: 100%;
text-align: center;
font-weight: normal;
}
.iconDivLeft {
width: 50%;
box-sizing: border-box;
}
.iconDivRight {
width: 50%;
box-sizing: border-box;
}
// 标题文字自适应大小
.iconDivTitle.title-md {
font-size: 14px !important;
}
.iconDivTitle.title-sm {
font-size: 13px !important;
}
.iconDivTitle.title-xs {
font-size: 12px !important;
}
.iconDivTitle.title-xxs {
font-size: 12px !important;
}
.iconEngDiv_large_eng_built,
.iconEngDiv_large_eng_ubuilt,
.iconEngDiv_large_eng_nbuilt {
width: 156px;
height: 170px;
background-repeat: no-repeat;
background-size: 100%;
display: flex;
flex-wrap: wrap;
margin-bottom: 0 !important;
.iconDivTitle {
width: 100%;
height: 48%;
line-height: 100px;
text-align: center;
align-items: center;
font-size: 16px;
text-align: center;
font-weight: normal;
position: relative;
&::after {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 2px;
width: 80%;
left: 50%;
transform: translateX(-50%);
content: ' ';
}
}
.iconDivContent {
width: 100%;
height: 52%;
font-size: 12px;
padding-top: 4px;
position: relative;
&::after {
position: absolute;
top: 0;
left: 50%;
right: 0;
width: 2px;
height: 62%;
transform: translateX(-50%);
content: ' ';
}
.iconDivLeft {
width: 50%;
padding-left: 38px;
box-sizing: border-box;
}
.iconDivRight {
width: 50%;
padding-left: 6px;
box-sizing: border-box;
padding-right: 34px;
div:nth-child(1) {
text-align: right;
}
}
}
}
.iconEngDiv_mid_eng_built,
.iconEngDiv_mid_eng_ubuilt,
.iconEngDiv_mid_eng_nbuilt {
width: 150px;
height: 112px;
background-repeat: no-repeat;
background-size: 100%;
display: flex;
flex-direction: column;
margin-bottom: 0 !important;
.iconDivTitle {
width: 100%;
height: 50px;
line-height: 52px;
text-align: center;
align-items: center;
font-size: 16px;
text-align: center;
font-weight: normal;
}
.iconDivContent {
width: 100%;
height: 36;
padding: 0 10px;
font-size: 11px;
position: relative;
&::after {
position: absolute;
top: 0;
left: 50%;
right: 0;
width: 2px;
height: 100%;
content: ' ';
}
.iconDivLeft {
width: 50%;
text-align: center;
}
.iconDivRight {
width: 50%;
text-align: center;
}
}
}
.iconEngDiv-large_eng_nbuilt-0 {
background-image: url('@/assets/images/mapTip/map-dxsdzGuihuaNetMonitor.svg');
color: #859ea3;
.iconDivTitle,
.iconDivContent {
&::after {
background-color: #859ea3;
}
}
}
.iconEngDiv-large_eng_ubuilt-1 {
background-image: url('@/assets/images/mapTip/map-dxsdzZaijianNetMonitor.svg');
color: #5389b9;
.iconDivTitle,
.iconDivContent {
&::after {
background-color: #5389b9;
}
}
}
.iconEngDiv-large_eng_built-2 {
background-image: url('@/assets/images/mapTip/map-dxsdzYijianNetMonitor.svg');
color: #7dbc18;
.iconDivTitle,
.iconDivContent {
&::after {
background-color: #95c842;
}
}
}
.iconEngDiv-mid_eng_nbuilt-0 {
background-image: url('@/assets/images/mapTip/map-zxsdzGuihuaNetMonitor.svg');
color: #859ea3;
.iconDivContent {
&::after {
background-color: #859ea3;
}
}
}
.iconEngDiv-mid_eng_ubuilt-1 {
background-image: url('@/assets/images/mapTip/map-zxsdzZaijianNetMonitor.svg');
color: #5389b9;
.iconDivContent {
&::after {
background-color: #5389b9;
}
}
}
.iconEngDiv-mid_eng_built-2 {
background-image: url('@/assets/images/mapTip/map-zxsdzYijianNetMonitor.svg');
color: #7dbc18;
.iconDivContent {
&::after {
background-color: #95c842;
}
}
}
.map-tooltip {
height: auto;
color: rgba(255, 255, 255, 0.85);
text-align: center;
position: relative;
padding: 24px 0 25px;
// width: 279px;
width: 260px;
&::after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 24px;
background: url(@/assets/images/mapTip/top@260.png) center no-repeat;
background-size: 100% auto;
}
&::before {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 25px;
background: url(@/assets/images/mapTip/bottom@260.png) center no-repeat;
background-size: 100% auto;
}
&-box {
padding: 0 12px;
&::before {
content: '';
position: absolute;
top: 24px;
bottom: 25px;
left: 0;
right: 0;
z-index: -1;
background: url(@/assets/images/mapTip/center@260.png) repeat-y;
background-size: 100% auto;
}
}
&-title {
font-size: 16px;
font-weight: 500;
color: #fff;
margin-top: 4px;
}
&-list {
font-size: 14px !important;
line-height: 1.5;
> li {
display: flex;
text-align: left;
.__label {
flex: 0 0 100px;
width: 100px;
text-align: right;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.__warn {
color: #ff4d4f;
}
}
}
&-content {
margin-top: 10px;
border-top: 1px dashed #12aaeb;
padding: 10px 0;
margin: 10px 0 0;
&.__noborder {
border: none;
margin-top: 6px;
}
&.__small {
font-size: 12px !important;
}
}
&-sub {
margin: 0;
padding: 4px 0 0 0;
text-align: center;
color: #fff;
font-size: 12px;
}
&-sub1 {
text-align: center;
position: relative;
height: 1px;
border-bottom: 1px dashed #12aaeb;
margin-top: 16px;
.__content {
position: absolute;
top: -9px;
left: 50%;
transform: translateX(-50%);
background-color: rgb(88 110 134);
padding: 0 6px;
font-size: 12px;
border-radius: 3px;
white-space: nowrap;
}
}
&.map-tooltip-small {
width: 190px;
padding: 18px 0 18px;
&::after {
background-image: url(@/assets/images/mapTip/top@175.png);
height: 18px;
}
&::before {
background-image: url(@/assets/images/mapTip/bottom@175.png);
height: 18px;
}
.map-tooltip-box {
padding: 0 10px;
&::before {
content: '';
position: absolute;
top: 18px;
bottom: 18px;
left: 0;
right: 0;
z-index: -1;
background-image: url(@/assets/images/mapTip/center@175.png);
}
}
.map-tooltip-list {
> li {
.__label {
flex: 0 0 84px;
width: 84px;
}
}
}
}
&.map-tooltip-middle {
width: 225px;
padding: 18px 0 18px;
&::after {
background-image: url(@/assets/images/mapTip/top@215.png);
height: 18px;
}
&::before {
background-image: url(@/assets/images/mapTip/bottom@215.png);
height: 18px;
}
.map-tooltip-box {
padding: 0 10px;
&::before {
content: '';
position: absolute;
top: 18px;
bottom: 18px;
left: 0;
right: 0;
z-index: -1;
background-image: url(@/assets/images/mapTip/center@215.png);
}
}
.map-tooltip-list {
> li {
.__label {
flex: 0 0 100px;
width: 100px;
}
}
&.__list2 {
> li {
.__label {
flex: 0 0 90px;
width: 90px;
}
}
}
}
}
.map-waterQuality-subtitle {
margin-top: 10px;
border: 1px solid rgba(77, 129, 167);
border-bottom: none;
.map-waterQuality-leftType,
.map-waterQuality-rightType {
width: 50%;
}
}
}

View File

@ -173,11 +173,13 @@ export function downloadFileByUrl(url: string, fileName?: string) {
document.body.removeChild(link);
});
}
const modules = import.meta.glob('@/assets/legend/*.svg', { eager: true });
const modules = import.meta.glob('@/assets/legend/*.{svg,png}', {
eager: true
});
// 图例图标映射
export const iconMap: Record<string, string> = {};
Object.entries(modules).forEach(([path, module]) => {
const fileName = path.match(/\/([^/]+)\.svg$/)?.[1];
const fileName = path.match(/\/([^/]+)\.(svg|png)$/)?.[1];
if (fileName) {
iconMap[fileName] = (module as any).default;
}
@ -188,10 +190,7 @@ export const getIconPath = (icon: string): string => {
};
// 动态计算表格滚动高度
export const calcTableScrollY = (
tableContainerRef: any,
otherHeight: number = 112
) => {
export const calcTableScrollY = (tableContainerRef: any, otherHeight = 112) => {
if (!tableContainerRef) return;
// 获取容器高度
const containerHeight = tableContainerRef.clientHeight;

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@ import router from '@/router';
// 创建 axios 实例
const service = axios.create({
baseURL: import.meta.env.VITE_APP_BASE_API,
timeout: 15000, // 15秒
timeout: 25000, // 15秒
headers: { 'Content-Type': 'application/json;charset=utf-8' }
});
@ -22,7 +22,8 @@ service.interceptors.request.use(
if (
config.url.includes('/dec-lygk-base-server') ||
config.url.includes('/wmp-env-server') ||
config.url.includes('/wmp-sys-server')
config.url.includes('/wmp-sys-server') ||
config.url.includes('/wmp-eng-server')
) {
config.headers._appid = '974975A6-47FD-4C04-9ACD-68938D2992BD';
config.headers._isolateid = '5b34aecb-adfb-4dfc-ad95-21505a9eb388';
@ -30,7 +31,7 @@ service.interceptors.request.use(
config.headers._sysid = '10EC2E0B-AEA9-4757-83A2-201BA1BC54E9';
config.headers.authorization =
'bearer a385ef90-a17d-429f-817f-7d961594020c';
'bearer a31a19b6-508c-4773-bde8-62df5c448183';
config.baseURL = '/';
} else {
const user = useUserStoreHook();

View File

@ -473,7 +473,7 @@ const ensureRowState = (index: number) => {
const handleHbrvcdChange = async (
hbrvcd: string,
index: number,
type: string = "start"
type = "start"
) => {
const state = ensureRowState(index);
editingData.value.hbrvnm = hbrvcdOptions.value.find(
@ -504,7 +504,7 @@ const handleHbrvcdChange = async (
}
};
const handleEngChange = async (rstcd: string, index: number, type: string = "start") => {
const handleEngChange = async (rstcd: string, index: number, type = "start") => {
const state = ensureRowState(index);
editingData.value.ennm = state.engOptions.find(
(item: any) => item.stcd === rstcd

View File

@ -34,13 +34,6 @@ export default ({ mode }: ConfigEnv): UserConfig => {
rewrite: path =>
path.replace(new RegExp('^' + env.VITE_APP_BASE_API), '')
},
'/geoserver': {
target: 'https://211.99.26.225:18085', // 地图-线上API地址
// target: 'http://172.16.31.112:8093', // 地图-本地API地址
changeOrigin: true,
secure: false,
rewrite: path => path.replace(new RegExp('^/geoserver'), '/geoserver')
},
'/process': {
target: 'http://localhost:5174',
changeOrigin: true
@ -55,6 +48,13 @@ export default ({ mode }: ConfigEnv): UserConfig => {
'/api/dec-lygk-base-server'
)
},
'/wmp-env-server': {
target: 'https://211.99.26.225:12122',
changeOrigin: true,
secure: false,
rewrite: path =>
path.replace(new RegExp('^/wmp-env-server'), '/api/wmp-env-server')
},
'/api/wmp-env-server': {
target: 'https://211.99.26.225:12122',
changeOrigin: true,
@ -65,6 +65,16 @@ export default ({ mode }: ConfigEnv): UserConfig => {
'/api/wmp-env-server'
)
},
'/api/wmp-eng-server': {
target: 'https://211.99.26.225:12122',
changeOrigin: true,
secure: false,
rewrite: path =>
path.replace(
new RegExp('^/api/wmp-eng-server'),
'/api/wmp-eng-server'
)
},
'/api/wmp-sys-server': {
target: 'https://211.99.26.225:12122',
changeOrigin: true,