feat: 目标检测分页筛选完成

master
donghao
parent c115e0221b
commit 01b43061d9

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 664 B

@ -20,3 +20,13 @@
.bg_basic_content{ .bg_basic_content{
// background: linear-gradient( 180deg, rgba(7,16,19,0) 0%, #081417 100%);; // background: linear-gradient( 180deg, rgba(7,16,19,0) 0%, #081417 100%);;
} }
.text_des_1{
color:#1D2129
}
.text_color_3 {
color: #333;
}
.text_color_6 {
color: #666;
}

@ -3,7 +3,7 @@
import { config } from '@/config'; import { config } from '@/config';
import Type1ObjectDetect from "./components/Type1ObjectDetect.vue"; import Type1ObjectDetect from "./components/Type1ObjectDetect.vue";
import Type2LicensePlateRecog from "./components/Type2LicensePlateRecog.vue"; import Type2LicensePlateRecog from "./components/Type2LicensePlateRecog.vue";
import Type3CigaretteOffer from "./components/Type3CigaretteOffer.vue"; import Type3TargetRecog from "./components/Type3TargetRecog.vue";
import Type4AudioDetection from "./components/Type4AudioDetection.vue"; import Type4AudioDetection from "./components/Type4AudioDetection.vue";
import { useAllData } from './hooks/useAllData'; import { useAllData } from './hooks/useAllData';
// //
@ -77,7 +77,7 @@ const tabDetails = (title: string) => {
detailInfo.value = filterDetailsByData(toRaw(dataList.value), title); detailInfo.value = filterDetailsByData(toRaw(dataList.value), title);
currentType.value = fetchTypeByTitle(title); currentType.value = fetchTypeByTitle(title);
isHomePage.value = false; isHomePage.value = false;
console.log(currentType.value, detailInfo.value, 'tabDetails', toRaw(dataList.value)); console.log(currentType.value, detailInfo.value, 'tabDetails');
} }
// //
@ -108,7 +108,7 @@ onUnmounted(() => {
<ul class="content-list-box"> <ul class="content-list-box">
<li class="content-detail-box"> <li class="content-detail-box">
<Type2LicensePlateRecog typeKey="2" :info="detailInfo" :title="currentTilte" v-if="currentType === '2'" /> <Type2LicensePlateRecog typeKey="2" :info="detailInfo" :title="currentTilte" v-if="currentType === '2'" />
<Type3CigaretteOffer typeKey="3" :info="detailInfo" :title="currentTilte" v-else-if="currentType === '3'" /> <Type3TargetRecog typeKey="3" :info="detailInfo" :title="currentTilte" v-else-if="currentType === '3'" />
<Type4AudioDetection typeKey="4" :info="detailInfo" :title="currentTilte" v-else-if="currentType === '4'" /> <Type4AudioDetection typeKey="4" :info="detailInfo" :title="currentTilte" v-else-if="currentType === '4'" />
<Type1ObjectDetect typeKey="1" :info="detailInfo" :title="currentTilte" v-else /> <Type1ObjectDetect typeKey="1" :info="detailInfo" :title="currentTilte" v-else />
</li> </li>

@ -2,14 +2,23 @@
* @Author: donghao donghao@supervision.ltd * @Author: donghao donghao@supervision.ltd
* @Date: 2025-06-12 10:26:59 * @Date: 2025-06-12 10:26:59
* @LastEditors: donghao donghao@supervision.ltd * @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-06-12 10:38:19 * @LastEditTime: 2025-06-13 10:39:45
* @FilePath: \Web-Traffic-Police\src\views\dataView\components\Type1ObjectDetect.vue * @FilePath: \Web-Traffic-Police\src\views\dataView\components\Type1ObjectDetect.vue
* @Description: 目标检测 * @Description: 目标检测
--> -->
<template> <template>
<div class="type-first"> <div class="type-first">
<div class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4 type-first-mid"> <div
<div class="type-first-mid-box" v-for="(item, index) in info" :key="index"> class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4 type-first-mid"
>
<div
class="type-first-mid-box"
v-for="(item, index) in info.slice(
(pagination.page - 1) * pagination.pageSize,
pagination.page * pagination.pageSize
)"
:key="index"
>
<div class="type-first-mid-box-video"> <div class="type-first-mid-box-video">
<video <video
class="w-[100%] h-[100%]" class="w-[100%] h-[100%]"
@ -18,35 +27,60 @@
></video> ></video>
</div> </div>
<div class="type-first-mid-box-text" v-if="title === '酒精度数'"> <div class="type-first-mid-box-text" v-if="title === '酒精度数'">
<span>酒精度数:</span> <span style="font-weight: normal;">{{ item['酒精度数'] }}</span> <span>酒精度数:</span>
<span style="font-weight: normal">{{ item["酒精度数"] }}</span>
</div> </div>
<div class="type-first-mid-box-text" v-else-if="title === ''"> <div class="type-first-mid-box-text" v-else-if="title === ''">
<span>语音角色:</span> <span style="font-weight: normal;">{{ item['语音角色'] }}</span> <span>语音角色:</span>
<span style="font-weight: normal">{{ item["语音角色"] }}</span>
</div> </div>
<div class="type-first-mid-box-text" v-else> <div class="type-first-mid-box-text" v-else>
<span>关键帧:</span> <span v-for="item1 in item[`${title}时间`]" style="font-weight: normal;">{{ item1 }}</span> <span>关键帧:</span>
<span
v-for="item1 in item[`${title}时间`]"
style="font-weight: normal"
>{{ item1 }}</span
>
</div> </div>
</div> </div>
</div> </div>
<div class="type-first-bottom"></div> <div class="type-first-bottom mt-[87px]" v-if="info?.length">
<BasePagination
class="bg-transparent"
:showTable="false"
:total="info?.length"
:pageSize="pagination.pageSize"
:dataSource="info"
:isFixedPagination="true"
:page="pagination.page"
@change="changePage"
>
</BasePagination>
</div>
</div> </div>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { BasePagination } from "@/components/CustomTable";
defineOptions({ defineOptions({
name: "Type1ObjectDetectWarp" name: "Type1ObjectDetectWarp",
}); });
interface Props { interface Props {
typeKey: String; typeKey: String;
info: Record<string, any>; info: Record<string, any>;
title: String; title: String;
} }
const props = withDefaults(defineProps<Props>(), {
const props = withDefaults(defineProps < Props > (), {
typeKey: "1", typeKey: "1",
info: {}, info: {},
title: String title: String,
}); });
const pagination = ref({ page: 1, pageSize: 8 });
//
function changePage({ page, pageSize }) {
pagination.value = { page, pageSize };
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.type-first { .type-first {
@ -56,16 +90,11 @@ const props = withDefaults(defineProps < Props > (), {
font-family: PingFang SC, PingFang SC; font-family: PingFang SC, PingFang SC;
font-weight: bold; font-weight: bold;
font-size: 20px; font-size: 20px;
color: #1D2129; color: #1d2129;
} }
.type-first-mid { .type-first-mid {
// display: flex; min-height: 744px;
// justify-self: start; max-height: 744px;
// justify-content: space-between;
// align-content: space-between;
// flex-direction: row;
// flex-wrap: wrap;
height: 744px;
overflow-y: auto; overflow-y: auto;
.type-first-mid-box { .type-first-mid-box {
box-sizing: border-box; box-sizing: border-box;
@ -89,11 +118,9 @@ const props = withDefaults(defineProps < Props > (), {
font-family: PingFang SC, PingFang SC; font-family: PingFang SC, PingFang SC;
font-weight: bold; font-weight: bold;
font-size: 14px; font-size: 14px;
color: #1D2129; color: #1d2129;
} }
} }
} }
} }
</style> </style>

@ -2,26 +2,27 @@
* @Author: donghao donghao@supervision.ltd * @Author: donghao donghao@supervision.ltd
* @Date: 2025-06-12 10:27:06 * @Date: 2025-06-12 10:27:06
* @LastEditors: donghao donghao@supervision.ltd * @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-06-12 17:37:33 * @LastEditTime: 2025-06-13 13:06:33
* @FilePath: \Web-Traffic-Police\src\views\dataView\components\Type2LicensePlateRecog.vue * @FilePath: \Web-Traffic-Police\src\views\dataView\components\Type2LicensePlateRecog.vue
* @Description: 车牌识别 * @Description: 车牌识别 人脸检测
--> -->
<template> <template>
<div class="type-second"> <div class="type-second">
<div class="type-second-mid"> <div class="type-second-mid">
<div class="type-second-mid-video"> <div class="type-second-mid-video">
<!-- //TODO --> <div class="arrow-icon left-arrow" @click="toPrev()" v-if="info?.length > 1"></div>
<video <video
class="w-[100%] h-[100%]" class="w-[100%] h-[100%]"
:src="info[0].video_url" :src="currentInfo?.video_url"
controls controls
></video> ></video>
<!-- <img src="https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg" class="w-[100%] h-[100%]"/> --> <div class="arrow-icon right-arrow" @click="toNext()" v-if="info?.length > 1"></div>
</div> </div>
<div <ul
class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4 type-second-mid-box" class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4 type-second-mid-box"
> >
<div <template v-if="title === '车牌识别'">
<li
class="type-second-mid-crad" class="type-second-mid-crad"
v-for="(item, index) in currentInfoList.slice( v-for="(item, index) in currentInfoList.slice(
(pagination.page - 1) * pagination.pageSize, (pagination.page - 1) * pagination.pageSize,
@ -32,19 +33,37 @@
<div class="type-second-mid-crad-image"> <div class="type-second-mid-crad-image">
<img :src="item['车牌图片']" class="w-[100%] h-[100%]" /> <img :src="item['车牌图片']" class="w-[100%] h-[100%]" />
</div> </div>
<div class="type-second-mid-crad-text"> <div class="type-second-mid-crad-text text_color_6">
<!-- 车辆识别 --> <!-- //TODO -->
<p> <p>
<span>牌照颜色</span><span>{{ item["车牌颜色"] }}</span> <span>牌照颜色</span
><span>{{
item["车牌颜色"] ? item["车牌颜色"] + "色" : "未知"
}}</span>
</p> </p>
<p> <p>
<span>车牌号</span><span>{{ item["车牌号"] }}</span> <span></span><span class="text_des_1">{{ item["车牌号"] }}</span>
</p> </p>
</div> </div>
</li>
</template>
<template v-else>
<li
class="type-second-mid-crad face-Recog-box"
v-for="(item, index) in currentInfoList.slice(
(pagination.page - 1) * pagination.pageSize,
pagination.page * pagination.pageSize
)"
:key="index"
>
<div class="type-second-mid-crad-image type-second-mid-crad-image-face-Recog flex justify-center items-center">
<img :src="item['人脸图片']" class="h-[100%]" />
</div> </div>
</li>
</template>
</ul>
</div> </div>
</div> <div class="type-second-bottom mt-[87px]" v-if="currentInfoList?.length">
<div class="type-second-bottom mt-[87px]">
<BasePagination <BasePagination
class="bg-transparent" class="bg-transparent"
:showTable="false" :showTable="false"
@ -70,7 +89,6 @@ interface Props {
info: Record<string, any>; info: Record<string, any>;
title: String; title: String;
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
typeKey: "4", typeKey: "4",
info: {}, info: {},
@ -92,12 +110,42 @@ function convertLPRArrToObjects() {
} }
return result; return result;
} }
//
function convertFRArrToObjects() {
const result = [];
for (let i = 0; i < currentInfo.value?.["人脸图片"].length; i++) {
result.push({
["人脸图片"]: currentInfo.value?.["人脸图片"][i],
});
}
return result;
}
// //
function changePage({ page, pageSize }) { function changePage({ page, pageSize }) {
pagination.value = { page, pageSize }; pagination.value = { page, pageSize };
} }
//
function changeCurrentVideo(index: number) {
pagination.value = {...toRaw(pagination.value), page: 1 };
currentIndex.value = index;
currentInfo.value = props.info[index];
}
function toPrev() {
if (currentIndex.value > 0) {
changeCurrentVideo(toRaw(currentIndex.value) - 1);
} else {
changeCurrentVideo(props.info.length - 1);
}
}
function toNext() {
if (currentIndex.value < props.info.length - 1) {
changeCurrentVideo(toRaw(currentIndex.value) + 1);
} else {
changeCurrentVideo(0);
}
}
watch( watch(
props.info, props.info,
() => { () => {
@ -110,13 +158,15 @@ watch(
); );
watch( watch(
currentInfo.value, () => [currentIndex.value],
() => { () => {
console.log(currentInfo.value, props.title); console.log(currentInfo.value, props.title, "watch-车牌识别-currentInfo.value");
switch (props.title) { switch (props.title) {
case "车牌识别": case "车牌识别":
currentInfoList.value = convertLPRArrToObjects(); currentInfoList.value = convertLPRArrToObjects();
break;
default: default:
currentInfoList.value = convertFRArrToObjects();
break; break;
} }
}, },
@ -136,7 +186,6 @@ watch(
font-family: PingFang SC, PingFang SC; font-family: PingFang SC, PingFang SC;
font-weight: bold; font-weight: bold;
font-size: 20px; font-size: 20px;
color: #1d2129;
} }
.type-second-mid { .type-second-mid {
.type-second-mid-video { .type-second-mid-video {
@ -148,6 +197,20 @@ watch(
width: 100%; width: 100%;
height: 324px; height: 324px;
border-radius: 4px; border-radius: 4px;
.arrow-icon {
width: 40px;
height: 40px;
margin: 0 32px;
cursor: pointer;
background-image: url("@/assets/images/left_arrow.png");
background-size: 100%;
background-position: center;
background-repeat: no-repeat;
}
.right-arrow{
background-image: url("@/assets/images/right_arrow.png");
}
video { video {
width: 720px; width: 720px;
height: 100%; height: 100%;
@ -178,6 +241,9 @@ watch(
border-radius: 4px 4px 0 0; border-radius: 4px 4px 0 0;
} }
} }
.type-second-mid-crad-image-face-Recog{
height: 232px;
}
.type-second-mid-crad-text { .type-second-mid-crad-text {
box-sizing: border-box; box-sizing: border-box;
width: 100%; width: 100%;
@ -186,7 +252,6 @@ watch(
font-family: PingFang SC, PingFang SC; font-family: PingFang SC, PingFang SC;
font-weight: bold; font-weight: bold;
font-size: 14px; font-size: 14px;
color: #1d2129;
} }
} }
} }

@ -1,125 +0,0 @@
<!--
* @Author: donghao donghao@supervision.ltd
* @Date: 2025-06-12 10:37:10
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-06-12 10:38:40
* @FilePath: \Web-Traffic-Police\src\views\dataView\components\Type4AudioDetection.vue
* @Description: 递烟
-->
<template>
<div class="type-fourth">
<!-- <div class="type-fourth-top">
<span></span> <span>车牌识别</span>
</div> -->
<div class="type-fourth-mid">
<div class="type-fourth-mid-video">
<video
class="w-[720px] h-[100%]"
:src="info[0].video_url"
controls
></video>
</div>
<div class="type-fourth-mid-tab">
<el-button type="primary" class="w-[76px] h-[32px!important]">全部</el-button>
<el-button class="w-[76px] h-[32px!important]">人员</el-button>
<el-button class="w-[76px] h-[32px!important]">车辆</el-button>
<el-button class="w-[76px] h-[32px!important]">路灯</el-button>
</div>
<div class="type-fourth-mid-box">
<div class="type-fourth-mid-crad" v-for="(item, index) in 8">
<div class="type-fourth-mid-crad-image">
<img src="https://cube.elemecdn.com/6/94/4d3ea53c084bad6931a56d5158a48jpeg.jpeg" class="w-[100%] h-[100%]"/>
</div>
<div class="type-fourth-mid-crad-text">
<span style="color: #666;">检测类型:</span> 123123
</div>
</div>
</div>
</div>
<div class="type-fourth-bottom"></div>
</div>
</template>
<script lang="ts" setup>
defineOptions({
name: "Type3CigaretteOfferWarp"
});
interface Props {
typeKey: String;
info: Record<string, any>;
title: String;
}
const props = withDefaults(defineProps<Props>(), {
typeKey: "3",
info: {},
title: String,
});
</script>
<style lang="scss" scoped>
.type-fourth {
.type-fourth-top {
cursor: pointer;
margin-bottom: 16px;
font-family: PingFang SC, PingFang SC;
font-weight: bold;
font-size: 20px;
color: #1D2129;
}
.type-fourth-mid {
.type-fourth-mid-video {
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 324px;
border-radius: 4px;
img {
width: 720px;
height: 100%;
border-radius: 4px;
}
}
.type-fourth-mid-tab {
box-sizing: border-box;
margin-top: 24px;
margin-bottom: 16px;
width: 100%;
height: 32px;
}
.type-fourth-mid-box {
display: flex;
justify-content: space-between;
align-content: space-between;
flex-direction: row;
flex-wrap: wrap;
height: 420px;
.type-fourth-mid-crad {
box-sizing: border-box;
width: 348px;
height: 202px;
background: #fff;
border-radius: 4px;
.type-fourth-mid-crad-image {
box-sizing: border-box;
width: 100%;
height: 148px;
img {
border-radius: 4px 4px 0 0;
}
}
.type-fourth-mid-crad-text {
box-sizing: border-box;
width: 100%;
height: 54px;
padding: 16px;
font-family: PingFang SC, PingFang SC;
font-weight: bold;
font-size: 14px;
color: #1D2129;
}
}
}
}
}
</style>

@ -0,0 +1,275 @@
<!--
* @Author: donghao donghao@supervision.ltd
* @Date: 2025-06-12 10:37:10
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-06-13 13:13:42
* @FilePath: \Web-Traffic-Police\src\views\dataView\components\Type4AudioDetection.vue
* @Description: 递烟
-->
<template>
<div class="type-fourth">
<!-- <div class="type-fourth-top">
<span></span> <span>车牌识别</span>
</div> -->
<div class="type-fourth-mid">
<div class="type-fourth-mid-video">
<div
class="arrow-icon left-arrow"
@click="toPrev()"
v-if="info?.length > 1"
></div>
<video
class="w-[720px] h-[100%]"
:src="currentInfo?.video_url"
controls
></video>
<div
class="arrow-icon right-arrow"
@click="toNext()"
v-if="info?.length > 1"
></div>
</div>
<div class="type-fourth-mid-tab">
<el-button
v-for="v in regTypeMap"
:type="currentRegType === v.key ? 'primary' : ''"
class="w-[76px] h-[32px!important]"
:key="v.key"
@click="changeRegType(v)"
>{{ v.title }}</el-button
>
</div>
<div
class="grid grid-cols-1 gap-4 md:grid-cols-2 lg:grid-cols-4 type-fourth-mid-box"
>
<div
class="type-fourth-mid-crad"
v-for="(item, index) in currentInfoList.slice(
(pagination.page - 1) * pagination.pageSize,
pagination.page * pagination.pageSize
)"
:key="index"
>
<div class="type-fourth-mid-crad-image">
<img :src="item['图片']" class="w-[100%] h-[100%]" />
</div>
<div class="type-fourth-mid-crad-text">
<span style="color: #666">检测类型:</span> {{ item["检测类型"] }}
</div>
</div>
</div>
</div>
<div class="type-fourth-bottom mt-[100px]" v-if="currentInfoList?.length">
<BasePagination
class="bg-transparent"
:showTable="false"
:total="currentInfoList?.length"
:pageSize="pagination.pageSize"
:dataSource="currentInfoList"
:isFixedPagination="true"
:page="pagination.page"
@change="changePage"
>
</BasePagination>
</div>
</div>
</template>
<script lang="ts" setup>
import { BasePagination } from "@/components/CustomTable";
defineOptions({
name: "Type3TargetRecog",
});
interface Props {
typeKey: String;
info: Record<string, any>;
title: String;
}
const props = withDefaults(defineProps<Props>(), {
typeKey: "3",
info: {},
title: String,
});
//
const regTypeMap = [
{
key: "0",
title: "全部",
},
{
key: "人",
title: "人员",
},
{
key: "车",
title: "车辆",
},
{
key: "信号灯",
title: "路灯",
},
];
const currentRegType = ref<string>("0");
const pagination = ref({ page: 1, pageSize: 8 });
const currentIndex = ref<number>(0); //
const currentInfo = ref<Record<string, any> | null>(null);
const currentInfoList = ref<Record<string, any>[]>([]);
//
function convertObjects(key) {
const targetArr = currentInfo.value?.["目标检测"]?.[key];
const result = [];
for (let i = 0; i < targetArr.length; i++) {
result.push({
["图片"]: targetArr[i],
["检测类型"]: key,
});
}
return result;
}
//
function changePage({ page, pageSize }) {
pagination.value = { page, pageSize };
}
//
function changeCurrentVideo(index: number) {
currentIndex.value = index;
currentInfo.value = props.info[index];
}
function toPrev() {
if (currentIndex.value > 0) {
changeCurrentVideo(toRaw(currentIndex.value) - 1);
} else {
changeCurrentVideo(props.info.length - 1);
}
}
function toNext() {
if (currentIndex.value < props.info.length - 1) {
changeCurrentVideo(toRaw(currentIndex.value) + 1);
} else {
changeCurrentVideo(0);
}
}
//
function changeRegType(record) {
currentRegType.value = record.key;
console.log(record, "changeRegType");
}
watch(
props.info,
() => {
currentInfo.value = props.info[0];
},
{
immediate: true,
deep: true,
}
);
watch(
() => [currentIndex.value, currentRegType.value],
() => {
console.log(
currentInfo.value,
props.title,
"watch-目标检测-currentInfo.value"
);
pagination.value = { ...toRaw(pagination.value), page: 1 };
const currRegTypeKey = toRaw(currentRegType.value);
if (currRegTypeKey === "0") {
currentInfoList.value = [
...convertObjects("人"),
...convertObjects("车"),
...convertObjects("信号灯"),
];
} else {
currentInfoList.value = convertObjects(currRegTypeKey);
}
},
{
immediate: true,
deep: true,
}
);
</script>
<style lang="scss" scoped>
.type-fourth {
.type-fourth-top {
cursor: pointer;
margin-bottom: 16px;
font-family: PingFang SC, PingFang SC;
font-weight: bold;
font-size: 20px;
color: #1d2129;
}
.type-fourth-mid {
.type-fourth-mid-video {
box-sizing: border-box;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 324px;
border-radius: 4px;
.arrow-icon {
width: 40px;
height: 40px;
margin: 0 32px;
cursor: pointer;
background-image: url("@/assets/images/left_arrow.png");
background-size: 100%;
background-position: center;
background-repeat: no-repeat;
}
.right-arrow {
background-image: url("@/assets/images/right_arrow.png");
}
video {
width: 720px;
height: 100%;
border-radius: 4px;
}
}
.type-fourth-mid-tab {
box-sizing: border-box;
margin-top: 24px;
margin-bottom: 16px;
width: 100%;
height: 32px;
}
.type-fourth-mid-box {
min-height: 420px;
max-height: 420px;
overflow-y: auto;
.type-fourth-mid-crad {
box-sizing: border-box;
width: 348px;
height: 202px;
background: #fff;
border-radius: 4px;
.type-fourth-mid-crad-image {
box-sizing: border-box;
width: 100%;
height: 148px;
img {
border-radius: 4px 4px 0 0;
}
}
.type-fourth-mid-crad-text {
box-sizing: border-box;
width: 100%;
height: 54px;
padding: 16px;
font-family: PingFang SC, PingFang SC;
font-weight: bold;
font-size: 14px;
color: #1d2129;
}
}
}
}
}
</style>
Loading…
Cancel
Save