pull/1/head
鲁洪霞 2024-01-25 10:28:53 +08:00
parent 70f10de762
commit added38399
100 changed files with 4461 additions and 512 deletions

1557
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -15,8 +15,10 @@
"@vueuse/core": "^9.13.0",
"@vueuse/integrations": "^10.7.1",
"animate.css": "^4.1.1",
"autofit.js": "^3.0.7",
"axios": "^1.6.3",
"dayjs": "^1.11.10",
"echarts": "^5.4.3",
"element-plus": "^2.4.4",
"html2canvas": "^1.4.1",
"jspdf": "^2.5.1",
@ -32,6 +34,7 @@
"throttle-debounce": "^5.0.0",
"v-viewer": "^3.0.11",
"vue": "^3.4.3",
"vue-countup-v3": "^1.4.1",
"vue-draggable-plus": "^0.3.4",
"vue-esign": "^1.1.4",
"vue-router": "^4.2.5",

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

View File

@ -4,6 +4,10 @@
<div class="logo">管理平台</div>
<div class="menu">
<ul>
<li @click="router.push({ path: '/BI' })">
<div v-for="item1 in 4" :key="item1" :class="'horn' + item1" />
<div class="title">11111111</div>
</li>
<template v-for="(item, index) in MENU" :key="index">
<li
@click="switchMenu(item.model)"

View File

@ -29,6 +29,12 @@ const routes = [
},
],
},
{
path: "/BI",
name: "/BI",
meta: { title: "BI", isBreadcrumb: false, isMenu: false },
component: () => import("@/views/BI/index"),
},
{
path: "/404",
name: "/404",

View File

@ -0,0 +1,429 @@
<template>
<div class="container">
<div
class="options"
v-for="(item, index) in data.bottomOptionsList"
:key="item.title"
@click="fnBottomOptionsListChange(item, index)"
>
<div class="option">
<img :src="item.check ? item.imgSelect : item.img" alt="" />
<div class="title">{{ item.title }}</div>
</div>
<div :class="['child_container', { active: item.check }]">
<div class="child_options">
<div
class="child_option"
v-for="(item1, index1) in item.list"
:key="item1.title"
@click.stop="fnBottomChildOptionsListChange(index, item1, index1)"
>
<img :src="item1.check ? item1.imgSelect : item1.img" alt="" />
<div class="tit" :class="item1.check ? 'active' : ''">
{{ item1.title }}
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { reactive, markRaw } from "vue";
import Personnel from "@/views/BI/components/personnel.vue";
import WorkSafely from "@/views/BI/components/work_safely.vue";
import EntranceControl from "@/views/BI/components/entrance_control.vue";
import GraveDangerous from "@/views/BI/components/grave_dangerous.vue";
import VideoAIAnalysis from "@/views/BI/components/video_ai_analysis.vue";
import VideoAIAnalysisRight from "@/views/BI/components/video_ai_analysisRight.vue";
import { useVModels } from "@vueuse/core";
const props = defineProps({
leftCurrentComponent: {
type: [Object, Function, String],
required: true,
default: "",
},
rightCurrentComponent: {
type: [Object, Function, String],
required: true,
default: "",
},
rightOption: {
type: Boolean,
required: true,
default: false,
},
});
const emits = defineEmits([
"update:leftCurrentComponent",
"update:rightCurrentComponent",
"update:rightOption",
]);
const { leftCurrentComponent, rightCurrentComponent, rightOption } = useVModels(
props,
emits
);
const bottomOptionsList = [
{
img: new URL("/src/assets/images/map/bico1.png", import.meta.url).href,
imgSelect: new URL("/src/assets/images/map/bico1_on.png", import.meta.url)
.href,
title: "人员定位",
type: "personnelPositioning",
check: false,
components: [markRaw(Personnel)],
list: [
{
img: new URL("/src/assets/images/map/bottom/ico1.png", import.meta.url)
.href,
imgSelect: new URL(
"/src/assets/images/map/bottom/ico1_on.png",
import.meta.url
).href,
title: "人员",
type: "personnel",
check: false,
},
{
img: new URL("/src/assets/images/map/bottom/ico2.png", import.meta.url)
.href,
imgSelect: new URL(
"/src/assets/images/map/bottom/ico2_on.png",
import.meta.url
).href,
title: "视频",
type: "video",
check: false,
},
{
img: new URL("/src/assets/images/map/bottom/ico3.png", import.meta.url)
.href,
imgSelect: new URL(
"/src/assets/images/map/bottom/ico3_on.png",
import.meta.url
).href,
title: "电子围栏",
type: "electronicFence",
check: false,
},
],
},
{
img: new URL("/src/assets/images/map/bico2.png", import.meta.url).href,
imgSelect: new URL("/src/assets/images/map/bico2_on.png", import.meta.url)
.href,
title: "安全作业",
type: "workSafely",
check: false,
components: [markRaw(WorkSafely)],
list: [
{
img: new URL("/src/assets/images/map/bottom/ico4.png", import.meta.url)
.href,
imgSelect: new URL(
"/src/assets/images/map/bottom/ico4_on.png",
import.meta.url
).href,
title: "动火作业",
type: "hotWork",
check: false,
},
{
img: new URL("/src/assets/images/map/bottom/ico5.png", import.meta.url)
.href,
imgSelect: new URL(
"/src/assets/images/map/bottom/ico5_on.png",
import.meta.url
).href,
title: "受限空间作业",
type: "acceptance",
check: false,
},
{
img: new URL("/src/assets/images/map/bottom/ico6.png", import.meta.url)
.href,
imgSelect: new URL(
"/src/assets/images/map/bottom/ico6_on.png",
import.meta.url
).href,
title: "临时用电作业",
type: "temporaryElectricalWork",
check: false,
},
{
img: new URL("/src/assets/images/map/bottom/ico7.png", import.meta.url)
.href,
imgSelect: new URL(
"/src/assets/images/map/bottom/ico7_on.png",
import.meta.url
).href,
title: "高处作业",
type: "workAtHeight",
check: false,
},
{
img: new URL("/src/assets/images/map/bottom/ico8.png", import.meta.url)
.href,
imgSelect: new URL(
"/src/assets/images/map/bottom/ico8_on.png",
import.meta.url
).href,
title: "断路作业",
type: "circuitBreakingOperations",
check: false,
},
{
img: new URL("/src/assets/images/map/bottom/ico9.png", import.meta.url)
.href,
imgSelect: new URL(
"/src/assets/images/map/bottom/ico9_on.png",
import.meta.url
).href,
title: "动土作业",
type: "groundbreakingWork",
check: false,
},
{
img: new URL("/src/assets/images/map/bottom/ico10.png", import.meta.url)
.href,
imgSelect: new URL(
"/src/assets/images/map/bottom/ico10_on.png",
import.meta.url
).href,
title: "吊装作业",
type: "hoistingOperations",
check: false,
},
{
img: new URL("/src/assets/images/map/bottom/ico11.png", import.meta.url)
.href,
imgSelect: new URL(
"/src/assets/images/map/bottom/ico11_on.png",
import.meta.url
).href,
title: "盲板抽堵作业",
type: "blindPlatePluggingOperation",
check: false,
},
{
img: new URL("/src/assets/images/map/bottom/ico12.png", import.meta.url)
.href,
imgSelect: new URL(
"/src/assets/images/map/bottom/ico12_on.png",
import.meta.url
).href,
title: "摄像头",
type: "camera",
check: false,
},
],
},
{
img: new URL("/src/assets/images/map/bico3.png", import.meta.url).href,
imgSelect: new URL("/src/assets/images/map/bico3_on.png", import.meta.url)
.href,
title: "口门门禁",
type: "entranceControl",
check: false,
components: [markRaw(EntranceControl)],
list: [
{
img: new URL("/src/assets/images/map/bottom/ico13.png", import.meta.url)
.href,
imgSelect: new URL(
"/src/assets/images/map/bottom/ico13_on.png",
import.meta.url
).href,
title: "人员",
type: "personnel",
check: false,
},
{
img: new URL("/src/assets/images/map/bottom/ico14.png", import.meta.url)
.href,
imgSelect: new URL(
"/src/assets/images/map/bottom/ico14_on.png",
import.meta.url
).href,
title: "车辆",
type: "vehicle",
check: false,
},
{
img: new URL("/src/assets/images/map/bottom/ico15.png", import.meta.url)
.href,
imgSelect: new URL(
"/src/assets/images/map/bottom/ico15_on.png",
import.meta.url
).href,
title: "摄像头",
type: "camera",
check: false,
},
],
},
{
img: new URL("/src/assets/images/map/bico4.png", import.meta.url).href,
imgSelect: new URL("/src/assets/images/map/bico4_on.png", import.meta.url)
.href,
title: "重大危险源",
type: "significantSourcesOfDanger",
check: false,
components: [markRaw(GraveDangerous)],
list: [
{
img: new URL("/src/assets/images/map/bottom/ico16.png", import.meta.url)
.href,
imgSelect: new URL(
"/src/assets/images/map/bottom/ico16_on.png",
import.meta.url
).href,
title: "储罐区",
type: "tankFarms",
check: false,
},
{
img: new URL("/src/assets/images/map/bottom/ico17.png", import.meta.url)
.href,
imgSelect: new URL(
"/src/assets/images/map/bottom/ico17_on.png",
import.meta.url
).href,
title: "压力管道",
type: "pressurePiping",
check: false,
},
],
},
{
img: new URL("/src/assets/images/map/bico5.png", import.meta.url).href,
imgSelect: new URL("/src/assets/images/map/bico5_on.png", import.meta.url)
.href,
title: "视频AI分析",
type: "videoAIAnalysis",
check: false,
components: [markRaw(VideoAIAnalysis), markRaw(VideoAIAnalysisRight)],
},
];
const data = reactive({
bottomOptionsList,
});
const fnBottomOptionsListChange = (item, index) => {
for (let i = 0; i < data.bottomOptionsList.length; i++) {
if (index === i) {
data.bottomOptionsList[index].check =
!data.bottomOptionsList[index].check;
continue;
}
data.bottomOptionsList[i].check = false;
}
leftCurrentComponent.value = data.bottomOptionsList[index].check
? item.components[0]
: "";
rightCurrentComponent.value = data.bottomOptionsList[index].check
? item.components[1]
: "";
rightOption.value = index !== 4;
};
const fnBottomChildOptionsListChange = (index, item1, index1) => {
data.bottomOptionsList[index].list[index1].check =
!data.bottomOptionsList[index].list[index1].check;
};
</script>
<style scoped lang="scss">
.container {
width: 100%;
position: relative;
.options {
width: 80px;
height: 95px;
position: absolute;
text-align: center;
cursor: pointer;
&:nth-child(1) {
left: 130px;
bottom: -54px;
}
&:nth-child(2) {
left: 280px;
bottom: -34px;
}
&:nth-child(3) {
left: 430px;
bottom: -25px;
}
&:nth-child(4) {
left: 580px;
bottom: -34px;
}
&:nth-child(5) {
left: 730px;
bottom: -54px;
}
.title {
margin-top: 5px;
font-size: 14px;
}
.child_container {
position: relative;
width: 80px;
height: 95px;
left: 0;
top: -95px;
display: none;
&.active {
display: block;
}
.child_options {
position: absolute;
left: 50%;
top: -120px;
transform: translateX(-50%);
background-image: linear-gradient(
to right,
rgba(0, 0, 0, 0) 0%,
rgba(0, 0, 0, 0.4) 50%,
rgba(0, 0, 0, 0) 100%
);
border: 1px solid;
border-image: linear-gradient(
to right,
rgba(0, 0, 0, 0) 0%,
rgba(2, 119, 142, 1) 50%,
rgba(255, 255, 255, 0) 100%
)
1;
border-left: none;
border-right: none;
display: flex;
animation: 0.5s all;
.child_option {
text-align: center;
display: inline-block;
padding: 15px 25px;
.tit {
white-space: nowrap;
}
.active {
color: #28b9fe;
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,370 @@
<template>
<div class="container">
<div class="block1">
<layout-title title="设备在线情况" />
<div class="option">
<div
class="list"
v-for="(item, index) in data.block1OptionsList"
:key="index"
>
<img :src="item.img" alt="" class="img" />
<div class="label">{{ item.label }}</div>
<div class="num">
<count-up :end-val="item.count"></count-up>
</div>
</div>
</div>
</div>
<div class="block2">
<layout-title title="堆料场进出数据" />
<div class="options">
<div class="option">
<div class="title">今日人员情况</div>
<div class="wraps">
<div class="wrap">进堆料场人员数: 0</div>
<div class="wrap">出堆料场人员数: 0</div>
<div class="wrap">堆料场内人员数: 0</div>
</div>
</div>
<div class="option">
<div class="title">今日车辆情况</div>
<div class="wraps">
<div class="wrap">进堆料场车辆数: 0</div>
<div class="wrap">出堆料场车辆数: 0</div>
<div class="wrap">堆料场内车辆数: 0</div>
</div>
</div>
</div>
</div>
<div class="block3">
<layout-title title="口门进出记录" />
<div class="option">
<div class="tab_list">
<div
class="list"
v-for="(item, index) in tabsList"
:class="['item', { active: index === tabIndex }]"
:key="index"
@click="tabIndex = index"
>
{{ item }}
</div>
</div>
<div class="table">
<div class="tr">
<div class="td">卡口名称</div>
<div class="td">车牌</div>
<div class="td">时间</div>
<div class="td">状态</div>
</div>
<div class="tr" v-for="(item, index) in data.block3List" :key="index">
<div class="td line-1">{{ item.name }}</div>
<div class="td">{{ item.licensePlate }}</div>
<div class="td line-1">{{ item.time }}</div>
<div class="td">{{ item.state }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import LayoutTitle from "./title.vue";
import CountUp from "vue-countup-v3";
import { reactive, ref } from "vue";
const data = reactive({
block1OptionsList: [
{
img: new URL("/src/assets/images/map/img7.png", import.meta.url).href,
label: "人员闸机数",
count: 3500,
},
{
img: new URL("/src/assets/images/map/img8.png", import.meta.url).href,
label: "车辆闸机数",
count: 3500,
},
{
img: new URL("/src/assets/images/map/img9.png", import.meta.url).href,
label: "摄像头数",
count: 3500,
},
],
block3List: [
{
name: "南大门卡口",
licensePlate: "冀CAD097",
time: "2023-5-16 12:36:25",
state: "正常",
},
{
name: "南大门卡口",
licensePlate: "冀CAD097",
time: "2023-5-16 12:36:25",
state: "正常",
},
{
name: "南大门卡口",
licensePlate: "冀CAD097",
time: "2023-5-16 12:36:25",
state: "正常",
},
{
name: "南大门卡口",
licensePlate: "冀CAD097",
time: "2023-5-16 12:36:25",
state: "正常",
},
{
name: "南大门卡口",
licensePlate: "冀CAD097",
time: "2023-5-16 12:36:25",
state: "正常",
},
{
name: "南大门卡口",
licensePlate: "冀CAD097",
time: "2023-5-16 12:36:25",
state: "正常",
},
{
name: "南大门卡口",
licensePlate: "冀CAD097",
time: "2023-5-16 12:36:25",
state: "正常",
},
{
name: "南大门卡口",
licensePlate: "冀CAD097",
time: "2023-5-16 12:36:25",
state: "正常",
},
{
name: "南大门卡口",
licensePlate: "冀CAD097",
time: "2023-5-16 12:36:25",
state: "正常",
},
],
});
const tabsList = ["人员闸机", "车辆闸机"];
const tabIndex = ref(0);
</script>
<style scoped lang="scss">
.container {
width: 100%;
.block1 {
width: 430px;
.option {
width: 100%;
min-height: 100px;
background-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8)
);
border-radius: 10px;
border: 1px solid;
border-image: linear-gradient(
to bottom,
rgba(58, 122, 149, 0),
rgba(16, 188, 236, 1)
)
1;
border-top: none;
display: flex;
justify-content: space-around;
padding: 20px 0;
text-align: center;
.list {
text-align: center;
width: 33%;
.img {
animation: slideY 2s infinite;
}
.label {
margin-top: 5px;
}
.num {
font-size: 24px;
margin-top: 10px;
background: linear-gradient(to top, #ffffff, #00a8ff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
font-weight: bold;
font-family: "Pingfang SC", "Microsoft YaHei", "Monospaced Number",
"Chinese Quote", -apple-system, BlinkMacSystemFont, "Segoe UI",
Roboto, "PingFang SC", "Hiragino Sans GB", "Helvetica Neue",
Helvetica, Arial, sans-serif;
text-shadow: 0 0 20px #2c67ec;
}
}
}
}
.block2 {
width: 430px;
margin-top: 10px;
.options {
width: 100%;
min-height: 100px;
background-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8)
);
border-radius: 10px;
border: 1px solid;
border-image: linear-gradient(
to bottom,
rgba(58, 122, 149, 0),
rgba(16, 188, 236, 1)
)
1;
border-top: none;
padding: 10px;
text-align: left;
display: flex;
flex-direction: column;
.option {
width: 100%;
.title {
background: rgba(10, 69, 203, 0.5);
border: 1px solid;
border-image: linear-gradient(
to bottom,
rgba(58, 122, 149, 0),
rgba(16, 188, 236, 1)
)
1;
border-top: none;
display: inline-block;
padding: 6px 20px;
margin: 10px 0;
}
.wraps {
width: 100%;
display: flex;
justify-content: space-between;
flex-wrap: wrap;
.wrap {
width: 45%;
text-align: left;
margin: 10px;
}
}
}
}
}
.block3 {
width: 430px;
margin-top: 10px;
.tab_list {
}
.option {
width: 100%;
min-height: 100px;
background-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8)
);
border-radius: 10px;
border: 1px solid;
border-image: linear-gradient(
to bottom,
rgba(58, 122, 149, 0),
rgba(16, 188, 236, 1)
)
1;
border-top: none;
padding: 10px;
.tab_list {
display: flex;
background: rgba(52, 147, 245, 0.3);
border: 1px solid rgba(63, 145, 197, 0.4);
border-radius: 2px;
width: 38%;
justify-content: space-between;
.list {
padding: 8px 10px;
cursor: pointer;
&:hover,
&.active {
background-image: linear-gradient(
to bottom,
rgba(1, 168, 255, 1),
rgba(17, 74, 152, 1)
);
}
}
}
.table {
margin-top: 5px;
.tr {
display: flex;
&:nth-child(odd) {
background-color: rgba(42, 86, 158, 0.53);
}
.td {
flex: 1;
text-align: left;
font-size: 14px;
color: #fff;
padding: 10px 10px;
&:nth-child(1) {
flex-basis: 25%;
}
&:nth-child(2) {
flex-basis: 25%;
}
&:nth-child(3) {
flex-basis: 35%;
}
&:nth-child(4) {
flex-basis: 15%;
}
}
.empty {
flex: 1;
text-align: center;
font-size: 12px;
color: #fff;
padding: 5px;
}
}
}
}
}
@keyframes slideY {
0% {
transform: translateY(0);
}
50% {
transform: translateY(-5px);
}
100% {
transform: translateY(0);
}
}
}
</style>

View File

@ -0,0 +1,268 @@
<template>
<div class="container">
<div class="block1">
<layout-title title="数据统计" />
<div class="option">
<div
class="list"
v-for="(item, index) in data.block1OptionsList"
:key="index"
>
<img :src="item.img" alt="" class="img" />
<div class="info">
<div class="label">{{ item.label }}</div>
<div class="num">
<count-up :end-val="item.count"></count-up>
</div>
</div>
</div>
</div>
</div>
<div class="block2">
<layout-title title="重大危险源统计" />
<div class="option" id="main1"></div>
</div>
<div class="block2">
<layout-title title="报警处置情况" />
<div class="option" id="main2"></div>
</div>
<div class="block3">
<layout-title title="危险源列表" />
<div class="option">
<div class="table">
<div class="tr">
<div class="td">设备名称</div>
<div class="td">报警时间</div>
<div class="td">处置状态</div>
</div>
<div class="tr" v-for="(item, index) in data.block4List" :key="index">
<div class="td">{{ item.name }}</div>
<div class="td line-1">{{ item.time }}</div>
<div class="td">{{ item.state }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import LayoutTitle from "./title.vue";
import CountUp from "vue-countup-v3";
import { onMounted, reactive } from "vue";
import echarts3 from "../js/echarts3.js";
import echarts4 from "../js/echarts4.js";
const data = reactive({
block1OptionsList: [
{
img: new URL("/src/assets/images/map/img10.png", import.meta.url).href,
label: "重大危险源",
count: 3500,
},
{
img: new URL("/src/assets/images/map/img11.png", import.meta.url).href,
label: "检测点数",
count: 3500,
},
{
img: new URL("/src/assets/images/map/img12.png", import.meta.url).href,
label: "检测天数",
count: 3500,
},
],
block4List: [
{
name: "1号油罐",
time: "2023-12-13 12:25:36",
state: "完成处置",
},
{
name: "1号油罐",
time: "2023-12-13 12:25:36",
state: "完成处置",
},
{
name: "1号油罐",
time: "2023-12-13 12:25:36",
state: "完成处置",
},
],
});
onMounted(() => {
echarts3("main1");
echarts4("main2");
});
</script>
<style scoped lang="scss">
.container {
width: 100%;
.block1 {
width: 430px;
.option {
width: 100%;
min-height: 100px;
background-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8)
);
border-radius: 10px;
border: 1px solid;
border-image: linear-gradient(
to bottom,
rgba(58, 122, 149, 0),
rgba(16, 188, 236, 1)
)
1;
border-top: none;
padding: 20px 0;
text-align: center;
display: flex;
flex-wrap: wrap;
.list {
text-align: left;
width: 50%;
display: flex;
padding-left: 20px;
margin-bottom: 20px;
align-items: center;
&:last-child {
margin-bottom: 0;
}
.img {
animation: slideY 2s infinite;
}
.info {
padding-left: 10px;
.label {
margin-top: 5px;
}
.num {
font-size: 24px;
background: linear-gradient(to top, #ffffff, #00a8ff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
font-weight: bold;
font-family: "Pingfang SC", "Microsoft YaHei", "Monospaced Number",
"Chinese Quote", -apple-system, BlinkMacSystemFont, "Segoe UI",
Roboto, "PingFang SC", "Hiragino Sans GB", "Helvetica Neue",
Helvetica, Arial, sans-serif;
text-shadow: 0 0 20px #2c67ec;
}
}
}
}
}
.block2 {
width: 430px;
margin-top: 10px;
.option {
width: 100%;
min-height: 100px;
background-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8)
);
border-radius: 10px;
border: 1px solid;
border-image: linear-gradient(
to bottom,
rgba(58, 122, 149, 0),
rgba(16, 188, 236, 1)
)
1;
border-top: none;
padding: 20px 0;
height: 225px;
}
}
.block3 {
width: 430px;
margin-top: 10px;
.option {
width: 100%;
min-height: 100px;
background-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8)
);
border-radius: 10px;
border: 1px solid;
border-image: linear-gradient(
to bottom,
rgba(58, 122, 149, 0),
rgba(16, 188, 236, 1)
)
1;
border-top: none;
padding: 10px;
.table {
margin-top: 5px;
.tr {
display: flex;
&:nth-child(odd) {
background-color: rgba(42, 86, 158, 0.53);
}
.td {
flex: 1;
text-align: center;
font-size: 14px;
color: #fff;
padding: 10px 10px;
&:nth-child(1) {
flex-basis: 20px;
}
&:nth-child(2) {
flex-basis: 30%;
}
&:nth-child(4) {
flex-basis: 15%;
}
}
.empty {
flex: 1;
text-align: center;
font-size: 12px;
color: #fff;
padding: 5px;
}
}
}
}
}
@keyframes slideY {
0% {
transform: translateY(0);
}
50% {
transform: translateY(-5px);
}
100% {
transform: translateY(0);
}
}
}
</style>

View File

@ -0,0 +1,364 @@
<template>
<div class="container">
<div class="block1">
<layout-title title="人员类型统计" />
<div class="option">
<div
class="list"
v-for="(item, index) in block1OptionsList"
:key="index"
>
<img :src="item.img" alt="" class="img" />
<div class="label">{{ item.label }}</div>
<div class="num">
<count-up :end-val="item.count"></count-up>
</div>
</div>
</div>
</div>
<div class="block2">
<layout-title title="告警类型统计" />
<div class="option">
<div
class="list"
v-for="(item, index) in block2OptionsList"
:key="index"
>
<div class="name">{{ item.label }}</div>
<div class="num">
<count-up :end-val="item.count"></count-up>
</div>
</div>
</div>
</div>
<div class="block3">
<layout-title title="人员定位情况" />
<div class="option">
<div class="tab_list">
<div
class="list"
v-for="(item, index) in tabsList"
:class="['item', { active: index === tabIndex }]"
:key="index"
@click="tabIndex = index"
>
{{ item }}
</div>
</div>
<div class="table">
<div class="tr">
<div class="td">姓名</div>
<div class="td">职务</div>
<div class="td">电量</div>
</div>
<div class="tr" v-for="(item, index) in block3List" :key="index">
<div class="td">{{ item.name }}</div>
<div class="td">{{ item.Office }}</div>
<div class="td">{{ item.electricity }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import LayoutTitle from "./title.vue";
import CountUp from "vue-countup-v3";
import { ref } from "vue";
const block1OptionsList = [
{
img: new URL("/src/assets/images/map/img1.png", import.meta.url).href,
label: "人员",
count: 3500,
},
{
img: new URL("/src/assets/images/map/img2.png", import.meta.url).href,
label: "相关方人员",
count: 3500,
},
{
img: new URL("/src/assets/images/map/img3.png", import.meta.url).href,
label: "外来人员",
count: 3500,
},
];
const block2OptionsList = [
{
label: "滞留报警",
count: 3500,
},
{
label: "越界报警",
count: 235,
},
{
label: "超员报警",
count: 569,
},
{
label: "缺员报警",
count: 569,
},
{
label: "静止报警",
count: 423,
},
{
label: "串岗报警",
count: 789,
},
{
label: "一键告警",
count: 236,
},
{
label: "聚集告警",
count: 214,
},
{
label: "作业告警",
count: 852,
},
];
const block3List = [
{
name: "赵一诺",
Office: "大堂经理",
electricity: "30%",
},
{
name: "赵一诺",
Office: "大堂经理",
electricity: "30%",
},
{
name: "赵一诺",
Office: "大堂经理",
electricity: "30%",
},
{
name: "赵一诺",
Office: "大堂经理",
electricity: "30%",
},
{
name: "赵一诺",
Office: "大堂经理",
electricity: "30%",
},
{
name: "赵一诺",
Office: "大堂经理",
electricity: "30%",
},
{
name: "赵一诺",
Office: "大堂经理",
electricity: "30%",
},
{
name: "赵一诺",
Office: "大堂经理",
electricity: "30%",
},
];
const tabsList = ["人员", "相关方人员", "外来人员"];
const tabIndex = ref(0);
</script>
<style scoped lang="scss">
.container {
width: 100%;
.block1 {
width: 430px;
.option {
width: 100%;
min-height: 100px;
background-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8)
);
border-radius: 10px;
border: 1px solid;
border-image: linear-gradient(
to bottom,
rgba(58, 122, 149, 0),
rgba(16, 188, 236, 1)
)
1;
border-top: none;
display: flex;
justify-content: space-around;
padding: 20px 0;
text-align: center;
.list {
text-align: center;
width: 33%;
.img {
animation: slideY 2s infinite;
}
.label {
margin-top: 5px;
}
.num {
font-size: 24px;
margin-top: 10px;
background: linear-gradient(to top, #ffffff, #00a8ff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
font-weight: bold;
font-family: "Pingfang SC", "Microsoft YaHei", "Monospaced Number",
"Chinese Quote", -apple-system, BlinkMacSystemFont, "Segoe UI",
Roboto, "PingFang SC", "Hiragino Sans GB", "Helvetica Neue",
Helvetica, Arial, sans-serif;
text-shadow: 0 0 20px #2c67ec;
}
}
}
}
.block2 {
width: 430px;
margin-top: 10px;
.option {
width: 100%;
min-height: 100px;
background-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8)
);
border-radius: 10px;
border: 1px solid;
border-image: linear-gradient(
to bottom,
rgba(58, 122, 149, 0),
rgba(16, 188, 236, 1)
)
1;
border-top: none;
display: flex;
padding: 10px;
text-align: center;
flex-wrap: wrap;
justify-content: space-between;
.list {
width: 48%;
background: rgba(20, 88, 177, 0.3);
border: 1px solid rgba(63, 145, 197, 0.5);
border-radius: 4px;
margin-top: 10px;
display: flex;
justify-content: space-between;
padding: 10px;
}
}
}
.block3 {
width: 430px;
margin-top: 10px;
.tab_list {
}
.option {
width: 100%;
min-height: 100px;
background-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8)
);
border-radius: 10px;
border: 1px solid;
border-image: linear-gradient(
to bottom,
rgba(58, 122, 149, 0),
rgba(16, 188, 236, 1)
)
1;
border-top: none;
padding: 10px;
.tab_list {
display: flex;
background: rgba(52, 147, 245, 0.3);
border: 1px solid rgba(63, 145, 197, 0.4);
border-radius: 2px;
width: 55%;
justify-content: space-between;
.list {
padding: 8px 10px;
cursor: pointer;
&:hover,
&.active {
background-image: linear-gradient(
to bottom,
rgba(1, 168, 255, 1),
rgba(17, 74, 152, 1)
);
}
}
}
.table {
margin-top: 5px;
.tr {
display: flex;
&:nth-child(odd) {
background-color: rgba(42, 86, 158, 0.53);
}
.td {
flex: 1;
text-align: left;
font-size: 14px;
color: #fff;
padding: 10px 10px;
&:nth-child(1) {
flex-basis: 30%;
}
&:nth-child(2) {
flex-basis: 50%;
}
&:nth-child(3) {
flex-basis: 20%;
}
}
.empty {
flex: 1;
text-align: center;
font-size: 12px;
color: #fff;
padding: 5px;
}
}
}
}
}
@keyframes slideY {
0% {
transform: translateY(0);
}
50% {
transform: translateY(-5px);
}
100% {
transform: translateY(0);
}
}
}
</style>

View File

@ -0,0 +1,113 @@
<template>
<div class="right_options">
<div
v-for="(item, index) in data.rightOptionsList"
:key="index"
class="option"
>
<div class="tooltip">{{ item.label }}</div>
<img :src="item.check ? item.checkImg : item.img" alt="" />
</div>
</div>
</template>
<script setup>
import { reactive } from "vue";
const data = reactive({
rightOptionsList: [
{
img: new URL("/src/assets/images/map/rico1.png", import.meta.url).href,
checkImg: new URL("/src/assets/images/map/rico1_on.png", import.meta.url)
.href,
check: true,
label: "全屏",
},
{
img: new URL("/src/assets/images/map/rico2.png", import.meta.url).href,
checkImg: new URL("/src/assets/images/map/rico2_on.png", import.meta.url)
.href,
check: false,
label: "返回中心点",
},
{
img: new URL("/src/assets/images/map/rico3.png", import.meta.url).href,
checkImg: new URL("/src/assets/images/map/rico3_on.png", import.meta.url)
.href,
check: false,
label: "切换视角",
},
{
img: new URL("/src/assets/images/map/rico4.png", import.meta.url).href,
checkImg: new URL("/src/assets/images/map/rico4_on.png", import.meta.url)
.href,
check: false,
label: "纯净地图",
},
],
});
</script>
<style scoped lang="scss">
.right_options {
width: 40px;
background: rgba(21, 54, 105, 0.4);
border: 1px solid rgba(63, 145, 197, 0.3);
border-radius: 4px;
display: flex;
flex-direction: column;
.option {
cursor: pointer;
position: relative;
width: 40px;
height: 50px;
border-bottom: 1px solid rgba(63, 145, 197, 0.3);
text-align: center;
line-height: 40px;
img {
width: 30px;
height: 30px;
margin-top: 10px;
}
&:hover {
animation: slideX 0.5s;
.tooltip {
opacity: 1;
right: 80px;
}
}
&:last-child {
border-bottom: none;
}
.tooltip {
transition: 0.5s;
opacity: 0;
width: 112px;
height: 36px;
background-image: url("/src/assets/images/map/rightbg.png");
background-size: 100% 100%;
background-repeat: no-repeat;
color: #fff;
font-size: 14px;
text-align: center;
line-height: 36px;
position: absolute;
left: -125px;
top: 7px;
}
}
@keyframes slideX {
0% {
transform: translateX(0);
}
50% {
transform: translateX(0px);
}
100% {
transform: translateX(0);
}
}
}
</style>

View File

@ -0,0 +1,46 @@
<template>
<div class="title_main">
<div class="img">
<img src="/src/assets/images/map/titimg.png" alt="" />
</div>
<div class="title">{{ title }}</div>
</div>
</template>
<script setup>
defineProps({
title: {
type: String,
required: true,
default: "",
},
});
</script>
<style scoped lang="scss">
.title_main {
width: 430px;
height: 36px;
background-image: url("/src/assets/images/map/titbg.png");
display: flex;
padding: 13px 20px;
.img {
animation: scale 2s infinite;
}
.title {
font-size: 14px;
font-weight: bold;
}
@keyframes scale {
0% {
transform: translateX(-50%) scale(1);
}
50% {
transform: translateX(-50%) scale(0.5);
}
100% {
transform: translateX(-50%) scale(1);
}
}
}
</style>

View File

@ -0,0 +1,266 @@
<template>
<div class="container">
<div class="block1">
<layout-title title="告警数" />
<div class="option">
<div
class="list"
v-for="(item, index) in data.block1OptionsList"
:key="index"
>
<img :src="item.img" alt="" class="img" />
<div class="label">{{ item.label }}</div>
<div class="num">
<count-up :end-val="item.count"></count-up>
</div>
</div>
</div>
</div>
<div class="block2">
<layout-title title="报警类型" />
<div class="option" id="main1"></div>
</div>
<div class="block2">
<layout-title title="告警时间趋势" />
<div class="option" id="main2"></div>
</div>
<div class="block3">
<layout-title title="告警来源" />
<div class="option">
<div class="table">
<div class="tr">
<div class="td">序号</div>
<div class="td">告警数据类型</div>
<div class="td">时间</div>
</div>
<div class="tr" v-for="(item, index) in data.block4List" :key="index">
<div class="td">{{ item.serialNumber }}</div>
<div class="td line-1">{{ item.type }}</div>
<div class="td">{{ item.time }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import LayoutTitle from "./title.vue";
import CountUp from "vue-countup-v3";
import { onMounted, reactive } from "vue";
import echarts1 from "../js/echarts1.js";
import echarts2 from "../js/echarts2.js";
const data = reactive({
block1OptionsList: [
{
img: new URL("/src/assets/images/map/img13.png", import.meta.url).href,
label: "总数",
count: 3500,
},
{
img: new URL("/src/assets/images/map/img14.png", import.meta.url).href,
label: "已处理数",
count: 3500,
},
{
img: new URL("/src/assets/images/map/img15.png", import.meta.url).href,
label: "待处理数",
count: 3500,
},
],
block4List: [
{
serialNumber: 1,
type: "有限空间作业(编号ZYHJ12)",
time: "2023-12-13 12:25:36",
},
{
serialNumber: 1,
type: "有限空间作业(编号ZYHJ12)",
time: "2023-12-13 12:25:36",
},
{
serialNumber: 1,
type: "有限空间作业(编号ZYHJ12)",
time: "2023-12-13 12:25:36",
},
],
});
onMounted(() => {
echarts1("main1");
echarts2("main2");
});
</script>
<style scoped lang="scss">
.container {
width: 100%;
.block1 {
width: 430px;
.option {
width: 100%;
min-height: 100px;
background-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8)
);
border-radius: 10px;
border: 1px solid;
border-image: linear-gradient(
to bottom,
rgba(58, 122, 149, 0),
rgba(16, 188, 236, 1)
)
1;
border-top: none;
display: flex;
justify-content: space-around;
padding: 20px 0;
text-align: center;
.list {
text-align: center;
width: 33%;
.img {
animation: slideY 2s infinite;
}
.label {
margin-top: 5px;
}
.num {
font-size: 24px;
margin-top: 10px;
background: linear-gradient(to top, #ffffff, #00a8ff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
font-weight: bold;
font-family: "Pingfang SC", "Microsoft YaHei", "Monospaced Number",
"Chinese Quote", -apple-system, BlinkMacSystemFont, "Segoe UI",
Roboto, "PingFang SC", "Hiragino Sans GB", "Helvetica Neue",
Helvetica, Arial, sans-serif;
text-shadow: 0 0 20px #2c67ec;
}
}
}
}
.block2 {
width: 430px;
margin-top: 10px;
.option {
width: 100%;
min-height: 100px;
background-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8)
);
border-radius: 10px;
border: 1px solid;
border-image: linear-gradient(
to bottom,
rgba(58, 122, 149, 0),
rgba(16, 188, 236, 1)
)
1;
border-top: none;
padding: 20px 0;
height: 225px;
}
}
.block3 {
width: 430px;
margin-top: 10px;
.option {
width: 100%;
min-height: 100px;
background-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8)
);
border-radius: 10px;
border: 1px solid;
border-image: linear-gradient(
to bottom,
rgba(58, 122, 149, 0),
rgba(16, 188, 236, 1)
)
1;
border-top: none;
padding: 10px;
.table {
margin-top: 5px;
.tr {
display: flex;
&:nth-child(odd) {
background-color: rgba(42, 86, 158, 0.53);
}
.td {
flex: 1;
text-align: left;
font-size: 14px;
color: #fff;
padding: 10px 10px;
&:nth-child(1) {
flex-basis: 50px;
}
&:nth-child(2) {
flex-basis: 50%;
}
&:nth-child(3) {
flex-basis: 40%;
}
}
.empty {
flex: 1;
text-align: center;
font-size: 12px;
color: #fff;
padding: 5px;
}
}
}
}
}
@keyframes slideY {
0% {
transform: translateY(0);
}
50% {
transform: translateY(-5px);
}
100% {
transform: translateY(0);
}
}
@keyframes scale {
0% {
transform: translateX(-50%) scale(1);
}
50% {
transform: translateX(-50%) scale(0.5);
}
100% {
transform: translateX(-50%) scale(1);
}
}
}
</style>

View File

@ -0,0 +1,208 @@
<template>
<div class="container">
<div class="block1">
<div class="video">
<img src="/src/assets/images/map/img16.png" alt="" />
</div>
</div>
<div class="block2">
<layout-title title="实时告警监控" />
<div class="options">
<div
class="option mb-10"
v-for="(item, index) in data.block1OptionsList"
:key="index"
>
<div class="img">
<img :src="item.img" alt="" />
</div>
<div class="info" :class="item.type === 1 ? '' : 'bg_blue'">
<div class="title">
<div class="tit">{{ item.title }}</div>
<div class="ico">
<img :src="item.type === 1 ? item.img1 : item.img2" alt="" />
</div>
</div>
<div class="time">{{ item.time }}</div>
<div class="text">{{ item.text }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import LayoutTitle from "./title.vue";
import { reactive } from "vue";
const data = reactive({
block1OptionsList: [
{
img: new URL("/src/assets/images/map/img16.png", import.meta.url).href,
img1: new URL("/src/assets/images/map/img17.png", import.meta.url).href,
img2: new URL("/src/assets/images/map/img18.png", import.meta.url).href,
title: "未戴安全帽",
time: "2023-08-09 15:14:23",
text: "告警源:油品库包装裤袋",
type: 1,
},
{
img: new URL("/src/assets/images/map/img16.png", import.meta.url).href,
img1: new URL("/src/assets/images/map/img17.png", import.meta.url).href,
img2: new URL("/src/assets/images/map/img18.png", import.meta.url).href,
title: "未戴安全帽",
time: "2023-08-09 15:14:23",
text: "告警源:油品库包装裤袋",
type: 1,
},
{
img: new URL("/src/assets/images/map/img16.png", import.meta.url).href,
img1: new URL("/src/assets/images/map/img17.png", import.meta.url).href,
img2: new URL("/src/assets/images/map/img18.png", import.meta.url).href,
title: "未戴安全帽",
time: "2023-08-09 15:14:23",
text: "告警源:油品库包装裤袋",
type: 1,
},
{
img: new URL("/src/assets/images/map/img16.png", import.meta.url).href,
img1: new URL("/src/assets/images/map/img17.png", import.meta.url).href,
img2: new URL("/src/assets/images/map/img18.png", import.meta.url).href,
title: "未戴安全帽",
time: "2023-08-09 15:14:23",
text: "告警源:油品库包装裤袋",
type: 1,
},
{
img: new URL("/src/assets/images/map/img16.png", import.meta.url).href,
img1: new URL("/src/assets/images/map/img17.png", import.meta.url).href,
img2: new URL("/src/assets/images/map/img18.png", import.meta.url).href,
title: "未戴安全帽",
time: "2023-08-09 15:14:23",
text: "告警源:油品库包装裤袋",
type: 2,
},
],
});
</script>
<style scoped lang="scss">
.container {
width: 100%;
.block1 {
width: 430px;
.video {
width: 100%;
height: 260px;
border: 2px solid #11acd7;
border-radius: 4px;
img {
width: 100%;
height: 100%;
}
}
}
.block2 {
width: 430px;
margin-top: 10px;
.options {
width: 100%;
min-height: 100px;
background-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8)
);
border-radius: 10px;
border: 1px solid;
border-image: linear-gradient(
to bottom,
rgba(58, 122, 149, 0),
rgba(16, 188, 236, 1)
)
1;
border-top: none;
display: flex;
flex-direction: column;
padding: 10px;
.option {
width: 100%;
display: flex;
align-items: center;
.img {
width: 180px;
height: 115px;
border: 1px solid #11acd7;
img {
width: 100%;
height: 100%;
}
}
.info {
flex: 1;
background-image: linear-gradient(
to top,
rgba(0, 0, 0, 0),
rgba(148, 129, 39, 0.6)
);
padding: 10px;
height: 115px;
display: flex;
justify-content: space-between;
flex-direction: column;
.title {
width: 100%;
display: flex;
justify-content: space-between;
font-size: 16px;
.tit {
font-weight: bold;
}
}
}
.bg_blue {
background-image: linear-gradient(
to top,
rgba(0, 0, 0, 0),
rgba(2, 119, 242, 0.6)
);
}
}
}
}
@keyframes slideY {
0% {
transform: translateY(0);
}
50% {
transform: translateY(-5px);
}
100% {
transform: translateY(0);
}
}
@keyframes scale {
0% {
transform: translateX(-50%) scale(1);
}
50% {
transform: translateX(-50%) scale(0.5);
}
100% {
transform: translateX(-50%) scale(1);
}
}
}
</style>

View File

@ -0,0 +1,297 @@
<template>
<div class="container">
<div class="block1">
<layout-title title="安全作业状态统计" />
<div class="option">
<div
class="list"
v-for="(item, index) in data.block1OptionsList"
:key="index"
>
<img :src="item.img" alt="" class="img" />
<div class="label">{{ item.label }}</div>
<div class="num">
<count-up :end-val="item.count"></count-up>
</div>
</div>
</div>
</div>
<div class="block2">
<layout-title title="安全作业情况统计" />
<div class="option" id="main1"></div>
</div>
<div class="block3">
<layout-title title="安全作业记录" />
<div class="option">
<div class="table">
<div class="tr">
<div class="td">序号</div>
<div class="td">作业类型</div>
<div class="td">状态</div>
<div class="td">下一步操作人</div>
</div>
<div class="tr" v-for="(item, index) in data.block3List" :key="index">
<div class="td">{{ item.serialNumber }}</div>
<div class="td line-1">{{ item.type }}</div>
<div class="td">{{ item.state }}</div>
<div class="td">{{ item.operator }}</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import LayoutTitle from "./title.vue";
import CountUp from "vue-countup-v3";
import { onMounted, reactive } from "vue";
import echarts5 from "../js/echarts5.js";
const data = reactive({
block1OptionsList: [
{
img: new URL("/src/assets/images/map/img4.png", import.meta.url).href,
label: "申请数",
count: 3500,
},
{
img: new URL("/src/assets/images/map/img5.png", import.meta.url).href,
label: "审批中",
count: 3500,
},
{
img: new URL("/src/assets/images/map/img6.png", import.meta.url).href,
label: "归档数",
count: 3500,
},
],
block3List: [
{
serialNumber: 1,
type: "有限空间作业(编号ZYHJ12)",
state: "待采样",
operator: "齐老大",
},
{
serialNumber: 2,
type: "有限空间作业(编号ZYHJ12)",
state: "待采样",
operator: "齐老大",
},
{
serialNumber: 3,
type: "有限空间作业(编号ZYHJ12)",
state: "待采样",
operator: "齐老大",
},
{
serialNumber: 4,
type: "有限空间作业(编号ZYHJ12)",
state: "待采样",
operator: "齐老大",
},
{
serialNumber: 5,
type: "有限空间作业(编号ZYHJ12)",
state: "待采样",
operator: "齐老大",
},
{
serialNumber: 6,
type: "有限空间作业(编号ZYHJ12)",
state: "待采样",
operator: "齐老大",
},
{
serialNumber: 7,
type: "有限空间作业(编号ZYHJ12)",
state: "待采样",
operator: "齐老大",
},
{
serialNumber: 8,
type: "有限空间作业(编号ZYHJ12)",
state: "待采样",
operator: "齐老大",
},
{
serialNumber: 9,
type: "有限空间作业(编号ZYHJ12)",
state: "待采样",
operator: "齐老大",
},
{
serialNumber: 10,
type: "有限空间作业(编号ZYHJ12)",
state: "待采样",
operator: "齐老大",
},
],
});
onMounted(() => {
echarts5("main1");
});
</script>
<style scoped lang="scss">
.container {
width: 100%;
.block1 {
width: 430px;
.option {
width: 100%;
min-height: 100px;
background-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8)
);
border-radius: 10px;
border: 1px solid;
border-image: linear-gradient(
to bottom,
rgba(58, 122, 149, 0),
rgba(16, 188, 236, 1)
)
1;
border-top: none;
display: flex;
justify-content: space-around;
padding: 20px 0;
text-align: center;
.list {
text-align: center;
width: 33%;
.img {
animation: slideY 2s infinite;
}
.label {
margin-top: 5px;
}
.num {
font-size: 24px;
margin-top: 10px;
background: linear-gradient(to top, #ffffff, #00a8ff);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
font-weight: bold;
font-family: "Pingfang SC", "Microsoft YaHei", "Monospaced Number",
"Chinese Quote", -apple-system, BlinkMacSystemFont, "Segoe UI",
Roboto, "PingFang SC", "Hiragino Sans GB", "Helvetica Neue",
Helvetica, Arial, sans-serif;
text-shadow: 0 0 20px #2c67ec;
}
}
}
}
.block2 {
width: 430px;
margin-top: 10px;
.option {
width: 100%;
min-height: 100px;
background-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8)
);
border-radius: 10px;
border: 1px solid;
border-image: linear-gradient(
to bottom,
rgba(58, 122, 149, 0),
rgba(16, 188, 236, 1)
)
1;
border-top: none;
padding: 20px 0;
height: 225px;
}
}
.block3 {
width: 430px;
margin-top: 10px;
.option {
width: 100%;
min-height: 100px;
background-image: linear-gradient(
to bottom,
rgba(0, 0, 0, 0),
rgba(0, 0, 0, 0.8)
);
border-radius: 10px;
border: 1px solid;
border-image: linear-gradient(
to bottom,
rgba(58, 122, 149, 0),
rgba(16, 188, 236, 1)
)
1;
border-top: none;
padding: 10px;
.table {
margin-top: 5px;
.tr {
display: flex;
&:nth-child(odd) {
background-color: rgba(42, 86, 158, 0.53);
}
.td {
flex: 1;
text-align: center;
font-size: 14px;
color: #fff;
padding: 10px 10px;
&:nth-child(1) {
flex-basis: 20px;
}
&:nth-child(2) {
flex-basis: 30%;
}
&:nth-child(4) {
flex-basis: 15%;
}
}
.empty {
flex: 1;
text-align: center;
font-size: 12px;
color: #fff;
padding: 5px;
}
}
}
}
}
@keyframes slideY {
0% {
transform: translateY(0);
}
50% {
transform: translateY(-5px);
}
100% {
transform: translateY(0);
}
}
}
</style>

169
src/views/BI/index.vue Normal file
View File

@ -0,0 +1,169 @@
<template>
<div id="container">
<div class="map_bg"></div>
<transition
enter-active-class="animate__animated animate__fadeInDown"
leave-active-class="animate__animated animate__fadeOutUp"
>
<div class="header" :key="transitionKey">
<div class="back">
<img src="/src/assets/images/map/back.png" alt="" />
</div>
<div class="light"></div>
<div class="title" />
</div>
</transition>
<div class="left_container" v-if="leftCurrentComponent">
<transition
enter-active-class="animate__animated animate__fadeInLeft"
leave-active-class="animate__animated animate__fadeOutLeft"
mode="out-in"
>
<component :is="leftCurrentComponent" />
</transition>
</div>
<div class="mid-container">
<bottom-options
v-model:left-current-component="leftCurrentComponent"
v-model:right-current-component="rightCurrentComponent"
v-model:right-option="right_option"
/>
</div>
<transition
enter-active-class="animate__animated animate__fadeInRight"
leave-active-class="animate__animated animate__fadeOutRight"
mode="out-in"
>
<div class="right_container" v-if="rightCurrentComponent">
<component :is="rightCurrentComponent" />
</div>
</transition>
<div class="right_ico" v-show="right_option">
<RightIco></RightIco>
</div>
</div>
</template>
<script setup>
import autofit from "autofit.js";
import { onMounted, ref } from "vue";
import RightIco from "./components/rightico.vue";
import BottomOptions from "./components/bottom_options.vue";
const right_option = ref(true);
const transitionKey = ref(0);
const leftCurrentComponent = ref("");
const rightCurrentComponent = ref("");
onMounted(() => {
autofit.init({
designHeight: 1080,
designWidth: 1920,
renderDom: "#container",
resize: true,
});
transitionKey.value = Math.random();
});
</script>
<style scoped lang="scss">
#container {
width: 100%;
height: 100%;
color: #ffffff;
position: relative;
font-size: 14px;
.map_bg {
width: 100%;
height: 100%;
background: url("/src/assets/images/map/bg.png") no-repeat center center;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: -9;
background-size: 100% 100%;
}
.header {
width: 100%;
height: 100px;
background: url("/src/assets/images/map/titlebg.png") no-repeat top center;
background-size: 100% 100%;
position: absolute;
.back {
position: absolute;
top: 0;
left: 0;
cursor: pointer;
}
.light {
background-image: url("/src/assets/images/map/gunag.png");
background-size: 100% 100%;
background-repeat: no-repeat;
width: 619px;
height: 55px;
position: absolute;
top: 50px;
left: 50%;
animation: scale 2s infinite;
@keyframes scale {
0% {
transform: translateX(-50%) scale(1);
}
50% {
transform: translateX(-50%) scale(0.5);
}
100% {
transform: translateX(-50%) scale(1);
}
}
}
.title {
width: 355px;
height: 50px;
text-align: center;
position: absolute;
left: 50%;
top: 15%;
transform: translate(-50%, 0%);
background: url("/src/assets/images/map/title.png") no-repeat top center;
}
}
.left_container {
width: 435px;
position: absolute;
left: 20px;
top: 100px;
}
.right_container {
width: 435px;
position: absolute;
right: 20px;
top: 100px;
}
.mid-container {
width: 934px;
height: 88px;
background-image: url("/src/assets/images/map/bottombg.png");
background-repeat: no-repeat;
position: fixed;
bottom: 0;
left: 50%;
transform: translateX(-50%);
}
.right_ico {
position: fixed;
right: 20px;
bottom: 50px;
}
}
</style>

190
src/views/BI/js/echarts1.js Normal file
View File

@ -0,0 +1,190 @@
import * as echarts from "echarts";
import { tryOnMounted, tryOnUnmounted } from "@vueuse/core";
let myChart1;
function echarts1(id) {
myChart1 = echarts.init(document.querySelector(`#${id}`));
function xWrapText(params, num = 2) {
let newParamsName = "";
const paramsNameNumber = params.length;
const provideNumber = num; // 一行显示几个字
const rowNumber = Math.ceil(paramsNameNumber / provideNumber);
if (paramsNameNumber > provideNumber) {
for (let p = 0; p < rowNumber; p++) {
let tempStr = "";
const start = p * provideNumber;
const end = start + provideNumber;
if (p === rowNumber - 1) {
tempStr = params.substring(start, paramsNameNumber);
} else {
tempStr = params.substring(start, end) + "";
}
newParamsName += tempStr;
}
} else {
newParamsName = params;
}
return newParamsName;
}
const legend = ["烟雾", "水电", "烟雾", "烟雾", "烟雾"];
const echartCount = [12, 15, 11, 8, 16];
const option = {
backgroundColor: "",
grid: {
top: "10%",
left: "10%",
right: "5%",
bottom: "10%",
},
tooltip: {
trigger: "axis",
backgroundColor: "#3A4667",
borderColor: "#3A4667",
textStyle: {
color: "#fff",
},
formatter: "{b} : {c} %",
axisPointer: {
type: "cross",
crossStyle: {
color: "#999",
},
},
},
xAxis: {
type: "category",
axisPointer: {
type: "shadow",
},
axisLabel: {
textStyle: {
color: "#B3CFFF", // x轴文本颜色
fontSize: 10,
},
formatter(params) {
const res = xWrapText(params, 6);
return params.length > 15 ? `${res.slice(0, 15)}...` : res;
},
},
axisTick: {
show: false,
},
data: legend,
},
yAxis: {
type: "value",
splitLine: {
show: true,
lineStyle: {
color: "#162647",
type: "solid",
},
},
axisLabel: {
formatter: "{value}%",
textStyle: {
color: "#B3CFFF", // x轴文本颜色
fontSize: 12,
},
},
name: "",
nameTextStyle: {
color: "#B3CFFF",
fontSize: 12,
padding: [0, -20, 0, 30],
},
},
series: [
{
type: "bar",
name: "基金投资回报率",
barWidth: 8,
emphasis: {
itemStyle: {
color: "#7fb7e9",
},
},
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 1,
color: "rgba(109, 131, 180, 1)",
opacity: 0.6,
},
{
offset: 0,
color: "rgba(66, 91, 147, 1)",
opacity: 1,
},
]),
barBorderRadius: [0, 0, 0, 0],
},
},
data: echartCount,
},
{
name: "基金投资回报率",
tooltip: {
show: false,
},
type: "bar",
barWidth: 8,
emphasis: {
itemStyle: {
color: "#2e9bff",
},
},
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{
offset: 1,
color: "rgba(109, 131, 180, 1)",
opacity: 0.6,
},
{
offset: 0,
color: "rgba(99, 126, 188, 1)",
opacity: 1,
},
]),
barBorderRadius: [0, 0, 0, 0],
},
},
data: echartCount,
barGap: 0,
legendHoverLink: false,
},
{
name: "基金投资回报率",
tooltip: {
show: false,
},
type: "pictorialBar",
itemStyle: {
normal: {
color: "rgba(183, 195, 226, 1)",
},
},
symbol: "diamond",
symbolRotate: 0,
symbolSize: ["17", "7"],
symbolOffset: ["0", "-4"],
symbolPosition: "end",
data: echartCount,
z: 3,
},
],
};
myChart1.setOption(option);
}
tryOnMounted(() => {
window.onresize = function () {
myChart1 && myChart1.resize();
};
});
tryOnUnmounted(() => {
myChart1 = null;
});
export default echarts1;

140
src/views/BI/js/echarts2.js Normal file
View File

@ -0,0 +1,140 @@
import * as echarts from "echarts";
import { tryOnMounted, tryOnUnmounted } from "@vueuse/core";
let myChart2;
function echarts2(id) {
myChart2 = echarts.init(document.querySelector(`#${id}`));
const option = {
backgroundColor: "",
tooltip: {},
grid: {
top: "5%",
left: "1%",
right: "1%",
bottom: "0%",
containLabel: true,
},
legend: {
icon: "circle",
data: ["累计推荐", "本月推荐"],
textStyle: {
color: "#999999",
borderColor: "#fff",
},
},
xAxis: [
{
type: "category",
boundaryGap: true,
axisLine: {
// 坐标轴轴线相关设置。数学上的x轴
show: true,
lineStyle: {
color: "#f9f9f9",
},
},
axisLabel: {
// 坐标轴刻度标签的相关设置
textStyle: {
color: "#d1e6eb",
margin: 15,
},
},
axisTick: {
show: false,
},
data: ["1月", "2月", "3月", "4月", "5月", "6月", "7月"],
},
],
yAxis: [
{
type: "value",
min: 0,
// max: 140,
splitNumber: 7,
splitLine: {
show: true,
lineStyle: {
color: "#0a3256",
},
},
axisLine: {
show: false,
},
axisLabel: {
margin: 20,
textStyle: {
color: "#d1e6eb",
},
},
axisTick: {
show: false,
},
},
],
series: [
{
name: "累计推荐",
type: "line",
symbol: "circle", // 默认是空心圆(中间是白色的),改成实心圆
showAllSymbol: true,
symbolSize: 8,
lineStyle: {
color: "#28ffb3", // 线条颜色
},
itemStyle: {
color: "#28ffb3",
borderColor: "#fff",
},
tooltip: {
show: true,
},
areaStyle: {
// 区域填充样式
// 线性渐变前4个参数分别是x0,y0,x2,y2(范围0~1);相当于图形包围盒中的百分比。如果最后一个参数是true则该四个值是绝对像素位置。
color: new echarts.graphic.LinearGradient(
0,
0,
0,
1,
[
{
offset: 0,
color: "rgba(0,154,120,1)",
},
{
offset: 1,
color: "rgba(0,0,0, 0)",
},
],
false
),
shadowColor: "rgba(53,142,215, 0.9)", // 阴影颜色
shadowBlur: 20, // shadowBlur设图形阴影的模糊大小。配合shadowColor,shadowOffsetX/Y, 设置图形的阴影效果。
},
data: [393, 438, 485, 631, 689, 824, 987],
},
{
name: "本月推荐",
type: "bar",
barWidth: 20,
tooltip: {
show: false,
},
itemStyle: {
color: "#1492FF",
},
data: [200, 382, 102, 267, 186, 315, 316],
},
],
};
myChart2.setOption(option);
}
tryOnMounted(() => {
window.onresize = function () {
myChart2 && myChart2.resize();
};
});
tryOnUnmounted(() => {
myChart2 = null;
});
export default echarts2;

166
src/views/BI/js/echarts3.js Normal file
View File

@ -0,0 +1,166 @@
import * as echarts from "echarts";
import { tryOnMounted, tryOnUnmounted } from "@vueuse/core";
let myChart3;
function echarts3(id) {
myChart3 = echarts.init(document.querySelector(`#${id}`));
const pieData = [
{
name: "指标1",
value: 920,
},
{
name: "指标2",
value: 458,
},
{
name: "指标3",
value: 653,
},
{
name: "指标4",
value: 372,
},
];
// 饼图位置
const pieCenter = ["30%", "50%"];
const option = {
title: {
text: "",
textStyle: {
color: "#FFF",
},
top: 20,
left: 20,
},
backgroundColor: "",
color: [
"#FFEF00",
"#00E899",
"#006FFF",
"#73d0fd",
"#25C1F1",
"#C4F9F3",
"#E062AE",
"#8378EA",
"#C4F926",
"#FF5722",
"#ffd32a",
"#3c40c6",
"#ffa801",
],
tooltip: {
show: true,
},
legend: {
show: true,
orient: "vertical",
textStyle: {
color: "#FFF",
},
right: "20",
top: "18",
itemWidth: 5,
itemHeight: 5,
itemGap: 18,
formatter(name) {
// 通过 name 获取到数组对象中的单个对象
const singleData = pieData.filter((item) => item.name === name);
return `${name} ${singleData[0].value}`;
},
},
series: [
// 背景装饰0 实心白圆 层级最高zlevel: 4
{
type: "pie",
zlevel: 4,
radius: ["0%", "7%"],
center: pieCenter,
silent: true,
clockwise: false,
label: {
show: false,
},
data: [
{
name: null,
value: 0,
itemStyle: {
color: "#FFF",
},
},
],
},
// 背景装饰1 半透明圆 zlevel: 3 层级第二
{
type: "pie",
radius: ["0%", "15%"],
center: pieCenter,
zlevel: 3,
silent: true,
clockwise: false,
label: {
show: false,
},
data: [
{
name: null,
value: 0,
itemStyle: {
color: "rgba(255,255,255, 1)",
},
},
],
},
// 背景装饰3 半透明圆 zlevel: 1 层级最低 作为底盘
{
type: "pie",
zlevel: 1,
radius: ["70%", "0%"],
center: pieCenter,
silent: true,
clockwise: false,
label: {
show: false,
},
data: [
{
name: null,
value: 0,
itemStyle: {
color: "rgba(255,255,255, 0.1)",
},
},
],
},
// 数据源
{
type: "pie",
zlevel: 1,
// roseType: true 和 roseType: 'area' 在填充值后显示方式不同
roseType: true,
clockwise: false,
center: pieCenter,
radius: ["4%", "70%"], // 第一个参数控制玫瑰图圆心大小,第二个参数控制玫瑰图大小
itemStyle: {
borderRadius: 0,
},
data: pieData,
label: {
show: true,
},
},
],
};
myChart3.setOption(option);
}
tryOnMounted(() => {
window.onresize = function () {
myChart3 && myChart3.resize();
};
});
tryOnUnmounted(() => {
myChart3 = null;
});
export default echarts3;

237
src/views/BI/js/echarts4.js Normal file
View File

@ -0,0 +1,237 @@
import * as echarts from "echarts";
import { tryOnMounted, tryOnUnmounted } from "@vueuse/core";
let myChart4;
function echarts4(id) {
myChart4 = echarts.init(document.querySelector(`#${id}`));
const list = [
{ name: "城东", value: 88 },
{ name: "横峰", value: 75 },
{ name: "城西", value: 66 },
];
const option = {
backgroundColor: "",
title: {
text: "",
textStyle: {
color: "#ffffff",
fontSize: 25,
},
top: "10%",
left: "center",
// right: '5%'
},
grid: {
left: "10%",
top: "5%",
bottom: "10%",
right: "10%",
},
xAxis: {
// name: 'X',
nameTextStyle: {
color: "#184876",
padding: [0, 0, 0, 20],
},
show: true,
axisLine: {
show: true,
lineStyle: {
color: "#184876",
shadowColor: "rgba(91,100,134,0)",
shadowOffsetX: "20",
},
symbol: ["none", "arrow"],
symbolOffset: [0, 25],
},
splitLine: {
show: false,
lineStyle: {
color: "rgba(255,255,255,1)",
},
},
axisLabel: {
show: true,
// rotate: -1,
textStyle: {
fontSize: 14,
// fontFamily: PangMenZhengDao,
color: "#fff",
},
},
axisTick: {
show: false,
},
// data: ['物业纠纷', '其他合同', '道路交通']
data: list.map((val) => {
return val.name;
}),
},
yAxis: [
{
nameTextStyle: {
color: "#ffffff",
padding: [0, 0, 0, 20],
},
max: 123,
min: 0,
splitNumber: (123 % 5).toFixed(0),
show: true,
axisTick: {
show: false,
},
axisLine: {
show: true,
symbol: ["none", "arrow"],
symbolOffset: [0, 15],
lineStyle: {
// color: 'rgba(255, 129, 109, 0.1)',
width: 1, // 这里是为了突出显示加上的
color: "#7bb4dc",
shadowColor: "rgba(91,100,134,1)",
},
},
axisLabel: {
show: true,
textStyle: {
fontSize: 12,
// fontFamily: PangMenZhengDao,
color: "#ffffff",
},
},
splitArea: {
areaStyle: {
color: "rgba(255,255,255,.5)",
},
},
splitLine: {
show: true,
lineStyle: {
color: "#153a65",
width: 1,
type: "solid",
},
},
},
],
series: [
{
type: "pictorialBar",
barCategoryGap: "-20%",
/* 多个并排柱子设置柱子之间的间距 */
// symbol: 'path://M0,10 L10,10 C5.5,10 5.5,5 5,0 C4.5,5 4.5,10 0,10 z',
symbol: "path://M0,10 L10,10 C5.5,10 6.5,5 5,5 C3.5,5 4.5,10 0,10 z",
label: {
show: true,
position: "top",
distance: 10,
color: "#fff",
fontWeight: "bolder",
fontSize: 12,
},
itemStyle: {
// normal: {
// color: {
// type: 'linear',
// x: 0,
// y: 0,
// x2: 0,
// y2: 1,
// colorStops: [
// {
// offset: 0,
// color: '#3b89f4',
// },
// {
// offset: 1,
// color: '#cce7fc',
// },
// ],
// global: false, // 缺省为 false
// },
// },
// emphasis: {
// opacity: 1,
// },
normal: {
color: (params) => {
const colorList = [
{
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: "#297ff2",
},
{
offset: 1,
color: "#cce7fc",
},
],
},
{
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: "#3bfafe",
},
{
offset: 1,
color: "#aaf4fe",
},
],
},
{
type: "linear",
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{
offset: 0,
color: "#e08440",
},
{
offset: 1,
color: "#decabd",
},
],
},
];
return colorList[params.dataIndex];
},
opacity: 0.7,
},
// 鼠标移入柱子上 透明度变为 1
emphasis: {
opacity: 1,
},
},
data: list.map((v) => {
return v.value;
}),
// data: [123, 60, 25]
},
],
};
myChart4.setOption(option);
}
tryOnMounted(() => {
window.onresize = function () {
myChart4 && myChart4.resize();
};
});
tryOnUnmounted(() => {
myChart4 = null;
});
export default echarts4;

140
src/views/BI/js/echarts5.js Normal file
View File

@ -0,0 +1,140 @@
import * as echarts from "echarts";
import { tryOnMounted, tryOnUnmounted } from "@vueuse/core";
let myChart5;
function echarts2(id) {
myChart5 = echarts.init(document.querySelector(`#${id}`));
const option = {
backgroundColor: "",
tooltip: {},
grid: {
top: "5%",
left: "1%",
right: "1%",
bottom: "0%",
containLabel: true,
},
legend: {
icon: "circle",
data: ["累计推荐", "本月推荐"],
textStyle: {
color: "#999999",
borderColor: "#fff",
},
},
xAxis: [
{
type: "category",
boundaryGap: true,
axisLine: {
// 坐标轴轴线相关设置。数学上的x轴
show: true,
lineStyle: {
color: "#f9f9f9",
},
},
axisLabel: {
// 坐标轴刻度标签的相关设置
textStyle: {
color: "#d1e6eb",
margin: 15,
},
},
axisTick: {
show: false,
},
data: ["1月", "2月", "3月", "4月", "5月", "6月", "7月"],
},
],
yAxis: [
{
type: "value",
min: 0,
// max: 140,
splitNumber: 7,
splitLine: {
show: true,
lineStyle: {
color: "#0a3256",
},
},
axisLine: {
show: false,
},
axisLabel: {
margin: 20,
textStyle: {
color: "#d1e6eb",
},
},
axisTick: {
show: false,
},
},
],
series: [
{
name: "累计推荐",
type: "line",
symbol: "circle", // 默认是空心圆(中间是白色的),改成实心圆
showAllSymbol: true,
symbolSize: 8,
lineStyle: {
color: "#28ffb3", // 线条颜色
},
itemStyle: {
color: "#28ffb3",
borderColor: "#fff",
},
tooltip: {
show: true,
},
areaStyle: {
// 区域填充样式
// 线性渐变前4个参数分别是x0,y0,x2,y2(范围0~1);相当于图形包围盒中的百分比。如果最后一个参数是true则该四个值是绝对像素位置。
color: new echarts.graphic.LinearGradient(
0,
0,
0,
1,
[
{
offset: 0,
color: "rgba(0,154,120,1)",
},
{
offset: 1,
color: "rgba(0,0,0, 0)",
},
],
false
),
shadowColor: "rgba(53,142,215, 0.9)", // 阴影颜色
shadowBlur: 20, // shadowBlur设图形阴影的模糊大小。配合shadowColor,shadowOffsetX/Y, 设置图形的阴影效果。
},
data: [393, 438, 485, 631, 689, 824, 987],
},
{
name: "本月推荐",
type: "bar",
barWidth: 20,
tooltip: {
show: false,
},
itemStyle: {
color: "#1492FF",
},
data: [200, 382, 102, 267, 186, 315, 316],
},
],
};
myChart5.setOption(option);
}
tryOnMounted(() => {
window.onresize = function () {
myChart5 && myChart5.resize();
};
});
tryOnUnmounted(() => {
myChart5 = null;
});
export default echarts2;