pull/1/head
LiuJiaNan 2024-02-20 14:57:09 +08:00
parent 4315877414
commit 6b17aa7db0
49 changed files with 1790 additions and 8 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 423 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

BIN
src/assets/images/bi/bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 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.6 KiB

BIN
src/assets/images/bi/ri.png Normal file

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: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -277,8 +277,7 @@ const props = defineProps({
},
listType: {
type: String,
required: true,
default: "",
default: "1",
},
});
const emits = defineEmits(["throw-data"]);

View File

@ -4,8 +4,7 @@
<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" />-->
<li @click="router.push({ path: '/large_screen_data_display' })">
<div class="title">BI</div>
</li>
<template v-for="(item, index) in MENU" :key="index">
@ -13,7 +12,6 @@
@click="switchMenu(item.model)"
:class="{ active: item.model === menuStore.getModel }"
>
<!-- <div v-for="item1 in 4" :key="item1" :class="'horn' + item1" />-->
<div class="title">{{ item.title }}</div>
</li>
</template>

View File

@ -0,0 +1,23 @@
import { post } from "@/request/axios.js";
export const getRiskManagement = (params) =>
post("/riskpoint/statistic", params); // 风险管控统计分析
export const getTroubleshootingTypeNumber = (params) =>
post("/listmanager/countNumBi", params); // 排查类型
export const getTroubleshootingTypeEcharts = (params) =>
post("/checkrecord/listTypeBi", params); // 排查类型
export const getUserUsage = (params) => post("/checkrecord/countNumBi", params); // 企业排查情况
export const getTaskProcessingHidden = (params) =>
post("/hidden/getBICount", params); // 任务处理情况隐患处理
export const getTaskProcessingCheck = (params) =>
post("/checkrecord/goBiListCount", params); // 任务处理情况日常检查
export const getHiddenCount = (params) => post("/hidden/hiddenSta", params); // 隐患数量
export const getAssignmentType = (params) =>
post("/eightWork/eightWorkBI", params); // 作业类型
export const getVideo = (params) => post("/video/getObjectForBiLogin", params); // 视频中心
export const getFullStaffTraining = (params) =>
post("/studytask/BIstatistics", params); // 全员培训统计
export const getExamStatisticsUser = (params) =>
post("/performanceexamine_user/list", params); // 考核情况统计用户
export const getExamStatisticsDepartment = (params) =>
post("/performanceexamine_dept/list", params); // 考核情况统计部门

View File

@ -35,6 +35,16 @@ const routes = [
meta: { title: "BI", isBreadcrumb: false, isMenu: false },
component: () => import("@/views/BI/index"),
},
{
path: "/large_screen_data_display",
name: "/large_screen_data_display",
meta: {
title: "large_screen_data_display",
isBreadcrumb: false,
isMenu: false,
},
component: () => import("@/views/large_screen_data_display/index"),
},
{
path: "/mobile",
meta: { isBreadcrumb: false, isMenu: false, isLogin: false },

View File

@ -3,7 +3,7 @@
<layout-card>
<div id="printContent">
<el-divider content-position="left">检查信息</el-divider>
<el-descriptions border>
<el-descriptions border :column="2">
<el-descriptions-item label="隐患照片 ">
<img
v-viewer

View File

@ -3,7 +3,7 @@
<layout-card>
<div id="printContent">
<el-divider content-position="left">检查信息</el-divider>
<el-descriptions border>
<el-descriptions border :column="2">
<el-descriptions-item label="隐患照片 ">
<img
v-viewer

View File

@ -3,7 +3,7 @@
<layout-card>
<div id="printContent">
<el-divider content-position="left">检查信息</el-divider>
<el-descriptions border>
<el-descriptions border :column="2">
<el-descriptions-item label="处罚原因 ">
{{ data.info.REASON }}
</el-descriptions-item>

View File

@ -0,0 +1,114 @@
<template>
<div class="assignment_type">
<div class="title">作业类型</div>
<div id="main4" />
</div>
</template>
<script setup>
import { getAssignmentType } from "@/request/large_screen_data_display.js";
import { onMounted } from "vue";
import * as echarts from "echarts";
const fnGetData = async () => {
const resData = await getAssignmentType();
fnInitEcharts(resData.count);
};
onMounted(() => {
fnGetData();
});
const fnInitEcharts = (data) => {
const myChart = echarts.init(document.querySelector("#main4"));
const option = {
color: [
"#459AF0",
"#38C3B0",
"#86CA5A",
"#BFD44F",
"#FCC248",
"#FCE448",
"#F58B41",
"#F7765B",
],
legend: {
orient: "vertical",
right: "20",
top: "center",
data: [
"盲板抽堵作业",
"动土作业",
"受限空间作业",
"临时用电作业",
"断路作业",
"高处作业",
"吊装作业",
"动火作业",
],
textStyle: {
color: "#2aaef2",
},
},
tooltip: {
trigger: "item",
formatter: "{b} {c} <br />{d}%",
},
series: [
{
name: "",
type: "pie",
radius: ["0%", "80%"],
center: ["30%", "50%"],
label: {
show: true,
position: "inside",
formatter: (params) => {
return `${params.percent}%`;
},
},
labelLine: {
show: false,
},
data: [
{ value: data.blindboard_num, name: "盲板抽堵作业" },
{ value: data.breakground_num, name: "动土作业" },
{ value: data.confinedspace_num, name: "受限空间作业" },
{ value: data.electricity_num, name: "临时用电作业" },
{ value: data.cutroad_num, name: "断路作业" },
{ value: data.highwork_num, name: "高处作业" },
{ value: data.hoisting_num, name: "吊装作业" },
{ value: data.hotwork_num, name: "动火作业" },
],
},
],
};
myChart.setOption(option);
};
</script>
<style scoped lang="scss">
.assignment_type {
margin-top: 15px;
background-image: url("/src/assets/images/bi/C-2.png");
background-size: 100% 100%;
background-repeat: no-repeat;
width: 100%;
height: 212px;
position: relative;
display: flex;
flex-direction: column;
justify-content: space-between;
.title {
color: #34dcfc;
font-size: 16px;
position: absolute;
top: -8px;
left: 0;
}
#main4 {
width: 100%;
height: 100%;
}
}
</style>

View File

@ -0,0 +1,158 @@
<template>
<div class="exam_statistics">
<div class="title">考核情况统计()</div>
<div class="content">
<div class="tabs">
<div
v-for="(item, index) in tabsList"
:key="index"
:class="['tab', { active: index === tabsIndex }]"
@click="tabsIndex = index"
>
{{ item }}
</div>
</div>
<table>
<thead>
<tr>
<th>名次</th>
<th v-if="tabsIndex === 0"></th>
<th v-if="tabsIndex === 1"></th>
<th>等级</th>
</tr>
</thead>
<tbody>
<tr
v-for="(item, index) in tabsIndex === 0 ? userList : departmentList"
:key="index"
>
<td>{{ index + 1 }}</td>
<td v-if="tabsIndex === 0">
{{ item.DEPT_NAME_ALL }} - {{ item.USER_NAME }}
</td>
<td v-if="tabsIndex === 1">{{ item.DEPT_NAME_ALL }}</td>
<td>
{{
fnComputeLevel(
item.SCORE1 +
item.SCORE2 +
item.SCORE3 +
item.SCORE4 +
item.SCORE5
)
}}
</td>
</tr>
</tbody>
</table>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
import useListData from "@/assets/js/useListData.js";
import {
getExamStatisticsDepartment,
getExamStatisticsUser,
} from "@/request/large_screen_data_display.js";
import dayjs from "dayjs";
const tabsList = ["人员考核成绩", "部门考核成绩"];
const tabsIndex = ref(0);
const { list: userList } = useListData(getExamStatisticsUser, {
otherParams: {
MONTH: dayjs().subtract(1, "months").format("YYYY-MM"),
},
});
const { list: departmentList } = useListData(getExamStatisticsDepartment, {
otherParams: {
MONTH: dayjs().subtract(1, "months").format("YYYY-MM"),
},
});
const fnComputeLevel = (total) => {
if (total >= 75) return "一级";
else if (total >= 50) return "二级";
else if (total >= 25) return "三级";
else return "四级";
};
</script>
<style scoped lang="scss">
.exam_statistics {
margin-top: 15px;
background-image: url("/src/assets/images/bi/R-3.png");
background-size: 100% 100%;
background-repeat: no-repeat;
width: 100%;
height: 357px;
position: relative;
display: flex;
flex-direction: column;
justify-content: space-between;
.title {
color: #34dcfc;
font-size: 16px;
position: absolute;
top: -8px;
left: 0;
}
.content {
padding: 15px;
.tabs {
display: flex;
padding-top: 15px;
.tab {
width: 116px;
height: 26px;
line-height: 26px;
text-align: center;
color: #fff;
cursor: pointer;
background-image: url("/src/assets/images/bi/tab-1.png");
background-size: 100% 100%;
background-repeat: no-repeat;
&:nth-child(2) {
margin-left: 15px;
}
&.active {
background-image: url("/src/assets/images/bi/tab-2.png");
}
}
}
table {
margin-top: 15px;
width: 100%;
border-collapse: collapse;
border-spacing: 0;
text-align: center;
thead {
th {
color: #14a3dd;
padding: 4px 0;
background-color: rgba(241, 241, 241, 0.059);
}
}
tbody {
tr:nth-child(even) {
background-color: rgba(241, 241, 241, 0.059);
}
td {
color: #d4eaf6;
padding: 4px 0;
}
}
}
}
}
</style>

View File

@ -0,0 +1,141 @@
<template>
<div class="full_staff_training">
<div class="title">全员培训统计</div>
<div id="main6" />
</div>
</template>
<script setup>
import { getFullStaffTraining } from "@/request/large_screen_data_display.js";
import { onMounted } from "vue";
import * as echarts from "echarts";
const fnGetData = async () => {
const resData = await getFullStaffTraining();
fnInitEcharts(resData.varList);
};
onMounted(() => {
fnGetData();
});
const fnInitEcharts = (data) => {
const myChart = echarts.init(document.querySelector("#main6"));
const xData = [];
const yData = [];
data.forEach((item) => {
xData.push(item.NAME);
yData.push(item.count);
});
const option = {
tooltip: {
trigger: "axis",
axisPointer: {
type: "shadow",
},
},
legend: {
data: ["各培训类型学习人数"],
top: "15",
textStyle: {
color: "#2aaef2",
},
orient: "horizontal",
},
grid: {
top: "25%",
right: "3%",
left: "10%",
bottom: "10%",
},
xAxis: {
type: "category",
data: xData,
axisLine: {
lineStyle: {
color: "rgba(255,255,255,0.12)",
},
},
axisLabel: {
show: false,
margin: 10,
color: "#e2e9ff",
},
},
yAxis: {
name: "",
nameTextStyle: {
color: "#fff",
},
axisLabel: {
formatter: "{value}",
color: "#e2e9ff",
},
axisLine: {
show: false,
},
splitLine: {
lineStyle: {
color: "rgba(255,255,255,0.12)",
},
},
},
series: [
{
name: "各培训类型学习数",
type: "bar",
data: yData,
barWidth: "10px",
itemStyle: {
normal: {
color: new echarts.graphic.LinearGradient(
0,
0,
0,
1,
[
{
offset: 0,
color: "#4abd91", // 0%
},
{
offset: 1,
color: "#28b2d5", // 100%
},
],
false
),
},
},
},
],
};
myChart.setOption(option);
};
</script>
<style scoped lang="scss">
.full_staff_training {
margin-top: 15px;
background-image: url("/src/assets/images/bi/R-2.png");
background-size: 100% 100%;
background-repeat: no-repeat;
width: 100%;
height: 190px;
position: relative;
display: flex;
flex-direction: column;
justify-content: space-between;
.title {
color: #34dcfc;
font-size: 16px;
position: absolute;
top: -8px;
left: 0;
}
#main6 {
width: 100%;
height: 100%;
}
}
</style>

View File

@ -0,0 +1,82 @@
<template>
<div class="header">
<div class="date">
<span> {{ dayjs(now).format("YYYY-MM-DD") }}</span>
<span class="pl-10">{{ dayjs(now).format("HH:mm:ss") }}</span>
<span class="pl-10"> {{ weekList[dayjs(now).day()] }}</span>
</div>
<div class="title" />
<div class="options">
<div @click="router.push({ path: 'BI' })">
<icon-world theme="outline" size="18" fill="#2aa7d3" />
<span class="ml-5">地图</span>
</div>
<div class="ml-20" @click="router.back()">
<icon-logout theme="outline" size="18" fill="#2aa7d3" />
<span class="ml-5" style="vertical-align: center">退出</span>
</div>
<div class="ml-20">
<div v-if="!isFullscreen" @click="enter">
<icon-full-screen-one theme="outline" size="18" fill="#2aa7d3" />
<span class="ml-5">全屏</span>
</div>
<div v-else @click="exit">
<icon-off-screen theme="outline" size="18" fill="#2aa7d3" />
<span class="ml-5">退出全屏</span>
</div>
</div>
</div>
</div>
</template>
<script setup>
import dayjs from "dayjs";
import { useFullscreen, useNow } from "@vueuse/core";
import { useRouter } from "vue-router";
const router = useRouter();
const { now } = useNow({ controls: true });
const { isFullscreen, exit, enter } = useFullscreen();
const weekList = {
0: "星期日",
1: "星期一",
2: "星期二",
3: "星期三",
4: "星期四",
5: "星期五",
6: "星期六",
};
</script>
<style scoped lang="scss">
.header {
position: relative;
color: #2aa7d3;
.title {
background-image: url("/src/assets/images/bi/title.png");
background-size: 100% 100%;
background-repeat: no-repeat;
width: 1436px;
height: 164px;
margin: auto;
}
.date {
position: absolute;
}
.options {
position: absolute;
top: 0;
right: 0;
display: flex;
div {
cursor: pointer;
display: flex;
align-items: flex-start;
}
}
}
</style>

View File

@ -0,0 +1,179 @@
<template>
<div class="hidden_danger_situation">
<div class="title">隐患情况统计</div>
<div id="main5" />
</div>
</template>
<script setup>
import { getHiddenCount } from "@/request/large_screen_data_display.js";
import { onMounted } from "vue";
import * as echarts from "echarts";
const fnGetData = async () => {
const resData = await getHiddenCount();
fnInitEcharts(resData);
};
onMounted(() => {
fnGetData();
});
const fnInitEcharts = (data) => {
const myChart = echarts.init(document.querySelector("#main5"));
const colorList = ["#f6f644", "#ea5514", "#00b6ce", "#33ff00"];
const option = {
title: {
text: "",
textStyle: {
fontSize: 12,
fontWeight: 400,
color: "#2aaef2",
},
left: "0",
top: "5%",
},
legend: {
icon: "rect",
top: "5%",
right: "5%",
itemWidth: 12,
itemHeight: 12,
itemGap: 20,
textStyle: {
color: "#2aaef2",
},
},
tooltip: {
trigger: "axis",
},
grid: {
top: "25%",
bottom: "20%",
left: "7%",
right: "5%",
},
xAxis: [
{
type: "category",
data: data.names,
axisLine: {
lineStyle: {
color: "#DCE2E8",
},
},
axisTick: {
show: false,
},
axisLabel: {
interval: 0,
textStyle: {
color: "#fff",
},
fontSize: 12,
margin: 15,
},
boundaryGap: false,
},
],
yAxis: [
{
type: "value",
axisTick: {
show: false,
},
axisLine: {
show: true,
lineStyle: {
color: "#DCE2E8",
},
},
axisLabel: {
textStyle: {
color: "#fff",
},
},
splitLine: {
show: false,
},
},
],
series: [
{
name: "隐患总数",
type: "line",
data: data.all,
smooth: true,
itemStyle: {
normal: {
color: colorList[0],
borderColor: colorList[0],
},
},
},
{
name: "未整改隐患数",
type: "line",
data: data.wzg,
smooth: true,
itemStyle: {
normal: {
color: colorList[1],
borderColor: colorList[1],
},
},
},
{
name: "已整改隐患数",
type: "line",
data: data.yzg,
smooth: true,
itemStyle: {
normal: {
color: colorList[2],
borderColor: colorList[2],
},
},
},
{
name: "已验收隐患数",
type: "line",
data: data.yys,
smooth: true,
itemStyle: {
normal: {
color: colorList[3],
borderColor: colorList[3],
},
},
},
],
};
myChart.setOption(option);
};
</script>
<style scoped lang="scss">
.hidden_danger_situation {
background-image: url("/src/assets/images/bi/R-1.png");
background-size: 100% 100%;
background-repeat: no-repeat;
width: 100%;
height: 190px;
position: relative;
display: flex;
flex-direction: column;
justify-content: space-between;
.title {
color: #34dcfc;
font-size: 16px;
position: absolute;
top: -8px;
left: 0;
}
#main5 {
width: 100%;
height: 100%;
}
}
</style>

View File

@ -0,0 +1,120 @@
<template>
<div class="risk_management">
<div class="title">风险管控统计分析</div>
<div class="round-box">
<div class="content">
<h1>{{ info.unitcount }}</h1>
<span>风险点单元</span>
</div>
<div class="round-jt" />
<div class="content">
<h1>{{ info.idcount }}</h1>
<span>辨识部位</span>
</div>
<div class="round-jt" />
<div class="content">
<h1>
{{ info.acount + info.bcount + info.ccount + info.dcount }}
</h1>
<span>存在风险</span>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
import { getRiskManagement } from "@/request/large_screen_data_display.js";
const info = ref({
unitcount: 0,
idcount: 0,
acount: 0,
bcount: 0,
ccount: 0,
dcount: 0,
});
const fnGetData = async () => {
const resData = await getRiskManagement();
if (resData.idAll && resData.idAll.length > 0)
info.value.idcount = resData.idAll.length;
if (resData.unitAll && resData.unitAll.length > 0)
info.value.unitcount = resData.unitAll.length;
const key = {
levelA: "acount",
levelB: "bcount",
levelC: "ccount",
levelD: "dcount",
};
resData.riskAll.forEach((item) => {
info.value[key[item.LEVELID]] = item.COUNT;
});
};
fnGetData();
</script>
<style scoped lang="scss">
.risk_management {
background-image: url("/src/assets/images/bi/L-1.png");
background-size: 100% 100%;
background-repeat: no-repeat;
width: 100%;
height: 185px;
position: relative;
display: flex;
align-items: center;
justify-content: center;
.title {
color: #34dcfc;
font-size: 16px;
position: absolute;
top: -8px;
left: 0;
}
.round-box {
padding: 15px 0;
display: flex;
align-items: center;
justify-content: center;
.content {
background-image: url("/src/assets/images/bi/yuanl.png");
background-size: 100% 100%;
background-repeat: no-repeat;
width: 97px;
height: 97px;
text-align: center;
position: relative;
h1 {
padding-top: 25px;
color: #70c5ff;
font-size: 20px;
}
span {
display: inline-block;
width: 100%;
color: #aaddff;
font-size: 12px;
position: absolute;
bottom: -19px;
left: 50%;
transform: translateX(-50%);
}
}
.round-jt {
background-image: url("/src/assets/images/bi/jt-right.png");
background-size: 100% 100%;
background-repeat: no-repeat;
width: 20px;
height: 29px;
margin: 0 18px;
}
}
}
</style>

View File

@ -0,0 +1,126 @@
<template>
<div class="situation">
<div class="title">双重预防建设情况</div>
<div class="map"></div>
<div class="statistics">
<div class="item">
<div>
<img src="/src/assets/images/bi/faxianico.png" alt="" />
</div>
<div>
<span>{{ info.all }}</span>
<span>发现隐患数</span>
</div>
</div>
<div class="item">
<div>
<img src="/src/assets/images/bi/noonico.png" alt="" />
</div>
<div>
<span>{{ info.wzg }}</span>
<span>未完成整改隐患</span>
</div>
</div>
<div class="item">
<div>
<img src="/src/assets/images/bi/yinhuan.png" alt="" />
</div>
<div>
<span>
{{
info.all !== 0 ? ((info.wzg / info.all) * 100).toFixed(2) : 0.0
}}%
</span>
<span>未整改率</span>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
import { getHiddenCount } from "@/request/large_screen_data_display.js";
const info = ref({
all: 0,
wzg: 0,
yzg: 0,
yys: 0,
});
const fnGetData = async () => {
const resData = await getHiddenCount();
for (let i = 0; i < resData.all.length; i++) {
info.value.all += Number(resData.all[i]);
}
for (let i = 0; i < resData.wzg.length; i++) {
info.value.wzg += Number(resData.wzg[i]);
}
for (let i = 0; i < resData.yzg.length; i++) {
info.value.yzg += Number(resData.yzg[i]);
}
for (let i = 0; i < resData.yys.length; i++) {
info.value.yys += Number(resData.yys[i]);
}
};
fnGetData();
</script>
<style scoped lang="scss">
.situation {
background-image: url("/src/assets/images/bi/C-1.png");
background-size: 100% 100%;
background-repeat: no-repeat;
width: 100%;
height: 540px;
position: relative;
display: flex;
flex-direction: column;
justify-content: space-between;
.title {
color: #34dcfc;
font-size: 16px;
position: absolute;
top: -8px;
left: 0;
}
.map {
flex: 1;
}
.statistics {
margin-bottom: 10px;
display: flex;
justify-content: space-around;
.item {
flex-basis: 30%;
border: 4px solid #0d2565;
display: flex;
align-items: center;
padding: 10px;
color: #fff;
img {
width: 34px;
height: 34px;
}
div:nth-child(2) {
margin-left: 10px;
span {
display: block;
&:first-child {
color: #f8b62d;
font-size: 20px;
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,311 @@
<template>
<div class="task_processing">
<div class="title">任务处理情况</div>
<div class="tabs">
<div
v-for="(item, index) in tabsList"
:key="index"
:class="['tab', { active: index === tabsIndex }]"
@click="fnChangeTabs(index)"
>
{{ item }}
</div>
</div>
<div class="content">
<el-carousel :autoplay="false" indicator-position="none" height="182px">
<el-carousel-item v-for="item1 in 2" :key="item1">
<template v-for="(item, index) in tabsContentList" :key="index">
<div
v-if="(item1 === 1 && index < 3) || (item1 === 2 && index >= 3)"
class="item"
>
<div>
<div>
<img :src="item.img" alt="" />
</div>
<div class="item_title">{{ item.title1 }}</div>
</div>
<div>
<div>{{ item.title2 }}</div>
<div class="data">{{ item.dayUncheck }}</div>
</div>
<div>
<div>{{ item.title3 }}</div>
<div class="data">{{ item.dayChecked }}</div>
</div>
<div>
<div>{{ item.title4 }}</div>
<div class="data proportion">
<span>{{ item.proportion }}</span>
<span>%</span>
</div>
</div>
</div>
</template>
</el-carousel-item>
</el-carousel>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
import {
getTaskProcessingCheck,
getTaskProcessingHidden,
} from "@/request/large_screen_data_display.js";
const tabsList = ["隐患处理", "日常检查"];
const tabsIndex = ref(0);
const hiddenDangersList = ref([
{
img: new URL("/src/assets/images/bi/ri.png", import.meta.url).href,
title1: "本日隐患",
title2: "待处理",
title3: "已处理",
title4: "隐患整改率",
dayChecked: 0,
dayUncheck: 0,
proportion: 0,
},
{
img: new URL("/src/assets/images/bi/ri2.png", import.meta.url).href,
title1: "本周隐患",
title2: "待处理",
title3: "已处理",
title4: "隐患整改率",
dayChecked: 0,
dayUncheck: 0,
proportion: 0,
},
{
img: new URL("/src/assets/images/bi/ri3.png", import.meta.url).href,
title1: "本旬隐患",
title2: "待处理",
title3: "已处理",
title4: "隐患整改率",
dayChecked: 0,
dayUncheck: 0,
proportion: 0,
},
{
img: new URL("/src/assets/images/bi/ri4.png", import.meta.url).href,
title1: "本月隐患",
title2: "待处理",
title3: "已处理",
title4: "隐患整改率",
dayChecked: 0,
dayUncheck: 0,
proportion: 0,
},
{
img: new URL("/src/assets/images/bi/ri5.png", import.meta.url).href,
title1: "本季隐患",
title2: "待处理",
title3: "已处理",
title4: "隐患整改率",
dayChecked: 0,
dayUncheck: 0,
proportion: 0,
},
{
img: new URL("/src/assets/images/bi/ri6.png", import.meta.url).href,
title1: "本年隐患",
title2: "待处理",
title3: "已处理",
title4: "隐患整改率",
dayChecked: 0,
dayUncheck: 0,
proportion: 0,
},
]);
const dailyInspectionList = ref([
{
img: new URL("/src/assets/images/bi/ri.png", import.meta.url).href,
title1: "本日应检查",
title2: "待检查",
title3: "已检查",
title4: "本日完成率",
dayChecked: 0,
dayUncheck: 0,
proportion: 0,
},
{
img: new URL("/src/assets/images/bi/ri2.png", import.meta.url).href,
title1: "本周应检查",
title2: "待检查",
title3: "已检查",
title4: "本周完成率",
dayChecked: 0,
dayUncheck: 0,
proportion: 0,
},
{
img: new URL("/src/assets/images/bi/ri3.png", import.meta.url).href,
title1: "本旬应检查",
title2: "待检查",
title3: "已检查",
title4: "本旬完成率",
dayChecked: 0,
dayUncheck: 0,
proportion: 0,
},
{
img: new URL("/src/assets/images/bi/ri4.png", import.meta.url).href,
title1: "本月应检查",
title2: "待检查",
title3: "已检查",
title4: "本月完成率",
dayChecked: 0,
dayUncheck: 0,
proportion: 0,
},
{
img: new URL("/src/assets/images/bi/ri5.png", import.meta.url).href,
title1: "本季应检查",
title2: "待检查",
title3: "已检查",
title4: "本季完成率",
dayChecked: 0,
dayUncheck: 0,
proportion: 0,
},
{
img: new URL("/src/assets/images/bi/ri6.png", import.meta.url).href,
title1: "本年应检查",
title2: "待检查",
title3: "已检查",
title4: "本年完成率",
dayChecked: 0,
dayUncheck: 0,
proportion: 0,
},
]);
const tabsContentList = ref(hiddenDangersList.value);
const fnChangeTabs = (index) => {
tabsIndex.value = index;
tabsContentList.value =
index === 0 ? hiddenDangersList.value : dailyInspectionList.value;
};
const fnGetDataHidden = async () => {
const key = {
0: "IS_DAY",
1: "IS_WEEK",
2: "IS_XUN",
3: "IS_MONTH",
4: "IS_QUARTER",
5: "IS_YEAR",
};
for (const keyKey in key) {
const resData = await getTaskProcessingHidden({ [key[keyKey]]: 1 });
hiddenDangersList.value[keyKey].dayChecked = resData.checked;
hiddenDangersList.value[keyKey].dayUncheck = resData.uncheck;
hiddenDangersList.value[keyKey].proportion =
resData.total === 0
? 0
: ((resData.checked / resData.total) * 100).toFixed(2);
}
};
fnGetDataHidden();
const fnGetDataCheck = async () => {
const key = {
0: "day",
1: "week",
2: "xun",
3: "month",
4: "quarter",
5: "year",
};
for (const keyKey in key) {
const resData = await getTaskProcessingCheck({ COUNTTYPE: key[keyKey] });
dailyInspectionList.value[keyKey].dayUncheck =
resData.all.denominator - resData.all.molecule;
dailyInspectionList.value[keyKey].dayChecked = resData.all.molecule;
dailyInspectionList.value[keyKey].proportion = resData.all.percentage;
}
};
fnGetDataCheck();
</script>
<style scoped lang="scss">
.task_processing {
margin-top: 15px;
background-image: url("/src/assets/images/bi/L-4.png");
background-size: 100% 100%;
background-repeat: no-repeat;
width: 100%;
height: 236px;
position: relative;
.title {
color: #34dcfc;
font-size: 16px;
position: absolute;
top: -8px;
left: 0;
}
.tabs {
display: flex;
justify-content: end;
padding-top: 20px;
.tab {
width: 116px;
height: 26px;
line-height: 26px;
text-align: center;
color: #fff;
cursor: pointer;
background-image: url("/src/assets/images/bi/tab-1.png");
background-size: 100% 100%;
background-repeat: no-repeat;
&:nth-child(2) {
margin-left: 15px;
margin-right: 15px;
}
&.active {
background-image: url("/src/assets/images/bi/tab-2.png");
}
}
}
.content {
padding: 0 20px 20px 20px;
color: #aaddff;
.item {
display: flex;
align-items: center;
justify-content: space-between;
text-align: center;
border-bottom: 1px solid #1e3677;
padding: 7px 0;
&:last-child {
border-bottom: none;
}
img {
width: 27px;
height: 27px;
}
.data {
padding-top: 7px;
font-size: 20px;
&.proportion {
color: #ffb956;
span:last-child {
font-size: 14px;
}
}
}
}
}
}
</style>

View File

@ -0,0 +1,205 @@
<template>
<div class="troubleshooting_type">
<div class="title">排查类型</div>
<div class="p-20">
<div class="top">
<div>
<div>现场类清单数</div>
<div>{{ info["现场清单"] || 0 }}</div>
</div>
<div>
<div>基础类清单数</div>
<div>{{ info["基础类清单"] || 0 }}</div>
</div>
<div>
<div>综合类清单数</div>
<div>{{ info["综合类清单"] || 0 }}</div>
</div>
</div>
<div class="bottom">
<div>
<div class="dunpai1" />
<div class="bottom_title">现场排查数</div>
<div id="main1" />
</div>
<div>
<div class="dunpai2" />
<div class="bottom_title">基础排查数</div>
<div id="main2" />
</div>
<div>
<div class="dunpai3" />
<div class="bottom_title">综合排查数</div>
<div id="main3" />
</div>
</div>
</div>
</div>
</template>
<script setup>
import { onMounted, ref } from "vue";
import {
getTroubleshootingTypeEcharts,
getTroubleshootingTypeNumber,
} from "@/request/large_screen_data_display.js";
import { sumBy } from "lodash-es";
import { arrayObjectDeduplication } from "@/assets/js/utils.js";
import * as echarts from "echarts";
const info = ref({});
const fnGetData = async () => {
const resDataNumber = await getTroubleshootingTypeNumber();
resDataNumber.typeList.forEach((item) => {
info.value[item.NAME] = item.count;
});
const resDataEcharts = await getTroubleshootingTypeEcharts();
const total = sumBy(resDataEcharts.typeList, (item) => item.count);
const key = {
现场清单: { color: "#ec2c26", el: "#main1" },
基础类清单: { color: "#ea4e26", el: "#main2" },
综合类清单: { color: "#ea6e27", el: "#main3" },
};
const typeList = [
...resDataEcharts.typeList,
{ count: 0, NAME: "现场清单" },
{ count: 0, NAME: "基础类清单" },
{ count: 0, NAME: "综合类清单" },
];
arrayObjectDeduplication(typeList, "NAME").forEach((item) => {
fnInitEcharts(item.count, total, key[item.NAME].color, key[item.NAME].el);
});
};
onMounted(() => {
fnGetData();
});
const fnInitEcharts = (count, total, color, el) => {
const myChart = echarts.init(document.querySelector(el));
const option = {
grid: {
left: "10%",
right: "0%",
bottom: "0%",
top: "100%",
containLabel: true,
},
xAxis: {
show: false,
type: "value",
},
yAxis: {
type: "category",
show: false,
},
series: [
{
name: "次数",
type: "bar",
zlevel: 1,
itemStyle: {
normal: {
barBorderRadius: 0,
color,
},
},
label: {
show: true,
position: "inside",
},
barWidth: 15,
data: [count],
},
{
name: "背景",
type: "bar",
barWidth: 15,
barGap: "-100%",
data: [total],
itemStyle: {
normal: {
color: "#101f48",
barBorderRadius: 0,
},
},
},
],
};
myChart.setOption(option);
};
</script>
<style scoped lang="scss">
.troubleshooting_type {
margin-top: 15px;
background-image: url("/src/assets/images/bi/L-2.png");
background-size: 100% 100%;
background-repeat: no-repeat;
width: 100%;
height: 190px;
position: relative;
.title {
color: #34dcfc;
font-size: 16px;
position: absolute;
top: -8px;
left: 0;
}
.top {
display: flex;
justify-content: space-between;
> div {
flex-basis: 32%;
border: 4px solid #0d2565;
padding: 5px 20px 5px 5px;
div:nth-child(1) {
color: #fff;
}
div:nth-child(2) {
color: #04cbfd;
text-align: right;
padding-top: 5px;
font-size: 18px;
}
}
}
.bottom {
color: #fff;
> div {
margin-top: 10px;
display: flex;
align-items: center;
justify-content: space-between;
.bottom_title {
width: max-content;
}
@for $i from 1 through 3 {
.dunpai#{$i} {
background-image: url("/src/assets/images/bi/dunpai#{$i}.png");
background-size: 100% 100%;
background-repeat: no-repeat;
width: 18px;
height: 20px;
margin-right: 10px;
}
}
#main1,
#main2,
#main3 {
flex: 1;
height: 20px;
}
}
}
}
</style>

View File

@ -0,0 +1,131 @@
<template>
<div class="user_usage">
<div class="title">企业排查情况</div>
<div class="content">
<div>
<div>企业人员数</div>
<div>
<span>{{ info.workUser }}/{{ info.allUser }}</span>
<span></span>
</div>
<div>
<span>使用率</span>
<span>
{{
info.allUser !== 0
? ((info.workUser / info.allUser) * 100).toFixed(2)
: 0.0
}}%
</span>
</div>
</div>
<div>
<div>部门</div>
<div>
<span>{{ info.workDep }}/{{ info.allDep }}</span>
<span></span>
</div>
<div>
<span>使用率</span>
<span>
{{
info.allDep !== 0
? ((info.workDep / info.allDep) * 100).toFixed(2)
: 0.0
}}%
</span>
</div>
</div>
<div>
<div>清单</div>
<div>
<span>{{ info.workList }}/{{ info.allList }}</span>
<span></span>
</div>
<div>
<span>使用率</span>
<span>
{{
info.allList !== 0
? ((info.workList / info.allList) * 100).toFixed(2)
: 0.0
}}%
</span>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
import { getUserUsage } from "@/request/large_screen_data_display.js";
const info = ref({});
const fnGetData = async () => {
const resData = await getUserUsage();
info.value.allUser = resData.allUser;
info.value.workUser = resData.workUser;
info.value.allDep = resData.allDep;
info.value.workDep = resData.workDep;
info.value.allList = resData.allList;
info.value.workList = resData.workList;
};
fnGetData();
</script>
<style scoped lang="scss">
.user_usage {
margin-top: 15px;
background-image: url("/src/assets/images/bi/L-3.png");
background-size: 100% 100%;
background-repeat: no-repeat;
width: 100%;
height: 108px;
position: relative;
.title {
color: #34dcfc;
font-size: 16px;
position: absolute;
top: -8px;
left: 0;
}
.content {
padding: 20px;
display: flex;
justify-content: space-between;
color: #fff;
> div {
flex-basis: 32%;
background-color: #061e55;
padding: 5px 15px;
div {
padding-top: 5px;
&:first-child {
padding: 0;
}
}
div:nth-child(2) {
span:nth-child(1) {
color: #f8b62d;
padding-right: 5px;
}
}
div:nth-child(3) {
span:nth-child(2) {
color: #f8b62d;
padding-left: 5px;
}
}
}
}
}
</style>

View File

@ -0,0 +1,97 @@
<template>
<div class="video_center">
<div class="title">视频中心</div>
<div class="tabs">
<div
v-for="(item, index) in tabsList"
:key="index"
:class="['tab', { active: index === tabsIndex }]"
@click="tabsIndex = index"
>
{{ item }}
</div>
</div>
<div class="video">
<ali-player
:source="VITE_FILE_URL + ptVideoSrc"
v-if="tabsIndex === 0 && ptVideoSrc"
height="182px"
/>
<ali-player
:source="VITE_FILE_URL + cpVideoSrc"
v-if="tabsIndex === 1 && cpVideoSrc"
height="182px"
/>
</div>
</div>
</template>
<script setup>
import { ref } from "vue";
import { getVideo } from "@/request/large_screen_data_display.js";
import AliPlayer from "@/components/ali-player/index.vue";
const VITE_FILE_URL = import.meta.env.VITE_FILE_URL;
const tabsList = ["平台视频", "企业视频"];
const tabsIndex = ref(0);
const ptVideoSrc = ref("");
const cpVideoSrc = ref("");
const fnGetData = async () => {
const resData = await getVideo();
ptVideoSrc.value = resData.ptVarList?.[0]?.FILEPATH;
cpVideoSrc.value = resData.cpvarList?.[0]?.FILEPATH;
};
fnGetData();
</script>
<style scoped lang="scss">
.video_center {
margin-top: 15px;
background-image: url("/src/assets/images/bi/C-3.png");
background-size: 100% 100%;
background-repeat: no-repeat;
width: 100%;
height: 212px;
position: relative;
.title {
color: #34dcfc;
font-size: 16px;
position: absolute;
top: -8px;
left: 0;
}
.tabs {
display: flex;
position: absolute;
top: -8px;
right: 20px;
.tab {
width: 95px;
height: 19px;
line-height: 19px;
text-align: center;
color: #fff;
cursor: pointer;
background-image: url("/src/assets/images/bi/558.png");
background-size: 100% 100%;
background-repeat: no-repeat;
&.active {
background-image: url("/src/assets/images/bi/559.png");
}
}
}
.video {
width: 95%;
height: 100%;
margin: auto;
display: flex;
align-items: center;
justify-content: center;
}
}
</style>

View File

@ -0,0 +1,88 @@
<template>
<div class="main_container p-20" id="main_container">
<header-view />
<div class="main_content">
<div class="left">
<risk-management />
<troubleshooting-type />
<user-usage />
<task-processing />
</div>
<div class="center">
<situation />
<div class="flex">
<assignment-type class="mr-5" />
<video-center class="ml-5" />
</div>
</div>
<div class="right">
<hidden-danger-situation />
<full-staff-training />
<exam-statistics />
</div>
</div>
</div>
</template>
<script setup>
import { onBeforeUnmount, onMounted } from "vue";
import autofit from "autofit.js";
import HeaderView from "./components/header.vue";
import RiskManagement from "./components/risk_management.vue";
import TroubleshootingType from "./components/troubleshooting_type.vue";
import UserUsage from "./components/user_usage.vue";
import TaskProcessing from "./components/task_processing.vue";
import Situation from "./components/situation.vue";
import AssignmentType from "./components/assignment_type.vue";
import videoCenter from "./components/video_center.vue";
import HiddenDangerSituation from "./components/hidden_danger_situation.vue";
import FullStaffTraining from "./components/full_staff_training.vue";
import ExamStatistics from "./components/exam_statistics.vue";
onMounted(() => {
autofit.init({
dh: document.querySelector("#main_container").offsetHeight,
dw: 1920,
el: "#main_container",
resize: true,
});
});
onBeforeUnmount(() => {
autofit.off();
});
</script>
<style scoped lang="scss">
.main_container {
background-image: url("/src/assets/images/bi/bg.jpg");
background-size: 100% 100%;
background-repeat: no-repeat;
width: 100%;
height: 100vh;
font-size: 14px;
.main_content {
margin-top: -50px;
display: flex;
.left {
flex-basis: 25%;
}
.center {
flex-basis: 50%;
margin-left: 15px;
margin-right: 15px;
.flex {
display: flex;
justify-content: space-between;
}
}
.right {
flex-basis: 25%;
}
}
}
</style>