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

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,4 @@
<!-- 拥堵次数占比 -->
<template>
<div class="jam-count" :id="id" />
</template>
@@ -15,7 +16,8 @@
const { id, setOption } = useEchart()
var colorList = ['#FDC40A', '#FF5232', '#50F0A6']
let params = null
const colorList = ['#FDC40A', '#FF5232', '#50F0A6']
watch(
() => props.list,
@@ -27,7 +29,7 @@
}
)
const setSeriesData = () => {
const getSeriesData = () => {
return props.list.map((item) => {
return {
name: item.name,
@@ -41,75 +43,80 @@
}, 0)
}
const init = () => {
setOption({
color: colorList,
grid: {
left: '4%',
right: '4%',
top: '4%',
bottom: '4%',
containLabel: true
},
legend: {
orient: 'horizontal',
x: 'center',
bottom: '-2%',
itemHeight: fitChartSize(16),
itemWidth: fitChartSize(16),
itemGap: fitChartSize(10),
formatter: (name) => {
let obj = props.list.find((item) => item.name == name)
return '{name|' + name + '} {value|' + obj?.count + '}{value|%}'
if (!params) {
params = {
color: colorList,
grid: {
left: '4%',
right: '4%',
top: '4%',
bottom: '4%',
containLabel: true
},
textStyle: {
rich: {
name: {
color: '#fff',
fontSize: fitChartSize(12)
},
value: {
color: '#00D5F6',
fontSize: fitChartSize(12)
}
}
}
},
series: [
{
type: 'pie',
center: ['50%', '40%'],
radius: ['45%', '60%'],
itemStyle: {
borderWidth: fitChartSize(4),
borderColor: '#093672'
legend: {
orient: 'horizontal',
x: 'center',
bottom: '-3%',
itemHeight: fitChartSize(12),
itemWidth: fitChartSize(12),
itemGap: fitChartSize(6),
formatter: (name) => {
let obj = props.list.find((item) => item.name == name)
return '{name|' + name + '} {value|' + obj?.count + '}{value|%}'
},
label: {
show: true,
position: 'center',
fontWeight: 'bold',
formatter: function (o) {
return `{label|拥堵次数}` + '\n' + `{value|${calcCount()}}`
},
textStyle: {
rich: {
label: {
color: '#7894A8',
padding: [0, 0, 5, 0],
name: {
color: '#fff',
fontSize: fitChartSize(12)
},
value: {
color: '#fff',
fontSize: fitChartSize(18),
fontWeight: 'bold'
color: '#00D5F6',
fontSize: fitChartSize(12)
}
}
},
labelLine: {
show: false
},
data: setSeriesData()
}
]
})
}
},
series: [
{
type: 'pie',
center: ['50%', '40%'],
radius: ['45%', '60%'],
itemStyle: {
borderWidth: fitChartSize(4),
borderColor: '#093672'
},
label: {
show: true,
position: 'center',
fontWeight: 'bold',
formatter: function (o) {
return `{label|拥堵次数}` + '\n' + `{value|${calcCount()}}`
},
rich: {
label: {
color: '#7894A8',
padding: [0, 0, 5, 0],
fontSize: fitChartSize(12)
},
value: {
color: '#fff',
fontSize: fitChartSize(16),
fontWeight: 'bold'
}
}
},
labelLine: {
show: false
},
data: getSeriesData()
}
]
}
} else {
params.series[0].data = getSeriesData()
}
setOption(params)
}
onMounted(() => {

View File

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

View File

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

View File

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

View File

@@ -1,3 +1,4 @@
<!-- 客源地分析TOP5 -->
<template>
<div class="top" :id="id" />
</template>
@@ -5,11 +6,11 @@
<script setup>
import { fitChartSize } from '@/utils/dataUtil'
import { useEchart } from '@/hooks/echart'
import { useHomeStore } from '@/stores/home'
const homeStore = useHomeStore()
const { id, setOption } = useEchart()
const homeData = inject('homeData')
const init = () => {
setOption({
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: [
@@ -91,7 +92,7 @@
return params.data.name ?? '其他'
}
},
data: homeData.value?.userPortrait?.provinceRate.map((item) => {
data: homeStore?.userPortraitData?.provinceRate.map((item) => {
return {
name: item.name,
value: Number(item.value),
@@ -107,9 +108,12 @@
}
watch(
() => homeData.value?.userPortrait?.provinceRate,
() => {
init()
() => homeStore?.userPortraitData?.provinceRate,
(val) => {
if (val.length > 0) init()
},
{
immediate: true
}
)
</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,189 +1,194 @@
<template>
<div class="vacancy" id="vacancy" />
<!-- 景区停车场空位 -->
<div class="vacancy" :id="id" />
</template>
<script setup>
import { fitChartSize } from '@/utils/dataUtil'
import * as echarts from 'echarts'
import { useEchart } from '@/hooks/echart'
let topChart = null
let result = [
{ name: '三峡之颠', value: 86 },
{ name: '白帝城', value: 83 },
{ name: '瞿塘峡', value: 73 },
{ name: '天坑地缝', value: 61 }
]
let option = {
backgroundColor: 'transparent',
tooltip: {
show: false
const { id, setOption } = useEchart()
let props = defineProps({
list: {
type: Array,
default: () => []
}
})
watch(
() => props.list,
(val) => {
if (val.length > 0) init()
},
legend: {
show: false
},
grid: {
left: '4%',
right: '4%',
top: '20%',
bottom: '-4%',
containLabel: true
},
xAxis: [
{
splitLine: {
show: false
},
type: 'value',
show: false
}
],
yAxis: [
{
splitLine: {
show: false
},
axisLine: {
show: false
},
type: 'category',
axisTick: {
show: false
},
data: result.map((item) => item.name),
axisLabel: {
show: false
}
},
{
type: 'category',
inverse: true,
axisTick: 'none',
axisLine: 'none',
show: true,
axisLabel: {
textStyle: {
color: '#fff',
fontSize: fitChartSize(12)
},
verticalAlign: 'bottom',
padding: [0, 0, fitChartSize(6), 0],
inside: true,
formatter: function (value) {
return `{label|余} {value|${value}}`
},
rich: {
label: {
align: 'center',
color: '#fff',
fontSize: fitChartSize(14),
fontFamily: 'Source Han Sans CN'
},
value: {
align: 'center',
color: '#fff',
fontSize: fitChartSize(14),
fontFamily: 'Source Han Sans CN'
}
}
},
data: result.map((item) => item.value)
}
],
series: [
{
name: '',
type: 'bar',
barWidth: fitChartSize(4),
MaxSize: 0,
showBackground: true,
barBorderRadius: [30, 0, 0, 30],
backgroundStyle: {
color: 'rgba(0, 150, 255, 0.15)'
},
label: {
show: true,
offset: [10, -13],
color: '#D3E5FF',
fontWeight: 500,
position: 'left',
align: 'left',
fontSize: fitChartSize(14),
fontFamily: 'Source Han Sans CN',
formatter: function (params) {
return params.data.name
}
},
data: result.map((item, index) => {
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)'
}
]
{ 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'
}
}
]
}
})
},
{
name: '外圆',
type: 'scatter',
emphasis: {
scale: false
},
showSymbol: true,
symbol: 'circle',
symbolSize: fitChartSize(10),
z: 2,
data: result.map((item, index) => {
return {
name: item.name,
value: item.value,
itemStyle: {
color: '#fff',
opacity: 1
}
}
}),
animationDelay: 500
}
}
]
})
}
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 = () => {
topChart = echarts.init(document.getElementById('vacancy'))
topChart.setOption(option)
}
const resize = () => {
if (topChart) {
topChart.dispose()
topChart = null
init()
if (!params) {
params = {
backgroundColor: 'transparent',
tooltip: {
show: false
},
legend: {
show: false
},
grid: {
left: '4%',
right: '4%',
top: '16%',
bottom: '-10%',
containLabel: true
},
xAxis: [
{
splitLine: {
show: false
},
type: 'value',
show: false
}
],
yAxis: [
{
splitLine: {
show: false
},
axisLine: {
show: false
},
type: 'category',
axisTick: {
show: false
},
data: [],
axisLabel: {
show: false
}
},
{
type: 'category',
inverse: true,
axisTick: 'none',
axisLine: 'none',
show: true,
axisLabel: {
textStyle: {
color: '#fff',
fontSize: fitChartSize(12)
},
verticalAlign: 'bottom',
padding: [0, 0, 6, 0],
inside: true,
formatter: function (value) {
return `{value|余}{value|${value}}`
},
rich: {
value: {
align: 'center',
color: '#fff',
fontWeight: 600,
fontSize: fitChartSize(14)
}
}
},
data: getYAxisData()
}
],
series: [
{
name: '',
type: 'bar',
barWidth: fitChartSize(8),
showBackground: true,
barBorderRadius: [0, 0, 0, 0],
backgroundStyle: {
color: 'rgba(0, 150, 255, 0.15)'
},
label: {
show: true,
offset: [10, -10],
color: '#fff',
fontWeight: 500,
position: 'left',
align: 'left',
fontSize: fitChartSize(14),
formatter: function (params) {
return params.data.name
}
},
data: getSeriesData()
},
{
name: '外圆',
type: 'scatter',
emphasis: {
scale: false
},
showSymbol: true,
symbol: 'circle',
symbolSize: fitChartSize(10),
z: 2,
animationDelay: 500,
data: getScatterData()
}
]
}
} else {
params.yAxis[1].data = getYAxisData()
params.series[0].data = getSeriesData()
params.series[1].data = getScatterData()
}
setOption(params)
}
onMounted(() => {
init()
window.addEventListener('resize', resize)
})
</script>
<style scoped lang="scss">
.vacancy {
width: 100%;
height: vh(170);
width: vw(250);
height: vh(160);
}
</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 { useWebSocket } from '@/hooks/socket'
const { data, isConnected, sendMessage } = useWebSocket('ws://36.138.38.16:81/ws/third-party')
provide('homeData', data)
const { isConnected, sendMessage } = useWebSocket('ws://36.138.38.16:81/ws/third-party')
watch(
() => isConnected.value,
(val) => {
if (val) {
console.log('--------------------------------------------')
sendMessage(
JSON.stringify({
action: 'start',