feat:完善首页功能
This commit is contained in:
19
package-lock.json
generated
19
package-lock.json
generated
@@ -18,7 +18,8 @@
|
|||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-countup-v3": "^1.4.2",
|
"vue-countup-v3": "^1.4.2",
|
||||||
"vue-echarts": "^7.0.3",
|
"vue-echarts": "^7.0.3",
|
||||||
"vue-router": "^4.4.5"
|
"vue-router": "^4.4.5",
|
||||||
|
"vue3-seamless-scroll": "^2.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^5.2.1",
|
"@vitejs/plugin-vue": "^5.2.1",
|
||||||
@@ -3368,6 +3369,14 @@
|
|||||||
"url": "https://opencollective.com/webpack"
|
"url": "https://opencollective.com/webpack"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/throttle-debounce": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmmirror.com/throttle-debounce/-/throttle-debounce-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-2iQTSgkkc1Zyk0MeVrt/3BvuOXYPl/R8Z0U2xxo9rjwNciaHDG3R+Lm6dh4EeUci49DanvBnuqI6jshoQQRGEg==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.22"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tinyglobby": {
|
"node_modules/tinyglobby": {
|
||||||
"version": "0.2.10",
|
"version": "0.2.10",
|
||||||
"resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.10.tgz",
|
"resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.10.tgz",
|
||||||
@@ -3887,6 +3896,14 @@
|
|||||||
"vue": "^3.2.0"
|
"vue": "^3.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vue3-seamless-scroll": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmmirror.com/vue3-seamless-scroll/-/vue3-seamless-scroll-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-mI3BaDU3pjcPUhVSw3/xNKdfPBDABTi/OdZaZqKysx4cSdNfGRbVvGNDzzptBbJ5S7imv5T55l6x/SqgnxKreg==",
|
||||||
|
"dependencies": {
|
||||||
|
"throttle-debounce": "5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/watchpack": {
|
"node_modules/watchpack": {
|
||||||
"version": "2.4.2",
|
"version": "2.4.2",
|
||||||
"resolved": "https://registry.npmmirror.com/watchpack/-/watchpack-2.4.2.tgz",
|
"resolved": "https://registry.npmmirror.com/watchpack/-/watchpack-2.4.2.tgz",
|
||||||
|
|||||||
@@ -19,7 +19,8 @@
|
|||||||
"vue": "^3.5.13",
|
"vue": "^3.5.13",
|
||||||
"vue-countup-v3": "^1.4.2",
|
"vue-countup-v3": "^1.4.2",
|
||||||
"vue-echarts": "^7.0.3",
|
"vue-echarts": "^7.0.3",
|
||||||
"vue-router": "^4.4.5"
|
"vue-router": "^4.4.5",
|
||||||
|
"vue3-seamless-scroll": "^2.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@vitejs/plugin-vue": "^5.2.1",
|
"@vitejs/plugin-vue": "^5.2.1",
|
||||||
|
|||||||
BIN
src/assets/images/legend-item-blue.png
Normal file
BIN
src/assets/images/legend-item-blue.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.7 KiB |
BIN
src/assets/images/legend-item-green.png
Normal file
BIN
src/assets/images/legend-item-green.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 9.3 KiB |
BIN
src/assets/images/legend-item-orange.png
Normal file
BIN
src/assets/images/legend-item-orange.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
@@ -8,6 +8,7 @@
|
|||||||
:style="{ backgroundImage: `url(${index == 0 ? primary : error})` }"
|
:style="{ backgroundImage: `url(${index == 0 ? primary : error})` }"
|
||||||
v-for="(item, index) in list"
|
v-for="(item, index) in list"
|
||||||
:key="index"
|
:key="index"
|
||||||
|
@click.shop="handleItem(item)"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<p :class="[index % 2 === 0 ? 'item-title--primary' : 'item-title--error']">
|
<p :class="[index % 2 === 0 ? 'item-title--primary' : 'item-title--error']">
|
||||||
@@ -15,11 +16,11 @@
|
|||||||
</p>
|
</p>
|
||||||
<video
|
<video
|
||||||
class="item-img"
|
class="item-img"
|
||||||
:ref="(el) => getRefs(el, item, index)"
|
:id="'video' + index"
|
||||||
muted
|
muted
|
||||||
autoplay
|
autoplay
|
||||||
controls
|
:controls="false"
|
||||||
style="object-fit: fill"
|
style="object-fit: cover"
|
||||||
>
|
>
|
||||||
<source src="" type="application/x-mpegURL" />
|
<source src="" type="application/x-mpegURL" />
|
||||||
</video>
|
</video>
|
||||||
@@ -27,6 +28,7 @@
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<VideoDialog v-model="videoShow" :src="src" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -36,27 +38,39 @@
|
|||||||
import Hls from 'hls.js'
|
import Hls from 'hls.js'
|
||||||
|
|
||||||
let list = ref([])
|
let list = ref([])
|
||||||
|
let src = ref('')
|
||||||
|
let videoShow = ref(false)
|
||||||
|
|
||||||
const getRefs = async (el, item) => {
|
const handleItem = (item) => {
|
||||||
if (el) {
|
src.value = item.hlsUrl
|
||||||
let res = await postRefreshApi({
|
videoShow.value = true
|
||||||
businessVideoDisplayPosition: item.businessVideoDisplayPosition,
|
|
||||||
cameraIndexCode: item.cameraIndexCode
|
|
||||||
})
|
|
||||||
let hlsUrl = res.data.hlsUrl.replace('http://172.22.15.170:8050', 'http://36.138.38.16:6150')
|
|
||||||
const hls = new Hls()
|
|
||||||
hls.loadSource(hlsUrl)
|
|
||||||
hls.attachMedia(el)
|
|
||||||
hls.on(Hls.Events.MANIFEST_PARSED, () => {
|
|
||||||
el.play()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const getVideoList = async () => {
|
const getVideoList = async () => {
|
||||||
let res = await getVideoListApi({
|
let res = await getVideoListApi({
|
||||||
businessVideoDisplayPosition: ''
|
businessVideoDisplayPosition: ''
|
||||||
})
|
})
|
||||||
list.value = res.data
|
list.value = res.data
|
||||||
|
nextTick(() => {
|
||||||
|
list.value.forEach(async (item, index) => {
|
||||||
|
var video = document.getElementById(`video${index}`)
|
||||||
|
let res1 = await postRefreshApi({
|
||||||
|
businessVideoDisplayPosition: item.businessVideoDisplayPosition,
|
||||||
|
cameraIndexCode: item.cameraIndexCode
|
||||||
|
})
|
||||||
|
let hlsUrl = res1.data.hlsUrl.replace(
|
||||||
|
'http://172.22.15.170:8050',
|
||||||
|
'http://36.138.38.16:6150'
|
||||||
|
)
|
||||||
|
item.hlsUrl = hlsUrl
|
||||||
|
const hls = new Hls()
|
||||||
|
hls.loadSource(hlsUrl)
|
||||||
|
hls.attachMedia(video)
|
||||||
|
hls.on(Hls.Events.MANIFEST_PARSED, () => {
|
||||||
|
video.play()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
getVideoList()
|
getVideoList()
|
||||||
@@ -128,6 +142,7 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
z-index: 999;
|
||||||
}
|
}
|
||||||
&-title--error {
|
&-title--error {
|
||||||
@extend .item-title;
|
@extend .item-title;
|
||||||
|
|||||||
73
src/components/VideoDialog/index.vue
Normal file
73
src/components/VideoDialog/index.vue
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
<template>
|
||||||
|
<div class="dialog">
|
||||||
|
<el-dialog v-model="modelValue" align-center :modal="false" :show-close="false">
|
||||||
|
<video class="video" ref="videoRef" muted autoplay controls style="object-fit: cover">
|
||||||
|
<source src="" type="application/x-mpegURL" />
|
||||||
|
</video>
|
||||||
|
<img class="close" src="@/assets/images/close.png" @click="modelValue = false" />
|
||||||
|
</el-dialog>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import Hls from 'hls.js'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
src: {
|
||||||
|
type: String,
|
||||||
|
default: ''
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
let modelValue = defineModel()
|
||||||
|
let videoRef = ref()
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => modelValue.value,
|
||||||
|
(val) => {
|
||||||
|
if (val) {
|
||||||
|
nextTick(() => {
|
||||||
|
init()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const init = () => {
|
||||||
|
const hls = new Hls()
|
||||||
|
hls.loadSource(props.src)
|
||||||
|
hls.attachMedia(videoRef.value)
|
||||||
|
hls.on(Hls.Events.MANIFEST_PARSED, () => {
|
||||||
|
videoRef.value.play()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.dialog {
|
||||||
|
z-index: 9999;
|
||||||
|
:deep(.el-dialog) {
|
||||||
|
width: vw(2540);
|
||||||
|
height: vh(900);
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
:deep(.el-dialog__header) {
|
||||||
|
padding-bottom: 0 !important;
|
||||||
|
}
|
||||||
|
.video {
|
||||||
|
width: vw(2540);
|
||||||
|
height: vh(900);
|
||||||
|
}
|
||||||
|
.close {
|
||||||
|
cursor: pointer;
|
||||||
|
position: absolute;
|
||||||
|
right: vw(20);
|
||||||
|
top: vw(20);
|
||||||
|
width: vw(60);
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -7,6 +7,9 @@ export function useMap() {
|
|||||||
map.value = new BMapGL.Map(id)
|
map.value = new BMapGL.Map(id)
|
||||||
map.value.centerAndZoom(new BMapGL.Point(lat, lng), scale)
|
map.value.centerAndZoom(new BMapGL.Point(lat, lng), scale)
|
||||||
map.value.enableScrollWheelZoom(true)
|
map.value.enableScrollWheelZoom(true)
|
||||||
|
map.value.setMapStyleV2({
|
||||||
|
styleId: '23c9fb8e1c604995f97f0f1cebd7036f'
|
||||||
|
})
|
||||||
if (satellite) map.value.setMapType(BMAP_SATELLITE_MAP)
|
if (satellite) map.value.setMapType(BMAP_SATELLITE_MAP)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import router from './router'
|
|||||||
import '@/styles/reset.css'
|
import '@/styles/reset.css'
|
||||||
import '@/styles/common.scss'
|
import '@/styles/common.scss'
|
||||||
import '@/assets/fonts/index.css'
|
import '@/assets/fonts/index.css'
|
||||||
|
|
||||||
const app = createApp(App)
|
const app = createApp(App)
|
||||||
|
|
||||||
app.use(createPinia())
|
app.use(createPinia())
|
||||||
|
|||||||
@@ -21,6 +21,7 @@
|
|||||||
const init = () => {
|
const init = () => {
|
||||||
if (!params) {
|
if (!params) {
|
||||||
params = {
|
params = {
|
||||||
|
color: ['#00B1FF', '#00FFFF', '#FF3737', '#DD5627', '#D3F0FE'],
|
||||||
legend: {
|
legend: {
|
||||||
orient: 'vertical',
|
orient: 'vertical',
|
||||||
left: '54%',
|
left: '54%',
|
||||||
|
|||||||
@@ -186,7 +186,7 @@
|
|||||||
<div class="box-1">
|
<div class="box-1">
|
||||||
<Title3 title="购票来源" />
|
<Title3 title="购票来源" />
|
||||||
<div class="count">游客总数:<countup :end-val="channelTotal" /></div>
|
<div class="count">游客总数:<countup :end-val="channelTotal" /></div>
|
||||||
<ticket />
|
<ticket :list="channelData" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -210,6 +210,7 @@
|
|||||||
{ value: 0, name: '低感景区总数' }
|
{ value: 0, name: '低感景区总数' }
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
// 景区购票数
|
||||||
const admission = computed(() => {
|
const admission = computed(() => {
|
||||||
if (homeData.value) return homeData.value?.admission
|
if (homeData.value) return homeData.value?.admission
|
||||||
return [
|
return [
|
||||||
@@ -225,6 +226,11 @@
|
|||||||
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 homeData.value?.userPortrait?.channel.reduce(
|
||||||
(total, current) => Number(current.count) + total,
|
(total, current) => Number(current.count) + total,
|
||||||
|
|||||||
@@ -5,15 +5,15 @@
|
|||||||
<div class="left">
|
<div class="left">
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="label">今年总游客数</div>
|
<div class="label">今年总游客数</div>
|
||||||
<ScrollNumber :count="count" prefix="1" />
|
<scroll-number :count="visitorInfo.total_count_this_year" prefix="1" />
|
||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="label">全县景区总游客人数</div>
|
<div class="label">全县景区总游客人数</div>
|
||||||
<ScrollNumber :count="count" prefix="2" />
|
<scroll-number :count="visitorInfo.total_count_today" prefix="2" />
|
||||||
</div>
|
</div>
|
||||||
<div class="item">
|
<div class="item">
|
||||||
<div class="label">总在园人数</div>
|
<div class="label">总在园人数</div>
|
||||||
<ScrollNumber :count="count" prefix="3" />
|
<scroll-number :count="visitorInfo.total_count_today_within_three_hours" prefix="3" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
@@ -149,7 +149,15 @@
|
|||||||
|
|
||||||
const homeData = inject('homeData')
|
const homeData = inject('homeData')
|
||||||
|
|
||||||
let count = ref(69459)
|
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([
|
||||||
@@ -180,7 +188,6 @@
|
|||||||
let res1 = await getBaiduMapCrowdedApi({
|
let res1 = await getBaiduMapCrowdedApi({
|
||||||
nodeId: res.data[0].nodeid
|
nodeId: res.data[0].nodeid
|
||||||
})
|
})
|
||||||
console.log(res1, 'res1')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
@@ -200,7 +207,7 @@
|
|||||||
arr.push(new BMapGL.Point(j[0], j[1]))
|
arr.push(new BMapGL.Point(j[0], j[1]))
|
||||||
})
|
})
|
||||||
var polyline = new BMapGL.Polyline(arr, {
|
var polyline = new BMapGL.Polyline(arr, {
|
||||||
strokeColor: '#1EBA29',
|
strokeColor: '#38DBFF',
|
||||||
strokeWeight: 4,
|
strokeWeight: 4,
|
||||||
strokeOpacity: 0.8
|
strokeOpacity: 0.8
|
||||||
})
|
})
|
||||||
@@ -280,7 +287,7 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
top: vw(20);
|
top: vw(20);
|
||||||
left: vw(20);
|
left: vw(20);
|
||||||
z-index: 99999;
|
z-index: 99;
|
||||||
.alarm-item {
|
.alarm-item {
|
||||||
width: vw(110);
|
width: vw(110);
|
||||||
height: vh(40);
|
height: vh(40);
|
||||||
@@ -303,7 +310,7 @@
|
|||||||
position: absolute;
|
position: absolute;
|
||||||
bottom: vw(20);
|
bottom: vw(20);
|
||||||
left: vw(20);
|
left: vw(20);
|
||||||
z-index: 99999;
|
z-index: 999;
|
||||||
}
|
}
|
||||||
.spot-list {
|
.spot-list {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -2,11 +2,32 @@
|
|||||||
<div class="box-4">
|
<div class="box-4">
|
||||||
<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 v-for="item in list" class="cell">
|
<div class="cell">
|
||||||
<img class="icon" :src="item.icon" alt="" width="64" height="64" />
|
<img class="icon" :src="icon1" alt="" />
|
||||||
<div>
|
<div>
|
||||||
<countup :end-val="item.value" />
|
<countup :end-val="countItems.now_yongdu_sum" />
|
||||||
<div class="label">{{ item.label }}</div>
|
<div class="label">路段总数</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell">
|
||||||
|
<img class="icon" :src="icon2" alt="" />
|
||||||
|
<div>
|
||||||
|
<countup :end-val="countItems.yongdu_luduan_count" />
|
||||||
|
<div class="label">当前拥堵路段</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell">
|
||||||
|
<img class="icon" :src="icon3" alt="" />
|
||||||
|
<div>
|
||||||
|
<countup :end-val="countItems.yongdu_sum" />
|
||||||
|
<div class="label">总拥堵次数</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="cell">
|
||||||
|
<img class="icon" :src="icon4" alt="" />
|
||||||
|
<div>
|
||||||
|
<countup :end-val="countItems.max_congestion_duration" />
|
||||||
|
<div class="label">最大拥堵时长 </div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -14,77 +35,25 @@
|
|||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="pt-10">
|
<div class="pt-10">
|
||||||
<Title3 title="拥堵路段总数" />
|
<Title3 title="拥堵路段总数" />
|
||||||
<div class="">
|
|
||||||
<Line
|
<Line
|
||||||
:width="250"
|
:width="250"
|
||||||
:height="150"
|
:height="150"
|
||||||
:config="{ legend: false }"
|
:config="{ legend: false }"
|
||||||
:data="[
|
:data="congestionData"
|
||||||
{
|
:xAxisData="congestionXAxisData"
|
||||||
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 class="box">
|
|
||||||
<div class="pt-10">
|
|
||||||
<Title3 title="拥堵路段总数" />
|
|
||||||
<Line
|
|
||||||
: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'
|
|
||||||
]"
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box">
|
<div class="box">
|
||||||
<div class="pt-10">
|
<div class="pt-10">
|
||||||
<Title3 title="拥堵路段总数" />
|
<Title3 title="拥堵次数占比" />
|
||||||
<jam :width="250" :height="200" />
|
<jam-count :list="countRate" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="box">
|
||||||
|
<div class="pt-10">
|
||||||
|
<Title3 title="拥堵时长" />
|
||||||
|
<jam-duration :list="timeRate" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -127,11 +96,11 @@
|
|||||||
<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">
|
||||||
<Title3 title="拥堵路段总数" />
|
<Title3 title="停车场车流量" />
|
||||||
<div class="pt-20">
|
<div class="pt-10">
|
||||||
<Line
|
<Line
|
||||||
:width="250"
|
:width="250"
|
||||||
:height="120"
|
:height="150"
|
||||||
:config="{ legend: false }"
|
:config="{ legend: false }"
|
||||||
:data="[
|
:data="[
|
||||||
{
|
{
|
||||||
@@ -163,7 +132,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="box-1">
|
<div class="box-1">
|
||||||
<div class="pt-10">
|
<div class="pt-10">
|
||||||
<Title3 title="拥堵路段总数" />
|
<Title3 title="车源地" />
|
||||||
<traffic />
|
<traffic />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -199,6 +168,14 @@
|
|||||||
<div>空余</div>
|
<div>空余</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
<vue3-seamless-scroll
|
||||||
|
:list="homeData?.carShipData?.car.info"
|
||||||
|
:limitScrollNum="3"
|
||||||
|
:hover="true"
|
||||||
|
:step="0.2"
|
||||||
|
:wheel="true"
|
||||||
|
:isWatch="true"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
class="cell"
|
class="cell"
|
||||||
v-for="(item, index) in homeData?.carShipData?.car.info"
|
v-for="(item, index) in homeData?.carShipData?.car.info"
|
||||||
@@ -208,6 +185,7 @@
|
|||||||
<div>{{ item.started_count }}<span class="unit-1">辆</span></div>
|
<div>{{ item.started_count }}<span class="unit-1">辆</span></div>
|
||||||
<div>{{ item.not_started_count }}<span class="unit-1">辆</span></div>
|
<div>{{ item.not_started_count }}<span class="unit-1">辆</span></div>
|
||||||
</div>
|
</div>
|
||||||
|
</vue3-seamless-scroll>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -226,15 +204,24 @@
|
|||||||
<div>空余</div>
|
<div>空余</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
<vue3-seamless-scroll
|
||||||
|
:list="homeData?.carShipData?.car.info"
|
||||||
|
:limitScrollNum="3"
|
||||||
|
:hover="true"
|
||||||
|
:step="0.2"
|
||||||
|
:wheel="true"
|
||||||
|
:isWatch="true"
|
||||||
|
>
|
||||||
<div
|
<div
|
||||||
class="cell"
|
class="cell"
|
||||||
v-for="(item, index) in homeData?.carShipData.ship.info"
|
v-for="(item, index) in homeData?.carShipData?.ship.info"
|
||||||
:key="index"
|
:key="index"
|
||||||
>
|
>
|
||||||
<div>{{ item.name }}</div>
|
<div>{{ item.name }}</div>
|
||||||
<div>{{ item.started_count }}<span class="unit-1">辆</span></div>
|
<div>{{ item.started_count }}<span class="unit-1">辆</span></div>
|
||||||
<div>{{ item.not_started_count }}<span class="unit-1">辆</span></div>
|
<div>{{ item.not_started_count }}<span class="unit-1">辆</span></div>
|
||||||
</div>
|
</div>
|
||||||
|
</vue3-seamless-scroll>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -279,7 +266,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import jam from './jam.vue'
|
import jamDuration from './jam-duration.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 traffic from './traffic.vue'
|
||||||
@@ -289,30 +277,45 @@
|
|||||||
import icon3 from '@/assets/images/icon-3.png'
|
import icon3 from '@/assets/images/icon-3.png'
|
||||||
import icon4 from '@/assets/images/icon-4.png'
|
import icon4 from '@/assets/images/icon-4.png'
|
||||||
|
|
||||||
|
import { Vue3SeamlessScroll } from 'vue3-seamless-scroll'
|
||||||
|
|
||||||
const homeData = inject('homeData')
|
const homeData = inject('homeData')
|
||||||
|
|
||||||
let list = ref([
|
const congestionData = computed(() => {
|
||||||
{
|
if (homeData.value) {
|
||||||
label: '路段总数',
|
return [{ data: homeData.value?.trafficInformation?.congestion.map((item) => item.value) }]
|
||||||
value: '1234',
|
|
||||||
icon: icon1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '当前拥堵路段',
|
|
||||||
value: '1234',
|
|
||||||
icon: icon2
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '总拥堵次数',
|
|
||||||
value: '1234',
|
|
||||||
icon: icon3
|
|
||||||
},
|
|
||||||
{
|
|
||||||
label: '最大拥堵时长',
|
|
||||||
value: '1234',
|
|
||||||
icon: icon4
|
|
||||||
}
|
}
|
||||||
])
|
return []
|
||||||
|
})
|
||||||
|
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 []
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
@@ -338,6 +341,7 @@
|
|||||||
color: #02f9fa;
|
color: #02f9fa;
|
||||||
font-size: vw(24);
|
font-size: vw(24);
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
text-shadow: 0 0 9px #0096ff;
|
||||||
}
|
}
|
||||||
.label {
|
.label {
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
@@ -466,21 +470,21 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.content {
|
.content {
|
||||||
overflow-y: auto;
|
overflow-y: hidden;
|
||||||
height: vh(82);
|
height: vh(82);
|
||||||
/* 滚动条整体样式 */
|
// /* 滚动条整体样式 */
|
||||||
&::-webkit-scrollbar {
|
// &::-webkit-scrollbar {
|
||||||
width: vw(4); /* 滚动条的宽度 */
|
// width: vw(4); /* 滚动条的宽度 */
|
||||||
}
|
// }
|
||||||
/* 滚动条轨道 */
|
// /* 滚动条轨道 */
|
||||||
&::-webkit-scrollbar-track {
|
// &::-webkit-scrollbar-track {
|
||||||
background: 'transparent'; /* 轨道的背景色 */
|
// background: 'transparent'; /* 轨道的背景色 */
|
||||||
}
|
// }
|
||||||
/* 滚动条滑块 */
|
// /* 滚动条滑块 */
|
||||||
&::-webkit-scrollbar-thumb {
|
// &::-webkit-scrollbar-thumb {
|
||||||
background: rgba(0, 150, 255, 0.63); /* 滑块的背景色 */
|
// background: rgba(0, 150, 255, 0.63); /* 滑块的背景色 */
|
||||||
border-radius: 5px; /* 滑块的圆角 */
|
// border-radius: 5px; /* 滑块的圆角 */
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
.cell {
|
.cell {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
125
src/views/home/components/jam-count.vue
Normal file
125
src/views/home/components/jam-count.vue
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
<template>
|
||||||
|
<div class="jam-count" :id="id" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { fitChartSize } from '@/utils/dataUtil'
|
||||||
|
import { useEchart } from '@/hooks/echart'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
list: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const { id, setOption } = useEchart()
|
||||||
|
|
||||||
|
var colorList = ['#FDC40A', '#FF5232', '#50F0A6']
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.list,
|
||||||
|
(val) => {
|
||||||
|
if (val.length > 0) init()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
immediate: true
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const setSeriesData = () => {
|
||||||
|
return props.list.map((item) => {
|
||||||
|
return {
|
||||||
|
name: item.name,
|
||||||
|
value: parseFloat(item.count)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const calcCount = () => {
|
||||||
|
return props.list.reduce((total, currentValue) => {
|
||||||
|
return total + parseFloat(currentValue.count)
|
||||||
|
}, 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|%}'
|
||||||
|
},
|
||||||
|
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'
|
||||||
|
},
|
||||||
|
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(18),
|
||||||
|
fontWeight: 'bold'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
labelLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
data: setSeriesData()
|
||||||
|
}
|
||||||
|
]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
init()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.jam-count {
|
||||||
|
width: vw(250);
|
||||||
|
height: vh(150);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
195
src/views/home/components/jam-duration.vue
Normal file
195
src/views/home/components/jam-duration.vue
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
<template>
|
||||||
|
<!-- 拥堵时长 -->
|
||||||
|
<div class="jam" :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 setSeriesData = () => {
|
||||||
|
return props.list.map((item) => {
|
||||||
|
return {
|
||||||
|
name: item.name,
|
||||||
|
value: item.count,
|
||||||
|
itemStyle: {
|
||||||
|
color: {
|
||||||
|
type: 'linear',
|
||||||
|
x: 0,
|
||||||
|
y: 0,
|
||||||
|
x2: 1,
|
||||||
|
y2: 1,
|
||||||
|
colorStops: [
|
||||||
|
{
|
||||||
|
offset: 0,
|
||||||
|
color: 'rgba(255, 112, 33, 0)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
offset: 1,
|
||||||
|
color: '#FF7021'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const setScatterData = () => {
|
||||||
|
return props.list.map((item) => {
|
||||||
|
return {
|
||||||
|
name: item.name,
|
||||||
|
value: item.count,
|
||||||
|
itemStyle: {
|
||||||
|
color: '#fff',
|
||||||
|
opacity: 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const setYAxisData = () => {
|
||||||
|
return props.list.map((item) => item.count)
|
||||||
|
}
|
||||||
|
const 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: setYAxisData()
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '',
|
||||||
|
type: 'bar',
|
||||||
|
barWidth: fitChartSize(4),
|
||||||
|
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: setSeriesData()
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '外圆',
|
||||||
|
type: 'scatter',
|
||||||
|
emphasis: {
|
||||||
|
scale: false
|
||||||
|
},
|
||||||
|
showSymbol: true,
|
||||||
|
symbol: 'circle',
|
||||||
|
symbolSize: fitChartSize(10),
|
||||||
|
z: 2,
|
||||||
|
data: setScatterData(),
|
||||||
|
animationDelay: 500
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
params.series[0].data = setSeriesData()
|
||||||
|
params.series[1].data = setScatterData()
|
||||||
|
}
|
||||||
|
setOption(params)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.jam {
|
||||||
|
width: vw(250);
|
||||||
|
height: vh(160);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -1,190 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="top" id="jam" />
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup>
|
|
||||||
import { fitChartSize } from '@/utils/dataUtil'
|
|
||||||
import * as echarts from 'echarts'
|
|
||||||
|
|
||||||
let topChart = null
|
|
||||||
let result = [
|
|
||||||
{ name: '路段1', value: 86 },
|
|
||||||
{ name: '路段1', value: 83 },
|
|
||||||
{ name: '路段1', value: 73 },
|
|
||||||
{ name: '路段1', value: 61 },
|
|
||||||
{ name: '路段1', value: 61 }
|
|
||||||
]
|
|
||||||
let option = {
|
|
||||||
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: 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, 6, 0],
|
|
||||||
inside: true,
|
|
||||||
formatter: function (value) {
|
|
||||||
return `{value|${value}}`
|
|
||||||
},
|
|
||||||
rich: {
|
|
||||||
name: {
|
|
||||||
align: 'center',
|
|
||||||
color: '#D3E5FF',
|
|
||||||
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, -10],
|
|
||||||
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(255, 112, 33, 0)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
offset: 1,
|
|
||||||
color: 'rgba(255, 112, 33, 1)'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
},
|
|
||||||
{
|
|
||||||
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 init = () => {
|
|
||||||
topChart = echarts.init(document.getElementById('jam'))
|
|
||||||
topChart.setOption(option)
|
|
||||||
}
|
|
||||||
const resize = () => {
|
|
||||||
if (topChart) {
|
|
||||||
topChart.dispose()
|
|
||||||
topChart = null
|
|
||||||
init()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
onMounted(() => {
|
|
||||||
init()
|
|
||||||
window.addEventListener('resize', resize)
|
|
||||||
})
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped lang="scss">
|
|
||||||
.top {
|
|
||||||
width: 100%;
|
|
||||||
height: vh(160);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,18 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="ticket" :id="id" />
|
<div class="ticket" :id="id" />
|
||||||
<!-- <div class="legend">
|
|
||||||
<ul class="legend__wrapper">
|
|
||||||
<li
|
|
||||||
class="legend-item"
|
|
||||||
v-for="(item, index) in homeData?.userPortrait?.channel"
|
|
||||||
:key="index"
|
|
||||||
>
|
|
||||||
<p class="legend-item-label">{{ item.name }}</p>
|
|
||||||
<p class="legend-item-value">{{ item.value }}%</p>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div> -->
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -20,6 +8,13 @@
|
|||||||
import { fitChartSize } from '@/utils/dataUtil'
|
import { fitChartSize } from '@/utils/dataUtil'
|
||||||
import { useEchart } from '@/hooks/echart'
|
import { useEchart } from '@/hooks/echart'
|
||||||
|
|
||||||
|
let props = defineProps({
|
||||||
|
list: {
|
||||||
|
type: Array,
|
||||||
|
default: () => []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const { id, setOption } = useEchart()
|
const { id, setOption } = useEchart()
|
||||||
|
|
||||||
const homeData = inject('homeData')
|
const homeData = inject('homeData')
|
||||||
@@ -29,9 +24,9 @@
|
|||||||
let params = null
|
let params = null
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => homeData.value?.userPortrait?.channel,
|
() => props.list,
|
||||||
(val) => {
|
(val) => {
|
||||||
if (val) init()
|
if (val.length > 0) init()
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
immediate: true
|
immediate: true
|
||||||
@@ -39,11 +34,12 @@
|
|||||||
)
|
)
|
||||||
|
|
||||||
const setSeries = () => {
|
const setSeries = () => {
|
||||||
return homeData.value?.userPortrait?.channel.map((item, index) => {
|
return props.list.map((item, index) => {
|
||||||
return {
|
return {
|
||||||
name: item.name,
|
name: item.name,
|
||||||
clockwise: false,
|
|
||||||
type: 'pie',
|
type: 'pie',
|
||||||
|
clockwise: false,
|
||||||
|
silent: true,
|
||||||
radius: [`${x * (index + 1)}%`, `${y + index * 15}%`],
|
radius: [`${x * (index + 1)}%`, `${y + index * 15}%`],
|
||||||
center: ['50%', '40%'],
|
center: ['50%', '40%'],
|
||||||
label: { show: false },
|
label: { show: false },
|
||||||
@@ -73,20 +69,22 @@
|
|||||||
show: true,
|
show: true,
|
||||||
x: 'center',
|
x: 'center',
|
||||||
y: 'bottom',
|
y: 'bottom',
|
||||||
itemHeight: fitChartSize(8),
|
itemHeight: fitChartSize(12),
|
||||||
itemWidth: fitChartSize(8),
|
itemWidth: fitChartSize(12),
|
||||||
itemGap: fitChartSize(20),
|
itemGap: fitChartSize(10),
|
||||||
formatter: function (name) {
|
formatter: function (name) {
|
||||||
return '{title|' + name + '}'
|
let obj = props.list.find((item) => item.name == name)
|
||||||
|
return '{name|' + name + '} {value|' + obj?.value + '}{value|%}'
|
||||||
},
|
},
|
||||||
textStyle: {
|
textStyle: {
|
||||||
rich: {
|
rich: {
|
||||||
title: {
|
name: {
|
||||||
color: '#fff',
|
color: '#fff',
|
||||||
fontSize: fitChartSize(14)
|
fontSize: fitChartSize(14)
|
||||||
},
|
},
|
||||||
value: {
|
value: {
|
||||||
color: '#00D5F6',
|
color: '#00D5F6',
|
||||||
|
fontWeight: 600,
|
||||||
fontSize: fitChartSize(14)
|
fontSize: fitChartSize(14)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,8 +24,8 @@
|
|||||||
<div class="flex justify-center">
|
<div class="flex justify-center">
|
||||||
<div class="top flex justify-evenly">
|
<div class="top flex justify-evenly">
|
||||||
<count-item label="今日舆情总数" :count="total" suffix="条" color="#ffffff" />
|
<count-item label="今日舆情总数" :count="total" suffix="条" color="#ffffff" />
|
||||||
<count-item label="今日正面舆情" :count="sensitive" suffix="条" color="#ffffff" />
|
<count-item label="今日正面舆情" :count="unsensitive" suffix="条" color="#ffffff" />
|
||||||
<count-item label="今日负面舆情" :count="unsensitive" suffix="条" color="#ffffff" />
|
<count-item label="今日负面舆情" :count="sensitive" suffix="条" color="#ffffff" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex mt-20 gap-8 ml-8 mr-8">
|
<div class="flex mt-20 gap-8 ml-8 mr-8">
|
||||||
|
|||||||
Reference in New Issue
Block a user