318 lines
8.1 KiB
Vue
318 lines
8.1 KiB
Vue
<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>
|