feat: 历史视频弹窗交互完成

main
donghao 2 months ago
parent dca21403de
commit 9f0ff58efa

@ -2,17 +2,17 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2025-03-07 14:57:20
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-03-07 15:10:10
* @LastEditTime: 2025-03-13 14:34:44
* @FilePath: \5G-Loading-Bay-Web\mock\deviceStatus.ts
* @Description:
*/
import { MockMethod } from "vite-plugin-mock";
import { deviceStatusListData } from "./pools/deviceStatusData";
import { fetchCurrPageByList } from "./utils/apiMock";
import { deviceStatusListData, deviceHistoryListData } from "./pools/deviceStatusData";
import { fetchCurrPageByList, fetchMockSuccessFullByOther } from "./utils/apiMock";
export default [
{
url: "/api/getDeviceStatusList",
url: "/api/v1/device/device/",
method: "post",
response: req => {
const { page, pageSize } = req.body;
@ -28,5 +28,14 @@ export default [
})
};
}
},
{
url: "/api/v1/device/device_history/",
method: "post",
response: req => {
const { page, pageSize } = req.body;
// console.log(req);
return {...fetchMockSuccessFullByOther(deviceHistoryListData)}
}
}
] as MockMethod[];

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2024-02-22 13:38:04
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-03-07 15:07:28
* @LastEditTime: 2025-03-13 14:35:20
* @FilePath: \General-AI-Platform-Web-Client\mock\pools\deviceStatusData.ts
* @Description:
*/
@ -46,13 +46,130 @@ function fetchList(): Record<string, any>[] {
// 告警代码MSRF-0 RL0F HTFIF-02 TLOC-1 E1AIS-05
// 设备组核心检测组001 无尘总装组005 送料监测线02
const mockHistroyData = [
{
id: 10,
key: "10",
video_url: "https://www.w3schools.com/html/mov_bbb.mp4",
created_at: "2025-03-12 14:53:36",
device: 1
},
{
id: 11,
key: "11",
video_url: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4",
created_at: "2025-03-12 15:20:15",
device: 1
},
{
id: 12,
key: "12",
video_url: "https://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4",
created_at: "2025-03-13 09:45:22",
device: 1
},
{
id: 20,
key: "10",
video_url: "https://www.w3schools.com/html/mov_bbb.mp4",
created_at: "2025-03-12 14:53:36",
device: 1
},
{
id: 21,
key: "11",
video_url: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4",
created_at: "2025-03-12 15:20:15",
device: 1
},
{
id: 22,
key: "12",
video_url: "https://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4",
created_at: "2025-03-13 09:45:22",
device: 1
},
// {
// id: 10,
// key: "10",
// video_url: "https://www.w3schools.com/html/mov_bbb.mp4",
// created_at: "2025-03-12 14:53:36",
// device: 1
// },
// {
// id: 11,
// key: "11",
// video_url: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4",
// created_at: "2025-03-12 15:20:15",
// device: 1
// },
// {
// id: 12,
// key: "12",
// video_url: "https://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4",
// created_at: "2025-03-13 09:45:22",
// device: 1
// },
// {
// id: 10,
// key: "10",
// video_url: "https://www.w3schools.com/html/mov_bbb.mp4",
// created_at: "2025-03-12 14:53:36",
// device: 1
// },
// {
// id: 11,
// key: "11",
// video_url: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4",
// created_at: "2025-03-12 15:20:15",
// device: 1
// },
// {
// id: 12,
// key: "12",
// video_url: "https://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4",
// created_at: "2025-03-13 09:45:22",
// device: 1
// },
// {
// id: 10,
// key: "10",
// video_url: "https://www.w3schools.com/html/mov_bbb.mp4",
// created_at: "2025-03-12 14:53:36",
// device: 1
// },
// {
// id: 11,
// key: "11",
// video_url: "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4",
// created_at: "2025-03-12 15:20:15",
// device: 1
// },
// {
// id: 12,
// key: "12",
// video_url: "https://download.blender.org/peach/bigbuckbunny_movies/BigBuckBunny_320x180.mp4",
// created_at: "2025-03-13 09:45:22",
// device: 1
// }
];
const currentData = fetchList();
const currentHistroyData = mockHistroyData;
//
export const deviceStatusListData = {
data: {
list: currentData,
data: currentData,
total: currentData.length,
page: 1,
current: 1,
pageSize: 10
}
};
export const deviceHistoryListData = {
data: currentHistroyData
}

@ -1,39 +1,47 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2025-03-07 14:58:39
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-03-13 14:29:26
* @FilePath: \5G-Loading-Bay-Web\mock\utils\apiMock.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import { failMockApiProps, successMockApiProps } from "../typing";
export function fetchMockSuccessFullByOther({
data,
msg
msg,
}): successMockApiProps {
// return {
// code: 0, // 0 成功
// code: 200, // 200 成功
// success: true, // true 成功
// data: data || null, // mock业务层数据
// msg: msg | "ok", // 成功提示
// isMock: true // true 标识当前是模拟数据
// } as successMockApiProps;
const result: successMockApiProps = {
code: 0, // 0 成功
code: 200, // 200 成功
success: true, // true 成功
data: data || null, // mock业务层数据
msg: msg as string | "ok", // 成功提示
isMock: true // true 标识当前是模拟数据
isMock: true, // true 标识当前是模拟数据
};
return result;
}
export function fetchMockFailFullByOther({ data, msg }): failMockApiProps {
// return {
// code: 599, // 0 成功
// code: 599, // 200 成功
// success: true, // true 成功
// data: data || null, // mock业务层数据
// msg: msg | "fail", // 成功提示
// isMock: true // true 标识当前是模拟数据
// } as failMockApiProps;
const result: failMockApiProps = {
code: 599, // 0 成功
code: 599, // 200 成功
success: false, // true 成功
data: data || null, // mock业务层数据
msg: msg as string | "fail", // 成功提示
isMock: true // true 标识当前是模拟数据
isMock: true, // true 标识当前是模拟数据
};
return result;
}
@ -41,11 +49,11 @@ export function fetchMockFailFullByOther({ data, msg }): failMockApiProps {
// 分页展示
export function fetchCurrPageByList({ data }): successMockApiProps {
// console.log("fetchCurrPageByList_data", data);
const { page, pageSize } = data;
const prevPage = page - 1;
const { current, pageSize } = data;
const prevPage = current - 1;
const currPageData = {
...data,
list: data.list.slice(prevPage * pageSize, page * pageSize)
data: data.data.slice(prevPage * pageSize, current * pageSize),
};
return fetchMockSuccessFullByOther({ data: currPageData });
}

@ -15,6 +15,7 @@
"dependencies": {
"axios": "^1.8.3",
"echarts": "^5.6.0",
"moment": "^2.30.1",
"postcss-scss": "^4.0.9",
"sass": "^1.85.1",
"swiper": "^11.2.5",

@ -14,6 +14,9 @@ importers:
echarts:
specifier: ^5.6.0
version: 5.6.0
moment:
specifier: ^2.30.1
version: 2.30.1
postcss-scss:
specifier: ^4.0.9
version: 4.0.9(postcss@8.5.3)
@ -1455,6 +1458,9 @@ packages:
resolution: {integrity: sha512-eQsKcWzIaZzEZ07NuEyO4Nw65g0hdWAyurVol1IPl1gahRwY+svqzfgfey8U8dahLwG44d6/RwEzuK52rSa/JQ==}
hasBin: true
moment@2.30.1:
resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==}
mpd-parser@1.3.1:
resolution: {integrity: sha512-1FuyEWI5k2HcmhS1HkKnUAQV7yFPfXPht2DnRRGtoiiAAW+ESTbtEXIDpRkwdU+XyrQuwrIym7UkoPKsZ0SyFw==}
hasBin: true
@ -3224,6 +3230,8 @@ snapshots:
dependencies:
commander: 13.1.0
moment@2.30.1: {}
mpd-parser@1.3.1:
dependencies:
'@babel/runtime': 7.26.10

Binary file not shown.

After

Width:  |  Height:  |  Size: 876 B

@ -2,10 +2,178 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2025-03-12 13:48:31
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-03-12 13:56:15
* @LastEditTime: 2025-03-13 15:01:16
* @FilePath: \5G-Loading-Bay-Web\src\components\videoPlayer\player.vue
* @Description: 视频播放器
-->
<template>
<!-- 视频播放器 -->
<div class="video-player-box">
<video ref="videoRef" class="video-element" controls @timeupdate="handleTimeUpdate"
@loadedmetadata="handleLoadedMetadata" @play="handlePlay" @pause="handlePause" @waiting="handleWaiting"
@canplay="handleCanPlay" style="object-fit: fill;">
<source :src="src" type="video/mp4">
您的浏览器不支持视频播放
</video>
<!-- 加载状态提示 -->
<div v-if="loading" class="loading-overlay">
<el-icon class="is-loading">
<Loading />
</el-icon>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, watch, onMounted, onUnmounted } from 'vue'
import { ElIcon } from 'element-plus'
import { Loading } from '@element-plus/icons-vue'
type ProgressData = {
currentTime: number
duration: number
progress: number
}
const props = defineProps({
src: {
type: String,
required: true
},
isPlaying: {
type: Boolean,
default: false
}
})
const emit = defineEmits<{
(e: 'update:progress', data: ProgressData): void
(e: 'update:duration', duration: number): void
(e: 'play'): void
(e: 'pause'): void
}>()
const videoRef = ref<HTMLVideoElement | null>(null)
const loading = ref(false)
let currentDuration = 0
//
watch(() => props.isPlaying, (newVal) => {
if (!videoRef.value) return
newVal ? videoRef.value.play() : videoRef.value.pause()
})
//
watch(() => props.src, (newVal) => {
if (!videoRef.value) return
videoRef.value.pause()
videoRef.value.src = newVal
videoRef.value.load()
if (props.isPlaying) {
videoRef.value.play()
}
})
//
const handleTimeUpdate = () => {
if (!videoRef.value) return
const currentTime = videoRef.value.currentTime
const progress = currentDuration > 0
? (currentTime / currentDuration) * 100
: 0
emit('update:progress', {
currentTime,
duration: currentDuration,
progress
})
}
//
const handleLoadedMetadata = () => {
if (!videoRef.value) return
currentDuration = videoRef.value.duration
emit('update:duration', currentDuration)
}
//
const handlePlay = () => emit('play')
const handlePause = () => emit('pause')
//
const handleWaiting = () => loading.value = true
const handleCanPlay = () => loading.value = false
onMounted(() => {
if (videoRef.value) {
videoRef.value.src = props.src
}
})
onUnmounted(() => {
if (videoRef.value) {
videoRef.value.pause()
videoRef.value.removeAttribute('src')
videoRef.value.load()
}
})
//
defineExpose({
play: () => videoRef.value?.play(),
pause: () => videoRef.value?.pause(),
seek: (time: number) => {
if (videoRef.value) {
videoRef.value.currentTime = time
}
}
})
</script>
<style lang="scss">
.video-player-box {
position: relative;
width: 100%;
margin: 0 auto;
.video-element {
width: 100%;
height: auto;
border-radius: 8px;
}
.loading-overlay {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
color: white;
}
.el-icon.is-loading {
font-size: 32px;
animation: rotating 2s linear infinite;
}
@keyframes rotating {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
}
</style>

@ -0,0 +1,32 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2025-03-13 16:12:49
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-03-13 16:25:52
* @FilePath: \5G-Loading-Bay-Web\src\utils\array.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import moment from 'moment';
export function extractUniqueDatesWithMoment(data: { created_at: string }[]): string[] {
const dateSet = new Set<string>();
data.forEach(item => {
// 使用 moment 解析 created_at 字段并格式化为 YYYY-MM-DD
const formattedDate = moment(item.created_at).format('YYYY-MM-DD');
dateSet.add(formattedDate);
});
return Array.from(dateSet);
}
export function filterDataByDate(data: { created_at: string }[], targetDate: string): { created_at: string }[] {
// 补全开始时间为目标日期的 0 点
const startTime = moment(targetDate).startOf('day').format('YYYY-MM-DD HH:mm:ss');
// 补全结束时间为目标日期的 23:59:59
const endTime = moment(targetDate).endOf('day').format('YYYY-MM-DD HH:mm:ss');
return data.filter(item => {
const createdAt = moment(item.created_at);
return createdAt.isBetween(startTime, endTime, null, '[]');
});
}

@ -1,3 +1,11 @@
/*
* @Author: donghao donghao@supervision.ltd
* @Date: 2025-03-12 15:12:58
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-03-13 13:42:24
* @FilePath: \5G-Loading-Bay-Web\src\utils\request\instance.ts
* @Description: ,`customMade`, koroFileHeader : https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
*/
import Request from './index'
import { config } from '@/config'
import { ElLoading } from "element-plus";
@ -20,7 +28,7 @@ const request = new Request({
}
// 全局 loading 配置
if (config.showLoading !== false) {
if (config.showLoading) {
const loading = ElLoading.service({
lock: true,
text: '加载中...',

@ -44,7 +44,8 @@
</div>
</div>
<RealVideoModal v-model:value="isRealOpen" :info="currentRow" @close="isRealOpen = false" />
<HistoryVideoModal />
<HistoryVideoModal ref="historyModalRef" v-model:value="isHistoryOpen" :info="currentRow"
:historyVideos="historyVideos" @close="isHistoryOpen = false" />
</div>
</template>
@ -59,6 +60,7 @@ import outLineIcon from '@/assets/common/outline_icon.png';
import errorIcon from '@/assets/common/error_icon.png';
import { getDeviceStatusApi } from '@/api/dashboard';
import { isSuccessApi } from "@/utils/forApi";
import { nextTick } from "vue";
defineOptions({
name: "DeviceStatusIndex"
});
@ -99,6 +101,8 @@ const alarmLevelStatusEnum = {
const currentRow = ref<Record<string, any>>({});
const isRealOpen = ref<Boolean>(false); //
const isHistoryOpen = ref<Boolean>(false); //
const historyVideos = ref<Record<string, any>[]>([]); //
const historyModalRef = ref(null);
const columns = [
{
@ -120,8 +124,6 @@ const columns = [
console.log(val);
const currentLevelObj =
alarmLevelStatusEnum[val?.device_status] || alarmLevelStatusEnum.notFound;
return h(
"div",
{
@ -153,7 +155,6 @@ const columns = [
);
}
},
// TODO
{
type: "action",
label: "操作"
@ -197,12 +198,33 @@ function openCurrent(row) {
}
/**打开历史视频 */
// TODO mock
const fetchHistoryList = async () => {
try {
const resAll = await fetch('/api/v1/device/device_history/', {
method: 'POST'
})
const res = await resAll.json()
if (isSuccessApi(res)) {
historyVideos.value = res.data;
isHistoryOpen.value = true;
nextTick(() => {
historyModalRef.value.loadData()
})
console.log(res, 'fetchHistoryList_data')
}
} catch (error) {
console.error('获取数据失败:', error)
}
}
function openHistory(row) {
console.log(row, "openHistory");
currentRow.value = row;
// TODO
isHistoryOpen.value = true;
fetchHistoryList();
}
onMounted(() => {
getList();
});

@ -1,12 +1,260 @@
<template>
<div class="historyVideoModal-wrap">
<el-dialog class="historyVideoModal-wrap" v-model="show" @close="handleClose">
<!-- 自定义标题栏 -->
<template #header="{ close, titleId, titleClass }">
<div class="flex items-center justify-between video-dialog-header">
<div class="flex items-center justify-center header-left">
<div class="header-icon mr-[12px]"></div>
<p class="overflow-hidden whitespace-nowrap text-ellipsis max-w-[650px]">{{
info.device_name }}</p>
</div>
</div>
</template>
<div class="flex main-content">
<!-- 播放器 -->
<Player :src="currentVideo.video_url" :is-playing="isPlaying" @update:progress="handleProgress"
@update:duration="handleDuration" @play="isPlaying = true" @pause="isPlaying = false" />
<div class="flex video-record-list">
<!-- 日期筛选 -->
<div class="flex pl-[16px] pr-[24px] items-center">
<span>时间</span>
<el-select v-model="selectedDate" placeholder="请选择" class="custom-select record_date_select"
clearable @change="handleDateChange" @clear="handleClear">
<el-option v-for="(item, index) in dateList" :key="item" :label="item"
:value="item"></el-option>
</el-select>
<!-- <el-date-picker v-model="selectedDate" type="date" placeholder="选择日期"
@change="handleDateChange"></el-date-picker> -->
</div>
<!-- 记录列表 -->
<el-scrollbar style="height: calc(100% - 80px)">
<ul class="record-list-box">
<li v-for="(item, index) in recordList" :key="item.id"
:class="{ active: currentVideo?.id === item.id }" @click="handleItemClick(item)"
class="flex items-center justify-between">
<span class="time">{{ item.created_at }}</span>
<div :class="{ 'play-btn': true, 'playing': isPlaying && currentVideo?.id === item.id }">
</div>
</li>
</ul>
</el-scrollbar>
</div>
</div>
</el-dialog>
</template>
<script lang="ts" setup>
import Player from '@/components/videoPlayer/Player.vue'
import { ElMessage } from 'element-plus';
import { extractUniqueDatesWithMoment, filterDataByDate } from '@/utils/array';
interface Props {
/** 弹窗显隐 */
value: boolean;
info: Record<string, any>;
historyVideos: Record<string, any>[];
}
interface Emits {
(e: "update:value", val: boolean): void;
}
const props = withDefaults(defineProps<Props>(), {
value: false,
info: {},
historyVideos: []
});
const emit = defineEmits<Emits>();
//
const dateList = ref<string[]>([]);
const selectedDate = ref(); //
const recordList = ref([]);
const currentVideo = ref<Record<string, any>>({})
const isPlaying = ref(false);
const togglePlay = () => {
isPlaying.value = !isPlaying.value;
};
// TODO 使
const handleProgress = (data: { currentTime: number, duration: number }) => {
console.log((data.currentTime / data.duration) * 100, "handleProgress")
const progressVal = (data.currentTime / data.duration) * 100
}
// TODO 使
const handleDuration = (newDuration: number) => {
// duration.value = newDuration
}
//
const loadData = () => {
recordList.value = props.historyVideos
dateList.value = extractUniqueDatesWithMoment(recordList.value);
currentVideo.value = props.historyVideos[0]; //
};
//
const handleDateChange = (date) => {
console.log(date, "handleDateChange_date");
if (date) {
selectedDate.value = date;
recordList.value = filterDataByDate(toRaw(props.historyVideos), date);
currentVideo.value = recordList.value[0]; //
} else {
loadData()
}
};
//
const handleItemClick = (item) => {
if (currentVideo.value?.id === item.id) {
togglePlay() //
} else {
currentVideo.value = item;
}
};
//
const handleVideoEnd = () => {
// currentIndex.value = -1;
};
//
const formatTime = (timeStr) => {
return timeStr.split(' ')[1].substring(0, 5); //
};
//
const handleClose = () => {
emits('close');
};
const show = computed({
get() {
return props.value;
},
set(val: boolean) {
emit("update:value", val);
}
});
// TODO
defineExpose({ loadData })
</script>
<style lang="scss">
.historyVideoModal-wrap.el-dialog {
border: none;
overflow: hidden;
box-shadow: none;
background-color: transparent;
background-image: url("@/assets/common/bg_player_dialog.png");
background-size: contain;
background-position: center;
background-repeat: no-repeat;
width: 1100px;
height: 612px;
padding: 0;
margin-top: calc(50vh - 316px);
.el-dialog__header.show-close {
padding: 0;
}
.el-dialog__close {
width: 56px;
height: 56px;
color: white;
font-size: 18px;
padding-top: 4px;
padding-right: 20px;
}
.video-dialog-header {
color: white;
padding: 0;
padding-top: 4px;
.header-left {
padding: 0 18px;
font-weight: bold;
font-size: 18px;
.header-icon {
margin-top: 8px;
width: 48px;
height: 48px;
background-image: url("@/assets/common/dialog_title_icon.png");
background-size: contain;
background-position: center;
background-repeat: no-repeat;
}
}
}
.main-content {
padding-left: 24px;
padding-top: 24px;
// background: red;
.video-player-box {
border-radius: 0px 0px 4px 4px;
overflow: hidden;
width: 752px;
height: 502px;
}
.video-record-list {
flex-direction: column;
flex: 1;
color: white;
.record_date_select {
width: 100%;
display: flex;
flex: 1;
.el-select__wrapper {
width: 100%;
}
}
.record-list-box {
margin-top: 5px;
li {
color: white;
height: 32px;
cursor: pointer;
padding-left: 16px;
padding-right: 24px;
&.active,
&:hover {
background: linear-gradient(90deg, rgba(30, 54, 88, 0) 0%, #0C4FAD 53%, rgba(65, 117, 190, 0) 100%);
color: #37DBFF;
}
.time {
flex: 1;
font-size: 14px;
}
.play-btn {
width: 18px;
height: 18px;
background: url("@/assets/common/player_icon.png") no-repeat center center;
background-size: contain;
}
.playing {
background: url("@/assets/common/pause_icon.png") no-repeat center center;
background-size: contain;
}
}
}
}
<style lang="scss" scoped>
}
}
</style>

@ -1,11 +1,12 @@
<template>
<el-dialog v-model="show" @close="handleClose">
<el-dialog class="realVideoModal-wrap" v-model="show" @close="handleClose">
<!-- 自定义标题栏 -->
<template #header="{ close, titleId, titleClass }">
<div class="flex items-center justify-between video-dialog-header">
<div class="flex items-center justify-center header-left">
<div class="header-icon mr-[12px]"></div>
<span>{{ info.name }}</span>
<p class="overflow-hidden whitespace-nowrap text-ellipsis max-w-[650px]">{{
info.device_name }}</p>
</div>
</div>
</template>
@ -28,14 +29,6 @@ interface Props {
interface Emits {
(e: "update:value", val: boolean): void;
}
// const props = withDefaults(defineProps<{
// isOpen: boolean;
// info: Record<string, any>;
// }>(), {
// isOpen: false,
// info: {}
// });
const props = withDefaults(defineProps<Props>(), {
value: false,
info: {}
@ -66,7 +59,7 @@ const show = computed({
</script>
<style lang="scss">
.el-dialog {
.realVideoModal-wrap.el-dialog {
border: none;
overflow: hidden;
box-shadow: none;
@ -78,6 +71,7 @@ const show = computed({
width: 805px;
height: 612px;
padding: 0;
margin-top: calc(50vh - 316px);
.el-dialog__header.show-close {
padding: 0;
@ -98,7 +92,7 @@ const show = computed({
padding-top: 4px;
.header-left {
padding: 0 20px;
padding: 0 18px;
font-weight: bold;
font-size: 18px;

@ -2,7 +2,7 @@
* @Author: donghao donghao@supervision.ltd
* @Date: 2025-03-06 17:57:05
* @LastEditors: donghao donghao@supervision.ltd
* @LastEditTime: 2025-03-13 10:50:03
* @LastEditTime: 2025-03-13 16:55:26
* @FilePath: \5G-Loading-Bay-Web\src\views\login\Login.vue
* @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE?
-->
@ -58,8 +58,8 @@ const router = useRouter()
const userStore = useUserStore()
const form = reactive({
username: 'admin',
password: 'admin',
username: '',
password: '',
remember: false
})
const handleLogin = async () => {

Loading…
Cancel
Save