diff --git a/packages/screen/package.json b/packages/screen/package.json index 00a2548..9091471 100644 --- a/packages/screen/package.json +++ b/packages/screen/package.json @@ -9,17 +9,18 @@ "preview": "vite preview" }, "dependencies": { - "vue": "^3.5.18", - "vue-router": "^4.6.3", - "pinia": "^3.0.3", - "element-plus": "^2.11.5", "@element-plus/icons-vue": "^2.3.2", - "echarts": "^6.0.0", - "vue-echarts": "^8.0.1", - "cesium": "^1.135.0", - "axios": "^1.13.2", + "@h5/shared": "workspace:*", + "@turf/turf": "^7.3.0", "@vueuse/core": "^14.0.0", - "@h5/shared": "workspace:*" + "axios": "^1.13.2", + "cesium": "^1.135.0", + "echarts": "^6.0.0", + "element-plus": "^2.11.5", + "pinia": "^3.0.3", + "vue": "^3.5.18", + "vue-echarts": "^8.0.1", + "vue-router": "^4.6.3" }, "devDependencies": { "@vitejs/plugin-vue": "^6.0.1", diff --git a/packages/screen/src/router/index.js b/packages/screen/src/router/index.js index 28e7400..8b66e8f 100644 --- a/packages/screen/src/router/index.js +++ b/packages/screen/src/router/index.js @@ -10,6 +10,9 @@ const routes = [ { path: '/cockpit', name: 'Cockpit', + meta: { + screen: true + }, component: () => import('../views/cockpit/index.vue') }, { diff --git a/packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/LocationPanel/地理位置内容背景.png b/packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/LocationPanel/地理位置内容背景.png index 43e9c7b..0ddb80c 100644 Binary files a/packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/LocationPanel/地理位置内容背景.png and b/packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/LocationPanel/地理位置内容背景.png differ diff --git a/packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/LocationPanel/地理位置按钮背景.png b/packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/LocationPanel/地理位置按钮背景.png index 25ba1d4..82d2275 100644 Binary files a/packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/LocationPanel/地理位置按钮背景.png and b/packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/LocationPanel/地理位置按钮背景.png differ diff --git a/packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/加载.gif b/packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/加载.gif new file mode 100644 index 0000000..596a2e8 Binary files /dev/null and b/packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/加载.gif differ diff --git a/packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/加载gif.gif b/packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/加载gif.gif deleted file mode 100644 index 159a5b0..0000000 Binary files a/packages/screen/src/views/3DSituationalAwarenessRefactor/assets/images/加载gif.gif and /dev/null differ diff --git a/packages/screen/src/views/3DSituationalAwarenessRefactor/components/LeftPanel/ForceDispatch.vue b/packages/screen/src/views/3DSituationalAwarenessRefactor/components/LeftPanel/ForceDispatch.vue index 18af93e..f978156 100644 --- a/packages/screen/src/views/3DSituationalAwarenessRefactor/components/LeftPanel/ForceDispatch.vue +++ b/packages/screen/src/views/3DSituationalAwarenessRefactor/components/LeftPanel/ForceDispatch.vue @@ -169,14 +169,14 @@ const handleStartDispatch = () => { .force-dispatch__level-label { font-size: fs(18); font-family: SourceHanSansCN-Regular, sans-serif; - color: rgba(255, 255, 255, 0.8); + color: var(--text-white); } .force-dispatch__level-value { font-size: fs(18); font-family: SourceHanSansCN-Bold, sans-serif; font-weight: 600; - color: rgba(255, 255, 255, 0.95); + color: var(--text-white); } /* 智能应急方案按钮 */ @@ -210,7 +210,7 @@ const handleStartDispatch = () => { font-size: fs(18); font-family: SourceHanSansCN-Medium, sans-serif; font-weight: 500; - color: rgba(255, 255, 255, 0.95); + color: var(--text-white); } .force-dispatch__plan-icon { @@ -254,7 +254,7 @@ const handleStartDispatch = () => { .force-dispatch__stat-label { font-size: fs(12); font-family: SourceHanSansCN-Regular, sans-serif; - color: rgba(255, 255, 255, 0.7); + color: var(--text-white); } .force-dispatch__stat-value { @@ -272,7 +272,7 @@ const handleStartDispatch = () => { font-size: fs(12); font-family: SourceHanSansCN-Regular, sans-serif; font-weight: 400; - color: rgba(255, 255, 255, 0.8); + color: var(--text-white); margin-left: vw(2); } @@ -349,14 +349,14 @@ const handleStartDispatch = () => { font-size: fs(14); font-family: SourceHanSansCN-Medium, sans-serif; font-weight: 500; - color: rgba(255, 255, 255, 0.9); + color: var(--text-white); } .force-dispatch__circle-line2 { font-size: fs(13); font-family: SourceHanSansCN-Regular, sans-serif; font-weight: 400; - color: rgba(255, 255, 255, 0.8); + color: var(--text-white); } /* 旋转动画 */ @@ -391,13 +391,13 @@ const handleStartDispatch = () => { .force-dispatch__eta-label { font-size: fs(11); font-family: SourceHanSansCN-Regular, sans-serif; - color: rgba(255, 255, 255, 0.6); + color: var(--text-white); } .force-dispatch__eta-value { font-size: fs(13); font-family: SourceHanSansCN-Bold, sans-serif; font-weight: 600; - color: rgba(255, 255, 255, 0.95); + color: var(--text-white); } diff --git a/packages/screen/src/views/3DSituationalAwarenessRefactor/components/PageHeader.vue b/packages/screen/src/views/3DSituationalAwarenessRefactor/components/PageHeader.vue index 6d360ca..68ee91e 100644 --- a/packages/screen/src/views/3DSituationalAwarenessRefactor/components/PageHeader.vue +++ b/packages/screen/src/views/3DSituationalAwarenessRefactor/components/PageHeader.vue @@ -106,7 +106,7 @@ const handleBack = () => { .logo-section { .logo-image { width: vw(42); - height: vh(30); + height: vw(42); border-radius: 50%; } } diff --git a/packages/screen/src/views/3DSituationalAwarenessRefactor/components/RightPanel/CollaborationInfo.vue b/packages/screen/src/views/3DSituationalAwarenessRefactor/components/RightPanel/CollaborationInfo.vue index 678aed4..baa9bbe 100644 --- a/packages/screen/src/views/3DSituationalAwarenessRefactor/components/RightPanel/CollaborationInfo.vue +++ b/packages/screen/src/views/3DSituationalAwarenessRefactor/components/RightPanel/CollaborationInfo.vue @@ -1,16 +1,17 @@ @@ -59,13 +78,19 @@ const getSourceColor = (source) => { &__header { position: absolute; - top: vh(16); + top: 10px; right: vw(5); z-index: 1; .header-icon { width: vw(20); height: vh(20); + cursor: pointer; + transition: all 0.3s ease; + + &:hover { + opacity: 0.8; + } } } @@ -76,6 +101,8 @@ const getSourceColor = (source) => { padding: vw(8) vw(16); max-height: vh(200); overflow-y: auto; + transition: max-height 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.3s ease; + opacity: 1; &::-webkit-scrollbar { width: vw(4); @@ -114,5 +141,27 @@ const getSourceColor = (source) => { } } } + + // 折叠状态 + &.is-collapsed { + .header-icon { + transform: rotate(180deg); + } + + .collaboration-info__list { + max-height: vh(30); // 折叠时只显示一行的高度 + overflow: hidden; + + .info-item:not(:first-child) { + opacity: 0; + transform: translateY(-10px); + } + } + } + + // 为列表项添加过渡 + .info-item { + transition: opacity 0.3s ease, transform 0.3s ease; + } } diff --git a/packages/screen/src/views/3DSituationalAwarenessRefactor/composables/use3DTiles.js b/packages/screen/src/views/3DSituationalAwarenessRefactor/composables/use3DTiles.js index b2423c8..4e40916 100644 --- a/packages/screen/src/views/3DSituationalAwarenessRefactor/composables/use3DTiles.js +++ b/packages/screen/src/views/3DSituationalAwarenessRefactor/composables/use3DTiles.js @@ -30,18 +30,18 @@ export function use3DTiles() { const tileset = await Cesium.Cesium3DTileset.fromUrl(url, { skipLevelOfDetail: true, - baseScreenSpaceError: 100, + baseScreenSpaceError: 1024, skipScreenSpaceErrorFactor: 16, skipLevels: 1, immediatelyLoadDesiredLevelOfDetail: false, loadSiblings: false, - maximumScreenSpaceError: 16.0, // 进一步增大,最大限度减少瓦片细化(之前是8.0) - dynamicScreenSpaceError: false, // 禁用动态屏幕空间误差调整 - dynamicScreenSpaceErrorDensity: 0, // 禁用密度调整 - dynamicScreenSpaceErrorFactor: 1, // 禁用动态因子 - foveatedScreenSpaceError: false, // 禁用视锥细化 - foveatedConeSize: 0.1, // 减小视锥大小 - foveatedMinimumScreenSpaceErrorRelaxation: 0 // 禁用放松 + maximumScreenSpaceError: 2.0, // 降低到2.0以提高模型精细度(原来是16.0) + dynamicScreenSpaceError: true, // 启用动态屏幕空间误差调整 + dynamicScreenSpaceErrorDensity: 0.00278, // 启用密度调整 + dynamicScreenSpaceErrorFactor: 4.0, // 动态因子 + foveatedScreenSpaceError: true, // 启用视锥细化 + foveatedConeSize: 0.1, // 视锥大小 + foveatedMinimumScreenSpaceErrorRelaxation: 0.0 // 最小放松 }) // 将tileset添加到viewer的primitives diff --git a/packages/screen/src/views/3DSituationalAwarenessRefactor/index.vue b/packages/screen/src/views/3DSituationalAwarenessRefactor/index.vue index 9f9660a..1c222c0 100644 --- a/packages/screen/src/views/3DSituationalAwarenessRefactor/index.vue +++ b/packages/screen/src/views/3DSituationalAwarenessRefactor/index.vue @@ -132,7 +132,7 @@
加载中 diff --git a/packages/screen/src/views/cockpit/api/commonHttp.js b/packages/screen/src/views/cockpit/api/commonHttp.js index a31e253..a436756 100644 --- a/packages/screen/src/views/cockpit/api/commonHttp.js +++ b/packages/screen/src/views/cockpit/api/commonHttp.js @@ -2,7 +2,6 @@ import { request } from '@shared/utils/request' // 获取业务底图 export function getBaseMap() { - // return [...ddt] return request({ url: '/snow-ops-platform/dataDirectory/queryCatalog', method: 'GET', @@ -14,7 +13,6 @@ export function getBaseMap() { // 获取业务图 export function getBusinessMap() { - // return [...si] return request({ url: '/snow-ops-platform/dataDirectory/queryCatalog', method: 'GET', @@ -24,6 +22,48 @@ export function getBusinessMap() { }) } +// 获取所有的养护站 +export function getAllYHZList() { + return request({ + url: '/snow-ops-platform/yhz/listByDistrict', + method: 'get', + params: { + qxmc: '' + } + }) +} + + +export function getYHZDetail(params) { + return request({ + url: '/snow-ops-platform/yhz/getById', + method: 'get', + params + }) +} + +// 获得高海拔路段图 high-altitude road +export function getHighAltitudeRoadMap () { + return request({ + url: '/snow-ops-platform/dataDirectory/queryCatalog', + method: 'GET', + params: { + pcatalog: 'GHBMAP' + } + }) +} + +// 获取天气预警统计 +export function getWeatherWarningStatistics (params) { + return request({ + url: '/snow-ops-platform/weatherWarning/statistics', + method: 'GET', + params + }) +} + + + diff --git a/packages/screen/src/views/cockpit/assets/img/header-bg.png b/packages/screen/src/views/cockpit/assets/img/header-bg.png index 3020925..b873c80 100644 Binary files a/packages/screen/src/views/cockpit/assets/img/header-bg.png and b/packages/screen/src/views/cockpit/assets/img/header-bg.png differ diff --git a/packages/screen/src/views/cockpit/components/CockpitLayout.vue b/packages/screen/src/views/cockpit/components/CockpitLayout.vue index 36beaf8..69834bd 100644 --- a/packages/screen/src/views/cockpit/components/CockpitLayout.vue +++ b/packages/screen/src/views/cockpit/components/CockpitLayout.vue @@ -1,6 +1,7 @@ @@ -60,9 +58,11 @@ import LegendToolbar from './LegendToolbar.vue' import EmergencyForceTooltip from './EmergencyForceTooltip.vue' import emergencyForceMarkerIcon from '../assets/legendTool/应急力量icon定位.png' -onMounted(()=>{ +onMounted(() => { // 加载地图业务底图 并 聚焦中心点 mapBase.loadBaseData() + + weatherWarningRef.value.loadData() }) // ==================== 常量定义 ==================== @@ -79,6 +79,9 @@ const EMERGENCY_FORCE_LAYER_ID = 'legend:emergencyForce' */ const EMERGENCY_FORCE_CACHE_TTL = 60 * 1000 +// ==================== 组件实例 ==================== +const weatherWarningRef = ref(null) + // ==================== 状态管理 ==================== const mapStore = useMapStore() @@ -101,7 +104,7 @@ const mapBase = useMapBase(mapStore) /** * 标记图hook,搭配lengendToolbar使用, 作用是点击某个图例项时,在地图上显示所有该图例的图 */ -const mapImageMark = useMapImageMark(mapStore) +const mapImageMarkHook = useMapImageMark(mapStore) /** * 应急力量数据加载状态 @@ -131,8 +134,21 @@ const emergencyForceAbortController = ref(null) /** * 工具图标列表通过key关联 * key具体有哪些,请根据LegendToolbar.vue中定义的defaultLegendItems + * 后续的ImageMarkData中也需要与这里的key值对应 */ -const legendKeys = ref(['serviceFacility','riskRoad','blockEvent','weatherAlert','emergencyForce']) +const legendKeys = ref(['serviceFacility', 'riskRoad', 'blockEvent', 'weatherAlert', 'emergencyForce']) + +/** + * 过滤标记对象,存放当前需要过滤的关键字 + */ +const filterMark = ref({ + serviceFacility: [] +}) + +/** + * 图例项 + */ +const legendToolActiveItem = ref([]) // ==================== 工具函数 ==================== @@ -413,6 +429,48 @@ const renderEmergencyForcePoints = async (entityService, points, markerIcon) => // ==================== 事件处理 ==================== +/** + * 应急资源表格行被点击时触发 + */ +const handleEmergencyResourceClick = (resource) => { + let focusKey = null + + // 根据区县名称,过滤养护站 + const filterList = filterMark.value.serviceFacility + const index = filterList.findIndex((item) => item == resource.qxmc) + // 实现第一次点击表示选中,第二次点击表示取消选中 + if (index > -1) { + filterList.splice(index, 1) + } + else { + filterList.push(resource.qxmc) + focusKey = resource.qxmc + } + + // 当点击了某个区县,需要将养护站的legend也点亮 + const legendIndex = legendToolActiveItem.value.indexOf('serviceFacility') + // 如果过滤列表存在数据,则需要点亮legend + if (filterList.length && legendIndex == -1) { + legendToolActiveItem.value.push('serviceFacility') + } + // 如果过滤列表不存在,则需要关闭legend + if (!filterList.length && legendIndex > -1) { + legendToolActiveItem.value.splice(legendIndex, 1) + } + + // 调用图例hook来进行数据的请求与图例的绘制,第一个回调函数是过滤点位,第二个是聚焦点位 + mapImageMarkHook.filterYHZMark( + "serviceFacility", + (item) => { + return filterList.find((filterItem) => filterItem == item.qxmc) + }, + (item) => { + return item.qxmc == focusKey + } + ) + +} + /** * 处理图例工具栏的标记切换事件 * @@ -422,10 +480,19 @@ const renderEmergencyForcePoints = async (entityService, points, markerIcon) => * @param {string} [payload.markerIcon] - 标记图标 */ const handleLegendMarkerToggle = async ({ key, active, markerIcon }) => { + if (key === 'riskRoad') { + mapBase.toggleHighAltitudeRoadMap(active) + return + } + + // 只处理应急力量图例项 if (key !== 'emergencyForce') { + if (active == false) { + filterMark.value[key] = [] + } - mapImageMark.toggleMark({ key, active, markerIcon }) + mapImageMarkHook.toggleMark({ key, active, markerIcon }) return } @@ -552,6 +619,7 @@ onBeforeUnmount(() => { @supports (width: 1cqw) { --cq-inline-100: 100cqw; } + @supports (height: 1cqh) { --cq-block-100: 100cqh; } @@ -568,13 +636,15 @@ onBeforeUnmount(() => { width: 100%; height: 100%; min-height: var(--cockpit-min-height); - min-width: 0; /* 允许 flex 子元素收缩 */ + min-width: 0; + /* 允许 flex 子元素收缩 */ background: url(../assets/img/cockpit-main-bg.png) no-repeat; background-size: cover; display: flex; flex-direction: column; - overflow: auto; /* 当宿主高度 < 最小高度时允许滚动 */ + overflow: auto; + /* 当宿主高度 < 最小高度时允许滚动 */ } /* 窄容器嵌入的紧凑布局(<1100px 宽度)*/ @@ -586,8 +656,10 @@ onBeforeUnmount(() => { .cockpit-main { position: relative; flex: 1; - min-height: 0; /* 允许网格在 flex 上下文中收缩 */ - overflow: hidden; /* 防止内容溢出 */ + min-height: 0; + /* 允许网格在 flex 上下文中收缩 */ + overflow: hidden; + /* 防止内容溢出 */ } /* 地图底层 - 填满整个容器 */ @@ -603,7 +675,8 @@ onBeforeUnmount(() => { position: absolute; inset: 0; z-index: 1; - pointer-events: none; /* 不阻挡交互 */ + pointer-events: none; + /* 不阻挡交互 */ background: url(../assets/img/遮罩层.png) no-repeat center/cover; } @@ -617,7 +690,8 @@ onBeforeUnmount(() => { gap: var(--cockpit-gap); height: 100%; box-sizing: border-box; - pointer-events: none; /* 容器不拦截事件,让中间区域透明 */ + pointer-events: none; + /* 容器不拦截事件,让中间区域透明 */ } /* 中间占位区域 - 透明且不可交互,点击穿透到地图 */ @@ -630,10 +704,13 @@ onBeforeUnmount(() => { display: flex; flex-direction: column; gap: var(--cockpit-gap); - min-width: 0; /* 防止在窄容器中溢出 */ - min-height: 0; /* 允许 flex 子元素收缩并启用滚动 */ + min-width: 0; + /* 防止在窄容器中溢出 */ + min-height: 0; + /* 允许 flex 子元素收缩并启用滚动 */ padding: 1rem; - pointer-events: auto; /* 恢复面板的交互能力 */ + pointer-events: auto; + /* 恢复面板的交互能力 */ } /* 图例工具栏 - 居中显示在底部 */ @@ -643,6 +720,7 @@ onBeforeUnmount(() => { left: 50%; transform: translateX(-50%); z-index: 3; - pointer-events: auto; /* 确保图例可交互 */ + pointer-events: auto; + /* 确保图例可交互 */ } diff --git a/packages/screen/src/views/cockpit/components/EmergencyResources.vue b/packages/screen/src/views/cockpit/components/EmergencyResources.vue index f94967f..5a44a18 100644 --- a/packages/screen/src/views/cockpit/components/EmergencyResources.vue +++ b/packages/screen/src/views/cockpit/components/EmergencyResources.vue @@ -21,7 +21,7 @@ :class="{ 'row-alt': index % 2 === 0 }" >
{{ index + 1 }}
- {{ resource.qxmc }} + {{ resource.qxmc }} {{ resource.yhzCount }} {{ resource.wzCount }}
@@ -43,7 +43,9 @@ import { ref, onMounted } from 'vue' import { request } from '@shared/utils/request' -const resources = ref([ +const emit = defineEmits(['clickEmergencyResource']) + +const testData = [ { id: 1, name: '万州区', @@ -98,7 +100,9 @@ const resources = ref([ equipmentClass: 'red', hasAlert: false } -]) +] + +const resources = ref([]) // 请求后端接口 /district/statistics const getDistrictStatistics = async () => { @@ -106,7 +110,6 @@ const getDistrictStatistics = async () => { url: '/snow-ops-platform/district/statistics', method: 'GET' }) - console.log(res) if(res.code === '00000') { resources.value = res.data } else { @@ -240,6 +243,7 @@ onMounted(() => { .district-name { text-align: left; + cursor: pointer; } .count { diff --git a/packages/screen/src/views/cockpit/components/ImageMarkTooltip/ImageMarkTooltip.vue b/packages/screen/src/views/cockpit/components/ImageMarkTooltip/YHZTooltip.vue similarity index 78% rename from packages/screen/src/views/cockpit/components/ImageMarkTooltip/ImageMarkTooltip.vue rename to packages/screen/src/views/cockpit/components/ImageMarkTooltip/YHZTooltip.vue index 1b7dfd1..1626400 100644 --- a/packages/screen/src/views/cockpit/components/ImageMarkTooltip/ImageMarkTooltip.vue +++ b/packages/screen/src/views/cockpit/components/ImageMarkTooltip/YHZTooltip.vue @@ -11,8 +11,32 @@ -
- +
+ +
+ 名称: + {{ detail.mc }} +
+ +
+ 所属区县: + {{ detail.qxmc }} +
+ +
+ 应急设备: + {{ detail.sbsl }} +
+ +
+ 应急物资: + {{ detail.wzsl }} +
+ +
+ 应急人员: + {{ detail.rysl }} +
@@ -36,11 +60,7 @@ \ No newline at end of file diff --git a/packages/screen/src/views/cockpit/components/PageHeader.vue b/packages/screen/src/views/cockpit/components/PageHeader.vue index c8655d6..9c55989 100644 --- a/packages/screen/src/views/cockpit/components/PageHeader.vue +++ b/packages/screen/src/views/cockpit/components/PageHeader.vue @@ -1,8 +1,6 @@ @@ -14,7 +12,7 @@ @use '@/styles/mixins.scss' as *; .page-header { - height: vh(137); + height: vw(111); background: url(../assets/img/header-bg.png) no-repeat; background-size: 100% 100%; display: flex; @@ -23,15 +21,6 @@ position: relative; } -.header-bg { - background-image: url(../assets/img/header-title-bg.png); - width: 100%; - height: vh(107); - display: flex; - align-items: center; - justify-content: center; - position: relative; -} .title { color: rgba(255, 255, 255, 1); @@ -43,24 +32,4 @@ text-align: center; } -.app-button { - position: absolute; - right: vw(40); - top: 50%; - transform: translateY(-50%); - width: vw(165); - height: vh(44); - background: url(../assets/img/header-btn-app-bg.png) no-repeat; - background-size: 100% 100%; - color: rgba(255, 255, 255, 1); - font-size: fs(16); - font-family: SourceHanSansCN-Regular, sans-serif; - border: none; - cursor: pointer; - transition: opacity 0.3s; - - &:hover { - opacity: 0.8; - } -} diff --git a/packages/screen/src/views/cockpit/components/WeatherWarning.vue b/packages/screen/src/views/cockpit/components/WeatherWarning.vue index 75b4cd7..17b0457 100644 --- a/packages/screen/src/views/cockpit/components/WeatherWarning.vue +++ b/packages/screen/src/views/cockpit/components/WeatherWarning.vue @@ -66,6 +66,7 @@