feat:完善景区页面

This commit is contained in:
zjc
2024-12-18 17:40:16 +08:00
parent a2386b2789
commit 42c5ac6355
19 changed files with 783 additions and 71 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

BIN
src/assets/images/car.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
src/assets/images/close.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 688 B

BIN
src/assets/images/full.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

BIN
src/assets/images/ship.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -5,7 +5,7 @@
<span class="label">{{ label }}</span>
</div>
<div class="count">
<img class="bg" src="@/assets/images/count-bg.svg" />
<img class="bg" src="@/assets/images/mask-success.png" />
<div class="flex align-center">
<countup class="value" :end-val="count" />
<span class="suffix">{{ suffix }}</span>
@@ -16,6 +16,7 @@
<script setup>
import countup from 'vue-countup-v3'
let props = defineProps({
label: {
type: String,
@@ -25,6 +26,10 @@
type: Number,
default: 0
},
mode: {
type: Number,
default: 0
},
suffix: {
type: String,
default: ''

View File

@@ -0,0 +1,124 @@
<template>
<div
:id="id"
:style="{
width: styleUtil.px2vw(width),
height: styleUtil.px2vh(height)
}"
/>
</template>
<script setup>
import * as echarts from 'echarts'
import styleUtil from '@/utils/styleUtil'
import { fitChartSize } from '@/utils/dataUtil'
import { guid } from '@/utils/util'
const props = defineProps({
width: {
type: Number,
default: () => 0
},
height: {
type: Number,
default: () => 0
},
config: {
type: Object,
default: () => {
return {}
}
}
})
let id = ref(guid())
let pieChart = null
var colorList = ['#FDC40A', '#FF5232', '#50F0A6', '#5FDFFA', '']
var title = ['企业', '农业', '工业', '纺织']
var dataValue = ['15', '30', '35', '20']
var dataList = title.map((item, index) => {
return {
name: item,
value: dataValue[index]
}
})
var defaultCofig = {
color: colorList,
legend: {
orient: 'horizontal',
bottom: '10%',
left: '4%',
data: dataList,
itemWidth: fitChartSize(16),
itemHeight: fitChartSize(16),
itemGap: fitChartSize(10),
formatter: (name) => {
return name + '\u3000' + '19%'
},
textStyle: {
color: '#ffffff',
fontSize: fitChartSize(12)
}
},
series: [
{
type: 'pie',
center: ['50%', '40%'],
radius: ['55%', '70%'],
itemStyle: {
borderWidth: fitChartSize(4),
borderColor: '#093672'
},
label: {
show: true,
position: 'center',
fontWeight: 'bold',
formatter: function (o) {
return `{value|123456}` + '\n' + `{name|整改率}`
},
rich: {
value: {
color: '#fff',
fontSize: fitChartSize(24),
fontWeight: 'bold',
padding: [0, 0, 5, 0]
},
name: {
color: '#7894A8',
fontSize: fitChartSize(12)
}
}
},
labelLine: {
show: false
},
data: dataList
}
]
}
const resize = () => {
if (pieChart) {
pieChart.dispose()
pieChart = null
init()
}
}
const init = () => {
const dom = document.getElementById(id.value)
pieChart = echarts.init(dom)
pieChart.setOption({
...defaultCofig,
...props.config
})
// 监听窗口大小变化
window.addEventListener('resize', resize)
}
onMounted(() => {
init()
})
</script>
<style scoped lang="scss"></style>

View File

@@ -13,6 +13,7 @@
import styleUtil from '@/utils/styleUtil'
import { fitChartSize } from '@/utils/dataUtil'
import { guid } from '@/utils/util'
const props = defineProps({
width: {
type: Number,
@@ -21,6 +22,12 @@
height: {
type: Number,
default: () => 0
},
config: {
type: Object,
default: () => {
return {}
}
}
})
@@ -38,57 +45,55 @@
var defaultCofig = {
color: colorList,
title: {
show: true,
text: '100%',
itemGap: 10,
x: 'center',
y: '30%',
subtext: '脱岗率',
textStyle: {
fontSize: fitChartSize(24),
fontWeight: 'bold',
color: '#ffffff'
legend: {
orient: 'vertical',
bottom: 'center',
left: '70%',
data: dataList,
itemWidth: fitChartSize(16),
itemHeight: fitChartSize(16),
itemGap: fitChartSize(10),
formatter: (name) => {
return name + '\u3000' + '19%'
},
subtextStyle: {
fontSize: fitChartSize(12),
fontWeight: 'bold',
color: '#7894A8'
textStyle: {
color: '#ffffff',
fontSize: fitChartSize(12)
}
},
legend: {
top: 'bottom',
left: 'center',
orient: 'horizontal',
data: dataList,
itemWidth: 16,
itemHeight: 16,
itemGap: 10
},
series: [
//
{
type: 'pie',
center: ['50%', '30%'],
center: ['30%', '50%'],
radius: ['40%', '55%'],
itemStyle: {
borderWidth: fitChartSize(2), //线
borderWidth: fitChartSize(4),
borderColor: '#093672'
},
label: {
show: false
},
labelLine: {
show: true,
normal: {
length: 20,
length2: 40,
align: 'center',
lineStyle: {
width: 1
position: 'center',
fontWeight: 'bold',
formatter: function (o) {
return `{value|123456}` + '\n' + `{name|整改率}`
},
rich: {
value: {
color: '#fff',
fontSize: fitChartSize(24),
fontWeight: 'bold',
padding: [0, 0, 5, 0]
},
name: {
color: '#7894A8',
fontSize: fitChartSize(12)
}
}
},
labelLine: {
show: false
},
data: dataList
}
]
@@ -105,7 +110,8 @@
const dom = document.getElementById(id.value)
pieChart = echarts.init(dom)
pieChart.setOption({
...defaultCofig
...defaultCofig,
...props.config
})
//
window.addEventListener('resize', resize)

30
src/hooks/map.js Normal file
View File

@@ -0,0 +1,30 @@
import { ref } from 'vue'
export function useMap() {
let map = ref(null)
// 初始化地图
const initMap = (id, lat, lng, scale = 15) => {
map.value = new BMapGL.Map(id)
map.value.centerAndZoom(new BMapGL.Point(lat, lng), scale)
map.value.enableScrollWheelZoom(true)
}
// 添加图标
const addMarker = (icon, position = [0, 0], size = [20, 20], offset = [0, 0]) => {
var iconPath = new BMapGL.Icon(icon, new BMapGL.Size(...size), {
// 指定定位位置。
// 当标注显示在地图上时,其所指向的地理位置距离图标左上
// 角各偏移10像素和25像素。您可以看到在本例中该位置即是
// 图标中央下端的尖角位置。
// 设置图片偏移。
// 当您需要从一幅较大的图片中截取某部分作为标注图标时,您
// 需要指定大图的偏移位置此做法与css sprites技术类似。
// imageOffset: new BMapGL.Size(...offset) // 设置图片偏移
})
var point = new BMapGL.Point(...position)
// 创建标注对象并添加到地图
var marker = new BMapGL.Marker(point, { icon: iconPath })
map.value.addOverlay(marker)
}
return { map, initMap, addMarker }
}

View File

@@ -4,11 +4,11 @@ import App from './App.vue'
import router from './router'
import '@/styles/reset.css'
import '@/styles/common.scss'
import vue3videoPlay from 'vue3-video-play' // 引入组件
import 'vue3-video-play/dist/style.css' // 引入css
// import vue3videoPlay from 'vue3-video-play' // 引入组件
// import 'vue3-video-play/dist/style.css' // 引入css
const app = createApp(App)
app.use(vue3videoPlay)
// app.use(vue3videoPlay)
app.use(createPinia())
app.use(router)

View File

@@ -1,5 +1,4 @@
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
@@ -8,16 +7,16 @@ const router = createRouter({
name: 'home',
component: () => import('@/views/home/index.vue')
},
{
path: '/monitor',
name: 'monitor',
component: () => import('../views/monitor/index.vue')
},
{
path: '/testing',
name: 'testing',
component: () => import('../views/testing/index.vue')
},
{
path: '/monitor',
name: 'monitor',
component: () => import('../views/monitor/index.vue')
},
{
path: '/testing',
name: 'testing',
component: () => import('../views/testing/index.vue')
},
{
path: '/scenic',
name: 'scenic',

View File

@@ -20,22 +20,22 @@
justify-content: space-evenly;
}
.mb-6 {
margin-bottom: vh(6);
margin-bottom: vh(6) !important;
}
.pt-10 {
padding-top: vh(10);
padding-top: vh(10) !important;
}
.pb-10 {
padding-bottom: vh(10);
padding-bottom: vh(10) !important;
}
.mb-10 {
margin-bottom: vh(10);
margin-bottom: vh(10) !important;
}
.mt-10 {
margin-top: vh(10) !important;
}
.mr-10 {
margin-right: vh(10);
margin-right: vh(10) !important;
}
.mt-20 {
margin-top: vh(20) !important;
@@ -44,8 +44,8 @@
margin-left: vh(20) !important;
}
.pt-20 {
padding-top: vh(20);
padding-top: vh(20) !important;
}
.pt-20 {
padding-top: vh(20);
.pr-20 {
padding-right: vh(20) !important;
}

View File

@@ -0,0 +1,63 @@
<template>
<div class="dialog">
<el-dialog v-model="modelValue" align-center :modal="false" :show-close="false">
<div id="big-car-ship" class="big-car-ship" />
<img class="close" src="@/assets/images/close.png" @click="modelValue = false" />
</el-dialog>
</div>
</template>
<script setup>
import carIcon from '@/assets/images/car.png'
import shipIcon from '@/assets/images/ship.png'
import { useMap } from '@/hooks/map'
let modelValue = defineModel()
const { map, initMap, addMarker } = useMap()
watch(
() => modelValue.value,
(val) => {
if (val && !map.value) {
setTimeout(() => {
initMap('big-car-ship', 109.491961, 31.024285, 16)
addMarker(carIcon, [109.491045, 31.028725], [36, 50])
addMarker(carIcon, [109.483266, 31.024718], [36, 50])
addMarker(shipIcon, [109.479062, 31.021499], [36, 50])
addMarker(shipIcon, [109.488907, 31.017476], [36, 50])
}, 500)
}
}
)
</script>
<style scoped lang="scss">
:deep(.BMap_cpyCtrl) {
display: none;
}
:deep(.anchorBL) {
display: none;
}
.dialog {
:deep(.el-dialog) {
width: vw(2540);
height: vh(900);
padding: 0;
}
:deep(.el-dialog__header) {
padding-bottom: 0 !important;
}
}
.big-car-ship {
width: vw(2540);
height: vh(900);
}
.close {
cursor: pointer;
position: absolute;
right: vw(20);
top: vh(20);
width: vw(60);
z-index: 9999;
}
</style>

View File

@@ -19,7 +19,7 @@
<div class="box mr-10">
<Title1 title="景区承载" />
<div class="flex">
<FProgress :width="200" :height="70" />
<progress1 :width="200" :height="70" />
<div class="flex flex-1 justify-between">
<count-item label="景区当前人数" :count="35600" suffix="张" />
<count-item label="景区最大承载" :count="35600" suffix="人" />
@@ -36,9 +36,9 @@
<Title1 title="停车信息" />
<div class="flex">
<div class="flex">
<FProgress :width="140" :height="70" />
<FProgress :width="140" :height="70" />
<FProgress :width="140" :height="70" />
<progress1 :width="140" :height="70" />
<progress1 :width="140" :height="70" />
<progress1 :width="140" :height="70" />
</div>
<div class="ml-20 flex flex-1 justify-between">
<count-item label="总停车场数" :count="561" suffix="个" />
@@ -47,28 +47,178 @@
</div>
<div class="flex">
<div class="border flex-1">
<Title3 title="今日景区承载量" />
<Line :width="350" :height="310" />
<div class="pt-10">
<Title3 title="今日景区承载量" />
</div>
<Line :width="350" :height="300" />
</div>
<div class="border flex-1">
<Title3 title="车辆归属地占比" />
<Pie :width="350" :height="310" />
<div class="pt-10">
<Title3 title="车辆归属地占比" />
</div>
<PieRow :width="340" :height="300" />
</div>
</div>
</div>
<div class="box-2">
<Title1 title="安全信息 " />
<div class="top flex">
<count-item label="当前告警总数" :count="561" suffix="次" />
<count-item label="安全告警总数" :count="561" suffix="次" />
<count-item label="已解除告警数" :count="561" />
</div>
<div class="border flex-1">
<div class="pt-10">
<Title3 title="今日景区承载量" />
</div>
<PieRow :width="350" :height="300" />
</div>
</div>
</div>
<div class="flex mt-10">
<div class="box-3 mr-10">
<Title1 title="交通信息" />
<div class="top flex">
<count-item label="总通景路段" :count="35600" suffix="张" />
<count-item label="通景路段拥堵数" :count="35600" suffix="人" />
<count-item label="拥堵开始时间" :count="35600" suffix="人" />
<count-item label="拥堵持续时间" :count="35600" suffix="S" />
</div>
<div class="flex">
<div class="border">
<Line :width="260" :height="330" />
</div>
<div class="border">
<PieCol :width="230" :height="330" />
</div>
<div class="border">
<PieCol :width="230" :height="330" />
</div>
</div>
</div>
<div class="box-4 mr-10">
<Title1 title="用户画像" />
<div class="flex">
<div class="border">1</div>
<div class="border">2</div>
<div class="border">3</div>
</div>
</div>
<div class="box-5">
<Title1 title="车船信息" />
<div class="flex mb-6">
<div class="border pt-10 pb-10">
<Title2 title="车车车车车车" />
<div class="car-box mt-10">
<div class="pr-20">
<div class="label">车总数</div>
<div class="value">130</div>
</div>
<div>
<div class="label">今日累计运营(班次)</div>
<div class="value">130</div>
</div>
</div>
<div class="progress-box">
<span class="text">运营130辆</span>
<div class="progress">
<el-progress
:percentage="50"
:show-text="false"
color="linear-gradient(to right, rgba(0,150,255,0) 0%, #F15A25 100%)"
/>
</div>
<span class="value">空余100辆</span>
</div>
</div>
<div class="border pt-10 pb-10">
<Title2 title="船船船船船船" />
<div class="car-box mt-10">
<div class="pr-20">
<div class="label">车总数</div>
<div class="value">130</div>
</div>
<div>
<div class="label">今日累计运营(班次)</div>
<div class="value">130</div>
</div>
</div>
<div class="progress-box">
<span class="text">运营130辆</span>
<div class="progress">
<el-progress
:percentage="50"
:show-text="false"
color="linear-gradient(to right, rgba(0,150,255,0) 0%, #F15A25 100%)"
/>
</div>
<span class="value">空余100辆</span>
</div>
</div>
</div>
<div class="border">
<div id="car-ship" class="car-ship" />
<img class="full" src="@/assets/images/full.png" @click="show = true" />
</div>
</div>
</div>
</div>
<BigCarShipMap v-model="show" />
</template>
<script setup>
import CountItem from './count-item.vue'
import FProgress from './progress-1.vue'
import progress1 from './progress-1.vue'
import { useMap } from '@/hooks/map'
import carIcon from '@/assets/images/car.png'
import shipIcon from '@/assets/images/ship.png'
import BigCarShipMap from './big-car-ship-map.vue'
const { initMap, addMarker } = useMap()
let show = ref(false)
onMounted(() => {
initMap('car-ship', 109.491961, 31.024285, 13)
addMarker(carIcon, [109.491045, 31.028725], [36, 50])
addMarker(carIcon, [109.483266, 31.024718], [36, 50])
addMarker(shipIcon, [109.479062, 31.021499], [36, 50])
addMarker(shipIcon, [109.488907, 31.017476], [36, 50])
})
</script>
<style scoped lang="scss">
:deep(.BMap_cpyCtrl) {
display: none;
}
:deep(.anchorBL) {
display: none;
}
.dialog {
:deep(.el-dialog) {
width: vw(2540);
height: vh(904);
}
}
.progress-box {
margin-top: vh(10);
height: vh(20);
display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(to right, rgba(0, 150, 255, 0) 0%, rgba(0, 150, 255, 0.17) 100%);
.text {
margin-right: vw(10);
font-weight: 400;
font-size: vw(14);
color: #ffffff;
}
.progress {
width: vw(100);
}
.value {
margin-left: vw(10);
font-weight: 400;
font-size: vw(14);
color: #f15a25;
}
}
.container {
flex: 1;
margin: vh(120) vw(10) 0 vw(10);
@@ -80,6 +230,8 @@
background: linear-gradient(321deg, #0b2f64 0%, #062b57 100%);
}
.border {
position: relative;
overflow: hidden;
padding: 0 vw(10);
margin: 0 vw(10);
box-sizing: border-box;
@@ -101,5 +253,52 @@
width: vw(440);
height: vh(475);
}
.box-3 {
@extend .bg;
width: vw(850);
height: vh(465);
}
.box-4 {
@extend .bg;
width: vw(850);
height: vh(465);
}
.box-5 {
@extend .bg;
width: vw(670);
height: vh(465);
}
.car-box {
width: vw(350);
height: vh(74);
padding-left: vw(75);
display: flex;
align-items: center;
background-image: url('@/assets/images/icon-6.png');
background-size: 100% 100%;
.label {
font-weight: 400;
font-size: vw(14);
color: #fff;
}
.value {
font-weight: bold;
font-size: vw(24);
color: #02f9fa;
margin-top: vh(10);
}
}
.car-ship {
width: vw(630);
height: vh(230);
}
.full {
cursor: pointer;
position: absolute;
right: vw(20);
bottom: vh(20);
width: vw(50);
z-index: 999;
}
}
</style>