From 8eb966fa14247be0372b8b82f86e53eb7dadf1b5 Mon Sep 17 00:00:00 2001 From: zjc <1034206993@qq.com> Date: Fri, 17 Jan 2025 19:15:14 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=9A=E5=AF=B9=E6=8E=A5=E6=99=AF?= =?UTF-8?q?=E5=8C=BA=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 10 +- package.json | 2 + src/api/sentiment.js | 8 + src/components/CircleProgress/index.vue | 61 +++-- src/components/CountItem/index.vue | 10 +- src/components/Header/index.vue | 88 +++---- src/hooks/socket.js | 2 +- src/stores/home.js | 5 +- src/stores/scenic.js | 45 +++- src/utils/config.js | 2 +- src/views/home/components/box-1.vue | 10 +- src/views/home/components/box-2.vue | 4 +- src/views/home/components/box-3.vue | 2 +- src/views/home/components/gauge.vue | 22 +- src/views/home/components/jam-duration.vue | 18 +- src/views/home/components/occupancy.vue | 10 +- src/views/home/components/ticket.vue | 8 +- src/views/home/components/top.vue | 10 +- src/views/home/components/vacancy.vue | 6 +- src/views/home/components/vehicle-source.vue | 10 +- src/views/scenic/components/age.vue | 1 - .../scenic/components/big-car-ship-map.vue | 18 +- src/views/scenic/components/box-1.vue | 46 +++- src/views/scenic/components/box-2.vue | 217 ++++++++++++------ src/views/scenic/components/jam.vue | 150 ++++++------ src/views/scenic/components/ticket.vue | 8 +- src/views/scenic/components/top.vue | 12 +- src/views/scenic/components/traffic-flow.vue | 11 +- src/views/scenic/index.vue | 29 ++- 29 files changed, 510 insertions(+), 315 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5b802c6..37d3d94 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,9 @@ "element-plus": "^2.9.0", "flv.js": "^1.6.2", "hls.js": "^1.5.18", + "mitt": "^3.0.1", "pinia": "^2.2.6", + "pubsub-js": "^1.9.5", "vue": "^3.5.13", "vue-countup-v3": "^1.4.2", "vue-echarts": "^7.0.3", @@ -2580,8 +2582,7 @@ "node_modules/mitt": { "version": "3.0.1", "resolved": "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz", - "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", - "dev": true + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==" }, "node_modules/mlly": { "version": "1.7.3", @@ -2864,6 +2865,11 @@ "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz", "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, + "node_modules/pubsub-js": { + "version": "1.9.5", + "resolved": "https://registry.npmmirror.com/pubsub-js/-/pubsub-js-1.9.5.tgz", + "integrity": "sha512-5MZ0I9i5JWVO7SizvOviKvZU2qaBbl2KQX150FAA+fJBwYpwOUId7aNygURWSdPzlsA/xZ/InUKXqBbzM0czTA==" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.3.1.tgz", diff --git a/package.json b/package.json index fcb01d6..afc64e7 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,9 @@ "element-plus": "^2.9.0", "flv.js": "^1.6.2", "hls.js": "^1.5.18", + "mitt": "^3.0.1", "pinia": "^2.2.6", + "pubsub-js": "^1.9.5", "vue": "^3.5.13", "vue-countup-v3": "^1.4.2", "vue-echarts": "^7.0.3", diff --git a/src/api/sentiment.js b/src/api/sentiment.js index 285ac08..acb5f8a 100644 --- a/src/api/sentiment.js +++ b/src/api/sentiment.js @@ -65,3 +65,11 @@ export function getSpotApi() { method: 'post' }) } + +// 景区列表 +export function getSpotListApi() { + return request({ + url: '/fjtcc-api/api/largeScreen/spot/list', + method: 'get' + }) +} diff --git a/src/components/CircleProgress/index.vue b/src/components/CircleProgress/index.vue index 763a372..578a99a 100644 --- a/src/components/CircleProgress/index.vue +++ b/src/components/CircleProgress/index.vue @@ -1,6 +1,5 @@ - --> +
{{ title }} @@ -63,9 +68,9 @@ import title2 from '@/assets/images/title-2.png' import title2Select from '@/assets/images/title-2-select.png' import { getWeatherApi } from '@/api/home' - import { getSpotApi } from '@/api/sentiment' + import { getSpotListApi } from '@/api/sentiment' - const emit = defineEmits(['change']) + import pubSub from 'pubsub-js' const router = useRouter() @@ -78,6 +83,18 @@ let isBack = ref(false) let current = ref(0) let otherScenic = ref('') + let otherNav = ref([ + { + name: '大窝景区' + }, + { + name: '天坑景区' + }, + { + name: '旅游环线' + } + ]) + let spotList = ref([]) // 补零 const fillZero = (value) => { @@ -102,6 +119,7 @@ const handleBack = () => { router.go(-1) } + const handleCommand = () => {} // 点击导航 const handleNav = (item, index) => { if (isSkip.value) { @@ -111,15 +129,24 @@ otherScenic.value = '' current.value = index title.value = item.name + pubSub.publish('scenicChange', item) } } + // 获取天气数据 const getWeather = async () => { let res = await getWeatherApi() weatherData.value = res.data } + // 获取景区列表 + const getSpotList = async () => { + let res = await getSpotListApi() + spotList.value = res.data + } // 设置当前路由导航栏 const setNav = async () => { + navLeft.value = [] + navRight.value = [] switch (router.currentRoute.value.path) { case '/home': title.value = '奉节县旅游指挥调度中心' @@ -138,55 +165,29 @@ case '/scenic': isSkip.value = false isBack.value = true - let res = await getSpotApi() - navLeft.value = res.data.map((item) => { - return { - name: item.ssname, - id: item.id - } - }) + let res = await getSpotListApi() + navLeft.value = res.data title.value = navLeft.value[current.value].name - navRight.value = [] + pubSub.publish('scenicChange', navLeft.value[current.value]) + break case '/sentiment': title.value = '舆情检测' - navLeft.value = [] - navRight.value = [] + isBack.value = true break case '/workOrder': title.value = '工单消息' - navLeft.value = [] - navRight.value = [] isBack.value = true break case '/traffic': title.value = '交通大屏' - navLeft.value = [] - navRight.value = [] isBack.value = true break case '/monitor': title.value = '监控大屏' - navLeft.value = [ - { - name: '奉节县', - path: '/sceneTesting' - }, - { - name: '三峡之巅', - path: '/sceneTesting' - }, - { - name: '白帝城', - path: '/sceneTesting' - }, - { - name: '龙河桥', - path: '/sceneTesting' - } - ] - navRight.value = [] + let res1 = await getSpotListApi() + navLeft.value = res1.data isBack.value = true break case '/sceneTesting': @@ -240,6 +241,7 @@ ) onMounted(() => { getWeather() + getSpotList() getCurrentDate() setInterval(() => { getCurrentDate() @@ -253,7 +255,7 @@ left: vw(326); .weather { position: absolute; - left: 0; + right: 0; top: vh(10); font-weight: 400; font-size: vw(18); @@ -264,7 +266,7 @@ } .date { position: absolute; - right: 0; + left: 0; top: vh(10); font-weight: 400; font-size: vw(18); @@ -293,7 +295,7 @@ } } .title { - width: vw(3133); + width: vw(3170); height: vh(120); line-height: vh(90); text-align: center; @@ -316,7 +318,7 @@ } .nav-left { position: absolute; - right: vw(2100); + right: vw(2120); top: vh(34); display: flex; &-item { @@ -338,7 +340,7 @@ } .nav-right { position: absolute; - left: vw(2110); + left: vw(2130); top: vh(34); display: flex; &-item { diff --git a/src/hooks/socket.js b/src/hooks/socket.js index eed6faa..978c97f 100644 --- a/src/hooks/socket.js +++ b/src/hooks/socket.js @@ -31,7 +31,7 @@ export function useWebSocket(url) { } const sendMessage = (message) => { - if (socket.value) { + if (socket.value && isConnected.value) { socket.value.send(message) } } diff --git a/src/stores/home.js b/src/stores/home.js index 8ce085e..549a481 100644 --- a/src/stores/home.js +++ b/src/stores/home.js @@ -46,10 +46,9 @@ export const useHomeStore = defineStore('home', () => { let wordkOrderList = ref([]) // 工单统计 let wordkOrderData = ref({ - toDayData: { count: 15, end: 0, rate: '0.0' }, - warnData: { count: 15, end: 0, rate: '0.0' } + toDayData: { count: 0, end: 0, rate: '0.0' }, + warnData: { count: 0, end: 0, rate: '0.0' } }) - // 交通信息 let trafficInfoData = ref({ data: { diff --git a/src/stores/scenic.js b/src/stores/scenic.js index 3ab9dbb..cbeb936 100644 --- a/src/stores/scenic.js +++ b/src/stores/scenic.js @@ -13,21 +13,30 @@ export const useScenicStore = defineStore('scenic', () => { // 景区排队信息 let scenicQueueData = ref({ dataList: [], header: { jrcp: 0, jrjdrs: 0, pdcxsj: 0, pdrs: 0 } }) // 景区负载信息 - let scenicBearData = ref({ dataList: [], header: { jqzdcz: 0, jrjdrs: 0 } }) + let scenicBearData = ref({ dataList: [], header: { jqRate: 0, jqzdcz: 0, jrjdrs: 0 } }) // 景区停车信息 let stopCarData = ref({ dataList: [], dataLists: [], - headList: [] + headList: [], + info: { + count: 0, + remain: 0 + } }) // 安全信息 let secureData = ref({ - dataList: [] + dataList: [], + headList: [ + { name: '当前告警总数', count: 0, type: 0 }, + { name: '安全告警总数', count: 0, type: 0 }, + { name: '已解除告警数', count: 0, type: 0 } + ] }) // 交通信息 let trafficData = ref({ infoList: [ - { name: '总通景路段', value: 100 }, + { name: '总通景路段', value: 0 }, { name: '通景路段拥堵', value: 0 }, { name: '通景拥堵开始时间', value: 0 }, { name: '拥堵持续时间', value: 0 } @@ -49,7 +58,29 @@ export const useScenicStore = defineStore('scenic', () => { }) // 工单列表 let wordkOrderList = ref([]) + // 工单统计 + let wordkOrderData = ref({ + toDayData: { count: 0, end: 0, rate: '0.0' }, + warnData: { count: 0, end: 0, rate: '0.0' } + }) + // 车船信息 + let carShipData = ref({ + car: { + count: { nonDrivingCount: 0, drivingCount: 0 }, + list: [] + }, + ship: { + count: { nonDrivingCount: 0, drivingCount: 0 }, + list: [] + } + }) + const setCarShipData = (val) => { + carShipData.value = val + } + const setWordkOrderData = (val) => { + wordkOrderData.value = val + } const setWordkOrderList = (val) => { wordkOrderList.value = val } @@ -75,6 +106,7 @@ export const useScenicStore = defineStore('scenic', () => { scenicSpotData.value = val } return { + wordkOrderData, wordkOrderList, scenicSpotData, scenicQueueData, @@ -83,6 +115,8 @@ export const useScenicStore = defineStore('scenic', () => { secureData, trafficData, userPortraitData, + carShipData, + setWordkOrderData, setWordkOrderList, setScenicSpotData, setScenicQueueData, @@ -90,6 +124,7 @@ export const useScenicStore = defineStore('scenic', () => { setStopCarData, setSecureData, setTrafficData, - setUserPortraitData + setUserPortraitData, + setCarShipData } }) diff --git a/src/utils/config.js b/src/utils/config.js index ac35dec..f83304e 100644 --- a/src/utils/config.js +++ b/src/utils/config.js @@ -4,7 +4,7 @@ export const proBaseUrl = 'http://192.168.77.200' export const socketBaseUrl = 'ws://36.138.38.16:81' export const proSocketBaseUrl = 'ws://192.168.77.200:8060' -export const mode = 'pro' +export const mode = 'pro' // 测试 dev 正式 pro export const devToken = 'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImE1OWFmNWYwLTU3OWItNDJkNy1hZDJhLTY0Y2JlODA5ZWI1NiJ9.BTxvu6jUWbN0qONWf5K6VzXopE8T8qXzKuX-mij21VJT4U0LdgnqToyqeNDQ2OyJ6cvpdJBzQ9mEEb-dnwrTpQ' diff --git a/src/views/home/components/box-1.vue b/src/views/home/components/box-1.vue index 8a68435..744f695 100644 --- a/src/views/home/components/box-1.vue +++ b/src/views/home/components/box-1.vue @@ -55,7 +55,7 @@ v-for="(item, index) in homeStore.scenicBearData.info" :key="index" > - + {{ item.name }}
@@ -131,10 +131,10 @@ diff --git a/src/views/scenic/components/big-car-ship-map.vue b/src/views/scenic/components/big-car-ship-map.vue index 49806ea..6b0e8cd 100644 --- a/src/views/scenic/components/big-car-ship-map.vue +++ b/src/views/scenic/components/big-car-ship-map.vue @@ -20,15 +20,15 @@ (val) => { if (val && !map.value) { setTimeout(() => { - initMap('big-car-ship', 109.491961, 31.024285, 16) - addMarker(carIcon, [109.491045, 31.028725], [36, 50]) - addMarker(carIcon, [109.483266, 31.024718], [36, 50]) - addMarker(shipIcon, [109.479062, 31.021499], [36, 50]) - addMarker(shipIcon, [109.488907, 31.017476], [36, 50]) - }, 500) + initMap('big-car-ship', 109.552461, 31.049607, 15) + addMarker(carIcon, [109.551419, 31.050001], [36, 50]) + addMarker(shipIcon, [109.551671, 31.04847], [36, 50]) + }, 1000) } } ) + + onMounted(() => {}) diff --git a/src/views/scenic/components/ticket.vue b/src/views/scenic/components/ticket.vue index 3886033..17b9745 100644 --- a/src/views/scenic/components/ticket.vue +++ b/src/views/scenic/components/ticket.vue @@ -13,8 +13,8 @@ const { id, setOption } = useEchart() - let x = 15 - let y = 25 + let x = 30 + let y = 40 let params = null watch( @@ -38,7 +38,7 @@ type: 'pie', clockwise: false, silent: true, - radius: [`${x * (index + 1)}%`, `${y + index * 15}%`], + radius: [`${x * (index + 1)}%`, `${y + index * 30}%`], center: ['50%', '40%'], label: { show: false }, labelLine: { show: false }, @@ -100,7 +100,7 @@ diff --git a/src/views/scenic/components/top.vue b/src/views/scenic/components/top.vue index 5008163..a2d44b0 100644 --- a/src/views/scenic/components/top.vue +++ b/src/views/scenic/components/top.vue @@ -25,7 +25,7 @@ grid: { left: '4%', right: '4%', - top: '10%', + top: '4%', bottom: '-4%', containLabel: false }, @@ -52,10 +52,8 @@ axisLine: 'none', show: true, axisLabel: { - textStyle: { - color: '#fff', - fontSize: fitChartSize(18) - }, + color: '#fff', + fontSize: fitChartSize(18), verticalAlign: 'bottom', padding: [0, -fitChartSize(10), fitChartSize(10), 0], inside: true, @@ -78,7 +76,7 @@ type: 'bar', barWidth: fitChartSize(12), showBackground: true, - barBorderRadius: [0, 0, 0, 0], + borderRadius: [0, 0, 0, 0], backgroundStyle: { color: 'rgba(0, 150, 255, 0.15)' }, @@ -99,7 +97,7 @@ name: item.name, value: Number(item.value), itemStyle: { - barBorderRadius: [0, 0, 0, 0], + borderRadius: [0, 0, 0, 0], color: parseFloat(item.value) > 50 ? '#FF7021' : '#00CCFF' } } diff --git a/src/views/scenic/components/traffic-flow.vue b/src/views/scenic/components/traffic-flow.vue index af0ef29..977e564 100644 --- a/src/views/scenic/components/traffic-flow.vue +++ b/src/views/scenic/components/traffic-flow.vue @@ -1,3 +1,4 @@ + @@ -43,7 +44,7 @@ left: '4%', right: '4%', top: '10%', - bottom: '10%', + bottom: '4%', containLabel: true }, xAxis: { @@ -82,6 +83,14 @@ type: 'bar', showBackground: true, barWidth: fitChartSize(16), + label: { + show: true, + position: 'top', + textStyle: { + color: '#fff', + fontSize: fitChartSize(10) + } + }, itemStyle: { color: { type: 'linear', diff --git a/src/views/scenic/index.vue b/src/views/scenic/index.vue index 9082c10..847d643 100644 --- a/src/views/scenic/index.vue +++ b/src/views/scenic/index.vue @@ -10,20 +10,26 @@ import { useScenicStore } from '@/stores/scenic' import { mode, socketBaseUrl, proSocketBaseUrl } from '@/utils/config' + import PubSub from 'pubsub-js' + const scenicStore = useScenicStore() const { isConnected, sendMessage, dataRes } = useWebSocket( `${mode == 'dev' ? socketBaseUrl : proSocketBaseUrl}/ws/scenic-spot` ) + let id = ref('') + watch( - () => isConnected.value, + () => [isConnected.value, id.value], (val) => { - if (val) { - sendMessage(JSON.stringify({ action: 'start', type: '', scenicSpotId: '1' })) + if (val[0] && val[1]) { + sendMessage(JSON.stringify({ action: 'start', type: '', scenicSpotId: id.value })) } - } + }, + { immediate: true } ) + watch( () => dataRes.value, (val) => { @@ -33,6 +39,9 @@ case 'wordkOrderlist': scenicStore.setWordkOrderList(val.data) break + case 'wordkOrderTotal': + scenicStore.setWordkOrderData(val) + break case 'scenicSpotData': scenicStore.setScenicSpotData(val.data) break @@ -54,10 +63,22 @@ case 'userPortrait': scenicStore.setUserPortraitData(val) break + case 'carShipData': + scenicStore.setCarShipData(val.data) + break } } } ) + let scenicChange = null + onMounted(() => { + scenicChange = PubSub.subscribe('scenicChange', (msg, data) => { + id.value = data.scenicSpotId + }) + }) + onUnmounted(() => { + PubSub.unsubscribe(scenicChange) + })