WholeProcessPlatform/frontend/src/modules/liuyu/ai/spdzwaijc/components/VideoDetails.vue
2026-07-06 08:54:58 +08:00

318 lines
8.1 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="video-details">
<a-tabs v-model:activeKey="activeKey" @change="handleTabChange">
<a-tab-pane key="2" tab="运行">
<a-spin :spinning="loading">
<div class="video-container">
<VideoPlayer
:list="videoList"
:activeFid="activeFid"
:activeMedia="activeMedia"
:loading="loading"
:page="page"
:pageSize="pageSize"
:pageSizeOptions="pageSizeOptions"
:total="total"
@select="handleSelectMedia"
@pageChange="handlePageChange"
/>
</div>
</a-spin>
</a-tab-pane>
<a-tab-pane key="1" tab="未运行">
<a-spin :spinning="loading">
<div class="video-container">
<VideoPlayer
:list="videoList"
:activeFid="activeFid"
:activeMedia="activeMedia"
:loading="loading"
:page="page"
:pageSize="pageSize"
:pageSizeOptions="pageSizeOptions"
:total="total"
@select="handleSelectMedia"
@pageChange="handlePageChange"
/>
</div>
</a-spin>
</a-tab-pane>
</a-tabs>
</div>
</template>
<script lang="ts" setup>
import { ref, watch, onMounted } from 'vue';
import VideoPlayer from '@/modules/yunXingGaoJIng/Aisbdbyx/components/VideoPlayer.vue';
import { getAiFile } from '@/api/zngj';
import { postIdUrl } from '@/api/mapModal';
import dayjs from 'dayjs';
const baseUrl = import.meta.env.VITE_APP_ATTACHMENT_URL;
// ==================== Props ====================
const props = defineProps<{
baseid?: string;
month?: any;
type?: string;
vdDate?: string;
activeKey?: string;
stnm?: string;
rstcd?: string;
pieCode?: string[];
}>();
// ==================== 状态 ====================
const activeKey = ref(props.activeKey || '2');
const loading = ref(false);
const videoList = ref<any[]>([]);
const activeFid = ref('');
const activeMedia = ref<{ type: string; src: string }>({ type: '', src: '' });
const page = ref(1);
const pageSize = ref(20);
const pageSizeOptions = ['20', '50', '100'];
const total = ref(0);
// ==================== 获取视频列表 ====================
const fetchVideoList = async () => {
loading.value = true;
try {
const filters: any[] = [
// baseId过滤
props.pieCode && props.pieCode.length > 0 && props.baseid === 'all'
? {
field: 'baseId',
operator: 'in',
dataType: 'string',
value: props.pieCode
}
: props.baseid && props.baseid !== 'all'
? { field: 'baseId', operator: 'eq', value: props.baseid }
: null,
// rstcd过滤
props.pieCode && props.pieCode.length > 0 && props.baseid !== 'all'
? {
field: 'rstcd',
operator: 'in',
dataType: 'string',
value: props.pieCode
}
: null,
// type过滤
{ field: 'type', operator: 'eq', value: props.type },
// dataType过滤运行/未运行)
{ field: 'dataType', operator: 'eq', value: activeKey.value },
// 时间范围(按天)
{
field: 'tm',
operator: 'gte',
dataType: 'date',
value: dayjs(props.vdDate)
.startOf('day')
.format('YYYY-MM-DD 00:00:00')
},
{
field: 'tm',
operator: 'lte',
dataType: 'date',
value: dayjs(props.vdDate)
.endOf('day')
.format('YYYY-MM-DD 23:59:59')
},
// stnm文本搜索
props.stnm
? { field: 'stnm', operator: 'contains', value: props.stnm }
: null,
// rstcd电站选择
props.rstcd
? {
field: 'rstcd',
operator: 'in',
dataType: 'string',
value: [props.rstcd]
}
: null
].filter(Boolean);
const params = {
filter: { logic: 'and', filters },
sort: [{ field: 'tm', dir: 'desc' }],
skip: (page.value - 1) * pageSize.value,
take: pageSize.value
};
const res: any = await getAiFile(params);
const rData = res?.data ?? {};
const rawData = rData?.data || [];
total.value = rData?.total || rawData.length;
// 按 fid 展开
const expandedData = rawData
.map((item: any) => {
const fids = item.fid ? item.fid.split(',') : [];
return fids.map((fid: string) => ({ ...item, fid: fid.trim() }));
})
.flat();
// 收集所有 fid
const allFids = expandedData
.filter((item: any) => item.fid)
.map((item: any) => item.fid)
.join(',');
// 调用 postIdUrl 获取媒体详情
let mediaMap: Record<string, any> = {};
if (allFids) {
const formData = new FormData();
formData.append('id', allFids);
const mediaRes: any = await postIdUrl(formData);
mediaMap = mediaRes?.data || {};
}
// 构建列表
const list: any[] = [];
expandedData.forEach((vd: any) => {
const fileInfo = mediaMap[vd.fid];
const hasValidExtension =
fileInfo && ['.jpg', '.png'].includes(fileInfo.ext);
let flpth = '';
let imgPath = '';
let type = '';
if (hasValidExtension !== undefined && !hasValidExtension) {
flpth = fileInfo.fullpath;
type = 'vdsp';
} else if (hasValidExtension !== undefined) {
imgPath = fileInfo.fullpath;
type = 'img';
}
const tm = vd.tm ? dayjs(vd.tm).format('YYYY-MM-DD HH:mm:ss') : '-';
list.push({
...vd,
flpth,
imgPath,
flnm: `${vd.ennm || ''}${tm}`,
type,
tm
});
});
// 过滤掉无效项
const listMap = list.filter(
item => item.flpth !== '' || item.imgPath !== ''
);
videoList.value = listMap;
// 默认选中第一条
if (listMap.length > 0) {
const first = listMap[0];
activeFid.value = first.fid;
if (first.type === 'img') {
activeMedia.value = {
type: 'image',
src: baseUrl + '?' + first.fid + '&view=jpg'
};
} else if (first.type === 'vdsp') {
activeMedia.value = {
type: 'video',
src: baseUrl + '?' + first.fid + '&view=jpg'
};
} else {
activeMedia.value = { type: '', src: '' };
}
} else {
activeFid.value = '';
activeMedia.value = { type: '', src: '' };
}
} catch (error) {
console.error('获取视频详情列表失败:', error);
videoList.value = [];
activeFid.value = '';
activeMedia.value = { type: '', src: '' };
} finally {
loading.value = false;
}
};
// ==================== 事件处理 ====================
const handleTabChange = () => {
page.value = 1;
activeFid.value = '';
activeMedia.value = { type: '', src: '' };
fetchVideoList();
};
const handleSelectMedia = (item: any) => {
activeFid.value = item.fid;
if (item.type === 'img') {
activeMedia.value = {
type: 'image',
src: baseUrl + '?' + item.fid + '&view=jpg'
};
} else if (item.type === 'vdsp') {
activeMedia.value = {
type: 'video',
src: baseUrl + '?' + item.fid + '&view=jpg'
};
} else {
activeMedia.value = { type: '', src: '' };
}
};
const handlePageChange = (newPage: number, newPageSize: number) => {
page.value = newPage;
pageSize.value = newPageSize;
activeFid.value = '';
activeMedia.value = { type: '', src: '' };
fetchVideoList();
};
// ==================== 监听 ====================
watch(
() => [props.vdDate, props.type, activeKey.value],
() => {
if (props.vdDate) {
page.value = 1;
fetchVideoList();
}
}
);
// ==================== 生命周期 ====================
onMounted(() => {
if (props.vdDate) {
fetchVideoList();
}
});
</script>
<style lang="scss" scoped>
.video-details {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
:deep(.ant-tabs) {
flex: 1;
display: flex;
flex-direction: column;
}
:deep(.ant-tabs-content) {
flex: 1;
}
:deep(.ant-tabs-tabpane) {
height: 100%;
}
.video-container {
height: 100%;
}
}
</style>