124
This commit is contained in:
121
src/views/StationLevel/index.vue
Normal file
121
src/views/StationLevel/index.vue
Normal file
@ -0,0 +1,121 @@
|
||||
<template>
|
||||
<div class="homeBox" @click="handless">
|
||||
<Head :title="query.name" :query="query.name"></Head>
|
||||
<div class="mainBox_jcz hidden flex">
|
||||
<ul class="asideBox">
|
||||
<li class="asideItem" v-for="(item, idx) in meun.leftMeun" :key="idx">
|
||||
<div class="title">{{ item }}</div>
|
||||
<div class="asideCnt" @click="handless">
|
||||
<PeoCollection
|
||||
:jczId="query.id"
|
||||
v-if="item == '人员数据采集'"
|
||||
></PeoCollection>
|
||||
<PlowStatistics
|
||||
:jczId="query.id"
|
||||
v-if="item == '流入流出统计'"
|
||||
></PlowStatistics>
|
||||
<WarningCount
|
||||
:jczId="query.id"
|
||||
v-if="item == '预警统计'"
|
||||
></WarningCount>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="mainBox">
|
||||
<div class="main-top"><VideoMore></VideoMore></div>
|
||||
<div class="main-bottom"><VideoFoot></VideoFoot></div>
|
||||
</div>
|
||||
<ul class="asideBox">
|
||||
<li class="asideItem" v-for="(item, idx) in meun.rightMeun" :key="idx">
|
||||
<div class="title">{{ item }}</div>
|
||||
<div class="asideCnt">
|
||||
<BeOnDuty :jczId="query.id" v-if="item == '值班备勤'"></BeOnDuty>
|
||||
<CarWarning
|
||||
:jczId="query.id"
|
||||
v-if="item == '车辆预警'"
|
||||
></CarWarning>
|
||||
<PeoWarning
|
||||
:jczId="query.id"
|
||||
v-if="item == '人员预警'"
|
||||
></PeoWarning>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import Head from "@/views/home/layout/head.vue";
|
||||
import PeoCollection from "./layout/PeoCollection.vue";
|
||||
import PlowStatistics from "./layout/FlowStatistics.vue";
|
||||
import WarningCount from "./layout/WarningCount.vue";
|
||||
import BeOnDuty from "./layout/BeOnDuty.vue";
|
||||
import CarWarning from "./layout/CarWarning.vue";
|
||||
import PeoWarning from "./layout/PeoWarning.vue";
|
||||
import VideoMore from "./layout/VideoMore.vue";
|
||||
import VideoFoot from "./layout/VideoFoot.vue";
|
||||
import { useRoute } from "vue-router";
|
||||
import { ref, onMounted, onUnmounted, reactive, computed } from "vue";
|
||||
const router = useRoute();
|
||||
const meun = reactive({
|
||||
leftMeun: ["人员数据采集", "流入流出统计", "预警统计"],
|
||||
rightMeun: ["值班备勤", "车辆预警", "人员预警"]
|
||||
});
|
||||
const query = computed(() => {
|
||||
return router.query;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.homeBox {
|
||||
background: #000;
|
||||
}
|
||||
.mainBox_jcz {
|
||||
position: absolute;
|
||||
top: 65px;
|
||||
width: 100%;
|
||||
height: calc(100vh - 60px);
|
||||
background: #000;
|
||||
.asideBox {
|
||||
width: 420px;
|
||||
height: 100%;
|
||||
.asideItem {
|
||||
height: calc(100% / 3);
|
||||
background: url("~@/assets/images/bg12.png") no-repeat;
|
||||
background-size: 100% 100%;
|
||||
padding: 0 10px;
|
||||
box-sizing: border-box;
|
||||
.title {
|
||||
height: 50px;
|
||||
line-height: 50px;
|
||||
padding-left: 20px;
|
||||
font-size: 20px;
|
||||
font-family: "YSBTH";
|
||||
background: linear-gradient(0deg, #59a6f4 0%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
.asideCnt {
|
||||
height: calc(100% - 50px);
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
.mainBox {
|
||||
flex: 1 0 0;
|
||||
margin: 10px;
|
||||
.main-top {
|
||||
background: url("~@/assets/images/bg_13.png") no-repeat;
|
||||
background-size: 100% 100%;
|
||||
height: 70%;
|
||||
}
|
||||
.main-bottom {
|
||||
height: 30%;
|
||||
background: url("~@/assets/images/bg_14.png") no-repeat;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
229
src/views/StationLevel/layout/BeOnDuty.vue
Normal file
229
src/views/StationLevel/layout/BeOnDuty.vue
Normal file
@ -0,0 +1,229 @@
|
||||
<template>
|
||||
<div class="warning-container">
|
||||
<!-- 标签切换 -->
|
||||
<div class="tab-container">
|
||||
<div
|
||||
class="tab-item"
|
||||
@click="showchenge(1)"
|
||||
:class="{ active: show == 1 }"
|
||||
>
|
||||
<div class="tab-content">值班人员</div>
|
||||
</div>
|
||||
<div
|
||||
class="tab-item"
|
||||
@click="showchenge(2)"
|
||||
:class="{ active: show == 2 }"
|
||||
>
|
||||
<div class="tab-content">值班装备</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 预警列表 -->
|
||||
<div class="warning-list" v-if="show == 2 && warningList">
|
||||
<div class="warning-card">
|
||||
<div class="title flex align-center">
|
||||
<img src="@/assets/images/icon_06.png" alt="" />
|
||||
值班装备
|
||||
</div>
|
||||
<div
|
||||
class="cardItem flex"
|
||||
v-for="(item, index) in warningList.qxList"
|
||||
:key="index"
|
||||
>
|
||||
<span style="flex: 1">名称:{{ item.qxmc }}</span>
|
||||
<span style="flex: 1">数量:{{ item.qxsl }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="line mt6 mb6"></div>
|
||||
<div class="warning-card">
|
||||
<div class="title flex align-center">
|
||||
<img src="@/assets/images/icon_06.png" alt="" /> 值班车辆
|
||||
</div>
|
||||
<div
|
||||
class="cardItem"
|
||||
v-for="(item, index) in warningList.clList"
|
||||
:key="index"
|
||||
>
|
||||
车牌号:{{ item.cph }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Empty :show="warningList == null && show == 2" />
|
||||
<div class="warning-list" v-if="show == 1 && warningList">
|
||||
<div class="warning-card">
|
||||
<div class="title flex align-center">
|
||||
<img src="@/assets/images/icon_06.png" alt="" />
|
||||
值班人员
|
||||
</div>
|
||||
<div
|
||||
class="cardItem flex"
|
||||
v-for="(item, index) in warningList.ryList"
|
||||
:key="index"
|
||||
>
|
||||
<span style="flex: 1">名称:{{ item.ryXm }}</span>
|
||||
<span style="flex: 1"
|
||||
>警种:{{ item.ryJzlx == "01" ? "民警" : "辅警" }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<div class="line mt6 mb6"></div>
|
||||
</div>
|
||||
<Empty :show="warningList == null && show == 1" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
import Empty from "@/components/MyComponents/Empty/index.vue";
|
||||
import { jczqueryById } from "@/api/mosty-jcz";
|
||||
import emitter from "@/utils/eventBus.js";
|
||||
const warningList = ref({ qxList: [], ryList: [], clList: [] });
|
||||
|
||||
const show = ref(1);
|
||||
const props = defineProps({
|
||||
jczId: {
|
||||
type: String,
|
||||
default: ""
|
||||
}
|
||||
});
|
||||
const showchenge = (val) => {
|
||||
show.value = val;
|
||||
getjczqueryById();
|
||||
};
|
||||
|
||||
const getjczqueryById = () => {
|
||||
jczqueryById({ jczid: props.jczId }).then((res) => {
|
||||
if (res) {
|
||||
emitter.emit("chengZ", res);
|
||||
warningList.value.qxList = res.qxList
|
||||
? res.qxList.filter((item) => item.qxsl > 0)
|
||||
: [];
|
||||
warningList.value.ryList = res.ryList ? res.ryList : [];
|
||||
warningList.value.clList = res.clList ? res.clList : [];
|
||||
} else {
|
||||
warningList.value = res;
|
||||
}
|
||||
});
|
||||
};
|
||||
getjczqueryById();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.warning-container {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.tab-container {
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
width: 150px;
|
||||
height: 38px;
|
||||
text-align: center;
|
||||
line-height: 24px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
padding: 8px 30px;
|
||||
color: #fff;
|
||||
font-size: 16px;
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.tab-item::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: url("~@/assets/images/bg_08.png") no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
.tab-item.active::before {
|
||||
background: url("~@/assets/images/bg_09.png") no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
.warning-list {
|
||||
height: calc(100% - 50px);
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
padding: 4px 10px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.warning-card {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
// justify-content: space-between;
|
||||
.cardItem {
|
||||
height: 27px;
|
||||
line-height: 27px;
|
||||
margin-bottom: 5px;
|
||||
background: url("~@/assets/images/bg_12.png") no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
padding: 0 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
}
|
||||
.line {
|
||||
width: 100%;
|
||||
height: 3px;
|
||||
background: url("~@/assets/images/line.png") no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
|
||||
.warning-image {
|
||||
width: 100px;
|
||||
height: 80px;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.warning-image img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.warning-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
margin-bottom: 4px;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.highlight {
|
||||
color: #00f0ff;
|
||||
}
|
||||
|
||||
.tag {
|
||||
background: rgba(250, 177, 21, 0.9);
|
||||
color: #fff;
|
||||
padding: 2px 8px;
|
||||
border-radius: 2px;
|
||||
font-size: 12px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
149
src/views/StationLevel/layout/CarWarning.vue
Normal file
149
src/views/StationLevel/layout/CarWarning.vue
Normal file
@ -0,0 +1,149 @@
|
||||
<template>
|
||||
<div
|
||||
class="waning-cards noScollLine"
|
||||
v-infinite-scroll="rollingLoading"
|
||||
v-loading="loading"
|
||||
>
|
||||
<div
|
||||
class="warning-card"
|
||||
v-for="(item, index) in warningList.data"
|
||||
:key="index"
|
||||
>
|
||||
<div class="warning-image">
|
||||
<img :src="item.yjTp" alt="预警图片" />
|
||||
</div>
|
||||
<div class="warning-info">
|
||||
<div class="info-item">
|
||||
<span class="label">车牌号:</span>
|
||||
<span>{{ item.yjClcph }}</span>
|
||||
<span class="tag">{{ item.yjBt }}</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">相似度:</span>
|
||||
<span class="highlight">{{ item.xsd }}%</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">预警时间:</span>
|
||||
<span>{{ item.yjSj }}</span>
|
||||
</div>
|
||||
<div class="info-item flex align-center">
|
||||
<span class="label nowrap">抓拍地址:</span>
|
||||
<span class="one_text_detail">{{ item.yjDz }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Empty :show="warningList.data.length == 0" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref, getCurrentInstance } from "vue";
|
||||
import { jczgetPageList } from "@/api/mosty-jcz.js";
|
||||
import Empty from "@/components/MyComponents/Empty/index.vue";
|
||||
const props = defineProps({
|
||||
jczId: {
|
||||
type: String,
|
||||
default: ""
|
||||
}
|
||||
});
|
||||
const warningList = reactive({
|
||||
data: [],
|
||||
total: 0
|
||||
});
|
||||
const loading = ref(false);
|
||||
const linkQuery = ref({
|
||||
yjLx: 2,
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
jczid: props.jczId
|
||||
});
|
||||
// 获取预警数据
|
||||
const getPageList = () => {
|
||||
loading.value = true;
|
||||
jczgetPageList(linkQuery.value)
|
||||
.then((res) => {
|
||||
warningList.data =
|
||||
linkQuery.value.pageNum == 1
|
||||
? res.records
|
||||
: warningList.data.concat(res.records);
|
||||
warningList.total = res.total;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("预警数据请求错误", err);
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
//滚动
|
||||
const rollingLoading = () => {
|
||||
if (warningList.data.length < warningList.total) {
|
||||
linkQuery.value.pageNum++;
|
||||
getPageList();
|
||||
}
|
||||
};
|
||||
getPageList();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.waning-cards {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.warning-card {
|
||||
background: url("~@/assets/images/bg_10.png") no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
margin-bottom: 4px;
|
||||
padding: 4px 4px 4px 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.warning-image {
|
||||
width: 100px;
|
||||
height: 80px;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.warning-image img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.warning-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
margin-bottom: 4px;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.highlight {
|
||||
color: #00f0ff;
|
||||
}
|
||||
|
||||
.tag {
|
||||
background: rgba(250, 177, 21, 0.2);
|
||||
border-radius: 8px;
|
||||
border: 1px solid #ffac26;
|
||||
color: #fff;
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
font-size: 12px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
118
src/views/StationLevel/layout/FlowStatistics.vue
Normal file
118
src/views/StationLevel/layout/FlowStatistics.vue
Normal file
@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<div class="flow-grid">
|
||||
<div class="flow-item">
|
||||
<div class="flow-icon">
|
||||
<img width="64" src="@/assets/images/bg_06.png" alt="" />
|
||||
</div>
|
||||
<div class="flow-info">
|
||||
<span class="flow-label">进林人员</span>
|
||||
<span class="flow-number">{{ carAccess.rlsl }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flow-item">
|
||||
<div class="flow-icon">
|
||||
<img width="64" src="@/assets/images/bg_06.png" alt="" />
|
||||
</div>
|
||||
<div class="flow-info">
|
||||
<span class="flow-label">出林人员</span>
|
||||
<span class="flow-number">{{ carAccess.clsl }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flow-item">
|
||||
<div class="flow-icon">
|
||||
<img width="64" src="@/assets/images/bg_07.png" alt="" />
|
||||
</div>
|
||||
<div class="flow-info">
|
||||
<span class="flow-label">进林车辆</span>
|
||||
<span class="flow-number">{{ personneAccess.rlsl }}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flow-item">
|
||||
<div class="flow-icon">
|
||||
<img width="64" src="@/assets/images/bg_07.png" alt="" />
|
||||
</div>
|
||||
<div class="flow-info">
|
||||
<span class="flow-label">出林车辆</span>
|
||||
<span class="flow-number">{{ personneAccess.clsl }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// 可以在这里添加需要的响应式数据和方法
|
||||
import { jczgetcountCrl, jczGzrycountCrl } from "@/api/mosty-jcz";
|
||||
import { ref } from "vue";
|
||||
const props = defineProps({
|
||||
jczId: {
|
||||
type: String,
|
||||
default: ""
|
||||
}
|
||||
});
|
||||
const personneAccess = ref({
|
||||
clsl: 0,
|
||||
rlsl: 0
|
||||
});
|
||||
const carAccess = ref({
|
||||
clsl: 0,
|
||||
rlsl: 0
|
||||
});
|
||||
|
||||
const getcountCrl = () => {
|
||||
jczgetcountCrl({ kkId: props.jczId })
|
||||
.then((res) => {
|
||||
personneAccess.value = res;
|
||||
})
|
||||
.catch((err) => {});
|
||||
};
|
||||
const GzrycountCrl = () => {
|
||||
jczGzrycountCrl({ kkId: props.jczId })
|
||||
.then((res) => {
|
||||
carAccess.value = res;
|
||||
})
|
||||
.catch((err) => {});
|
||||
};
|
||||
GzrycountCrl();
|
||||
getcountCrl();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.flow-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 22px;
|
||||
padding: 10px 10px 10px 20px;
|
||||
box-sizing: border-box;
|
||||
align-items: center;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.flow-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.flow-icon {
|
||||
font-size: 24px;
|
||||
color: #00f0ff;
|
||||
}
|
||||
|
||||
.flow-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.flow-label {
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.flow-number {
|
||||
font-size: 24px;
|
||||
color: #00f0ff;
|
||||
margin-top: 5px;
|
||||
font-family: "HANYILINGXINTIJIAN";
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
</style>
|
68
src/views/StationLevel/layout/PeoCollection.vue
Normal file
68
src/views/StationLevel/layout/PeoCollection.vue
Normal file
@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div class="peo-cards">
|
||||
<div class="stat-card">
|
||||
<div class="stat-number">{{ personnelData.rzhy }}</div>
|
||||
<div class="f14">人证核验</div>
|
||||
<div><img src="@/assets/images/bg_03.png" alt="" /></div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-number">{{ personnelData.wgtx }}</div>
|
||||
<div class="f14">无感通行</div>
|
||||
<div><img src="@/assets/images/bg_04.png" alt="" /></div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="stat-number">{{ personnelData.sczd }}</div>
|
||||
<div class="f14">手持终端登记</div>
|
||||
<div><img src="@/assets/images/bg_05.png" alt="" /></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
// 可以在这里添加需要的响应式数据和方法
|
||||
import { jczCountWay } from "@/api/mosty-jcz";
|
||||
import { ref } from "vue";
|
||||
const props = defineProps({
|
||||
jczId: {
|
||||
type: String,
|
||||
default: ""
|
||||
}
|
||||
});
|
||||
|
||||
const personnelData = ref({
|
||||
rzhy: 0,
|
||||
sczd: 0,
|
||||
wgtx: 0
|
||||
});
|
||||
|
||||
const countWay = () => {
|
||||
jczCountWay({ kkId: props.jczId })
|
||||
.then((res) => {
|
||||
personnelData.value = res;
|
||||
})
|
||||
.catch((err) => {});
|
||||
};
|
||||
countWay();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.peo-cards {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
}
|
||||
.stat-card {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.stat-number {
|
||||
font-size: 32px;
|
||||
color: #00f0ff;
|
||||
margin-bottom: 5px;
|
||||
font-family: "HANYILINGXINTIJIAN";
|
||||
letter-spacing: 2px;
|
||||
}
|
||||
</style>
|
158
src/views/StationLevel/layout/PeoWarning.vue
Normal file
158
src/views/StationLevel/layout/PeoWarning.vue
Normal file
@ -0,0 +1,158 @@
|
||||
<template>
|
||||
<div
|
||||
class="waning-cards noScollLine"
|
||||
v-infinite-scroll="rollingLoading"
|
||||
v-loading="loading"
|
||||
>
|
||||
<div
|
||||
class="warning-card"
|
||||
v-for="(item, index) in warningList.data"
|
||||
:key="index"
|
||||
>
|
||||
<div class="warning-image">
|
||||
<img :src="item.yjTp" alt="预警图片" />
|
||||
</div>
|
||||
<div class="warning-info">
|
||||
<div class="info-item">
|
||||
<span class="label">姓名:</span>
|
||||
<span>{{ item.yjRyxm }}</span>
|
||||
<span class="tag">{{ item.yjBt }}</span>
|
||||
</div>
|
||||
<div class="info-item flex">
|
||||
<span class="label">性别:</span>
|
||||
<dict-tag
|
||||
:options="D_BZ_XB"
|
||||
:value="IdCard(item.yjRysfzh, 3)"
|
||||
:tag="false"
|
||||
></dict-tag>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">相似度:</span>
|
||||
<span class="highlight">{{ item.xsd }}%</span>
|
||||
</div>
|
||||
<div class="info-item">
|
||||
<span class="label">预警时间:</span>
|
||||
<span>{{ item.yjSj }}</span>
|
||||
</div>
|
||||
<div class="info-item flex align-center">
|
||||
<span class="label nowrap">抓拍地址:</span>
|
||||
<span class="one_text_detail">{{ item.yjDz }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Empty :show="warningList.data.length == 0" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref, getCurrentInstance } from "vue";
|
||||
import { jczgetPageList } from "@/api/mosty-jcz.js";
|
||||
import { IdCard } from "@/utils/dict.js";
|
||||
import Empty from "@/components/MyComponents/Empty/index.vue";
|
||||
const props = defineProps({
|
||||
jczId: {
|
||||
type: String,
|
||||
default: ""
|
||||
}
|
||||
});
|
||||
const warningList = reactive({
|
||||
data: [],
|
||||
total: 0
|
||||
});
|
||||
const loading = ref(false);
|
||||
const linkQuery = ref({
|
||||
yjLx: 1,
|
||||
pageNum: 1,
|
||||
pageSize: 10,
|
||||
jczid: props.jczId
|
||||
});
|
||||
// 获取预警数据
|
||||
const getPageList = () => {
|
||||
loading.value = true;
|
||||
jczgetPageList(linkQuery.value)
|
||||
.then((res) => {
|
||||
warningList.data =
|
||||
linkQuery.value.pageNum == 1
|
||||
? res.records
|
||||
: warningList.data.concat(res.records);
|
||||
warningList.total = res.total;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("预警数据请求错误", err);
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
//滚动
|
||||
const rollingLoading = () => {
|
||||
if (warningList.data.length < warningList.total) {
|
||||
linkQuery.value.pageNum++;
|
||||
getPageList();
|
||||
}
|
||||
};
|
||||
getPageList();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.waning-cards {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.warning-card {
|
||||
background: url("~@/assets/images/bg_10.png") no-repeat center center;
|
||||
background-size: 100% 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
margin-bottom: 4px;
|
||||
padding: 4px 4px 4px 10px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.warning-image {
|
||||
width: 100px;
|
||||
height: 80px;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.warning-image img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.warning-info {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.info-item {
|
||||
margin-bottom: 4px;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.label {
|
||||
color: rgba(255, 255, 255, 0.7);
|
||||
}
|
||||
|
||||
.highlight {
|
||||
color: #00f0ff;
|
||||
}
|
||||
|
||||
.tag {
|
||||
background: rgba(250, 177, 21, 0.2);
|
||||
border-radius: 8px;
|
||||
border: 1px solid #ffac26;
|
||||
color: #fff;
|
||||
padding: 2px 8px;
|
||||
border-radius: 10px;
|
||||
font-size: 12px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
</style>
|
97
src/views/StationLevel/layout/VideoFoot.vue
Normal file
97
src/views/StationLevel/layout/VideoFoot.vue
Normal file
@ -0,0 +1,97 @@
|
||||
<template>
|
||||
<div class="image-carousel">
|
||||
<div class="control-button prev" @click="prevImage">
|
||||
<img src="@/assets/images/icon_08.png" alt="">
|
||||
</div>
|
||||
<div class="carousel-container">
|
||||
<div class="hh100" :style="{transform: `translateX(-${currentIndex * 100}%)`}">
|
||||
<ul class="image-wrapper" style="margin-bottom:1%;">
|
||||
<li v-for="(image, index) in images" :key="index" class="image-item">
|
||||
<img :src="image" alt="carousel image">
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="image-wrapper">
|
||||
<li v-for="(image, index) in images" :key="index" class="image-item">
|
||||
<img :src="image" alt="carousel image">
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="control-button next" @click="nextImage">
|
||||
<img src="@/assets/images/icon_07.png" alt="">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
currentIndex: 0,
|
||||
images: [
|
||||
require('@/assets/images/person.png'),
|
||||
require('@/assets/images/person.png'),
|
||||
require('@/assets/images/person.png'),
|
||||
require('@/assets/images/person.png')
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
prevImage() {
|
||||
this.currentIndex = this.currentIndex > 0 ? this.currentIndex - 1 : this.images.length - 1
|
||||
},
|
||||
nextImage() {
|
||||
this.currentIndex = this.currentIndex < this.images.length - 1 ? this.currentIndex + 1 : 0
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.image-carousel {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
padding: 30px 20px;
|
||||
box-sizing: border-box;
|
||||
.carousel-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.image-wrapper {
|
||||
display: flex;
|
||||
height: 49.5%;
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.image-item {
|
||||
width: 24%;
|
||||
margin: 0 1%;
|
||||
height: 100%;
|
||||
img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
}
|
||||
|
||||
.control-button {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
color: #fff;
|
||||
z-index: 1;
|
||||
&.prev {
|
||||
left: 0;
|
||||
}
|
||||
&.next {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
141
src/views/StationLevel/layout/VideoMore.vue
Normal file
141
src/views/StationLevel/layout/VideoMore.vue
Normal file
@ -0,0 +1,141 @@
|
||||
<template>
|
||||
<div class="video-more-container">
|
||||
<div class="switch-btn prev" @click="handlePrev">
|
||||
<img src="@/assets/images/icon_08.png" alt="">
|
||||
</div>
|
||||
<div class="video-grid">
|
||||
<div v-for="index in 4" :key="index" class="video-cell">
|
||||
<div class="video-wrapper">
|
||||
<video class="video-player" controls>
|
||||
<source src="" type="video/mp4">
|
||||
</video>
|
||||
<div class="video-controls">
|
||||
<div class="time-display">01:32</div>
|
||||
<div class="control-buttons">
|
||||
<i class="el-icon-video-play"></i>
|
||||
<i class="el-icon-refresh-right"></i>
|
||||
<i class="el-icon-full-screen"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="switch-btn next" @click="handleNext">
|
||||
<img src="@/assets/images/icon_07.png" alt="">
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'VideoMore',
|
||||
data() {
|
||||
return {
|
||||
currentPage: 1,
|
||||
totalPages: 3
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handlePrev() {
|
||||
if (this.currentPage > 1) {
|
||||
this.currentPage--
|
||||
}
|
||||
},
|
||||
handleNext() {
|
||||
if (this.currentPage < this.totalPages) {
|
||||
this.currentPage++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.video-more-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
|
||||
.switch-btn {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
color: #fff;
|
||||
z-index: 1;
|
||||
|
||||
&.prev {
|
||||
left: 0;
|
||||
border-radius: 0 4px 4px 0;
|
||||
}
|
||||
|
||||
&.next {
|
||||
right: 0;
|
||||
border-radius: 4px 0 0 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.video-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
grid-template-rows: repeat(2, 1fr);
|
||||
gap: 20px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.video-cell {
|
||||
position: relative;
|
||||
background: url('~@/assets/images/bg13.png') no-repeat;
|
||||
background-size: 100% 100%;
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
|
||||
.video-wrapper {
|
||||
background-color: #000;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.video-player {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.video-controls {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
padding: 10px;
|
||||
background: linear-gradient(transparent, rgba(0, 0, 0, 0.8));
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
.time-display {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.control-buttons {
|
||||
display: flex;
|
||||
gap: 15px;
|
||||
|
||||
i {
|
||||
cursor: pointer;
|
||||
font-size: 20px;
|
||||
&:hover {
|
||||
color: #409EFF;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
159
src/views/StationLevel/layout/WarningCount.vue
Normal file
159
src/views/StationLevel/layout/WarningCount.vue
Normal file
@ -0,0 +1,159 @@
|
||||
<template>
|
||||
<div class="waning-cards">
|
||||
<div class="stat-card">
|
||||
<div class="flex align-center mb10">
|
||||
<img src="~@/assets/images/icon-05.png" alt="" />
|
||||
<div class="stat-title">
|
||||
<div class="mt4">人员预警</div>
|
||||
<div class="num">{{ dataList.RyData.total }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-details">
|
||||
<div
|
||||
class="stat-item red"
|
||||
v-for="(item, index) in dataList.RyData.YjData"
|
||||
:key="index"
|
||||
>
|
||||
<img :src="require(`@/assets/images/icon-0${index}.png`)" alt="" />
|
||||
<span class="label">{{ item.jbmc }}:</span>
|
||||
<span class="value mr10">{{ item.yjsl }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="stat-card">
|
||||
<div class="flex mb10">
|
||||
<img src="~@/assets/images/icon-04.png" alt="" />
|
||||
<div>
|
||||
<div class="stat-title mt4">车辆预警</div>
|
||||
<div class="num1 mr10">{{ dataList.CarlData.total }}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stat-details">
|
||||
<div
|
||||
class="stat-item red"
|
||||
v-for="(item, index) in dataList.CarlData.ClData"
|
||||
:key="index"
|
||||
>
|
||||
<img :src="require(`@/assets/images/icon-0${index}.png`)" alt="" />
|
||||
<span class="label">{{ item.jbmc }}:</span>
|
||||
<span class="value mr10">{{ item.yjsl }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, reactive } from "vue";
|
||||
import { jczgetYjdjtj } from "@/api/mosty-jcz";
|
||||
const props = defineProps({
|
||||
jczId: {
|
||||
type: String,
|
||||
default: ""
|
||||
}
|
||||
});
|
||||
const dataList = reactive({
|
||||
RyData: {
|
||||
YjData: [],
|
||||
total: 0
|
||||
},
|
||||
CarlData: {
|
||||
ClData: [],
|
||||
total: 0
|
||||
}
|
||||
});
|
||||
const getjczgetYjdjtj = () => {
|
||||
jczgetYjdjtj({ jczid: props.jczId, yjLx: 1 }).then((res) => {
|
||||
dataList.RyData.YjData = res.map((item, index) => {
|
||||
dataList.RyData.total = +item.yjsl;
|
||||
return { ...item };
|
||||
});
|
||||
});
|
||||
};
|
||||
const getCarlData = () => {
|
||||
jczgetYjdjtj({ jczid: props.jczId, yjLx: 2 }).then((res) => {
|
||||
dataList.CarlData.ClData = res.map((item) => {
|
||||
dataList.CarlData.total = +item.yjsl;
|
||||
return { ...item };
|
||||
});
|
||||
});
|
||||
};
|
||||
getjczgetYjdjtj();
|
||||
getCarlData();
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.waning-cards {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
flex: 1;
|
||||
border-radius: 4px;
|
||||
padding: 6px;
|
||||
}
|
||||
|
||||
.stat-title {
|
||||
font-size: 18px;
|
||||
color: #fff;
|
||||
font-family: "YSBTH";
|
||||
}
|
||||
.num {
|
||||
font-size: 20px;
|
||||
background: linear-gradient(0deg, #e38f2c 10%, #ffffff 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
font-family: "HANYILINGXINTIJIAN";
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
.num1 {
|
||||
font-size: 20px;
|
||||
background: linear-gradient(0deg, #d83327 10%, #ffffff 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
font-family: "HANYILINGXINTIJIAN";
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.stat-total {
|
||||
font-size: 32px;
|
||||
color: #00f0ff;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.stat-details {
|
||||
.stat-item {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
font-size: 14px;
|
||||
|
||||
&.red .value {
|
||||
color: #ff4d4f;
|
||||
}
|
||||
|
||||
&.orange .value {
|
||||
color: #ff7a45;
|
||||
}
|
||||
|
||||
&.yellow .value {
|
||||
color: #ffc53d;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 16px;
|
||||
color: rgba(255, 255, 255, 0.85);
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 16px;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
Reference in New Issue
Block a user