feat: 引入mock完成视频分析模块静态交互
parent
d8e35d30a0
commit
d0a2edeb6e
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* @Author: donghao donghao@supervision.ltd
|
||||||
|
* @Date: 2025-03-11 11:29:02
|
||||||
|
* @LastEditors: donghao donghao@supervision.ltd
|
||||||
|
* @LastEditTime: 2025-08-19 11:39:52
|
||||||
|
* @FilePath: \5G-Loading-Bay-Web\mock\poleMonitor.ts
|
||||||
|
* @Description: 撑杆监测
|
||||||
|
*/
|
||||||
|
import { MockMethod } from "vite-plugin-mock";
|
||||||
|
import { poleMonitorListData, fileListData } from "./pools/commonData";
|
||||||
|
import { fetchCurrPageByList, fetchMockSuccessFullByOther } from "./utils/apiMock";
|
||||||
|
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
url: "/api/v1/record/generator_result/",
|
||||||
|
method: "post",
|
||||||
|
response: req => {
|
||||||
|
// console.log(req);
|
||||||
|
return {...fetchMockSuccessFullByOther(fileListData)}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
] as MockMethod[];
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* @Author: donghao donghao@supervision.ltd
|
||||||
|
* @Date: 2025-03-11 11:30:09
|
||||||
|
* @LastEditors: donghao donghao@supervision.ltd
|
||||||
|
* @LastEditTime: 2025-08-19 17:35:17
|
||||||
|
* @FilePath: \5G-Loading-Bay-Web\mock\pools\poleMonitorData.ts
|
||||||
|
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||||
|
*/
|
||||||
|
import Mock from "mockjs";
|
||||||
|
import { isImage } from "../utils/is";
|
||||||
|
const fileUrls = [
|
||||||
|
"https://t7.baidu.com/it/u=72176654,472254471&fm=193",
|
||||||
|
"https://img2.baidu.com/it/u=1319203967,453193481&fm=253&fmt=auto&app=120&f=JPEG?w=1023&h=685",
|
||||||
|
"https://img2.baidu.com/it/u=1876217523,3868046800&fm=253&fmt=auto&app=120&f=JPEG?w=1200&h=800",
|
||||||
|
"https://picx.zhimg.com/v2-a8b8217d6aad02940be44a657cb55a99_r.jpg?source=1940ef5c",
|
||||||
|
"https://img0.baidu.com/it/u=108226426,371429720&fm=253&fmt=auto&app=138&f=JPEG?w=749&h=500",
|
||||||
|
"https://img1.baidu.com/it/u=967792105,51180745&fm=253&fmt=auto?w=1200&h=800",
|
||||||
|
"https://picx.zhimg.com/v2-026d3f92c9984a21dc217018d3b228a7_r.jpg?source=1def8aca",
|
||||||
|
];
|
||||||
|
const mockListData = Mock.mock({
|
||||||
|
// 生成 10 条数据,可以根据需要调整数量
|
||||||
|
"data|140": [
|
||||||
|
{
|
||||||
|
// 车号,生成随机的 4 位字母和数字组合
|
||||||
|
train_number: /[A-Z0-9]{10}/,
|
||||||
|
// 车型,从预定义的数组中随机选择一个
|
||||||
|
train_model: () => Mock.Random.pick(["轿车", "SUV", "客车", "货车"]),
|
||||||
|
// 车厢号,生成 1 到 10 的随机整数
|
||||||
|
"train_carriage_number|1-10": 1,
|
||||||
|
// 告警类型,从预定义的数组中随机选择一个
|
||||||
|
alarm_type: () =>
|
||||||
|
Mock.Random.pick(["超速告警", "碰撞告警", "低电量告警"]),
|
||||||
|
// 故障类型,从预定义的数组中随机选择一个
|
||||||
|
faultType: () => Mock.Random.pick(["撑杆弯曲", "撑杆断折"]),
|
||||||
|
// 等级,生成 1 到 3 的随机整数
|
||||||
|
"level|1-3": 1,
|
||||||
|
// 复核,随机生成 '是' 或 '否'
|
||||||
|
is_reviewed: () => Mock.Random.pick([true, false]),
|
||||||
|
// 时间,生成过去一个月内的随机日期和时间
|
||||||
|
created_at: () =>
|
||||||
|
Mock.Random.date("yyyy-MM-dd") + " " + Mock.Random.time("HH:mm:ss"),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const mockFilesData = Mock.mock({
|
||||||
|
[`list|${fileUrls.length}`]: [
|
||||||
|
{
|
||||||
|
"id|+1": 10,
|
||||||
|
key: "@id",
|
||||||
|
name: "@animal",
|
||||||
|
image_url: function () {
|
||||||
|
// 依次取出视频链接
|
||||||
|
const currFile = fileUrls[this.id - 10];
|
||||||
|
return fileUrls[this.id - 10];
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
created_at: '@datetime("yyyy-MM-dd HH:mm:ss")',
|
||||||
|
updated_at: '@datetime("yyyy-MM-dd HH:mm:ss")',
|
||||||
|
length: "@float(0.1, 10, 2, 2)",
|
||||||
|
width: "@float(0.1, 10, 2, 2)",
|
||||||
|
height: "@float(0.1, 10, 2, 2)",
|
||||||
|
weight: "@float(0.1, 1000, 1, 2)",
|
||||||
|
volume: function () {
|
||||||
|
return (this.length * this.width * this.height).toFixed(2);
|
||||||
|
},
|
||||||
|
record: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
// console.log(mockListData, 'mockListData');
|
||||||
|
const currentData = mockListData.data;
|
||||||
|
const currentFilesData = mockFilesData.list;
|
||||||
|
|
||||||
|
export const fileListData = {
|
||||||
|
data: {
|
||||||
|
data: currentFilesData,
|
||||||
|
},
|
||||||
|
};
|
Binary file not shown.
After Width: | Height: | Size: 755 KiB |
Binary file not shown.
After Width: | Height: | Size: 498 B |
Binary file not shown.
After Width: | Height: | Size: 7.3 KiB |
Binary file not shown.
After Width: | Height: | Size: 6.9 KiB |
@ -0,0 +1,169 @@
|
|||||||
|
<!--
|
||||||
|
* @Author: donghao donghao@supervision.ltd
|
||||||
|
* @Date: 2025-08-14 13:38:30
|
||||||
|
* @LastEditors: donghao donghao@supervision.ltd
|
||||||
|
* @LastEditTime: 2025-08-19 14:21:29
|
||||||
|
* @FilePath: \5G-Web\src\views\dashboard\components\SwpierMonitor.vue
|
||||||
|
* @Description: 外观、撑杆统一封装轮播图&视频组件
|
||||||
|
-->
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import Player from "@/components/videoPlayer/Player.vue";
|
||||||
|
import SwiperPlayer from "./SwiperPlayer.vue";
|
||||||
|
import { Swiper, SwiperSlide } from "swiper/vue";
|
||||||
|
import { Navigation, Scrollbar, Mousewheel, Pagination } from "swiper/modules";
|
||||||
|
import "swiper/css";
|
||||||
|
import "swiper/scss";
|
||||||
|
import "swiper/scss/navigation";
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
value: number;
|
||||||
|
fileList: Record<string, any>[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Emits {
|
||||||
|
(e: "update:value", val: boolean): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
value: false,
|
||||||
|
fileList: [],
|
||||||
|
});
|
||||||
|
const emit = defineEmits<Emits>();
|
||||||
|
|
||||||
|
|
||||||
|
const modules = [Navigation, Scrollbar];
|
||||||
|
const activeIndex = ref(-1);
|
||||||
|
const swiperRef = ref(null);
|
||||||
|
const isPlaying = ref<boolean>(false); // 是否播放
|
||||||
|
const currFile = ref<Record<string, any>>({}); // 详情数据
|
||||||
|
|
||||||
|
const togglePlay = () => {
|
||||||
|
isPlaying.value = !isPlaying.value;
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSlideClick = (index) => {
|
||||||
|
if (activeIndex.value === index) {
|
||||||
|
togglePlay(); // 播放 暂停
|
||||||
|
} else {
|
||||||
|
isPlaying.value = false;
|
||||||
|
emit("update:value", index);
|
||||||
|
currFile.value = props.fileList[index];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const onSwiper = (swiper) => {
|
||||||
|
swiperRef.value = swiper;
|
||||||
|
console.log("Swiper 实例已获取:", swiper);
|
||||||
|
};
|
||||||
|
const onSlideChange = () => {
|
||||||
|
console.log("slide change");
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.fileList,
|
||||||
|
(newVal) => {
|
||||||
|
currFile.value = newVal?.[0];
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.value,
|
||||||
|
(newVal) => {
|
||||||
|
console.log("swiperFile_newVal", newVal);
|
||||||
|
activeIndex.value = newVal;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="w-full h-full fg-swiper-file-wrap">
|
||||||
|
<!-- 缩略图区域 -->
|
||||||
|
<div class="flex" v-if="fileList?.length > 0">
|
||||||
|
<div class="thumbnail-container">
|
||||||
|
<!-- //TODO 轮播效果调整 -->
|
||||||
|
<swiper
|
||||||
|
ref="swiperRef"
|
||||||
|
:modules="modules"
|
||||||
|
:slides-per-view="4"
|
||||||
|
:space-between="12"
|
||||||
|
:navigation="true"
|
||||||
|
:scrollbar="{ draggable: false }"
|
||||||
|
:centered-slides="false"
|
||||||
|
:observer="true"
|
||||||
|
:observeParents="true"
|
||||||
|
@swiper="onSwiper"
|
||||||
|
@slideChange="onSlideChange"
|
||||||
|
>
|
||||||
|
<swiper-slide
|
||||||
|
v-for="(file, index) in fileList"
|
||||||
|
:key="index"
|
||||||
|
@click="handleSlideClick(index)"
|
||||||
|
:class="{ 'active-slide': activeIndex === index }"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:src="file?.image_url"
|
||||||
|
v-if="file?.image_url"
|
||||||
|
class="cursor-pointer"
|
||||||
|
/>
|
||||||
|
<SwiperPlayer
|
||||||
|
class="cursor-pointer"
|
||||||
|
:videoUrl="file?.video_url"
|
||||||
|
v-else-if="file?.video_url"
|
||||||
|
:isPlaying="isPlaying && activeIndex === index"
|
||||||
|
/>
|
||||||
|
<div v-else>
|
||||||
|
<!-- 视频【图片】加载失败 -->
|
||||||
|
</div>
|
||||||
|
</swiper-slide>
|
||||||
|
</swiper>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.fg-swiper-file-wrap {
|
||||||
|
.thumbnail-container {
|
||||||
|
overflow: visible;
|
||||||
|
margin-right: 16px;
|
||||||
|
.swiper {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
.swiper-slide {
|
||||||
|
img,
|
||||||
|
video {
|
||||||
|
border-radius: 4px;
|
||||||
|
object-fit: cover;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.active-slide img,
|
||||||
|
.active-slide video {
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 2px solid #2ecce0;
|
||||||
|
}
|
||||||
|
.swiper-button-prev,
|
||||||
|
.swiper-button-next {
|
||||||
|
background-color: rgba(0, 0, 0, 0.5);
|
||||||
|
color: white;
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swiper-button-prev::after,
|
||||||
|
.swiper-button-next::after {
|
||||||
|
font-size: 12px;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 修改按钮悬停样式 */
|
||||||
|
.swiper-button-prev:hover,
|
||||||
|
.swiper-button-next:hover {
|
||||||
|
background-color: rgba(0, 0, 0, 0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -0,0 +1,62 @@
|
|||||||
|
<!--
|
||||||
|
* @Author: donghao donghao@supervision.ltd
|
||||||
|
* @Date: 2025-08-19 11:04:59
|
||||||
|
* @LastEditors: donghao donghao@supervision.ltd
|
||||||
|
* @LastEditTime: 2025-08-19 11:26:43
|
||||||
|
* @FilePath: \5G-Web\src\components\Swiper\SwiperPlayer.vue
|
||||||
|
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<div class="flex items-center justify-center w-full h-full position-relative">
|
||||||
|
<video
|
||||||
|
ref="videoRef"
|
||||||
|
:controls="false"
|
||||||
|
muted
|
||||||
|
:src="videoUrl"
|
||||||
|
width="100%"
|
||||||
|
height="148"
|
||||||
|
style="object-fit: cover"
|
||||||
|
@error="handleVideoError"
|
||||||
|
v-if="!isVideoError"
|
||||||
|
></video>
|
||||||
|
<div class="bg_error_img" v-if="isVideoError"></div>
|
||||||
|
<div :class="{ bg_icon: true, playing: isPlaying }" v-if="!isVideoError">
|
||||||
|
<!-- {{ isPlaying }} -->
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script lang="ts" setup>
|
||||||
|
const props = defineProps<{
|
||||||
|
videoUrl: string;
|
||||||
|
isPlaying: boolean;
|
||||||
|
}>();
|
||||||
|
const videoRef = ref<HTMLVideoElement | null>(null);
|
||||||
|
const isVideoError = ref<boolean>(false);
|
||||||
|
|
||||||
|
const handleVideoError = () => {
|
||||||
|
console.log("handleVideoError");
|
||||||
|
isVideoError.value = true;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.bg_error_img {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: url("@/assets/common/load_file_error.png") no-repeat center center;
|
||||||
|
background-size: 50%;
|
||||||
|
border: 1px dashed red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bg_icon {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: url("@/assets/common/player_icon_1.png") no-repeat center center;
|
||||||
|
background-size: 40px;
|
||||||
|
|
||||||
|
&.playing {
|
||||||
|
background: url("@/assets/common/player_icon_2.png") no-repeat center center;
|
||||||
|
background-size: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue