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