27
0
Fork 0

feat: 视频分析页开发

develop
JINGYJ 2 years ago
parent 402ca4719e
commit fff9fc175c

@ -57,6 +57,7 @@
"@commitlint/cli": "^17.6.5",
"@commitlint/config-conventional": "^17.6.5",
"@iconify-icons/ep": "^1.2.11",
"@iconify-icons/icon-park-outline": "^1.2.11",
"@iconify-icons/ri": "^1.2.8",
"@iconify/vue": "^4.1.1",
"@pureadmin/theme": "^3.1.0",

File diff suppressed because it is too large Load Diff

@ -19,5 +19,5 @@
"CachingAsyncRoutes": false,
"TooltipEffect": "light",
"ResponsiveStorageNameSpace": "responsive-",
"AdminHostUrl": "http://192.168.10.13:8000"
"AdminHostUrl": "http://192.168.10.59:8000"
}

@ -30,6 +30,12 @@ export const submitAnalyse = (data?: object) => {
});
};
export const getVideoList = (data?: object) => {
return http.request<Data>("post", baseUrlApi("tps/get_analyzed_videos/"), {
data
});
};
export const beforeUploadVideo = (params?: object) => {
return http.request<Data>("get", baseUrlApi("tps/upload_video/"), {
params

@ -8,7 +8,9 @@ import { addIcon } from "@iconify/vue/dist/offline";
import HomeFilled from "@iconify-icons/ep/home-filled";
import InformationLine from "@iconify-icons/ri/information-line";
import Lollipop from "@iconify-icons/ep/lollipop";
import VideoT from "@iconify-icons/icon-park-outline/video-two";
addIcon("homeFilled", HomeFilled);
addIcon("informationLine", InformationLine);
addIcon("lollipop", Lollipop);
addIcon("videoT", VideoT);

@ -2,17 +2,27 @@ export default {
path: "/videoParse",
// redirect: "/error/403",
meta: {
icon: "lollipop",
icon: "videoT",
title: "视频分析",
showLink: true,
rank: 10
},
children: [
{
path: "/videoList/index",
name: "VideoListPage",
component: () => import("@/views/videoList/index.vue"),
meta: {
title: "视频分析"
}
},
{
path: "/videoParse/index",
name: "VideoParsePage",
component: () => import("@/views/videoParse/index.vue"),
meta: {
showLink: false,
activePath: "/videoList/index",
title: "视频分析"
}
}

@ -0,0 +1,318 @@
<script setup lang="ts">
import { PureTable } from "@pureadmin/table";
import { type PaginationProps } from "@pureadmin/table";
import { onMounted, ref, reactive } from "vue";
import { useWindowSize } from "@vueuse/core";
import { getVideoList } from "@/api/videoParse";
import { useRouter } from "vue-router";
import { useMultiTagsStoreHook } from "@/store/modules/multiTags";
defineOptions({
name: "VideoList"
});
const formInline = reactive({
date: "",
violation: ""
});
function pickerOptions(time) {
return time.getTime() > Date.now();
}
const now_date = new Date();
now_date.setMonth(now_date.getMonth() - 1);
const lastMonth = now_date;
const tableData = ref([]);
// const violationMap = ref({
// : "0",
// : "1",
// : "2",
// : "3",
// : "4"
// });
const options = [
{
value: "疑似静止",
label: "疑似静止"
},
{
value: "疑似遮挡",
label: "疑似遮挡"
},
{
value: "疑似抖动",
label: "疑似抖动"
},
{
value: "疑似递烟",
label: "疑似递烟"
},
{
value: "疑似递钱",
label: "疑似递钱"
}
];
const { height } = useWindowSize();
const tableSize = ref("default");
const columns: TableColumnList = [
{
label: "序号",
type: "index",
width: 70,
fixed: "left"
},
{
label: "视频名称",
// width: 200,
prop: "video_name"
},
{
label: "日期",
prop: "video_date",
// width: 140,
sortable: true
},
{
label: "异常数量",
// width: 100,
prop: "abnormal_count"
},
{
label: "异常表现",
prop: "abnormal_performance",
width: 370,
slot: "violation"
},
{
label: "文件地址",
prop: "video_path"
},
{
label: "操作",
fixed: "right",
// width: 160,
slot: "operation"
}
];
function tagStyle(type) {
switch (type) {
case "疑似遮挡":
return "span-occlusion";
case "疑似递烟":
return "span-smoke";
case "疑似递钱":
return "span-money";
case "疑似静止":
return "span-stillness";
default:
return "span-shake";
}
}
async function onSearch() {
const params = {
start_time: formInline.date === null ? undefined : formInline.date[0],
end_time: formInline.date === null ? undefined : formInline.date[1],
abnormal_behavior: formInline.violation || undefined,
page: pagination.currentPage || undefined,
page_size: pagination.pageSize || undefined
};
const { results, count } = await getVideoList(params);
pagination.total = count;
tableData.value = results;
setTimeout(() => {
loading.value = false;
}, 500);
}
function handleSearch() {
pagination.currentPage = 1;
onSearch();
}
function handleRefresh() {
Object.assign(formInline, { date: "", violation: "" });
onSearch();
}
function handleSizeChange(val) {
pagination.pageSize = val;
onSearch();
}
function handleCurrentChange(val) {
pagination.currentPage = val;
onSearch();
}
const router = useRouter();
function handleProductDetail(product) {
//
useMultiTagsStoreHook().handleTags("push", {
path: `/videoParse/index`,
name: "VideoParsePage",
query: product,
meta: {
title: `视频分析`,
showLink: false
}
});
router.push({ name: "VideoParsePage", query: product });
}
const loading = ref(true);
const pagination = reactive<PaginationProps>({
total: 0,
pageSize: 15,
currentPage: 1,
background: true
});
onMounted(() => {
onSearch();
});
</script>
<template>
<div class="main">
<h2 class="mb-4 text-xl">视频分析</h2>
<el-card shadow="never" :style="{ height: `calc(${height}px - 140px)` }">
<template #header>
<div class="card-header">
<span class="font-semibold">异常分析</span>
</div>
</template>
<el-form
:inline="true"
:model="formInline"
class="search-form bg-bg_color w-[99/100]"
>
<el-form-item style="margin-right: 10px">
<el-date-picker
v-model="formInline.date"
type="daterange"
unlink-panels
range-separator="~"
start-placeholder="起始日期"
end-placeholder="结束日期"
value-format="YYYY-MM-DD"
:disabled-date="pickerOptions"
:default-value="lastMonth"
/>
</el-form-item>
<el-form-item style="margin-right: 12px">
<el-select
v-model="formInline.violation"
placeholder="异常表现"
multiple
collapse-tags
collapse-tags-tooltip
clearable
>
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch"></el-button>
<el-button @click="handleRefresh"> </el-button>
</el-form-item>
</el-form>
<!-- <PureTableBar title="" :columns="columns" @refresh="onSearch"> -->
<!-- <template v-slot="{ size, columns }"> -->
<pure-table
adaptive
align-whole="left"
table-layout="auto"
:loading="loading"
:data="tableData"
showOverflowTooltip
:columns="columns"
:pagination="pagination"
:paginationSmall="tableSize === 'small' ? true : false"
:header-cell-style="{
background: 'var(--el-table-row-hover-bg-color)',
color: 'var(--el-text-color-primary)'
}"
@page-size-change="handleSizeChange"
@page-current-change="handleCurrentChange"
>
<template #violation="{ row }">
<!-- {{ row.is_violation ? "是" : "否" }} -->
<span
:class="tagStyle(item)"
v-for="(item, index) in row.abnormal_performance"
:key="index"
>{{ item }}</span
>
</template>
<template #operation="{ row }">
<el-button
class="reset-margin"
link
type="primary"
@click="handleProductDetail(row)"
>
详情
</el-button>
</template>
</pure-table>
<!-- </template> -->
<!-- </PureTableBar> -->
</el-card>
</div>
</template>
<style lang="scss" scoped>
.span-occlusion,
.span-smoke,
.span-money,
.span-stillness,
.span-shake {
box-sizing: border-box;
display: inline-block;
width: 64px;
height: 24px;
margin-right: 10px;
font-size: 12px;
color: rgb(247 95 25 / 100%);
text-align: center;
background: rgb(247 112 49 / 10%);
border: 1px solid #f75f19;
border-radius: 2px;
}
.span-smoke {
color: rgb(2 36 215 / 100%);
background: rgb(2 36 215 / 10%);
border: 1px solid rgb(2 36 215 / 100%);
}
.span-money {
color: rgb(232 13 13 / 100%);
background: rgb(232 13 13 / 10%);
border: 1px solid rgb(232 13 13 / 100%);
}
.span-stillness {
color: rgb(68 174 245 / 100%);
background: rgb(68 174 245 / 10%);
border: 1px solid rgb(68 174 245 / 100%);
}
.span-shake {
color: rgb(246 148 0 / 100%);
background: rgb(246 148 0 / 10%);
border: 1px solid rgb(246 148 0 / 100%);
}
.reset-margin {
color: #e80d0d;
&:hover {
color: #e80d0d;
opacity: 0.5;
}
}
</style>

@ -1,17 +1,31 @@
import { addDialog } from "@/components/ReDialog";
import { addDialog, closeDialog } from "@/components/ReDialog";
// import { ref, h } from "vue";
import OurPlayer from "@/components/VideoPlayer/OurPlayer.vue";
// import dayjs from "dayjs";
// import { http } from "@/utils/http";
export function videoUtil() {
// const currentPlayingIndex = ref(-1);
function dataFormate(time) {
const milliseconds = time * 1000;
let sec = Math.floor(milliseconds / 1000);
let min = Math.floor(sec / 60);
const hour = Math.floor(min / 60);
sec %= 60;
min %= 60;
return `${hour.toString().padStart(2, "0")}:${min
.toString()
.padStart(2, "0")}:${sec.toString().padStart(2, "0")}`;
}
const columns: TableColumnList = [
{
label: "视频内时间",
prop: "relative_time",
minWidth: 100,
sortable: true,
slot: "relative_time"
formatter: ({ relative_time }) => dataFormate(relative_time)
},
{
label: "异常类型",
@ -60,6 +74,25 @@ export function videoUtil() {
draggable: true,
fullscreenIcon: true,
closeOnClickModal: false,
footerButtons: [
{
label: "取消",
bg: true,
btnClick: ({ dialog: { options, index }, button }) => {
console.log(options, index, button);
closeDialog(options, index);
}
},
{
label: "确认",
bg: true,
type: "primary",
btnClick: ({ dialog: { options, index }, button }) => {
console.log(options, index, button);
closeDialog(options, index);
}
}
],
contentRenderer: () => <OurPlayer></OurPlayer>
// return h(
// "video",

@ -1,121 +1,129 @@
<script setup lang="ts">
import { useWindowSize } from "@vueuse/core";
import { Help } from "@element-plus/icons-vue";
// import { Help } from "@element-plus/icons-vue";
import { ref, reactive, onMounted } from "vue";
import { PureTableBar } from "@/components/RePureTableBar";
// import { PureTableBar } from "@/components/RePureTableBar";
import { PureTable } from "@pureadmin/table";
import { type PaginationProps } from "@pureadmin/table";
import { getToken } from "@/utils/auth";
import { ElMessage, ElMessageBox, genFileId } from "element-plus";
// import { getToken } from "@/utils/auth";
import { ElMessage } from "element-plus";
import { videoUtil } from "./hook";
import { baseUrlApi } from "@/api/utils";
// import { baseUrlApi } from "@/api/utils";
import { useRouter, useRoute } from "vue-router";
import { isEmpty } from "@pureadmin/utils";
import { Back } from "@element-plus/icons-vue";
import {
getPicList,
getTPList,
submitAnalyse,
beforeUploadVideo
getTPList
// submitAnalyse,
// beforeUploadVideo
} from "@/api/videoParse";
// import { fa } from "element-plus/es/locale";
import type {
UploadProps,
UploadUserFile,
UploadInstance,
UploadRawFile
} from "element-plus";
// import type {
// UploadProps,
// UploadUserFile,
// UploadInstance,
// UploadRawFile
// } from "element-plus";
defineOptions({
name: "videoParse"
});
const { columns, openDialog } = videoUtil();
const fileList = ref<UploadUserFile[]>([]);
const uploadFile = ref<UploadInstance>();
const submitUpload = () => {
uploadFile.value!.submit();
};
const handleRemove: UploadProps["onRemove"] = (file, uploadFiles) => {
console.log("移除文件:", file, uploadFiles);
};
const handlePreview: UploadProps["onPreview"] = uploadFile => {
console.log("预览文件:", uploadFile);
};
const handleExceed: UploadProps["onExceed"] = files => {
// ElMessage.warning(
// `${fileList.value[0].name}`
// );
ElMessageBox.confirm(`是否覆盖上传文件: ${fileList.value[0].name} ?`)
.then(() => {
console.log("开始覆盖");
uploadFile.value!.clearFiles();
const file = files[0] as UploadRawFile;
file.uid = genFileId();
uploadFile.value!.handleStart(file);
})
.catch(() => {
console.log("取消覆盖");
submitUpload();
});
};
const handleChange: UploadProps["onChange"] = files => {
if (files.status === "ready") {
const fileName = files.name.substring(files.name.lastIndexOf(".") + 1);
if (
fileName === "mp4" ||
fileName === "MP4" ||
fileName === "avi" ||
fileName === "AVI" ||
fileName === "mkv" ||
fileName === "MKV" ||
fileName === "mov" ||
fileName === "MOV"
) {
const params = { video_name: files.name };
beforeUploadVideo(params).then(response => {
if (!response.success) {
if (!(response.code === 201)) {
fileList.value = [];
ElMessage.warning(`上传文件失败,原因为:${response.msg}`);
return false;
} else {
ElMessage.warning(`上传文件失败,原因为:${response.msg}`);
}
} else {
console.log("开始上传");
submitUpload();
}
});
} else {
ElMessage.warning(`上传文件格式不正确,当前文件格式为:${fileName}`);
fileList.value = [];
return false;
}
}
};
const successCallback: UploadProps["onSuccess"] = (
response,
uploadFile,
uploadFiles
) => {
if (!response.success) {
fileList.value = [];
ElMessage.warning(`文件上传失败原因为:${response.msg},请稍后再试!`);
handleRemove(uploadFile, uploadFiles);
}
};
const beforeRemove: UploadProps["beforeRemove"] = uploadFile => {
console.log("删除文件前:", uploadFile);
return ElMessageBox.confirm(`是否取消上传文件: ${uploadFile.name} ?`).then(
() => true,
() => false
);
};
// const fileList = ref<UploadUserFile[]>([]);
// const uploadFile = ref<UploadInstance>();
const router = useRouter();
const route = useRoute();
const getParameter = isEmpty(route.params) ? route.query : route.params;
// console.log(getParameter);
// const submitUpload = () => {
// uploadFile.value!.submit();
// };
// const handleRemove: UploadProps["onRemove"] = (file, uploadFiles) => {
// console.log("", file, uploadFiles);
// };
// const handlePreview: UploadProps["onPreview"] = uploadFile => {
// console.log("", uploadFile);
// };
// const handleExceed: UploadProps["onExceed"] = files => {
// // ElMessage.warning(
// // `${fileList.value[0].name}`
// // );
// ElMessageBox.confirm(` ${fileList.value[0].name} ?`)
// .then(() => {
// console.log("");
// uploadFile.value!.clearFiles();
// const file = files[0] as UploadRawFile;
// file.uid = genFileId();
// uploadFile.value!.handleStart(file);
// })
// .catch(() => {
// console.log("");
// submitUpload();
// });
// };
// const handleChange: UploadProps["onChange"] = files => {
// if (files.status === "ready") {
// const fileName = files.name.substring(files.name.lastIndexOf(".") + 1);
// if (
// fileName === "mp4" ||
// fileName === "MP4" ||
// fileName === "avi" ||
// fileName === "AVI" ||
// fileName === "mkv" ||
// fileName === "MKV" ||
// fileName === "mov" ||
// fileName === "MOV"
// ) {
// const params = { video_name: files.name };
// beforeUploadVideo(params).then(response => {
// if (!response.success) {
// if (!(response.code === 201)) {
// fileList.value = [];
// ElMessage.warning(`${response.msg}`);
// return false;
// } else {
// ElMessage.warning(`${response.msg}`);
// }
// } else {
// console.log("");
// submitUpload();
// }
// });
// } else {
// ElMessage.warning(`${fileName}`);
// fileList.value = [];
// return false;
// }
// }
// };
// const successCallback: UploadProps["onSuccess"] = (
// response,
// uploadFile,
// uploadFiles
// ) => {
// if (!response.success) {
// fileList.value = [];
// ElMessage.warning(`${response.msg}`);
// handleRemove(uploadFile, uploadFiles);
// }
// };
// const beforeRemove: UploadProps["beforeRemove"] = uploadFile => {
// console.log("", uploadFile);
// return ElMessageBox.confirm(` ${uploadFile.name} ?`).then(
// () => true,
// () => false
// );
// };
const { height } = useWindowSize();
const videoData = ref([]);
@ -148,11 +156,12 @@ function handleCurrentChange(val) {
currentPage.value = val;
onSearch();
}
const hightFlag = ref(false);
function onSearch() {
let video_name = undefined;
if (fileList.value.length > 0) {
video_name = fileList.value[0].name;
}
const video_name = getParameter.video_name || undefined;
// if (fileList.value.length > 0) {
// video_name = fileList.value[0].name;
// }
const params = {
video_name: video_name,
page: currentPage.value || undefined,
@ -186,6 +195,19 @@ function onSearch() {
carEvenList.value = dataList.data.car.filter(
(item, index) => (index + 1) % 2 == 0
);
if (dataList.data.person.length > dataList.data.car.length) {
if (dataList.data.person.length > 4) {
hightFlag.value = true;
} else {
hightFlag.value = false;
}
} else {
if (dataList.data.person.length > 4) {
hightFlag.value = true;
} else {
hightFlag.value = false;
}
}
setTimeout(() => {
loading.value = false;
}, 500);
@ -206,6 +228,21 @@ function spanStyle(type) {
}
}
function tagStyle(type) {
switch (type) {
case "疑似遮挡":
return "span-occlusion";
case "疑似递烟":
return "span-smoke";
case "疑似递钱":
return "span-money";
case "疑似静止":
return "span-stillness";
default:
return "span-shake";
}
}
function getRandType(type) {
// const type = Math.floor(Math.random() * 5) + 1;
switch (type) {
@ -216,42 +253,28 @@ function getRandType(type) {
}
}
function startAnalyse() {
let video_name = undefined;
if (fileList.value.length > 0) {
video_name = fileList.value[0].name;
}
const params = {
video_name: video_name
};
submitAnalyse(params).then(response => {
if (!response.success) {
ElMessage.warning(`提示:${response.msg},请稍后重试`);
} else {
onSearch();
}
});
}
function dataFormate(time) {
const milliseconds = time * 1000;
let sec = Math.floor(milliseconds / 1000);
let min = Math.floor(sec / 60);
const hour = Math.floor(min / 60);
sec %= 60;
min %= 60;
return `${hour.toString().padStart(2, "0")}:${min
.toString()
.padStart(2, "0")}:${sec.toString().padStart(2, "0")}`;
}
// function startAnalyse() {
// let video_name = undefined;
// if (fileList.value.length > 0) {
// video_name = fileList.value[0].name;
// }
// const params = {
// video_name: video_name
// };
// submitAnalyse(params).then(response => {
// if (!response.success) {
// ElMessage.warning(`${response.msg}`);
// } else {
// onSearch();
// }
// });
// }
onMounted(() => {
onSearch();
setInterval(() => {
onSearch();
}, 1000 * 60 * 5);
// setInterval(() => {
// onSearch();
// }, 1000 * 60 * 5);
});
</script>
@ -259,11 +282,23 @@ onMounted(() => {
<div class="main">
<el-row :gutter="24">
<el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
<div class="w-full flex justify-between mb-4">
<el-button
:icon="Back"
key="视频详情"
link
text
class="btn-style"
@click="router.push('/videoList/index')"
>视频详情</el-button
>
</div>
<el-card
class="box-card"
:style="{ height: `calc(${height}px - 150px)` }"
shadow="never"
:style="{ height: `calc(${height}px - 140px)` }"
>
<template #header>
<!-- <template #header>
<div class="card-header">
<span>视频分析</span>
</div>
@ -287,13 +322,13 @@ onMounted(() => {
accept=".mp4, .MP4, .avi, .AVI, .mkv, .MKV, .mov, .MOV"
>
<span>{{ "选择分析文件" }}</span
><el-button type="primary">选择文件</el-button>
<!-- <template #tip>
><el-button type="primary">选择文件</el-button> -->
<!-- <template #tip>
<div class="el-upload__tip">
jpg/png files with a size less than 500KB.
</div>
</template> -->
</el-upload>
<!-- </el-upload>
</div>
<el-button type="success" size="large" @click="startAnalyse">
分析
@ -302,23 +337,22 @@ onMounted(() => {
</el-icon>
</el-button>
</div>
<el-divider border-style="dashed" />
<el-divider border-style="dashed" /> -->
<!-- <el-empty description="暂无数据" v-show="videoData.length == 0" /> -->
<div class="analysis-content flex justify-between">
<div
class="analysis-box"
:style="{ height: `calc(${height}px - 60vh - 150px)` }"
:style="{ height: hightFlag ? `360px` : `270px` }"
>
<span class="analysis-box-label">被执法人员推定</span>
<div
class="analysis-table"
:style="{ height: `calc(${height}px - 60vh - 240px)` }"
>
<div class="analysis-table">
<div class="analysis-table-left">
<div class="analysis-box-lable w-full flex justify-end">
<span>目标清晰度</span>
<div class="analysis-box-lable w-full">
<span class="w-[40px]" />
<span class="w-[120px]" />
<span class="ml-6">目标清晰度</span>
</div>
<el-scrollbar :height="`calc(${height}px - 60vh - 220px)`">
<el-scrollbar :height="hightFlag ? `270px` : `180px`">
<div
v-for="(item, index) in personOddList"
:key="index"
@ -327,27 +361,30 @@ onMounted(() => {
<span :class="spanStyle(item.id)">{{
2 * index + 1
}}</span>
<el-image
style="height: 100px"
:src="item.pic_path"
:zoom-rate="1.2"
:preview-src-list="[item.pic_path]"
fit="cover"
class="w-[100px]"
/>
<div class="defect-image">
<el-image
:src="item.pic_path"
:zoom-rate="1.2"
:preview-src-list="[item.pic_path]"
fit="cover"
class="w-[100%] h-[100%] rounded"
/>
</div>
<span>{{ item.pic_quality }}</span>
</div>
</el-scrollbar>
</div>
<el-divider
<!-- <el-divider
direction="vertical"
:style="{ height: `calc(${height}px - 60vh - 220px)` }"
/>
/> -->
<div class="analysis-table-left">
<div class="analysis-box-lable w-full flex justify-end">
<span>目标清晰度</span>
<span class="w-[40px]" />
<span class="w-[120px]" />
<span class="ml-1">目标清晰度</span>
</div>
<el-scrollbar :height="`calc(${height}px - 60vh - 220px)`">
<el-scrollbar :height="hightFlag ? `270px` : `180px`">
<div
v-for="(item, index) in personEvenList"
:key="index"
@ -356,14 +393,15 @@ onMounted(() => {
<span :class="spanStyle(item.id)">{{
2 * index + 2
}}</span>
<el-image
style="height: 100px"
:src="item.pic_path"
:zoom-rate="1.2"
:preview-src-list="[item.pic_path]"
fit="cover"
class="w-[100px]"
/>
<div class="defect-image">
<el-image
:src="item.pic_path"
:zoom-rate="1.2"
:preview-src-list="[item.pic_path]"
fit="cover"
class="w-[100%] h-[100%] rounded"
/>
</div>
<span>{{ item.pic_quality }}</span>
</div>
</el-scrollbar>
@ -372,18 +410,17 @@ onMounted(() => {
</div>
<div
class="analysis-box"
:style="{ height: `calc(${height}px - 60vh - 150px)` }"
:style="{ height: hightFlag ? `360px` : `270px` }"
>
<span class="analysis-box-label">被执法车辆推定</span>
<div
class="analysis-table"
:style="{ height: `calc(${height}px - 60vh - 240px)` }"
>
<div class="analysis-table">
<div class="analysis-table-left">
<div class="analysis-box-lable w-full flex justify-end">
<span>目标清晰度</span>
<span class="w-[40px]" />
<span class="w-[120px]" />
<span class="ml-1">目标清晰度</span>
</div>
<el-scrollbar :height="`calc(${height}px - 60vh - 220px)`">
<el-scrollbar :height="hightFlag ? `270px` : `180px`">
<div
v-for="(item, index) in carOddList"
:key="index"
@ -394,12 +431,11 @@ onMounted(() => {
}}</span>
<div class="defect-image">
<el-image
style="height: 100px"
:src="item.pic_path"
:zoom-rate="1.2"
:preview-src-list="[item.pic_path]"
fit="cover"
class="w-[100px]"
class="w-[100%] h-[100%] rounded"
/>
<span>{{ item.car_number }}</span>
</div>
@ -407,15 +443,17 @@ onMounted(() => {
</div>
</el-scrollbar>
</div>
<el-divider
<!-- <el-divider
direction="vertical"
:style="{ height: `calc(${height}px - 60vh - 240px)` }"
/>
/> -->
<div class="analysis-table-left">
<div class="analysis-box-lable w-full flex justify-end">
<span>目标清晰度</span>
<span class="w-[40px]" />
<span class="w-[120px]" />
<span class="ml-1">目标清晰度</span>
</div>
<el-scrollbar :height="`calc(${height}px - 60vh - 220px)`">
<el-scrollbar :height="hightFlag ? `270px` : `180px`">
<div
v-for="(item, index) in carEvenList"
:key="index"
@ -426,12 +464,11 @@ onMounted(() => {
}}</span>
<div class="defect-image">
<el-image
style="height: 100px"
:src="item.pic_path"
:zoom-rate="1.2"
:preview-src-list="[item.pic_path]"
fit="cover"
class="w-[100px]"
class="w-[100%] h-[100%] rounded"
/>
<span>{{ item.car_number }}</span>
</div>
@ -442,7 +479,7 @@ onMounted(() => {
</div>
</div>
</div>
<PureTableBar
<!-- <PureTableBar
title="视频分析列表"
:columns="columns"
@refresh="onSearch"
@ -450,7 +487,7 @@ onMounted(() => {
<template v-slot="{ size, dynamicColumns }">
<pure-table
adaptive
align-whole="center"
align-whole="left"
table-layout="auto"
:loading="loading"
:size="size"
@ -460,18 +497,16 @@ onMounted(() => {
:paginationSmall="size === 'small' ? true : false"
:header-cell-style="{
background: 'var(--el-table-row-hover-bg-color)',
backgroundColor: 'cornflowerblue',
color: 'var(--el-text-color-primary)'
// color: 'blue'
}"
@page-size-change="handleSizeChange"
@page-current-change="handleCurrentChange"
>
<template #relative_time="{ row }">
<span>{{ dataFormate(row.relative_time) }}</span>
</template>
<template #behavior="{ row }">
<span style="color: red">{{ row.abnormal_behavior }}</span>
<span :class="tagStyle(row.abnormal_behavior)">{{
row.abnormal_behavior
}}</span>
</template>
<template #image="{ row, index }">
<el-image
@ -481,13 +516,20 @@ onMounted(() => {
:preview-src-list="[row.abnormal_pic]"
:initial-index="index"
fit="cover"
class="w-[100px] h-[100px]"
class="h-[56px]"
/>
</template>
<template #exception_type="{ row }">
<el-button :type="getRandType(row.exception_type)">
<span
:class="
row.exception_type == '异常1'
? 'isbehavior'
: 'default-behavior'
"
:type="getRandType(row.exception_type)"
>
{{ row.exception_type }}
</el-button>
</span>
</template>
<template #video="{ row }">
<el-button
@ -502,7 +544,66 @@ onMounted(() => {
</template>
</pure-table>
</template>
</PureTableBar>
</PureTableBar> -->
<div class="w-full h-[58px] flex items-center">
<h4>视频分析列表</h4>
</div>
<pure-table
adaptive
align-whole="left"
table-layout="auto"
:loading="loading"
:data="videoData"
:columns="columns"
:pagination="pagination"
:paginationSmall="false"
:header-cell-style="{
background: 'var(--el-table-row-hover-bg-color)',
color: 'var(--el-text-color-primary)'
// color: 'blue'
}"
@page-size-change="handleSizeChange"
@page-current-change="handleCurrentChange"
>
<template #behavior="{ row }">
<span :class="tagStyle(row.abnormal_behavior)">{{
row.abnormal_behavior
}}</span>
</template>
<template #image="{ row, index }">
<el-image
preview-teleported
loading="lazy"
:src="row.abnormal_pic"
:preview-src-list="[row.abnormal_pic]"
:initial-index="index"
fit="cover"
class="h-[56px] rounded"
/>
</template>
<template #exception_type="{ row }">
<span
:class="
row.exception_type == '异常1'
? 'isbehavior'
: 'default-behavior'
"
:type="getRandType(row.exception_type)"
>
{{ row.exception_type }}
</span>
</template>
<template #video="{ row }">
<el-button
class="reset-margin"
link
type="primary"
@click="handleUpdate(row)"
>
播放视频
</el-button>
</template>
</pure-table>
</el-card>
</el-col>
</el-row>
@ -531,49 +632,78 @@ onMounted(() => {
.analysis-content {
.analysis-box {
width: 48%;
padding: 20px;
box-shadow: 5px 5px 5px rgb(0 0 0 / 2.5%), 5px -5px 5px rgb(0 0 0 / 2.5%),
-5px 5px 5px rgb(0 0 0 / 2.5%), -5px -5px 5px rgb(0 0 0 / 2.5%);
width: 49.5%;
// padding: 20px;
// box-shadow: 5px 5px 5px rgb(0 0 0 / 2.5%), 5px -5px 5px rgb(0 0 0 / 2.5%),
// -5px 5px 5px rgb(0 0 0 / 2.5%), -5px -5px 5px rgb(0 0 0 / 2.5%);
// background: skyblue;
// height: 400px;
// border: 1px solid #eee;
// border-radius: 4px;
.analysis-box-label {
font-size: 20px;
font-weight: bold;
color: dodgerblue;
display: block;
margin-bottom: 16px;
font-size: 16px;
font-weight: 600;
color: rgb(51 51 51 / 100%);
}
.analysis-table {
display: flex;
justify-content: space-between;
width: 100%;
border: 1px solid #eee;
border-radius: 4px;
.analysis-table-left {
width: 45%;
// width: 45%;
flex: 1;
.analysis-box-lable {
display: flex;
align-items: center;
justify-content: space-around;
// padding-left: 20px;
height: 48px;
padding-right: 10px;
font-size: 14px;
color: #303133;
background: #f5f7fa;
}
.scrollbar-item {
box-sizing: border-box;
display: flex;
align-items: center;
justify-content: space-around;
margin-bottom: 20px;
height: 90px;
padding: 10px 20px 10px 0;
font-size: 14px;
border-bottom: 1px solid #eee;
// margin-bottom: 20px;
.defect-image {
position: relative;
display: flex;
align-items: center;
justify-content: center;
width: 120px;
height: 70px;
background: #eee;
border-radius: 4px;
span {
position: absolute;
bottom: 7px;
bottom: 0;
left: 0;
width: 100%;
height: 30px;
line-height: 30px;
height: 24px;
font-size: 12px;
line-height: 24px;
color: #fff;
text-align: center;
background-color: rgb(0 0 0 / 50%);
background-color: rgb(0 0 0 / 60%);
border-radius: 0 0 4px 4px;
}
}
}
@ -587,26 +717,117 @@ onMounted(() => {
}
.span-first {
font-size: 28px;
font-weight: bold;
color: #e02828;
box-sizing: border-box;
width: 24px;
height: 24px;
font-size: 14px;
line-height: 20px;
color: #fff;
text-align: center;
background: rgb(224 40 40 / 100%);
border: 3px solid rgb(252 171 171 / 100%);
border-radius: 50%;
}
.span-second {
font-size: 28px;
font-weight: bold;
color: #e58b03;
box-sizing: border-box;
width: 24px;
height: 24px;
font-size: 14px;
line-height: 20px;
color: #fff;
text-align: center;
background: rgb(229 139 3 / 100%);
border: 3px solid rgb(255 223 173 / 100%);
border-radius: 50%;
}
.span-third {
font-size: 28px;
font-weight: bold;
color: #516ee0;
box-sizing: border-box;
width: 24px;
height: 24px;
font-size: 14px;
line-height: 20px;
color: #fff;
text-align: center;
background: rgb(81 110 224 / 100%);
border: 3px solid rgb(173 190 255 / 100%);
border-radius: 50%;
}
.span-default {
font-size: 28px;
font-weight: bold;
color: #555a64;
box-sizing: border-box;
width: 24px;
height: 24px;
font-size: 14px;
line-height: 24px;
color: rgb(51 51 51 / 100%);
text-align: center;
background: rgb(28 13 130 / 15%);
border-radius: 50%;
}
.btn-style {
font-size: 20px;
font-weight: 600;
color: rgb(51 51 51 / 100%);
}
.isbehavior,
.default-behavior {
box-sizing: border-box;
display: inline-block;
width: 64px;
height: 24px;
font-size: 12px;
color: #fff;
text-align: center;
background: #f56c6c;
border-radius: 2px;
}
.default-behavior {
background: #448bf5;
}
.span-occlusion,
.span-smoke,
.span-money,
.span-stillness,
.span-shake {
box-sizing: border-box;
display: inline-block;
width: 64px;
height: 24px;
font-size: 12px;
color: rgb(247 95 25 / 100%);
text-align: center;
background: rgb(247 112 49 / 10%);
border: 1px solid #f75f19;
border-radius: 2px;
}
.span-smoke {
color: rgb(2 36 215 / 100%);
background: rgb(2 36 215 / 10%);
border: 1px solid rgb(2 36 215 / 100%);
}
.span-money {
color: rgb(232 13 13 / 100%);
background: rgb(232 13 13 / 10%);
border: 1px solid rgb(232 13 13 / 100%);
}
.span-stillness {
color: rgb(68 174 245 / 100%);
background: rgb(68 174 245 / 10%);
border: 1px solid rgb(68 174 245 / 100%);
}
.span-shake {
color: rgb(246 148 0 / 100%);
background: rgb(246 148 0 / 10%);
border: 1px solid rgb(246 148 0 / 100%);
}
</style>

Loading…
Cancel
Save