feat:重新对接首页接口

This commit is contained in:
zjc
2025-01-14 19:01:09 +08:00
parent 880db48579
commit ebac43f818
28 changed files with 2250 additions and 2133 deletions

View File

@@ -11,8 +11,8 @@ export function getWeatherApi() {
// 核心景区视频 // 核心景区视频
export function getVideoListApi(data) { export function getVideoListApi(data) {
return request({ return request({
url: 'http://36.138.38.16:6180/fjtcc-api/api/video/list', url: '/api/largeScreen/video/list',
method: 'get', method: 'post',
params: data params: data
}) })
} }
@@ -20,8 +20,8 @@ export function getVideoListApi(data) {
// 刷新播放地址 // 刷新播放地址
export function postRefreshApi(data) { export function postRefreshApi(data) {
return request({ return request({
url: 'http://36.138.38.16:6180/fjtcc-api/api/video/refresh', url: '/api/largeScreen/video/refresh',
method: 'POST', method: 'post',
data data
}) })
} }

View File

@@ -2,6 +2,11 @@ import axios from 'axios'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { ElMessage } from 'element-plus' import { ElMessage } from 'element-plus'
//
let devToken =
'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImE1OWFmNWYwLTU3OWItNDJkNy1hZDJhLTY0Y2JlODA5ZWI1NiJ9.BTxvu6jUWbN0qONWf5K6VzXopE8T8qXzKuX-mij21VJT4U0LdgnqToyqeNDQ2OyJ6cvpdJBzQ9mEEb-dnwrTpQ'
let proToken =
'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImE1OWFmNWYwLTU3OWItNDJkNy1hZDJhLTY0Y2JlODA5ZWI1NiJ9.dSLZekRsYf5ZZDCYqFEOgHTi4GeHD0m10gGHXrbgpc-hD52Zt7Vw05cxhQ-lzY29yf2IxH0oYi28DBfHdtf9SA'
const router = useRouter() const router = useRouter()
/** /**
@@ -9,11 +14,11 @@ const router = useRouter()
*/ */
const instance = axios.create({ const instance = axios.create({
// baseURL: 'http://36.138.38.16:6180/fjtcc-api', // baseURL: 'http://36.138.38.16:6180/fjtcc-api',
baseURL: 'http://36.138.38.16:8001/fjtcc-api', // baseURL: 'http://36.138.38.16:8001/fjtcc-api',
baseURL: ' http://172.22.15.170/fjtcc-api',
timeout: 100000, timeout: 100000,
headers: { headers: {
Authorization: Authorization: proToken,
'eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImE1OWFmNWYwLTU3OWItNDJkNy1hZDJhLTY0Y2JlODA5ZWI1NiJ9.BTxvu6jUWbN0qONWf5K6VzXopE8T8qXzKuX-mij21VJT4U0LdgnqToyqeNDQ2OyJ6cvpdJBzQ9mEEb-dnwrTpQ',
'Content-Type': 'application/json;charset=UTF-8' 'Content-Type': 'application/json;charset=UTF-8'
} }
}) })

View File

@@ -55,16 +55,13 @@
list.value.forEach(async (item, index) => { list.value.forEach(async (item, index) => {
var video = document.getElementById(`video${index}`) var video = document.getElementById(`video${index}`)
let res1 = await postRefreshApi({ let res1 = await postRefreshApi({
type: 'hls',
businessVideoDisplayPosition: item.businessVideoDisplayPosition, businessVideoDisplayPosition: item.businessVideoDisplayPosition,
cameraIndexCode: item.cameraIndexCode cameraIndexCode: item.cameraIndexCode
}) })
let hlsUrl = res1.data.hlsUrl.replace( item.hlsUrl = res1.data.hlsUrl
'http://172.22.15.170:8050',
'http://36.138.38.16:6150'
)
item.hlsUrl = hlsUrl
const hls = new Hls() const hls = new Hls()
hls.loadSource(hlsUrl) hls.loadSource(res1.data.hlsUrl)
hls.attachMedia(video) hls.attachMedia(video)
hls.on(Hls.Events.MANIFEST_PARSED, () => { hls.on(Hls.Events.MANIFEST_PARSED, () => {
video.play() video.play()

View File

@@ -62,7 +62,7 @@
height: vh(28); height: vh(28);
font-weight: 400; font-weight: 400;
font-size: vw(12); font-size: vw(12);
color: #0096ff; color: #fff;
display: flex; display: flex;
background: linear-gradient(180deg, rgba(0, 99, 255, 0) 0%, #0063ff 100%); background: linear-gradient(180deg, rgba(0, 99, 255, 0) 0%, #0063ff 100%);
& > div { & > div {

View File

@@ -31,9 +31,9 @@
const toOrderNum = (num) => { const toOrderNum = (num) => {
num = num.toString() num = num.toString()
orderNum.value = num.split('') // 将其便变成数据,渲染至滚动数组 orderNum.value = num.split('') // 将其便变成数据,渲染至滚动数组
nextTick(() => { setTimeout(() => {
setNumberTransform() setNumberTransform()
}) }, 500)
} }
watch( watch(
() => props.count, () => props.count,

View File

@@ -1,8 +1,10 @@
import { ref } from 'vue' import { ref } from 'vue'
import { useHomeStore } from '@/stores/home'
const homeStore = useHomeStore()
export function useWebSocket(url) { export function useWebSocket(url) {
let socket = ref(null) // socket对象 let socket = ref(null) // socket对象
let data = ref(null) // 存储接收到的数据
let isConnected = ref(false) // 是否连接成功 let isConnected = ref(false) // 是否连接成功
const connectWebSocket = () => { const connectWebSocket = () => {
@@ -21,9 +23,47 @@ export function useWebSocket(url) {
} }
socket.value.onmessage = (message) => { socket.value.onmessage = (message) => {
// 处理接收到的消息 // 处理接收到的消息
console.log('Received message:', JSON.parse(message.data))
if (JSON.parse(message.data)) { if (JSON.parse(message.data)) {
data.value = JSON.parse(message.data) let data = JSON.parse(message.data)
console.log(data, '接收到的消息')
switch (data.type) {
case 'userPortrait':
homeStore.setUserPortraitData(data.data)
break
case 'admission':
homeStore.setScenicData(data)
break
case 'queuingInScenicSpots':
homeStore.setScenicQueueData(data)
break
case 'queuingScenicSpots':
homeStore.setScenicBearData(data)
break
case 'visitorInfo':
homeStore.setVisitorInfoData(data.data)
break
case 'visitorDataInfo':
homeStore.setVisitorInfoList(data.data)
break
case 'baiduMap':
homeStore.setBaiduMapData(data.data)
break
case 'wordkOrderlist':
homeStore.setWordkOrderList(data.data)
break
case 'trafficInformation':
homeStore.setTrafficInfoData(data)
break
case 'carStopInfo':
homeStore.setCarStopInfoData(data)
break
case 'carShipData':
homeStore.setCarShipData(data.data)
break
case 'hotelData':
homeStore.setHotelData(data.data)
break
}
} }
} }
socket.value.onclose = () => { socket.value.onclose = () => {
@@ -47,5 +87,5 @@ export function useWebSocket(url) {
} }
}) })
return { socket, data, isConnected, connectWebSocket, sendMessage } return { socket, isConnected, connectWebSocket, sendMessage }
} }

View File

@@ -1,12 +0,0 @@
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, doubleCount, increment }
})

143
src/stores/home.js Normal file
View File

@@ -0,0 +1,143 @@
import { ref } from 'vue'
import { defineStore } from 'pinia'
export const useHomeStore = defineStore('home', () => {
// 景区信息数据
let scenicData = ref({
scenicSpot: [
{ value: 0, name: '全县景区数量' },
{ value: 0, name: '核心景区数' },
{ value: 0, name: '低感景区总数' }
],
data: [
{ name: '当日购票量:', value: 0 },
{ name: '未来3天购票量', value: 0 },
{ name: '3天后购票量', value: 0 }
]
})
// 景区排队数据
let scenicQueueData = ref({
dataList: [],
info: []
})
// 景区承载量
let scenicBearData = ref({
dataList: [],
info: []
})
// 用户画像数据
let userPortraitData = ref({
genderRate: [],
provinceRate: [],
channel: [],
ageRate: []
})
// 景区游客统计
let visitorInfoData = ref({
total_count_this_year: 0,
total_count_today: 0,
total_count_today_within_three_hours: 0
})
// 景区拥堵情况统计
let visitorInfoList = ref([])
// 百度地图数据
let baiduMapData = ref(null)
// 工单列表
let wordkOrderList = ref([])
// 交通信息
let trafficInfoData = ref({
data: {
congestion: [],
congestionList: [],
countItem: {
max_congestion_duration: 0,
now_yongdu_sum: 0,
yongdu_luduan_count: 0,
yongdu_sum: 0
},
countRate: [],
timeRate: []
},
info: {
dqydld: 0,
ldzs: 0,
zdydsc: 0,
zydcs: 0
}
})
// 停车信息
let carStopInfoData = ref({
countInfo: { ckzs: 0, ysycws: 0, zcws: 0 },
dataList: [],
dataList1: [],
dataList2: [],
spotInfo: []
})
// 车船信息
let carShipData = ref(null)
// 酒店数据
let hotelData = ref(null)
const setVisitorInfoList = (val) => {
visitorInfoList.value = val
}
const setHotelData = (val) => {
hotelData.value = val
}
const setCarShipData = (val) => {
carShipData.value = val
}
const setCarStopInfoData = (val) => {
carStopInfoData.value = val
}
const setTrafficInfoData = (val) => {
trafficInfoData.value = val
}
const setVisitorInfoData = (val) => {
visitorInfoData.value = val
}
const setScenicBearData = (val) => {
scenicBearData.value = val
}
const setScenicQueueData = (val) => {
scenicQueueData.value = val
}
const setWordkOrderList = (val) => {
wordkOrderList.value = val
}
const setBaiduMapData = (val) => {
baiduMapData.value = val
}
const setScenicData = (val) => {
scenicData.value = val
}
const setUserPortraitData = (val) => {
userPortraitData.value = val
}
return {
scenicData,
userPortraitData,
baiduMapData,
wordkOrderList,
scenicQueueData,
scenicBearData,
visitorInfoData,
visitorInfoList,
trafficInfoData,
carStopInfoData,
carShipData,
hotelData,
setScenicData,
setUserPortraitData,
setBaiduMapData,
setWordkOrderList,
setScenicQueueData,
setScenicBearData,
setVisitorInfoData,
setVisitorInfoList,
setTrafficInfoData,
setCarStopInfoData,
setCarShipData,
setHotelData
}
})

View File

@@ -5,18 +5,19 @@
<script setup> <script setup>
import { fitChartSize } from '@/utils/dataUtil' import { fitChartSize } from '@/utils/dataUtil'
import { useEchart } from '@/hooks/echart' import { useEchart } from '@/hooks/echart'
import { useHomeStore } from '@/stores/home'
const homeStore = useHomeStore()
const { id, setOption } = useEchart() const { id, setOption } = useEchart()
const homeData = inject('homeData')
let params = null let params = null
watch( watch(
() => homeData.value?.userPortrait?.ageRate, () => homeStore.userPortraitData?.ageRate,
() => { (val) => {
init() if (val.length > 0) init()
} },
{ immediate: true }
) )
const init = () => { const init = () => {
if (!params) { if (!params) {
@@ -30,7 +31,7 @@
itemWidth: fitChartSize(8), itemWidth: fitChartSize(8),
itemGap: fitChartSize(10), itemGap: fitChartSize(10),
formatter: function (name) { formatter: function (name) {
let obj = homeData.value?.userPortrait?.ageRate.find((item) => item.name == name) let obj = homeStore.userPortraitData?.ageRate.find((item) => item.name == name)
return '{name|' + name + '} {value|' + obj.value + '}{value|%}' return '{name|' + name + '} {value|' + obj.value + '}{value|%}'
}, },
textStyle: { textStyle: {
@@ -63,7 +64,7 @@
color: '#D3F0FE', color: '#D3F0FE',
fontSize: fitChartSize(12) fontSize: fitChartSize(12)
}, },
data: homeData.value?.userPortrait?.ageRate || [] data: homeStore.userPortraitData?.ageRate || []
}, },
{ {
type: 'pie', type: 'pie',
@@ -81,7 +82,7 @@
color: '#D3F0FE', color: '#D3F0FE',
fontSize: fitChartSize(12) fontSize: fitChartSize(12)
}, },
data: homeData.value?.userPortrait?.ageRate || [] data: homeStore.userPortraitData?.ageRate || []
}, },
{ {
type: 'pie', type: 'pie',

View File

@@ -6,13 +6,13 @@
</template> </template>
</Title1> </Title1>
<div class="list flex pt-20"> <div class="list flex pt-20">
<div class="item" v-for="(item, index) in scenicSpot" :key="index"> <div class="item" v-for="(item, index) in homeStore.scenicData.scenicSpot" :key="index">
<img v-if="index == 0" class="item-icon" src="@/assets/images/core.png" /> <img v-if="index == 0" class="item-icon" src="@/assets/images/core.png" />
<img v-if="index == 1" class="item-icon" src="@/assets/images/queue.png" /> <img v-if="index == 1" class="item-icon" src="@/assets/images/queue.png" />
<img v-if="index == 2" class="item-icon" src="@/assets/images/congestion.png" /> <img v-if="index == 2" class="item-icon" src="@/assets/images/congestion.png" />
<span class="item-label">{{ item.name }}</span> <span class="item-label">{{ item.name }}</span>
<div class="item-value flex align-end rela"> <div class="item-value flex align-end rela">
<countup :end-val="item.value || 0" /><span class="unit"></span> <countup :end-val="item.value" /><span class="unit"></span>
</div> </div>
</div> </div>
</div> </div>
@@ -20,90 +20,44 @@
<div class="box"> <div class="box">
<Title2 title="景区排队人数" /> <Title2 title="景区排队人数" />
<div class="statistic"> <div class="statistic">
<div class="statistic-item"> <div
<span class="statistic-title">三峡之巅</span> class="statistic-item"
<span class="statistic-value"> v-for="(item, index) in homeStore.scenicQueueData.info"
:key="index"
>
<span class="statistic-title">{{ item.name }}</span>
<span v-if="item.value > 0" class="statistic-value">
<span class="prefix">排队</span> <span class="prefix">排队</span>
<span class="value">100</span> <!-- <span class="value">{{ item.value }}</span> -->
<countup class="value" :end-val="item.value" />
<span class="suffix"></span> <span class="suffix"></span>
</span> </span>
</div> <span v-else class="statistic-value">{{ item.value }}</span>
<div class="statistic-item">
<span class="statistic-title">白帝城</span>
<span class="statistic-value">通畅</span>
</div>
<div class="statistic-item">
<span class="statistic-title">天坑地缝</span>
<span class="statistic-value">通畅</span>
</div>
<div class="statistic-item">
<span class="statistic-title">永安宫</span>
<span class="statistic-value">通畅</span>
</div> </div>
</div> </div>
<div class="flex rela"> <div class="flex rela">
<Title3 title="景区排队人数" /> <Title3 title="景区排队人数" />
<div class="dropdown">
<Dropdown
label="选择排队景区"
:options="[
{ label: '山峡之巅', value: 100 },
{ label: '白帝城', value: 100 },
{ label: '龙桥河', value: 100 }
]"
/>
</div>
</div> </div>
<div class="pt-20"> <div class="pt-20">
<Line <Line
:width="370" :width="370"
:height="140" :height="140"
:config="{ legend: false }" :config="{ legend: false }"
:data="[ :data="scenicQueueList"
{ :xAxisData="scenicQueueXAxisData"
name: '企业数',
data: [64, 159, 112, 86, 151, 131, 118, 232, 23, 64, 159, 112, 86, 151, 131, 118]
}
]"
:xAxisData="[
'12-16 10:00',
'12-16 14:00',
'12-16 16:00',
'12-16 22:00',
'12-17 02:00',
'12-17 06:00',
'12-17 10:00',
'12-17 14:00',
'12-17 16:00',
'12-16 22:00',
'12-18 02:00',
'12-18 06:00',
'12-8 10:00',
'12-18 14:00',
'12-18 16:00',
'12-18 20:00'
]"
/> />
</div> </div>
</div> </div>
<div class="box"> <div class="box">
<Title2 title="景区承载量" /> <Title2 title="景区承载量" />
<div class="statistic"> <div class="statistic">
<div class="statistic-item"> <div
<gauge :value="80" /> class="statistic-item"
<span class="statistic-title">三峡之巅</span> v-for="(item, index) in homeStore.scenicBearData.info"
</div> :key="index"
<div class="statistic-item"> >
<gauge :value="50" /> <gauge :value="item.value" />
<span class="statistic-title">三峡之巅</span> <span class="statistic-title">{{ item.name }}</span>
</div>
<div class="statistic-item">
<gauge :value="50" />
<span class="statistic-title">三峡之巅</span>
</div>
<div class="statistic-item">
<gauge :value="50" />
<span class="statistic-title">三峡之巅</span>
</div> </div>
</div> </div>
<Title3 title="今日景区承载量" /> <Title3 title="今日景区承载量" />
@@ -112,30 +66,8 @@
:width="370" :width="370"
:height="140" :height="140"
:config="{ legend: false }" :config="{ legend: false }"
:data="[ :data="scenicBearList"
{ :xAxisData="scenicBearXAxisData"
name: '企业数',
data: [64, 159, 112, 86, 151, 131, 118, 232, 23, 64, 159, 112, 86, 151, 131, 118]
}
]"
:xAxisData="[
'12-16 10:00',
'12-16 14:00',
'12-16 16:00',
'12-16 22:00',
'12-17 02:00',
'12-17 06:00',
'12-17 10:00',
'12-17 14:00',
'12-17 16:00',
'12-16 22:00',
'12-18 02:00',
'12-18 06:00',
'12-8 10:00',
'12-18 14:00',
'12-18 16:00',
'12-18 20:00'
]"
/> />
</div> </div>
</div> </div>
@@ -145,7 +77,7 @@
<Title2 title="景区购票数" /> <Title2 title="景区购票数" />
<div class="ticket-wrap"> <div class="ticket-wrap">
<img src="@/assets/images/ticket.png" /> <img src="@/assets/images/ticket.png" />
<div v-for="(item, index) in admission" :key="index"> <div v-for="(item, index) in homeStore.scenicData.data" :key="index">
<span class="label">{{ item.name }}</span><countup :end-val="item.value" /> <span class="label">{{ item.name }}</span><countup :end-val="item.value" />
</div> </div>
</div> </div>
@@ -156,10 +88,10 @@
<div class="age-box"> <div class="age-box">
<Title3 title="年龄/性别占比" /> <Title3 title="年龄/性别占比" />
<div class="mt-8"> <age /></div> <div class="mt-8"> <age /></div>
<div class="count">总人数<countup :end-val="ageRateTotal" /></div> <div v-if="ageRateTotal > 0" class="count">总人数:<countup :end-val="ageRateTotal" /></div>
<div <div
class="cell pt-20" class="cell pt-20"
v-for="(item, index) in homeData?.userPortrait.genderRate" v-for="(item, index) in homeStore?.userPortraitData.genderRate"
:key="index" :key="index"
> >
<img v-if="item.name == '男'" class="icon" src="@/assets/images/man.png" /> <img v-if="item.name == '男'" class="icon" src="@/assets/images/man.png" />
@@ -179,14 +111,18 @@
</div> </div>
</div> </div>
</div> </div>
<div class="box-1"> <div class="box-1">
<Title3 title="客源地分析TOP5" /> <Title3 title="客源地分析TOP5" />
<top /> <top />
</div> </div>
<div class="box-1"> <div class="box-1">
<Title3 title="购票来源" /> <Title3 title="购票来源" />
<div class="count">游客总数<countup :end-val="channelTotal" /></div> <div v-if="channelTotal > 0" class="count">
<ticket :list="channelData" /> 游客总数<countup :end-val="channelTotal" />
</div>
<ticket />
</div> </div>
</div> </div>
</div> </div>
@@ -198,41 +134,39 @@
import gauge from './gauge.vue' import gauge from './gauge.vue'
import ticket from './ticket.vue' import ticket from './ticket.vue'
import countup from 'vue-countup-v3' import countup from 'vue-countup-v3'
import { useHomeStore } from '@/stores/home'
const homeData = inject('homeData') const homeStore = useHomeStore()
// 景区信息 // 今日景区承载量
const scenicSpot = computed(() => { const scenicBearList = computed(() => {
if (homeData.value) return homeData.value?.scenicSpot return [{ data: homeStore.scenicBearData.dataList.map((item) => item.value) }]
return [
{ value: 0, name: '全县景区数量' },
{ value: 0, name: '核心景区数' },
{ value: 0, name: '低感景区总数' }
]
}) })
// 景区购票数
const admission = computed(() => { const scenicBearXAxisData = computed(() => {
if (homeData.value) return homeData.value?.admission return homeStore.scenicBearData.dataList.map((item) => item.name)
return [
{ name: '当日购票量:', value: 0 },
{ name: '未来3天购票量', value: 0 },
{ name: '3天后购票量', value: 0 }
]
}) })
// 年龄占比
// 今日景区排队量
const scenicQueueList = computed(() => {
return [{ data: homeStore.scenicQueueData.dataList.map((item) => item.value) }]
})
const scenicQueueXAxisData = computed(() => {
return homeStore.scenicQueueData.dataList.map((item) => item.name)
})
// 年龄占比 - 游客总数
const ageRateTotal = computed(() => { const ageRateTotal = computed(() => {
return homeData.value?.userPortrait.genderRate.reduce( return homeStore?.userPortraitData?.genderRate.reduce(
(total, current) => Number(current.count) + total, (total, current) => Number(current.count) + total,
0 0
) )
}) })
// 年龄占比
const channelData = computed(() => { // 购票来源 - 游客总数
if (homeData.value) return homeData.value?.userPortrait.channel
return []
})
const channelTotal = computed(() => { const channelTotal = computed(() => {
return homeData.value?.userPortrait?.channel.reduce( return homeStore.userPortraitData?.channel.reduce(
(total, current) => Number(current.count) + total, (total, current) => Number(current.count) + total,
0 0
) )
@@ -326,14 +260,16 @@
justify-content: center; justify-content: center;
} }
&-title { &-title {
font-size: vw(18); font-size: vw(16);
color: rgba(255, 255, 255, 0.9); color: #fff;
} }
&-value { &-value {
margin-top: vh(10); margin-top: vh(10);
font-weight: bold; font-weight: bold;
font-size: vw(24); font-size: vw(20);
color: #02f9fa; color: #02f9fa;
display: flex;
align-items: flex-end;
} }
.value { .value {
font-weight: bold; font-weight: bold;
@@ -344,6 +280,7 @@
.suffix { .suffix {
color: #ff4400; color: #ff4400;
font-size: vw(12); font-size: vw(12);
margin-bottom: vh(4);
} }
} }
} }
@@ -366,7 +303,7 @@
} }
} }
.count { .count {
margin: vw(20) vw(20) 0 vw(20); margin: vh(10) vw(20) 0 vw(20);
height: vh(24); height: vh(24);
font-weight: bold; font-weight: bold;
font-size: vw(14); font-size: vw(14);

View File

@@ -5,37 +5,26 @@
<div class="left"> <div class="left">
<div class="item"> <div class="item">
<div class="label">今年总游客数</div> <div class="label">今年总游客数</div>
<scroll-number :count="visitorInfo.total_count_this_year" prefix="1" /> <scroll-number :count="homeStore.visitorInfoData.total_count_this_year" prefix="1" />
</div> </div>
<div class="item"> <div class="item">
<div class="label">全县景区总游客人数</div> <div class="label">全县景区总游客人数</div>
<scroll-number :count="visitorInfo.total_count_today" prefix="2" /> <scroll-number :count="homeStore.visitorInfoData.total_count_today" prefix="2" />
</div> </div>
<div class="item"> <div class="item">
<div class="label">总在园人数</div> <div class="label">总在园人数</div>
<scroll-number :count="visitorInfo.total_count_today_within_three_hours" prefix="3" /> <scroll-number
:count="homeStore.visitorInfoData.total_count_today_within_three_hours"
prefix="3"
/>
</div> </div>
</div> </div>
<div class="right"> <div class="right">
<div class="item"> <div class="item" v-for="(item, index) in homeStore.visitorInfoList" :key="index">
<div class="label">安全度</div> <div class="label">{{ item.name }}</div>
<div class="value">安全</div> <div :class="[item.type == 1 ? 'value--error' : 'value--primary']">{{
</div> item.value
<div class="item"> }}</div>
<div class="label">舒适度</div>
<div class="value">舒适</div>
</div>
<div class="item">
<div class="label">接待情况</div>
<div class="value">排队</div>
</div>
<div class="item">
<div class="label">交通拥挤度</div>
<div class="value">舒适</div>
</div>
<div class="item">
<div class="label">停车场负荷度</div>
<div class="value">超负荷</div>
</div> </div>
</div> </div>
</div> </div>
@@ -104,28 +93,23 @@
</div> </div>
</div> </div>
</div> </div>
<div class="right"> <div>
<div class="item"> <vue3-seamless-scroll
<span class="item-tag--warning">重要</span> class="right"
:list="homeStore.wordkOrderList"
:limitScrollNum="3"
:hover="true"
:step="0.2"
:wheel="true"
:isWatch="true"
>
<div class="item" v-for="(item, index) in homeStore.wordkOrderList" :key="index">
<span :class="`item-tag--${item.level}`">{{ item.level_text }}</span>
<p class="content"> <p class="content">
工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工工单信息工单信息工单信息工单信息工单信息 {{ item.title }}
工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工工单信息工单信息工单信息工单信息工单信息
</p>
</div>
<div class="item">
<span class="item-tag--error">紧急</span>
<p class="content">
工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工工单信息工单信息工单信息工单信息工单信息
工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工工单信息工单信息工单信息工单信息工单信息
</p>
</div>
<div class="item">
<span class="item-tag--primary">普通</span>
<p class="content">
工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工工单信息工单信息工单信息工单信息工单信息
工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工单信息工工单信息工单信息工单信息工单信息工单信息
</p> </p>
</div> </div>
</vue3-seamless-scroll>
</div> </div>
</div> </div>
</div> </div>
@@ -133,6 +117,7 @@
<script setup> <script setup>
import countup from 'vue-countup-v3' import countup from 'vue-countup-v3'
import { Vue3SeamlessScroll } from 'vue3-seamless-scroll'
import ScrollNumber from '@/components/ScrollNumber/index.vue' import ScrollNumber from '@/components/ScrollNumber/index.vue'
import { getSpotListApi, getBaiduMapCrowdedApi } from '@/api/home' import { getSpotListApi, getBaiduMapCrowdedApi } from '@/api/home'
@@ -142,22 +127,14 @@
import icon11 from '@/assets/images/icon-11.png' import icon11 from '@/assets/images/icon-11.png'
import { useMap } from '@/hooks/map' import { useMap } from '@/hooks/map'
import { useHomeStore } from '@/stores/home'
const homeStore = useHomeStore()
let emit = defineEmits(['switch-spot']) let emit = defineEmits(['switch-spot'])
const { map, initMap, addMarker } = useMap() const { map, initMap, addMarker } = useMap()
const homeData = inject('homeData')
const visitorInfo = computed(() => {
if (homeData.value) return homeData.value?.visitorInfo.data
return {
total_count_this_year: 0,
total_count_today: 0,
total_count_today_within_three_hours: 0
}
})
let spotList = ref([]) let spotList = ref([])
let list = ref([ let list = ref([
@@ -185,13 +162,13 @@
const getSpotList = async () => { const getSpotList = async () => {
let res = await getSpotListApi() let res = await getSpotListApi()
spotList.value = res.data spotList.value = res.data
let res1 = await getBaiduMapCrowdedApi({ // let res1 = await getBaiduMapCrowdedApi({
nodeId: res.data[0].nodeid // nodeId: res.data[0].nodeid
}) // })
} }
watch( watch(
() => homeData.value?.baiduMap, () => homeStore?.baiduMapData,
(val) => { (val) => {
if (val) init(val) if (val) init(val)
}, },
@@ -245,7 +222,7 @@
background-size: 100% 100%; background-size: 100% 100%;
.left { .left {
display: flex; display: flex;
width: vw(890); width: vw(740);
margin-top: vh(20); margin-top: vh(20);
} }
.right { .right {
@@ -264,8 +241,15 @@
.value { .value {
font-weight: bold; font-weight: bold;
font-size: vw(28); font-size: vw(28);
color: #02f9fa;
line-height: vh(33); line-height: vh(33);
&--error {
@extend .value;
color: #ff4400;
}
&--primary {
@extend .value;
color: #02f9fa;
}
} }
} }
.countup-wrap { .countup-wrap {
@@ -331,7 +315,7 @@
width: 100%; width: 100%;
height: vh(120); height: vh(120);
background-image: url('@/assets/images/bg-3.png'); background-image: url('@/assets/images/bg-3.png');
background-size: 100% 100%; background-size: 100% 400%;
.left { .left {
flex: 1; flex: 1;
display: flex; display: flex;
@@ -400,13 +384,14 @@
} }
} }
.right { .right {
padding: vh(10) vw(24); margin-top: vh(8);
padding: vh(10) vw(10);
height: vh(106);
width: vw(1040);
overflow: hidden;
.item { .item {
display: flex; display: flex;
margin-bottom: vh(12); margin-bottom: vh(10);
&:nth-last-child(1) {
margin-bottom: 0;
}
&-tag { &-tag {
padding: 0 vw(16); padding: 0 vw(16);
font-weight: bold; font-weight: bold;
@@ -417,22 +402,22 @@
justify-content: center; justify-content: center;
border-radius: vw(2); border-radius: vw(2);
} }
&-tag--warning { &-tag--important {
@extend .item-tag; @extend .item-tag;
background: #feae00; background: #feae00;
} }
&-tag--error { &-tag--warn {
@extend .item-tag; @extend .item-tag;
background: #d9011b; background: #d9011b;
} }
&-tag--primary { &-tag--normal {
@extend .item-tag; @extend .item-tag;
background: #2380fb; background: #2380fb;
} }
.content { .content {
margin-left: vw(4); margin-left: vw(4);
padding: 0 vw(10); padding: 0 vw(10);
width: vw(900); width: vw(950);
height: vh(24); height: vh(24);
line-height: vh(24); line-height: vh(24);
white-space: nowrap; white-space: nowrap;

View File

@@ -3,30 +3,30 @@
<Title1 title="交通信息" /> <Title1 title="交通信息" />
<div class="traffic-info flex justify-evenly pt-10 pb-20"> <div class="traffic-info flex justify-evenly pt-10 pb-20">
<div class="cell"> <div class="cell">
<img class="icon" :src="icon1" alt="" /> <img class="icon" src="@/assets/images/icon-1.png" alt="" />
<div> <div>
<countup :end-val="countItems.now_yongdu_sum" /> <countup :end-val="homeStore.trafficInfoData.info.ldzs" />
<div class="label">路段总数</div> <div class="label">路段总数</div>
</div> </div>
</div> </div>
<div class="cell"> <div class="cell">
<img class="icon" :src="icon2" alt="" /> <img class="icon" src="@/assets/images/icon-2.png" alt="" />
<div> <div>
<countup :end-val="countItems.yongdu_luduan_count" /> <countup :end-val="homeStore.trafficInfoData.info.dqydld" />
<div class="label">当前拥堵路段</div> <div class="label">当前拥堵路段</div>
</div> </div>
</div> </div>
<div class="cell"> <div class="cell">
<img class="icon" :src="icon3" alt="" /> <img class="icon" src="@/assets/images/icon-3.png" alt="" />
<div> <div>
<countup :end-val="countItems.yongdu_sum" /> <countup :end-val="homeStore.trafficInfoData.info.zydcs" />
<div class="label">总拥堵次数</div> <div class="label">总拥堵次数</div>
</div> </div>
</div> </div>
<div class="cell"> <div class="cell">
<img class="icon" :src="icon4" alt="" /> <img class="icon" src="@/assets/images/icon-4.png" alt="" />
<div> <div>
<countup :end-val="countItems.max_congestion_duration" /> <countup :end-val="homeStore.trafficInfoData.info.zdydsc" />
<div class="label">最大拥堵时长 </div> <div class="label">最大拥堵时长 </div>
</div> </div>
</div> </div>
@@ -47,13 +47,13 @@
<div class="box"> <div class="box">
<div class="pt-10"> <div class="pt-10">
<Title3 title="拥堵次数占比" /> <Title3 title="拥堵次数占比" />
<jam-count :list="countRate" /> <jam-count :list="homeStore.trafficInfoData.data.countRate" />
</div> </div>
</div> </div>
<div class="box"> <div class="box">
<div class="pt-10"> <div class="pt-10">
<Title3 title="拥堵时长" /> <Title3 title="拥堵时长" />
<jam-duration :list="timeRate" /> <jam-duration :list="homeStore.trafficInfoData.data.timeRate" />
</div> </div>
</div> </div>
</div> </div>
@@ -63,36 +63,27 @@
<img class="icon" src="@/assets/images/icon-5.png" alt="" /> <img class="icon" src="@/assets/images/icon-5.png" alt="" />
<div> <div>
<div class="label">车库总数</div> <div class="label">车库总数</div>
<countup class="value" :end-val="500" /> <countup class="value" :end-val="homeStore.carStopInfoData.countInfo.ckzs" />
</div> </div>
<div> <div>
<div class="label">总车位数</div> <div class="label">总车位数</div>
<countup class="value" :end-val="500" /> <countup class="value" :end-val="homeStore.carStopInfoData.countInfo.zcws" />
</div> </div>
<div> <div>
<div class="label">已使用车位数</div> <div class="label">已使用车位数</div>
<countup class="value" :end-val="500" /> <countup class="value" :end-val="homeStore.carStopInfoData.countInfo.ysycws" />
</div> </div>
</div> </div>
<div> <div>
<div> <div v-for="item in homeStore.carStopInfoData.spotInfo">
<div class="label">三峡之巅</div> <div class="label">{{ item.name }}</div>
<div class="value error">已满</div> <div class="value" :class="{ error: item.type == 1, success: item.type == 0 }">
</div> {{ item.value }}
<div>
<div class="label">白帝城</div>
<div class="value error">已满</div>
</div>
<div>
<div class="label">天坑地缝</div>
<div class="value success">空余</div>
</div>
<div>
<div class="label">永安宫</div>
<div class="value success">空余</div>
</div> </div>
</div> </div>
</div> </div>
</div>
<div class="flex pt-10"> <div class="flex pt-10">
<div class="box-1"> <div class="box-1">
<div class="pt-10"> <div class="pt-10">
@@ -102,30 +93,8 @@
:width="250" :width="250"
:height="150" :height="150"
:config="{ legend: false }" :config="{ legend: false }"
:data="[ :data="parkData"
{ :xAxisData="parkXAxisData"
name: '企业数',
data: [64, 159, 112, 86, 151, 131, 118, 232, 23, 64, 159, 112, 86, 151, 131, 118]
}
]"
:xAxisData="[
'12-16 10:00',
'12-16 14:00',
'12-16 16:00',
'12-16 22:00',
'12-17 02:00',
'12-17 06:00',
'12-17 10:00',
'12-17 14:00',
'12-17 16:00',
'12-16 22:00',
'12-18 02:00',
'12-18 06:00',
'12-8 10:00',
'12-18 14:00',
'12-18 16:00',
'12-18 20:00'
]"
/> />
</div> </div>
</div> </div>
@@ -133,16 +102,17 @@
<div class="box-1"> <div class="box-1">
<div class="pt-10"> <div class="pt-10">
<Title3 title="车源地" /> <Title3 title="车源地" />
<traffic /> <vehicle-source :list="homeStore.carStopInfoData.dataList1" />
</div> </div>
</div> </div>
<div class="box-1"> <div class="box-1">
<div class="pt-10"> <div class="pt-10">
<Title3 title="景区停车场空位" /> <Title3 title="景区停车场空位" />
<vacancy /> <vacancy :list="homeStore.carStopInfoData.dataList2" />
</div> </div>
</div> </div>
</div> </div>
<div class="flex"> <div class="flex">
<div class="flex-1"> <div class="flex-1">
<Title1 title="车船信息" class="title1" /> <Title1 title="车船信息" class="title1" />
@@ -151,13 +121,14 @@
<Title1 title="酒店信息" class="title1" /> <Title1 title="酒店信息" class="title1" />
</div> </div>
</div> </div>
<div class="flex"> <div class="flex">
<div class="car-ship"> <div class="car-ship">
<div class="mb-6"> <div class="mb-6">
<div class="car"> <div class="car">
<div class="label">车总数</div> <div class="label">车总数</div>
<div class="flex align-center"> <div class="flex align-center">
<countup class="value" :end-val="homeData?.carShipData?.car?.count || 0" /> <countup class="value" :end-val="homeStore.carShipData?.car?.count || 0" />
<span class="unit"></span> <span class="unit"></span>
</div> </div>
</div> </div>
@@ -169,16 +140,18 @@
</div> </div>
<div class="content"> <div class="content">
<vue3-seamless-scroll <vue3-seamless-scroll
:list="homeData?.carShipData?.car.info" v-model="carMove"
:list="homeStore.carShipData?.car?.info"
:limitScrollNum="3" :limitScrollNum="3"
:hover="true" :hover="true"
:step="0.2" :step="0.2"
:copy-num="0"
:wheel="true" :wheel="true"
:isWatch="true" :isWatch="true"
> >
<div <div
class="cell" class="cell"
v-for="(item, index) in homeData?.carShipData?.car.info" v-for="(item, index) in homeStore.carShipData?.car?.info"
:key="index" :key="index"
> >
<div>{{ item.name }}</div> <div>{{ item.name }}</div>
@@ -193,7 +166,7 @@
<div class="ship"> <div class="ship">
<div class="label">船总数</div> <div class="label">船总数</div>
<div class="flex align-center"> <div class="flex align-center">
<countup class="value" :end-val="homeData?.carShipData?.ship?.count || 0" /> <countup class="value" :end-val="homeStore.carShipData?.ship?.count || 0" />
<span class="unit"></span> <span class="unit"></span>
</div> </div>
</div> </div>
@@ -205,16 +178,18 @@
</div> </div>
<div class="content"> <div class="content">
<vue3-seamless-scroll <vue3-seamless-scroll
:list="homeData?.carShipData?.car.info" v-model="shipMove"
:list="homeStore.carShipData?.ship?.info"
:limitScrollNum="3" :limitScrollNum="3"
:hover="true" :hover="true"
:step="0.2" :step="0.2"
:copy-num="0"
:wheel="true" :wheel="true"
:isWatch="true" :isWatch="true"
> >
<div <div
class="cell" class="cell"
v-for="(item, index) in homeData?.carShipData?.ship.info" v-for="(item, index) in homeStore.carShipData?.ship?.info"
:key="index" :key="index"
> >
<div>{{ item.name }}</div> <div>{{ item.name }}</div>
@@ -230,17 +205,17 @@
<div> <div>
<div class="item"> <div class="item">
<div class="label">酒店总数</div> <div class="label">酒店总数</div>
<countup class="value" :end-val="homeData?.hotelData.info.hotel_count || 0" /> <countup class="value" :end-val="homeStore.hotelData?.info?.hotel_count || 0" />
</div> </div>
<div class="item"> <div class="item">
<div class="label">房间总数</div> <div class="label">房间总数</div>
<countup class="value" :end-val="homeData?.hotelData.info.total_room_count || 0" /> <countup class="value" :end-val="homeStore.hotelData?.info?.total_room_count || 0" />
</div> </div>
<div class="item"> <div class="item">
<div class="label">总入住</div> <div class="label">总入住</div>
<countup <countup
class="value success" class="value success"
:end-val="homeData?.hotelData.info.total_guest_count || 0" :end-val="homeStore.hotelData?.info?.total_guest_count || 0"
/> />
</div> </div>
<div class="item"> <div class="item">
@@ -248,7 +223,7 @@
<div class="flex align-center"> <div class="flex align-center">
<countup <countup
class="value success" class="value success"
:end-val="homeData?.hotelData.info.occupancy_rate || 0" :end-val="homeStore.hotelData?.info?.occupancy_rate || 0"
/> />
<span class="suffix">%</span> <span class="suffix">%</span>
</div> </div>
@@ -258,7 +233,7 @@
<div class="occupancy"> <div class="occupancy">
<Title3 title="酒店入住人数及入住率" /> <Title3 title="酒店入住人数及入住率" />
</div> </div>
<occupancy /> <occupancy :list="homeStore.hotelData?.list" />
</div> </div>
</div> </div>
</div> </div>
@@ -270,51 +245,32 @@
import jamCount from './jam-count.vue' import jamCount from './jam-count.vue'
import vacancy from './vacancy.vue' import vacancy from './vacancy.vue'
import occupancy from './occupancy.vue' import occupancy from './occupancy.vue'
import traffic from './traffic.vue' import vehicleSource from './vehicle-source.vue'
import countup from 'vue-countup-v3' import countup from 'vue-countup-v3'
import icon1 from '@/assets/images/icon-1.png'
import icon2 from '@/assets/images/icon-2.png'
import icon3 from '@/assets/images/icon-3.png'
import icon4 from '@/assets/images/icon-4.png'
import { Vue3SeamlessScroll } from 'vue3-seamless-scroll' import { Vue3SeamlessScroll } from 'vue3-seamless-scroll'
import { useHomeStore } from '@/stores/home'
const homeData = inject('homeData') const homeStore = useHomeStore()
const carMove = computed(() => {
return homeStore.carShipData?.car?.info.length > 3
})
const shipMove = computed(() => {
return homeStore.carShipData?.ship?.info.length > 3
})
const parkData = computed(() => {
return [{ data: homeStore.carStopInfoData.dataList.map((item) => item.value) }]
})
const parkXAxisData = computed(() => {
return homeStore.carStopInfoData.dataList.map((item) => item.name)
})
const congestionData = computed(() => { const congestionData = computed(() => {
if (homeData.value) { return [{ data: homeStore.trafficInfoData.data.congestion.map((item) => item.value) }]
return [{ data: homeData.value?.trafficInformation?.congestion.map((item) => item.value) }]
}
return []
}) })
const congestionXAxisData = computed(() => { const congestionXAxisData = computed(() => {
if (homeData.value) { return homeStore.trafficInfoData.data.congestion.map((item) => item.name)
return homeData.value?.trafficInformation?.congestion.map((item) => item.name)
}
return []
})
const countItems = computed(() => {
if (homeData.value) {
return homeData.value?.trafficInformation?.countItem
}
return {
max_congestion_duration: 0, // 最大拥堵时长
now_yongdu_sum: 0,
yongdu_luduan_count: 0,
yongdu_sum: 0
}
})
const countRate = computed(() => {
if (homeData.value) {
return homeData.value?.trafficInformation?.countRate
}
return []
})
const timeRate = computed(() => {
if (homeData.value) {
return homeData.value?.trafficInformation?.timeRate
}
return []
}) })
</script> </script>
@@ -466,7 +422,7 @@
flex: 1; flex: 1;
font-weight: 400; font-weight: 400;
font-size: vw(12); font-size: vw(12);
color: #52b8ff; color: #fff;
} }
} }
.content { .content {
@@ -492,9 +448,12 @@
line-height: vh(27); line-height: vh(27);
text-align: center; text-align: center;
background: #074686; background: #074686;
&:nth-child(2n + 1) { &:nth-child(odd) {
background: rgba(0, 150, 255, 0.1); background: rgba(0, 150, 255, 0.1);
} }
&:nth-child(even) {
background: #074686;
}
& > div { & > div {
flex: 1; flex: 1;
} }

View File

@@ -1,3 +1,4 @@
<!-- 景区承载量 -->
<template> <template>
<div class="gauge" :id="id" /> <div class="gauge" :id="id" />
</template> </template>
@@ -23,9 +24,14 @@
watch( watch(
() => props.value, () => props.value,
() => { (val) => {
if (val) {
nextTick(() => {
init() init()
})
} }
},
{ immediate: true }
) )
const init = () => { const init = () => {
@@ -97,12 +103,12 @@
}, },
rich: { rich: {
value: { value: {
fontSize: fitChartSize(18), fontSize: fitChartSize(14),
fontWeight: 'bolder', fontWeight: 'bolder',
color: '#02F9FA' color: '#02F9FA'
}, },
unit: { unit: {
fontSize: fitChartSize(18), fontSize: fitChartSize(14),
color: '#02F9FA' color: '#02F9FA'
} }
} }
@@ -120,10 +126,6 @@
} }
setOption(params) setOption(params)
} }
onMounted(() => {
init()
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>

View File

@@ -1,3 +1,4 @@
<!-- 拥堵次数占比 -->
<template> <template>
<div class="jam-count" :id="id" /> <div class="jam-count" :id="id" />
</template> </template>
@@ -15,7 +16,8 @@
const { id, setOption } = useEchart() const { id, setOption } = useEchart()
var colorList = ['#FDC40A', '#FF5232', '#50F0A6'] let params = null
const colorList = ['#FDC40A', '#FF5232', '#50F0A6']
watch( watch(
() => props.list, () => props.list,
@@ -27,7 +29,7 @@
} }
) )
const setSeriesData = () => { const getSeriesData = () => {
return props.list.map((item) => { return props.list.map((item) => {
return { return {
name: item.name, name: item.name,
@@ -41,7 +43,8 @@
}, 0) }, 0)
} }
const init = () => { const init = () => {
setOption({ if (!params) {
params = {
color: colorList, color: colorList,
grid: { grid: {
left: '4%', left: '4%',
@@ -53,10 +56,10 @@
legend: { legend: {
orient: 'horizontal', orient: 'horizontal',
x: 'center', x: 'center',
bottom: '-2%', bottom: '-3%',
itemHeight: fitChartSize(16), itemHeight: fitChartSize(12),
itemWidth: fitChartSize(16), itemWidth: fitChartSize(12),
itemGap: fitChartSize(10), itemGap: fitChartSize(6),
formatter: (name) => { formatter: (name) => {
let obj = props.list.find((item) => item.name == name) let obj = props.list.find((item) => item.name == name)
return '{name|' + name + '} {value|' + obj?.count + '}{value|%}' return '{name|' + name + '} {value|' + obj?.count + '}{value|%}'
@@ -98,7 +101,7 @@
}, },
value: { value: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(18), fontSize: fitChartSize(16),
fontWeight: 'bold' fontWeight: 'bold'
} }
} }
@@ -106,10 +109,14 @@
labelLine: { labelLine: {
show: false show: false
}, },
data: setSeriesData() data: getSeriesData()
} }
] ]
}) }
} else {
params.series[0].data = getSeriesData()
}
setOption(params)
} }
onMounted(() => { onMounted(() => {

View File

@@ -144,7 +144,7 @@
{ {
name: '', name: '',
type: 'bar', type: 'bar',
barWidth: fitChartSize(4), barWidth: fitChartSize(8),
showBackground: true, showBackground: true,
barBorderRadius: [0, 0, 0, 0], barBorderRadius: [0, 0, 0, 0],
backgroundStyle: { backgroundStyle: {

View File

@@ -1,6 +1,6 @@
<!-- 酒店入住人数及入住率 -->
<template> <template>
<div class="lodging-ratio" :id="id" /> <!-- 酒店入住人数及入住率 -->
<div class="occupancy" :id="id" />
</template> </template>
<script setup> <script setup>
@@ -9,24 +9,29 @@
const { id, setOption } = useEchart() const { id, setOption } = useEchart()
const homeData = inject('homeData') let props = defineProps({
list: {
type: Array,
default: () => []
}
})
watch(
() => props.list,
(val) => {
if (val.length > 0) init()
},
{ immediate: true }
)
let params = null let params = null
watch(
() => homeData.value?.hotelData?.list,
() => {
init()
}
)
const setSeriesData = () => { const setSeriesData = () => {
return homeData.value?.hotelData?.list.map((item) => { return props.list.map((item) => {
return { return {
name: item.hotel_name, name: item.hotel_name,
value: item.occupancy_rate, value: item.occupancy_rate,
itemStyle: { itemStyle: {
barBorderRadius: [0, 0, 0, 0],
color: { color: {
type: 'linear', type: 'linear',
x: 0, x: 0,
@@ -40,7 +45,7 @@
}, },
{ {
offset: 1, offset: 1,
color: parseFloat(item.occupancy_rate) > 50 ? '#FF7021' : '#00CCFF' color: '#FF7021'
} }
] ]
} }
@@ -48,9 +53,8 @@
} }
}) })
} }
const setScatterData = () => {
const setCircleData = () => { return props.list.map((item) => {
return homeData.value?.hotelData?.list.map((item) => {
return { return {
name: item.hotel_name, name: item.hotel_name,
value: item.occupancy_rate, value: item.occupancy_rate,
@@ -61,7 +65,9 @@
} }
}) })
} }
const setYAxisData = () => {
return props.list.map((item) => item.occupancy_rate)
}
const init = () => { const init = () => {
if (!params) { if (!params) {
params = { params = {
@@ -75,30 +81,40 @@
grid: { grid: {
left: '4%', left: '4%',
right: '4%', right: '4%',
top: '20%', top: '16%',
bottom: '-10%', bottom: '-10%',
containLabel: true containLabel: true
}, },
xAxis: [{ max: 100, show: false }], xAxis: [
{
splitLine: {
show: false
},
max: 100,
type: 'value',
show: false
}
],
yAxis: [ yAxis: [
{ {
type: 'category',
splitLine: { splitLine: {
show: false show: false
}, },
axisLine: { axisLine: {
show: false show: false
}, },
type: 'category',
axisTick: { axisTick: {
show: false show: false
}, },
data: [],
axisLabel: { axisLabel: {
show: false show: false
}, }
data: homeData.value?.hotelData?.list.map((item) => item.hotel_name)
}, },
{ {
type: 'category', type: 'category',
inverse: true,
axisTick: 'none', axisTick: 'none',
axisLine: 'none', axisLine: 'none',
show: true, show: true,
@@ -114,26 +130,22 @@
return `{value|${value}}{value|%}` return `{value|${value}}{value|%}`
}, },
rich: { rich: {
name: {
align: 'center',
color: '#D3E5FF',
fontSize: fitChartSize(14)
},
value: { value: {
align: 'center', align: 'center',
color: '#fff', color: '#fff',
fontWeight: 600,
fontSize: fitChartSize(14) fontSize: fitChartSize(14)
} }
} }
}, },
data: homeData.value?.hotelData?.list.map((item) => item.occupancy_rate) data: setYAxisData()
} }
], ],
series: [ series: [
{ {
name: '内圆', name: '',
type: 'bar', type: 'bar',
barWidth: 4, barWidth: fitChartSize(8),
showBackground: true, showBackground: true,
barBorderRadius: [0, 0, 0, 0], barBorderRadius: [0, 0, 0, 0],
backgroundStyle: { backgroundStyle: {
@@ -141,8 +153,8 @@
}, },
label: { label: {
show: true, show: true,
offset: [6, -10], offset: [10, -10],
color: '#D3E5FF', color: '#fff',
fontWeight: 500, fontWeight: 500,
position: 'left', position: 'left',
align: 'left', align: 'left',
@@ -163,22 +175,22 @@
symbol: 'circle', symbol: 'circle',
symbolSize: fitChartSize(10), symbolSize: fitChartSize(10),
z: 2, z: 2,
data: setCircleData(), data: setScatterData(),
animationDelay: 500 animationDelay: 500
} }
] ]
} }
} else { } else {
params.series[0].data = setSeriesData() params.series[0].data = setSeriesData()
params.series[1].data = setCircleData() params.series[1].data = setScatterData()
} }
setOption(params) setOption(params)
} }
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.lodging-ratio { .occupancy {
width: 100%; width: vw(360);
height: vh(130); height: vh(120);
} }
</style> </style>

View File

@@ -1,30 +1,24 @@
<!-- 购票来源 -->
<template> <template>
<div>
<div class="ticket" :id="id" /> <div class="ticket" :id="id" />
</div>
</template> </template>
<script setup> <script setup>
import { fitChartSize } from '@/utils/dataUtil' import { fitChartSize } from '@/utils/dataUtil'
import { useEchart } from '@/hooks/echart' import { useEchart } from '@/hooks/echart'
let props = defineProps({ import { useHomeStore } from '@/stores/home'
list: {
type: Array, const homeStore = useHomeStore()
default: () => []
}
})
const { id, setOption } = useEchart() const { id, setOption } = useEchart()
const homeData = inject('homeData')
let x = 15 let x = 15
let y = 25 let y = 25
let params = null let params = null
watch( watch(
() => props.list, () => homeStore.userPortraitData.channel,
(val) => { (val) => {
if (val.length > 0) init() if (val.length > 0) init()
}, },
@@ -34,7 +28,7 @@
) )
const setSeries = () => { const setSeries = () => {
return props.list.map((item, index) => { return homeStore.userPortraitData.channel.map((item, index) => {
return { return {
name: item.name, name: item.name,
type: 'pie', type: 'pie',
@@ -71,21 +65,21 @@
y: 'bottom', y: 'bottom',
itemHeight: fitChartSize(12), itemHeight: fitChartSize(12),
itemWidth: fitChartSize(12), itemWidth: fitChartSize(12),
itemGap: fitChartSize(10), itemGap: fitChartSize(6),
formatter: function (name) { formatter: function (name) {
let obj = props.list.find((item) => item.name == name) let obj = homeStore.userPortraitData.channel.find((item) => item.name == name)
return '{name|' + name + '} {value|' + obj?.value + '}{value|%}' return '{name|' + name + '} {value|' + obj?.value + '}{value|%}'
}, },
textStyle: { textStyle: {
rich: { rich: {
name: { name: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(14) fontSize: fitChartSize(12)
}, },
value: { value: {
color: '#00D5F6', color: '#00D5F6',
fontWeight: 600, fontWeight: 600,
fontSize: fitChartSize(14) fontSize: fitChartSize(12)
} }
} }
} }
@@ -103,7 +97,7 @@
<style scoped lang="scss"> <style scoped lang="scss">
.ticket { .ticket {
width: 100%; width: 100%;
height: vh(200); height: vh(230);
} }
.legend { .legend {
display: flex; display: flex;

View File

@@ -1,3 +1,4 @@
<!-- 客源地分析TOP5 -->
<template> <template>
<div class="top" :id="id" /> <div class="top" :id="id" />
</template> </template>
@@ -5,11 +6,11 @@
<script setup> <script setup>
import { fitChartSize } from '@/utils/dataUtil' import { fitChartSize } from '@/utils/dataUtil'
import { useEchart } from '@/hooks/echart' import { useEchart } from '@/hooks/echart'
import { useHomeStore } from '@/stores/home'
const homeStore = useHomeStore()
const { id, setOption } = useEchart() const { id, setOption } = useEchart()
const homeData = inject('homeData')
const init = () => { const init = () => {
setOption({ setOption({
backgroundColor: 'transparent', backgroundColor: 'transparent',
@@ -67,7 +68,7 @@
} }
} }
}, },
data: homeData.value?.userPortrait?.provinceRate.map((item) => Number(item.value)) data: homeStore?.userPortraitData?.provinceRate.map((item) => Number(item.value))
} }
], ],
series: [ series: [
@@ -91,7 +92,7 @@
return params.data.name ?? '其他' return params.data.name ?? '其他'
} }
}, },
data: homeData.value?.userPortrait?.provinceRate.map((item) => { data: homeStore?.userPortraitData?.provinceRate.map((item) => {
return { return {
name: item.name, name: item.name,
value: Number(item.value), value: Number(item.value),
@@ -107,9 +108,12 @@
} }
watch( watch(
() => homeData.value?.userPortrait?.provinceRate, () => homeStore?.userPortraitData?.provinceRate,
() => { (val) => {
init() if (val.length > 0) init()
},
{
immediate: true
} }
) )
</script> </script>

View File

@@ -1,102 +0,0 @@
<template>
<div class="traffic-flow" id="traffic-flow" />
</template>
<script setup>
import { fitChartSize } from '@/utils/dataUtil'
import * as echarts from 'echarts'
let trafficChart = null
let option = {
grid: {
left: '4%',
right: '4%',
top: '10%',
bottom: '10%',
containLabel: true
},
xAxis: {
boundaryGap: true,
type: 'category',
data: ['河北', '山西', '河南', '内蒙', '辽宁'],
axisTick: {
show: false
},
axisLine: {
lineStyle: {
color: 'rgba(5, 72, 134, 1)'
}
},
axisLabel: {
fontSize: fitChartSize(12),
color: 'rgba(255,255,255,0.9)'
}
},
yAxis: {
type: 'value',
axisLabel: {
fontSize: fitChartSize(12),
color: 'rgba(255,255,255,0.9)'
},
splitLine: {
show: false,
lineStyle: {
color: 'rgba(0, 150, 255,0.4)',
type: 'dashed'
}
}
},
series: [
{
data: [820, 932, 901, 934, 1290],
type: 'bar',
showBackground: true,
barWidth: fitChartSize(8),
itemStyle: {
barBorderRadius: [3, 3, 0, 0],
color: {
type: 'linear',
x: 0,
y: 1,
colorStops: [
{
offset: 0,
color: 'rgba(0, 208, 255, 0)'
},
{
offset: 1,
color: 'rgba(0, 208, 255, 1)'
}
]
}
},
backgroundStyle: {
color: 'rgba(0, 150, 255, 0.15)'
}
}
]
}
const init = () => {
trafficChart = echarts.init(document.getElementById('traffic-flow'))
trafficChart.setOption(option)
window.addEventListener('resize', resize)
}
const resize = () => {
if (trafficChart) {
trafficChart.dispose()
trafficChart = null
init()
}
}
onMounted(() => {
init()
})
</script>
<style scoped lang="scss">
.traffic-flow {
width: 100%;
height: vh(160);
}
</style>

View File

@@ -1,19 +1,74 @@
<template> <template>
<div class="vacancy" id="vacancy" /> <!-- 景区停车场空位 -->
<div class="vacancy" :id="id" />
</template> </template>
<script setup> <script setup>
import { fitChartSize } from '@/utils/dataUtil' import { fitChartSize } from '@/utils/dataUtil'
import * as echarts from 'echarts' import { useEchart } from '@/hooks/echart'
let topChart = null const { id, setOption } = useEchart()
let result = [
{ name: '三峡之颠', value: 86 }, let props = defineProps({
{ name: '白帝城', value: 83 }, list: {
{ name: '瞿塘峡', value: 73 }, type: Array,
{ name: '天坑地缝', value: 61 } default: () => []
}
})
watch(
() => props.list,
(val) => {
if (val.length > 0) init()
},
{ immediate: true }
)
let params = null
const getSeriesData = () => {
return props.list.map((item) => {
return {
...item,
itemStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 1,
y2: 1,
colorStops: [
{
offset: 0,
color: 'rgba(255, 112, 33, 0)'
},
{
offset: 1,
color: '#00CCFF'
}
] ]
let option = { }
}
}
})
}
const getScatterData = () => {
return props.list.map((item) => {
return {
...item,
itemStyle: {
color: '#fff',
opacity: 1
}
}
})
}
const getYAxisData = () => {
return props.list.map((item) => item.value)
}
const init = () => {
if (!params) {
params = {
backgroundColor: 'transparent', backgroundColor: 'transparent',
tooltip: { tooltip: {
show: false show: false
@@ -24,8 +79,8 @@
grid: { grid: {
left: '4%', left: '4%',
right: '4%', right: '4%',
top: '20%', top: '16%',
bottom: '-4%', bottom: '-10%',
containLabel: true containLabel: true
}, },
xAxis: [ xAxis: [
@@ -49,7 +104,7 @@
axisTick: { axisTick: {
show: false show: false
}, },
data: result.map((item) => item.name), data: [],
axisLabel: { axisLabel: {
show: false show: false
} }
@@ -66,79 +121,46 @@
fontSize: fitChartSize(12) fontSize: fitChartSize(12)
}, },
verticalAlign: 'bottom', verticalAlign: 'bottom',
padding: [0, 0, fitChartSize(6), 0], padding: [0, 0, 6, 0],
inside: true, inside: true,
formatter: function (value) { formatter: function (value) {
return `{label|余} {value|${value}}` return `{value|余}{value|${value}}`
}, },
rich: { rich: {
label: {
align: 'center',
color: '#fff',
fontSize: fitChartSize(14),
fontFamily: 'Source Han Sans CN'
},
value: { value: {
align: 'center', align: 'center',
color: '#fff', color: '#fff',
fontSize: fitChartSize(14), fontWeight: 600,
fontFamily: 'Source Han Sans CN' fontSize: fitChartSize(14)
} }
} }
}, },
data: result.map((item) => item.value) data: getYAxisData()
} }
], ],
series: [ series: [
{ {
name: '', name: '',
type: 'bar', type: 'bar',
barWidth: fitChartSize(4), barWidth: fitChartSize(8),
MaxSize: 0,
showBackground: true, showBackground: true,
barBorderRadius: [30, 0, 0, 30], barBorderRadius: [0, 0, 0, 0],
backgroundStyle: { backgroundStyle: {
color: 'rgba(0, 150, 255, 0.15)' color: 'rgba(0, 150, 255, 0.15)'
}, },
label: { label: {
show: true, show: true,
offset: [10, -13], offset: [10, -10],
color: '#D3E5FF', color: '#fff',
fontWeight: 500, fontWeight: 500,
position: 'left', position: 'left',
align: 'left', align: 'left',
fontSize: fitChartSize(14), fontSize: fitChartSize(14),
fontFamily: 'Source Han Sans CN',
formatter: function (params) { formatter: function (params) {
return params.data.name return params.data.name
} }
}, },
data: result.map((item, index) => { data: getSeriesData()
return {
name: item.name,
value: item.value,
itemStyle: {
barBorderRadius: [3, 0, 0, 3],
color: {
type: 'linear',
x: 0,
y: 0,
x2: 1,
y2: 1,
colorStops: [
{
offset: 0,
color: 'rgba(0, 204, 255, 0)'
},
{
offset: 1,
color: 'rgba(0, 204, 255, 1)'
}
]
}
}
}
})
}, },
{ {
name: '外圆', name: '外圆',
@@ -150,40 +172,23 @@
symbol: 'circle', symbol: 'circle',
symbolSize: fitChartSize(10), symbolSize: fitChartSize(10),
z: 2, z: 2,
data: result.map((item, index) => { animationDelay: 500,
return { data: getScatterData()
name: item.name,
value: item.value,
itemStyle: {
color: '#fff',
opacity: 1
}
}
}),
animationDelay: 500
} }
] ]
} }
const init = () => { } else {
topChart = echarts.init(document.getElementById('vacancy')) params.yAxis[1].data = getYAxisData()
topChart.setOption(option) params.series[0].data = getSeriesData()
params.series[1].data = getScatterData()
} }
const resize = () => { setOption(params)
if (topChart) {
topChart.dispose()
topChart = null
init()
} }
}
onMounted(() => {
init()
window.addEventListener('resize', resize)
})
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.vacancy { .vacancy {
width: 100%; width: vw(250);
height: vh(170); height: vh(160);
} }
</style> </style>

View File

@@ -0,0 +1,119 @@
<!-- 车源地 -->
<template>
<div class="vehicle-source" :id="id" />
</template>
<script setup>
import { fitChartSize } from '@/utils/dataUtil'
import { useEchart } from '@/hooks/echart'
const { id, setOption } = useEchart()
let props = defineProps({
list: {
type: Array,
default: () => []
}
})
watch(
() => props.list,
(val) => {
if (val.length > 0) init()
},
{ immediate: true }
)
let params = null
const getSeriesData = () => {
return props.list.map((item) => item.value)
}
const getXAxisData = () => {
return props.list.map((item) => item.name)
}
const init = () => {
if (!params) {
params = {
grid: {
left: '4%',
right: '4%',
top: '10%',
bottom: '10%',
containLabel: true
},
xAxis: {
boundaryGap: true,
type: 'category',
data: getXAxisData(),
axisTick: {
show: false
},
axisLine: {
lineStyle: {
color: 'rgba(5, 72, 134, 1)'
}
},
axisLabel: {
fontSize: fitChartSize(12),
color: 'rgba(255,255,255,0.9)'
}
},
yAxis: {
type: 'value',
axisLabel: {
fontSize: fitChartSize(12),
color: 'rgba(255,255,255,0.9)'
},
splitLine: {
show: false,
lineStyle: {
color: 'rgba(0, 150, 255,0.4)',
type: 'dashed'
}
}
},
series: [
{
data: getSeriesData(),
type: 'bar',
showBackground: true,
barWidth: fitChartSize(8),
itemStyle: {
barBorderRadius: [0, 0, 0, 0],
color: {
type: 'linear',
x: 0,
y: 1,
colorStops: [
{
offset: 0,
color: 'rgba(0, 208, 255, 0)'
},
{
offset: 1,
color: 'rgba(0, 208, 255, 1)'
}
]
}
},
backgroundStyle: {
color: 'rgba(0, 150, 255, 0.15)'
}
}
]
}
} else {
params.xAxis.data = getXAxisData()
params.series[0].data = getSeriesData()
}
setOption(params)
}
</script>
<style scoped lang="scss">
.vehicle-source {
width: 100%;
height: vh(160);
}
</style>

View File

@@ -10,14 +10,13 @@
import box3 from './components/box-3.vue' import box3 from './components/box-3.vue'
import { useWebSocket } from '@/hooks/socket' import { useWebSocket } from '@/hooks/socket'
const { data, isConnected, sendMessage } = useWebSocket('ws://36.138.38.16:81/ws/third-party') const { isConnected, sendMessage } = useWebSocket('ws://36.138.38.16:81/ws/third-party')
provide('homeData', data)
watch( watch(
() => isConnected.value, () => isConnected.value,
(val) => { (val) => {
if (val) { if (val) {
console.log('--------------------------------------------')
sendMessage( sendMessage(
JSON.stringify({ JSON.stringify({
action: 'start', action: 'start',

View File

@@ -84,10 +84,10 @@
import countup from 'vue-countup-v3' import countup from 'vue-countup-v3'
import { fitChartSize } from '@/utils/dataUtil' import { fitChartSize } from '@/utils/dataUtil'
import Map from '@/components/Map/marker.vue' import Map from '@/components/Map/marker.vue'
import VChart, { THEME_KEY } from 'vue-echarts'; import VChart, { THEME_KEY } from 'vue-echarts'
import { ref, provide } from 'vue'; import { ref, provide } from 'vue'
provide(THEME_KEY, 'dark'); provide(THEME_KEY, 'dark')
const option1 = ref({ const option1 = ref({
backgroundColor: 'transparent', backgroundColor: 'transparent',
tooltip: { tooltip: {
@@ -102,7 +102,7 @@
itemWidth: 5, itemWidth: 5,
itemHeight: 5, itemHeight: 5,
textStyle: { textStyle: {
fontSize:fitChartSize(14), fontSize: fitChartSize(14)
} }
}, },
series: [ series: [
@@ -143,19 +143,18 @@
{ value: 135, name: '异常状况4' }, { value: 135, name: '异常状况4' },
{ value: 100, name: '异常状况5' }, { value: 100, name: '异常状况5' },
{ value: 777, name: '异常状况6' }, { value: 777, name: '异常状况6' },
{ value: 777, name: '其他' }, { value: 777, name: '其他' }
] ]
}
}, ]
], })
});
const optionLine = ref({ const optionLine = ref({
backgroundColor: 'transparent', backgroundColor: 'transparent',
grid: { grid: {
top: '50', top: '50',
bottom: '50', bottom: '50',
left: '4%', left: '4%',
containLabel: true, containLabel: true
}, },
xAxis: { xAxis: {
nameLocation: 'middle', nameLocation: 'middle',
@@ -164,7 +163,7 @@
axisLabel: { axisLabel: {
fontSize: 10, fontSize: 10,
interval: 0, // 显示所有标签 interval: 0, // 显示所有标签
rotate: 0, // 旋转标签45度 rotate: 0 // 旋转标签45度
}, },
data: ['10:00', '10:00', '10:00', '10:00', '10:00', '10:00', '10:00', '10:00'], data: ['10:00', '10:00', '10:00', '10:00', '10:00', '10:00', '10:00', '10:00'],
axisTisk: { axisTisk: {
@@ -173,7 +172,7 @@
length: 1, length: 1,
lineStyle: { lineStyle: {
type: 'dashed', // 设置为虚线 type: 'dashed', // 设置为虚线
width:0, width: 0
} }
}, },
axisLine: { axisLine: {
@@ -189,7 +188,7 @@
interval: 15, interval: 15,
axisLabel: { axisLabel: {
fontSize: fitChartSize(12), // 设置Y轴刻度字体大小 fontSize: fitChartSize(12), // 设置Y轴刻度字体大小
color: 'rgba(255,255,255,0.9)', color: 'rgba(255,255,255,0.9)'
}, },
splitLine: { splitLine: {
show: true, show: true,
@@ -206,7 +205,7 @@
type: 'line', type: 'line',
smooth: true, smooth: true,
label: { label: {
show:false,//隐藏坐标点 show: false //隐藏坐标点
}, },
itemStyle: { itemStyle: {
color: 'transparent' color: 'transparent'
@@ -229,13 +228,12 @@
{ {
offset: 1, offset: 1,
color: '#009DFF' color: '#009DFF'
}, }
]), ]),
width:3, width: 3
} }
} }
] ]
}) })
const optionBar = ref({ const optionBar = ref({
backgroundColor: 'transparent', backgroundColor: 'transparent',
@@ -252,14 +250,14 @@
top: 0, top: 0,
bottom: 20, bottom: 20,
itemWidth: 5, itemWidth: 5,
itemHeight:5, itemHeight: 5
}, },
grid: { grid: {
left: '3%', left: '3%',
right: '4%', right: '4%',
bottom: '20%', bottom: '20%',
containLabel: true, containLabel: true,
show:false, show: false
}, },
xAxis: [ xAxis: [
{ {
@@ -269,10 +267,10 @@
axisLabel: { axisLabel: {
fontSize: fitChartSize(10), fontSize: fitChartSize(10),
interval: 0, // 显示所有标签 interval: 0, // 显示所有标签
rotate: 0, // 旋转标签45度 rotate: 0 // 旋转标签45度
}, },
minorTisk: { minorTisk: {
show:false, show: false
}, },
data: ['10:00', '10:00', '10:00', '10:00', '10:00', '10:00', '10:00', '10:00'], data: ['10:00', '10:00', '10:00', '10:00', '10:00', '10:00', '10:00', '10:00'],
axisTisk: { axisTisk: {
@@ -282,14 +280,13 @@
length: 0, length: 0,
lineStyle: { lineStyle: {
type: 'dashed', // 设置为虚线 type: 'dashed', // 设置为虚线
width:0, width: 0
}
} }
},
} }
], ],
yAxis: [ yAxis: [
{ {
type: 'value', type: 'value',
min: 0, min: 0,
max: 45, max: 45,
@@ -298,7 +295,7 @@
axisLabel: { axisLabel: {
fontSize: fitChartSize(12), // 设置Y轴刻度字体大小 fontSize: fitChartSize(12), // 设置Y轴刻度字体大小
color: 'rgba(255,255,255,0.9)', color: 'rgba(255,255,255,0.9)',
offset:10, offset: 10
}, },
splitLine: { splitLine: {
show: false, show: false,
@@ -306,12 +303,10 @@
type: 'dashed', type: 'dashed',
color: '#00D0FF' color: '#00D0FF'
} }
}, }
} }
], ],
series: [ series: [
{ {
itemStyle: { itemStyle: {
// 设置柱状图颜色 // 设置柱状图颜色
@@ -324,7 +319,7 @@
focus: 'series' focus: 'series'
}, },
data: [10, 0, 16, 10, 22, 11, 9, 30], data: [10, 0, 16, 10, 22, 11, 9, 30],
barWidth: '45%', // 设置柱体粗细,可以是百分比或者像素值 barWidth: '45%' // 设置柱体粗细,可以是百分比或者像素值
}, },
{ {
name: '白帝城', name: '白帝城',
@@ -351,8 +346,7 @@
color: '#FFCB39' color: '#FFCB39'
}, },
data: [15, 20, 8, 19, 20, 5, 22, 13] data: [15, 20, 8, 19, 20, 5, 22, 13]
}, }
] ]
}) })
onMounted(() => {}) onMounted(() => {})
@@ -371,20 +365,20 @@
span { span {
min-width: vw(55); min-width: vw(55);
padding: vw(5); padding: vw(5);
background: linear-gradient( 270deg, rgba(8,41,86,0.16) 0%, #0B61B4 100%); background: linear-gradient(270deg, rgba(8, 41, 86, 0.16) 0%, #0b61b4 100%);
border-radius: vw(50); border-radius: vw(50);
// border: 1px solid rgba(0,114,220,0.3); // border: 1px solid rgba(0,114,220,0.3);
margin-left: vw(5); margin-left: vw(5);
display: inline-block; display: inline-block;
font-weight: 400; font-weight: 400;
font-size: vw(13); font-size: vw(13);
color: #0084FF; color: #0084ff;
text-align: center; text-align: center;
font-style: normal; font-style: normal;
text-transform: none; text-transform: none;
} }
.active { .active {
background: linear-gradient( 270deg, #37D8FC 0%, #0084FF 100%); background: linear-gradient(270deg, #37d8fc 0%, #0084ff 100%);
border-radius: vw(50); border-radius: vw(50);
border: 1px solid rgba(0, 114, 220, 0.3); border: 1px solid rgba(0, 114, 220, 0.3);
color: #fff; color: #fff;
@@ -395,7 +389,7 @@
margin-top: vh(120); margin-top: vh(120);
width: vw(820); width: vw(820);
height: vh(950); height: vh(950);
background: linear-gradient( 321deg, #0B2F64 0%, #062B57 91%, rgba(5,40,79,0) 100%); background: linear-gradient(321deg, #0b2f64 0%, #062b57 91%, rgba(5, 40, 79, 0) 100%);
border-radius: 0px 0px 0px 0px; border-radius: 0px 0px 0px 0px;
.detection-top { .detection-top {
width: 100%; width: 100%;
@@ -538,7 +532,7 @@
display: block; display: block;
font-weight: bold; font-weight: bold;
font-size: vw(24); font-size: vw(24);
color: #FFFFFF; color: #ffffff;
line-height: 28px; line-height: 28px;
text-align: center; text-align: center;
font-style: normal; font-style: normal;
@@ -548,7 +542,7 @@
display: block; display: block;
font-weight: bold; font-weight: bold;
font-size: vw(24); font-size: vw(24);
color: #F15A25; color: #f15a25;
line-height: 28px; line-height: 28px;
text-align: center; text-align: center;
font-style: normal; font-style: normal;
@@ -562,7 +556,7 @@
text-align: center; text-align: center;
font-style: normal; font-style: normal;
text-transform: none; text-transform: none;
color:#A70000; color: #a70000;
} }
} }
} }
@@ -582,7 +576,7 @@
position: relative; position: relative;
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: vw(14);
color: #FFFFFF; color: #ffffff;
line-height: 16px; line-height: 16px;
text-align: left; text-align: left;
font-style: normal; font-style: normal;
@@ -591,7 +585,7 @@
padding-left: vw(30); padding-left: vw(30);
padding: 0 vw(10); padding: 0 vw(10);
padding-left: vw(15); padding-left: vw(15);
background: linear-gradient( 90deg, #1B5EC7 0%, rgba(27,94,199,0) 100%); background: linear-gradient(90deg, #1b5ec7 0%, rgba(27, 94, 199, 0) 100%);
border-radius: 0px 0px 0px 0px; border-radius: 0px 0px 0px 0px;
height: vh(24); height: vh(24);
line-height: vh(24); line-height: vh(24);
@@ -612,7 +606,7 @@
} }
} }
.li-1 { .li-1 {
background: linear-gradient( 90deg, #FFC10B 0%, rgba(255,209,44,0) 100%); background: linear-gradient(90deg, #ffc10b 0%, rgba(255, 209, 44, 0) 100%);
.rk-img { .rk-img {
background-image: url('/src/assets/images/rk-1.png'); background-image: url('/src/assets/images/rk-1.png');
} }
@@ -631,5 +625,4 @@
} }
} }
} }
</style> </style>

View File

@@ -31,7 +31,6 @@
<v-chart class="chart" :option="optionBar" autoresize /> <v-chart class="chart" :option="optionBar" autoresize />
<!-- <v-chart class="chart" :option="option1" autoresize /> --> <!-- <v-chart class="chart" :option="option1" autoresize /> -->
</div> </div>
</div> </div>
</div> </div>
</div> </div>
@@ -77,10 +76,10 @@
import countup from 'vue-countup-v3' import countup from 'vue-countup-v3'
import { fitChartSize } from '@/utils/dataUtil' import { fitChartSize } from '@/utils/dataUtil'
import Map from '@/components/Map/marker.vue' import Map from '@/components/Map/marker.vue'
import VChart, { THEME_KEY } from 'vue-echarts'; import VChart, { THEME_KEY } from 'vue-echarts'
import { ref, provide } from 'vue'; import { ref, provide } from 'vue'
provide(THEME_KEY, 'dark'); provide(THEME_KEY, 'dark')
const option1 = ref({ const option1 = ref({
backgroundColor: 'transparent', backgroundColor: 'transparent',
tooltip: { tooltip: {
@@ -95,7 +94,7 @@
itemWidth: 5, itemWidth: 5,
itemHeight: 5, itemHeight: 5,
textStyle: { textStyle: {
fontSize:fitChartSize(12), fontSize: fitChartSize(12)
} }
}, },
series: [ series: [
@@ -134,21 +133,19 @@
{ value: 135, name: '异常状况4' }, { value: 135, name: '异常状况4' },
{ value: 100, name: '异常状况5' }, { value: 100, name: '异常状况5' },
{ value: 777, name: '异常状况6' }, { value: 777, name: '异常状况6' },
{ value: 777, name: '其他' }, { value: 777, name: '其他' }
] ]
}
}, ]
], })
});
const optionLine = ref({ const optionLine = ref({
backgroundColor: 'transparent', backgroundColor: 'transparent',
grid: { grid: {
top: '50', top: '50',
bottom: '50', bottom: '50',
left: '4%', left: '4%',
containLabel: true, containLabel: true
}, },
xAxis: { xAxis: {
nameLocation: 'middle', nameLocation: 'middle',
@@ -157,7 +154,7 @@
axisLabel: { axisLabel: {
fontSize: 10, fontSize: 10,
interval: 0, // 显示所有标签 interval: 0, // 显示所有标签
rotate: 0, // 旋转标签45度 rotate: 0 // 旋转标签45度
}, },
data: ['10:00', '10:00', '10:00', '10:00', '10:00', '10:00', '10:00', '10:00'], data: ['10:00', '10:00', '10:00', '10:00', '10:00', '10:00', '10:00', '10:00'],
axisTisk: { axisTisk: {
@@ -166,7 +163,7 @@
length: 1, length: 1,
lineStyle: { lineStyle: {
type: 'dashed', // 设置为虚线 type: 'dashed', // 设置为虚线
width:0, width: 0
} }
}, },
axisLine: { axisLine: {
@@ -182,7 +179,7 @@
interval: 15, interval: 15,
axisLabel: { axisLabel: {
fontSize: fitChartSize(12), // 设置Y轴刻度字体大小 fontSize: fitChartSize(12), // 设置Y轴刻度字体大小
color: 'rgba(255,255,255,0.9)', color: 'rgba(255,255,255,0.9)'
}, },
splitLine: { splitLine: {
show: true, show: true,
@@ -199,7 +196,7 @@
type: 'line', type: 'line',
smooth: true, smooth: true,
label: { label: {
show:false,//隐藏坐标点 show: false //隐藏坐标点
}, },
itemStyle: { itemStyle: {
color: 'transparent' color: 'transparent'
@@ -222,13 +219,12 @@
{ {
offset: 1, offset: 1,
color: '#009DFF' color: '#009DFF'
}, }
]), ]),
width:3, width: 3
} }
} }
] ]
}) })
const optionBar = ref({ const optionBar = ref({
backgroundColor: 'transparent', backgroundColor: 'transparent',
@@ -247,16 +243,15 @@
itemWidth: 5, itemWidth: 5,
itemHeight: 5, itemHeight: 5,
textStyle: { textStyle: {
fontSize:fitChartSize(12), fontSize: fitChartSize(12)
} }
}, },
grid: { grid: {
left: '3%', left: '3%',
right: '4%', right: '4%',
bottom: '20%', bottom: '20%',
containLabel: true, containLabel: true,
show:false, show: false
}, },
xAxis: [ xAxis: [
{ {
@@ -266,10 +261,10 @@
axisLabel: { axisLabel: {
fontSize: fitChartSize(10), fontSize: fitChartSize(10),
interval: 0, // 显示所有标签 interval: 0, // 显示所有标签
rotate: 0, // 旋转标签45度 rotate: 0 // 旋转标签45度
}, },
minorTisk: { minorTisk: {
show:false, show: false
}, },
data: ['10:00', '10:00', '10:00', '10:00', '10:00', '10:00', '10:00', '10:00'], data: ['10:00', '10:00', '10:00', '10:00', '10:00', '10:00', '10:00', '10:00'],
axisTisk: { axisTisk: {
@@ -279,14 +274,13 @@
length: 0, length: 0,
lineStyle: { lineStyle: {
type: 'dashed', // 设置为虚线 type: 'dashed', // 设置为虚线
width:0, width: 0
}
} }
},
} }
], ],
yAxis: [ yAxis: [
{ {
type: 'value', type: 'value',
min: 0, min: 0,
max: 45, max: 45,
@@ -294,7 +288,7 @@
axisLabel: { axisLabel: {
fontSize: fitChartSize(12), // 设置Y轴刻度字体大小 fontSize: fitChartSize(12), // 设置Y轴刻度字体大小
color: 'rgba(255,255,255,0.9)', color: 'rgba(255,255,255,0.9)',
offset:10, offset: 10
}, },
splitLine: { splitLine: {
show: false, show: false,
@@ -302,8 +296,7 @@
type: 'dashed', type: 'dashed',
color: '#00D0FF' color: '#00D0FF'
} }
}, }
} }
], ],
series: [ series: [
@@ -319,7 +312,7 @@
focus: 'series' focus: 'series'
}, },
data: [10, 0, 16, 10, 22, 11, 9, 30], data: [10, 0, 16, 10, 22, 11, 9, 30],
barWidth: '45%', // 设置柱体粗细,可以是百分比或者像素值 barWidth: '45%' // 设置柱体粗细,可以是百分比或者像素值
}, },
{ {
name: '白帝城', name: '白帝城',
@@ -346,8 +339,7 @@
color: '#FFCB39' color: '#FFCB39'
}, },
data: [15, 20, 8, 19, 20, 5, 22, 13] data: [15, 20, 8, 19, 20, 5, 22, 13]
}, }
] ]
}) })
onMounted(() => {}) onMounted(() => {})
@@ -361,7 +353,7 @@
margin-top: vh(120); margin-top: vh(120);
width: vw(820); width: vw(820);
height: vh(950); height: vh(950);
background: linear-gradient( 321deg, #0B2F64 0%, #062B57 91%, rgba(5,40,79,0) 100%); background: linear-gradient(321deg, #0b2f64 0%, #062b57 91%, rgba(5, 40, 79, 0) 100%);
border-radius: 0px 0px 0px 0px; border-radius: 0px 0px 0px 0px;
.detection-top { .detection-top {
width: 100%; width: 100%;
@@ -504,7 +496,7 @@
display: block; display: block;
font-weight: bold; font-weight: bold;
font-size: vw(24); font-size: vw(24);
color: #FFFFFF; color: #ffffff;
line-height: 28px; line-height: 28px;
text-align: center; text-align: center;
font-style: normal; font-style: normal;
@@ -514,7 +506,7 @@
display: block; display: block;
font-weight: bold; font-weight: bold;
font-size: vw(24); font-size: vw(24);
color: #F15A25; color: #f15a25;
line-height: 28px; line-height: 28px;
text-align: center; text-align: center;
font-style: normal; font-style: normal;
@@ -528,7 +520,7 @@
text-align: center; text-align: center;
font-style: normal; font-style: normal;
text-transform: none; text-transform: none;
color:#A70000; color: #a70000;
} }
} }
} }
@@ -548,7 +540,7 @@
position: relative; position: relative;
font-weight: 400; font-weight: 400;
font-size: vw(14); font-size: vw(14);
color: #FFFFFF; color: #ffffff;
line-height: 16px; line-height: 16px;
text-align: left; text-align: left;
font-style: normal; font-style: normal;
@@ -557,7 +549,7 @@
padding-left: vw(30); padding-left: vw(30);
padding: 0 vw(10); padding: 0 vw(10);
padding-left: vw(15); padding-left: vw(15);
background: linear-gradient( 90deg, #1B5EC7 0%, rgba(27,94,199,0) 100%); background: linear-gradient(90deg, #1b5ec7 0%, rgba(27, 94, 199, 0) 100%);
border-radius: 0px 0px 0px 0px; border-radius: 0px 0px 0px 0px;
height: vh(24); height: vh(24);
line-height: vh(24); line-height: vh(24);
@@ -578,7 +570,7 @@
} }
} }
.li-1 { .li-1 {
background: linear-gradient( 90deg, #FFC10B 0%, rgba(255,209,44,0) 100%); background: linear-gradient(90deg, #ffc10b 0%, rgba(255, 209, 44, 0) 100%);
.rk-img { .rk-img {
background-image: url('/src/assets/images/rk-1.png'); background-image: url('/src/assets/images/rk-1.png');
} }
@@ -597,5 +589,4 @@
} }
} }
} }
</style> </style>

View File

@@ -11,7 +11,8 @@
<script setup> <script setup>
import box3 from './components/box-3.vue' import box3 from './components/box-3.vue'
import box5 from './components/box-5.vue' import box5 from './components/box-5.vue'
const navLeft = [{ const navLeft = [
{
name: '奉节县', name: '奉节县',
path: '/sceneTesting' path: '/sceneTesting'
}, },
@@ -22,12 +23,14 @@ const navLeft = [{
{ {
name: '白帝城', name: '白帝城',
path: '/sceneTesting' path: '/sceneTesting'
}, { },
{
name: '龙河桥', name: '龙河桥',
path: '/sceneTesting' path: '/sceneTesting'
} }
] ]
const navRight = [{ const navRight = [
{
name: '路段', name: '路段',
path: '/roadTesting' path: '/roadTesting'
}, },
@@ -54,6 +57,5 @@ const navLeft = [{
height: 100vh; height: 100vh;
overflow: hidden; overflow: hidden;
background-color: #0a254b; background-color: #0a254b;
} }
</style> </style>

View File

@@ -98,7 +98,7 @@
<p class="value">{{ item.value }}%</p> <p class="value">{{ item.value }}%</p>
</li> </li>
</ul> </ul>
<div class="alarm"> <div v-if="pointRankData.length > 0" class="alarm">
<Title2 title="异常点位告警排名" /> <Title2 title="异常点位告警排名" />
<ul class="alarm__wrapper"> <ul class="alarm__wrapper">
<li class="alarm-item" v-for="(item, index) in pointRankData" :key="index"> <li class="alarm-item" v-for="(item, index) in pointRankData" :key="index">
@@ -154,7 +154,6 @@
const getNewsPointRank = async () => { const getNewsPointRank = async () => {
let res = await getNewsPointRankApi() let res = await getNewsPointRankApi()
pointRankData.value = res.data pointRankData.value = res.data
console.log(res, '1111')
} }
const getTypeRate = async () => { const getTypeRate = async () => {
let res = await getTypeRateApi() let res = await getTypeRateApi()

View File

@@ -5,49 +5,54 @@
<div class="statistics"> <div class="statistics">
<div class="statistics-item"> <div class="statistics-item">
<div class="flex align-center"> <div class="flex align-center">
<img class="statistics-item__icon" src="@/assets/images/dot-primary.svg" alt="" /> <img class="statistics-item__icon" src="@/assets/images/dot-primary.svg" />
<span class="statistics-item__label">今日消息总条数</span> <span class="statistics-item__label">今日消息总条数</span>
</div> </div>
<div class="statistics-item__value--primary"> <div class="statistics-item__value--primary">
<countup end-val="45678" /> <countup :end-val="countInfo.total" />
<span class="statistics-item__value-suffix"></span> <span class="statistics-item__value-suffix"></span>
</div> </div>
</div> </div>
<div class="statistics-item"> <div class="statistics-item">
<div class="flex align-center"> <div class="flex align-center">
<img class="statistics-item__icon" src="@/assets/images/dot-error.svg" alt="" /> <img class="statistics-item__icon" src="@/assets/images/dot-error.svg" />
<span class="statistics-item__label">紧急消息</span> <span class="statistics-item__label">紧急消息</span>
</div> </div>
<div class="statistics-item__value--error"> <div class="statistics-item__value--error">
<countup end-val="45678" /> <countup :end-val="countInfo.warn" />
<span class="statistics-item__value-suffix"></span> <span class="statistics-item__value-suffix"></span>
</div> </div>
</div> </div>
<div class="statistics-item"> <div class="statistics-item">
<div class="flex align-center"> <div class="flex align-center">
<img class="statistics-item__icon" src="@/assets/images/dot-warning.svg" alt="" /> <img class="statistics-item__icon" src="@/assets/images/dot-warning.svg" />
<span class="statistics-item__label">重要消息</span> <span class="statistics-item__label">重要消息</span>
</div> </div>
<div class="statistics-item__value--warning"> <div class="statistics-item__value--warning">
<countup end-val="45678" /> <countup :end-val="countInfo.important" />
<span class="statistics-item__value-suffix"></span> <span class="statistics-item__value-suffix"></span>
</div> </div>
</div> </div>
<div class="statistics-item"> <div class="statistics-item">
<div class="flex align-center"> <div class="flex align-center">
<img class="statistics-item__icon" src="@/assets/images/dot-success.svg" alt="" /> <img class="statistics-item__icon" src="@/assets/images/dot-success.svg" />
<span class="statistics-item__label">普通消息</span> <span class="statistics-item__label">普通消息</span>
</div> </div>
<div class="statistics-item__value--success"> <div class="statistics-item__value--success">
<countup end-val="45678" /> <countup :end-val="countInfo.normal" />
<span class="statistics-item__value-suffix"></span> <span class="statistics-item__value-suffix"></span>
</div> </div>
</div> </div>
</div> </div>
<div class="chart-box"> <div class="chart-box">
<pie :width="150" :height="150" /> <pie
<pie :width="150" :height="150" /> v-for="(item, index) in newsStateList"
<pie :width="150" :height="150" /> :key="index"
:value="item.value"
:label="item.name"
:width="150"
:height="150"
/>
</div> </div>
</div> </div>
<div class="work-box-1"> <div class="work-box-1">
@@ -75,14 +80,22 @@
import pie from './pie.vue' import pie from './pie.vue'
import { getNewsListApi, getNewsStateApi, getNewsTotalApi } from '@/api/news' import { getNewsListApi, getNewsStateApi, getNewsTotalApi } from '@/api/news'
const list = ref([]) let list = ref([])
let countInfo = ref({
important: 0,
normal: 0,
total: 0,
warn: 0
})
let newsStateList = ref([])
const getNewsTotal = async () => { const getNewsTotal = async () => {
let res = await getNewsTotalApi() let res = await getNewsTotalApi()
console.log(res, '============') countInfo.value = res.data
} }
const getNewsState = async () => { const getNewsState = async () => {
let res = await getNewsStateApi() let res = await getNewsStateApi()
newsStateList.value = res.data
console.log(newsStateList.value, '=================')
} }
const getNewsList = async () => { const getNewsList = async () => {
let res = await getNewsListApi() let res = await getNewsListApi()

View File

@@ -8,22 +8,48 @@
const { id, setOption } = useEchart() const { id, setOption } = useEchart()
let option = { let props = defineProps({
value: {
type: Number,
default: () => 0
},
label: {
type: String,
default: () => ''
}
})
watch(
() => props.value,
(val) => {
if (val) {
nextTick(() => {
init()
})
}
},
{ immediate: true }
)
let params = null
const init = () => {
if (!params) {
params = {
backgroundColor: 'transparent', backgroundColor: 'transparent',
title: [ title: [
{ {
text: '45.5%', text: `${(props.value * 100).toFixed(2)}%`,
x: 'center', x: 'center',
top: '42%', top: '40%',
textStyle: { textStyle: {
color: '#02F9FA', color: '#02F9FA',
fontSize: fitChartSize(24) fontSize: fitChartSize(24)
} }
}, },
{ {
text: '完成率', text: props.label,
x: 'center', x: 'center',
top: '54%', top: '56%',
textStyle: { textStyle: {
color: '#fff', color: '#fff',
fontSize: fitChartSize(12) fontSize: fitChartSize(12)
@@ -36,7 +62,7 @@
radius: '100%', radius: '100%',
center: ['50%', '50%'], center: ['50%', '50%'],
min: 0, min: 0,
max: 100, max: 1,
startAngle: 90, startAngle: 90,
endAngle: 450, endAngle: 450,
clockwise: false, clockwise: false,
@@ -81,7 +107,7 @@
}, },
data: [ data: [
{ {
value: 50 value: props.value
} }
] ]
}, },
@@ -90,7 +116,7 @@
radius: '95%', radius: '95%',
center: ['50%', '50%'], center: ['50%', '50%'],
min: 0, min: 0,
max: 100, max: 1,
startAngle: 90, startAngle: 90,
endAngle: 450, endAngle: 450,
clockwise: false, clockwise: false,
@@ -134,19 +160,17 @@
}, },
data: [ data: [
{ {
value: 50 value: props.value
} }
] ]
} }
] ]
} }
const init = () => { } else {
setOption(option) params.series[0].data[0].value = props.value
}
setOption(params)
} }
onMounted(() => {
init()
})
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>