feat: 回放
This commit is contained in:
parent
d51c37ca36
commit
9d411034f6
|
@ -0,0 +1,49 @@
|
|||
import server from '@/utils/request';
|
||||
import { LocalStore } from '@/utils/comm';
|
||||
import { BASE_API_PATH, TOKEN_KEY } from '@/utils/variable';
|
||||
import { recordsItemType } from '@/views/media/Device/Playback/typings';
|
||||
|
||||
export default {
|
||||
// 开始直播
|
||||
ptzStart: (deviceId: string, channelId: string, type: string) =>
|
||||
`${BASE_API_PATH}/media/device/${deviceId}/${channelId}/live.${type}?:X_Access_Token=${LocalStore.get(TOKEN_KEY)}`,
|
||||
|
||||
// 查询设备通道详情
|
||||
queryDetail: (deviceId: string, data: any) => server.post(`/media/device/${deviceId}/channel/_query`, data),
|
||||
|
||||
// 查询本地回放记录
|
||||
queryRecordLocal: (deviceId: string, channelId: string, data?: any) =>
|
||||
server.post<any>(`/media/device/${deviceId}/${channelId}/records/in-local`, data),
|
||||
|
||||
// 下载到云端
|
||||
downloadRecord: (deviceId: string, channelId: string, data: any) =>
|
||||
server.post(`/media/device/${deviceId}/${channelId}/_record`, data),
|
||||
|
||||
// 播放本地回放
|
||||
playbackLocal: (
|
||||
deviceId: string,
|
||||
channelId: string,
|
||||
suffix: string,
|
||||
startTime: string,
|
||||
endTime: string,
|
||||
speed: number = 1
|
||||
) =>
|
||||
`${BASE_API_PATH}/media/device/${deviceId}/${channelId}/playback.${suffix}?:X_Access_Token=${LocalStore.get(TOKEN_KEY)}&startTime=${startTime}&endTime=${endTime}&speed=${speed}`,
|
||||
|
||||
// 本地录像播放控制
|
||||
playbackControl: (deviceId: string, channelId: string) =>
|
||||
server.post(`/media/device/${deviceId}/${channelId}/stream-control`),
|
||||
|
||||
// 查询云端回放记录
|
||||
recordsInServer: (deviceId: string, channelId: string, data: any) =>
|
||||
server.post<recordsItemType[]>(`/media/device/${deviceId}/${channelId}/records/in-server`, data),
|
||||
|
||||
// 查询云端回放文件信息
|
||||
recordsInServerFiles: (deviceId: string, channelId: string, data: any) =>
|
||||
server.post<recordsItemType[]>(`/media/device/${deviceId}/${channelId}/records/in-server/files`, data),
|
||||
|
||||
// 播放云端回放
|
||||
playbackStart: (recordId: string) => `${BASE_API_PATH}/record/${recordId}.mp4?:X_Access_Token=${LocalStore.get(TOKEN_KEY)}`,
|
||||
|
||||
downLoadFile: (recordId: string) => `${BASE_API_PATH}/record/${recordId}.mp4?download=true&:X_Access_Token=${LocalStore.get(TOKEN_KEY)}`
|
||||
}
|
|
@ -73,7 +73,9 @@ const iconKeys = [
|
|||
'BellOutlined',
|
||||
'UserOutlined',
|
||||
'LogoutOutlined',
|
||||
'ReadIconOutlined'
|
||||
'ReadIconOutlined',
|
||||
'CloudDownloadOutlined',
|
||||
'PauseCircleOutlined',
|
||||
]
|
||||
|
||||
const Icon = (props: {type: string}) => {
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
<!-- 视频图标组件 -->
|
||||
<template>
|
||||
<a @click="handleClick">
|
||||
<AIcon :type="iconType" />
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { recordsItemType } from './typings';
|
||||
import playBackApi from '@/api/media/playback';
|
||||
import { message } from 'ant-design-vue';
|
||||
|
||||
interface Props {
|
||||
type: string;
|
||||
item: recordsItemType;
|
||||
onCloudView: (startTime: number, endTime: number) => void;
|
||||
onDownLoad: () => void;
|
||||
}
|
||||
const props = defineProps<Props>();
|
||||
|
||||
// type 为local时有效,0:未下载; 1:下载中:2:已下载
|
||||
// const status = ref(props.item?.isServer ? 2 : 0);
|
||||
const status = computed({
|
||||
get: () => (props.item?.isServer ? 2 : 0),
|
||||
set: (val: number) => {},
|
||||
});
|
||||
|
||||
const getLocalIcon = (s: number) => {
|
||||
if (s === 0) {
|
||||
return 'CloudDownloadOutlined';
|
||||
} else if (s === 2) {
|
||||
return 'EyeOutlined';
|
||||
} else {
|
||||
return 'LoadingOutlined';
|
||||
}
|
||||
};
|
||||
|
||||
const iconType = computed(() =>
|
||||
props.type === 'local' ? getLocalIcon(status.value) : 'DownloadOutlined',
|
||||
);
|
||||
|
||||
const downLoadCloud = (item: recordsItemType) => {
|
||||
status.value = 1;
|
||||
playBackApi
|
||||
.downloadRecord(item.deviceId, item.channelId, {
|
||||
local: false,
|
||||
downloadSpeed: 4,
|
||||
startTime: item.startTime,
|
||||
endTime: item.endTime,
|
||||
})
|
||||
.then((res) => {
|
||||
if (res.status === 200) {
|
||||
message.success(
|
||||
'操作成功。上传云端需要一定时间,请稍后查看云端数据',
|
||||
);
|
||||
}
|
||||
status.value = res.status === 200 ? 2 : 0;
|
||||
});
|
||||
};
|
||||
|
||||
const handleClick = () => {
|
||||
if (props.type === 'local') {
|
||||
if (status.value === 2) {
|
||||
// 已下载,进行跳转
|
||||
props.onCloudView(props.item.startTime, props.item.endTime);
|
||||
} else if (status.value === 0) {
|
||||
// 未下载 进行下载
|
||||
downLoadCloud(props.item);
|
||||
}
|
||||
} else {
|
||||
props.onDownLoad();
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped></style>
|
|
@ -0,0 +1,120 @@
|
|||
@borderColor: #d9d9d9;
|
||||
|
||||
.playback-warp {
|
||||
display: flex;
|
||||
padding: 24px;
|
||||
background-color: #fff;
|
||||
|
||||
.playback-left {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 1;
|
||||
width: 0;
|
||||
|
||||
.playback-media {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.playback-right {
|
||||
width: 300px;
|
||||
margin-left: 24px;
|
||||
|
||||
.playback-calendar {
|
||||
margin-top: 16px;
|
||||
border: 1px solid @borderColor;
|
||||
border-radius: 2px;
|
||||
|
||||
.ant-picker-calendar-header {
|
||||
justify-content: space-between;
|
||||
|
||||
> div:nth-child(3) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.playback-list {
|
||||
display: flex;
|
||||
height: 300px;
|
||||
margin-top: 16px;
|
||||
overflow-y: auto;
|
||||
border: 1px solid @borderColor;
|
||||
|
||||
&.no-list {
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.playback-list-items {
|
||||
width: 100%;
|
||||
|
||||
.ant-list-item {
|
||||
padding-left: 12px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.time-line-warp {
|
||||
padding: 10px 0;
|
||||
|
||||
.time-line-clock {
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
justify-content: space-between;
|
||||
width: 100%;
|
||||
|
||||
> div {
|
||||
color: #666;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.time-line-content {
|
||||
position: relative;
|
||||
padding-bottom: 20px;
|
||||
|
||||
.time-line-progress {
|
||||
position: relative;
|
||||
height: 16px;
|
||||
overflow: hidden;
|
||||
background-color: #d9d9d9;
|
||||
border-radius: 2px;
|
||||
|
||||
> div {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
height: 100%;
|
||||
background-color: #52c41a;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.time-line-btn {
|
||||
position: absolute;
|
||||
top: -2px;
|
||||
left: 0;
|
||||
width: 3px;
|
||||
height: 19px;
|
||||
background-color: @primary-color;
|
||||
border-radius: 2px;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.time-line {
|
||||
position: absolute;
|
||||
bottom: -8px;
|
||||
left: -30px;
|
||||
width: 60px;
|
||||
padding: 2px 0;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
background-color: #d9d9d9;
|
||||
border-radius: 2px;
|
||||
box-shadow: 0 0 12px rgba(#000, 0.15);
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,203 @@
|
|||
<!-- 回放 -->
|
||||
<template>
|
||||
<page-container> 回放 </page-container>
|
||||
<page-container>
|
||||
<div class="playback-warp">
|
||||
<div class="playback-left">
|
||||
<LivePlayer :src="url" />
|
||||
<TimeLine
|
||||
ref="playTimeNode"
|
||||
:type="type"
|
||||
:data="historyList"
|
||||
:date-time="time"
|
||||
:on-change="handleTimeLineChange"
|
||||
:play-status="playStatus"
|
||||
:play-time="playNowTime + playTime * 1000"
|
||||
:local-to-server="cloudTime"
|
||||
/>
|
||||
</div>
|
||||
<div class="playback-right">
|
||||
<a-spin :spinning="loading">
|
||||
<a-tooltip title="">
|
||||
|
||||
</a-tooltip>
|
||||
</a-spin>
|
||||
</div>
|
||||
</div>
|
||||
</page-container>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts"></script>
|
||||
<script setup lang="ts">
|
||||
import playBackApi from '@/api/media/playback';
|
||||
import type { Moment } from 'moment';
|
||||
import moment from 'moment';
|
||||
import TimeLine from './timeLine.vue';
|
||||
import IconNode from './iconNode.vue';
|
||||
import type { recordsItemType } from './typings';
|
||||
import LivePlayer from '@/components/Player/index.vue';
|
||||
|
||||
<style lang="less" scoped></style>
|
||||
const route = useRoute();
|
||||
|
||||
const url = ref('');
|
||||
const type = ref('local');
|
||||
const historyList = ref<recordsItemType[]>([]);
|
||||
const time = ref<Moment | undefined>(undefined);
|
||||
const loading = ref(false);
|
||||
const cloudTime = ref<any>();
|
||||
const location = ref({ search: '' });
|
||||
const player = ref<any>();
|
||||
const playStatus = ref(0); // 播放状态, 0 停止, 1 播放, 2 暂停, 3 播放完成
|
||||
const playTime = ref(0);
|
||||
|
||||
const playNowTime = ref(0); // 当前播放视频标识
|
||||
const playTimeNode = ref<any>(null);
|
||||
const isEnded = ref(false); // 是否结束播放
|
||||
const param = new URLSearchParams(location.value.search);
|
||||
const deviceId = computed(() => route.params.id as string);
|
||||
const channelId = computed(() => route.params.channelId as string);
|
||||
|
||||
const deviceType = ref('');
|
||||
|
||||
const queryLocalRecords = async (date: Moment) => {
|
||||
playStatus.value = 0;
|
||||
url.value = '';
|
||||
if (deviceId.value && channelId.value && date) {
|
||||
loading.value = true;
|
||||
const params = {
|
||||
startTime: date.format('YYYY-MM-DD 00:00:00'),
|
||||
endTime: date.format('YYYY-MM-DD 23:59:59'),
|
||||
};
|
||||
const localResp = await playBackApi.queryRecordLocal(
|
||||
deviceId.value,
|
||||
channelId.value,
|
||||
params,
|
||||
);
|
||||
if (localResp.status === 200 && localResp.result.length) {
|
||||
const serviceResp = await playBackApi.recordsInServer(
|
||||
deviceId.value,
|
||||
channelId.value,
|
||||
{
|
||||
...params,
|
||||
includeFiles: false,
|
||||
},
|
||||
);
|
||||
loading.value = false;
|
||||
let newList: recordsItemType[] = serviceResp.result;
|
||||
// console.log(newList)
|
||||
|
||||
if (serviceResp.status === 200 && serviceResp.result) {
|
||||
// 判断是否已下载云端视频
|
||||
newList = localResp.result.map((item: recordsItemType) => {
|
||||
return {
|
||||
...item,
|
||||
isServer: serviceResp.result.length
|
||||
? serviceResp.result.some(
|
||||
(serverFile: any) =>
|
||||
item.startTime <=
|
||||
serverFile.streamStartTime &&
|
||||
serverFile.streamEndTime <= item.endTime,
|
||||
)
|
||||
: false,
|
||||
};
|
||||
});
|
||||
|
||||
historyList.value = newList;
|
||||
} else {
|
||||
historyList.value = newList;
|
||||
}
|
||||
} else {
|
||||
loading.value = false;
|
||||
historyList.value = [];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 查询云端视频
|
||||
* @param date
|
||||
*/
|
||||
const queryServiceRecords = async (date: Moment) => {
|
||||
playStatus.value = 0;
|
||||
url.value = '';
|
||||
if (deviceId.value && channelId.value && date) {
|
||||
loading.value = true;
|
||||
const params = {
|
||||
startTime: date.format('YYYY-MM-DD 00:00:00'),
|
||||
endTime: date.format('YYYY-MM-DD 23:59:59'),
|
||||
includeFiles: true,
|
||||
};
|
||||
|
||||
const resp = await playBackApi.recordsInServerFiles(
|
||||
deviceId.value,
|
||||
channelId.value,
|
||||
params,
|
||||
);
|
||||
loading.value = false;
|
||||
if (resp.status === 200) {
|
||||
historyList.value = resp.result;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const cloudView = (startTime: number, endTime: number) => {
|
||||
type.value = 'cloud';
|
||||
cloudTime.value = { startTime, endTime };
|
||||
queryServiceRecords(time.value!);
|
||||
};
|
||||
|
||||
const downloadClick = async (item: recordsItemType) => {
|
||||
const downloadUrl = playBackApi.downLoadFile(item.id);
|
||||
const downNode = document.createElement('a');
|
||||
downNode.href = downloadUrl;
|
||||
downNode.download = `${channelId}-${moment(item.startTime).format(
|
||||
'YYYY-MM-DD-HH-mm-ss',
|
||||
)}.mp4`;
|
||||
downNode.style.display = 'none';
|
||||
document.body.appendChild(downNode);
|
||||
downNode.click();
|
||||
document.body.removeChild(downNode);
|
||||
};
|
||||
|
||||
watch(
|
||||
() => location.value,
|
||||
(val: any) => {
|
||||
const _param = new URLSearchParams(val?.search);
|
||||
const _type = _param.get('type');
|
||||
|
||||
if (_type) {
|
||||
deviceType.value = _type;
|
||||
const _timeStr = moment(new Date());
|
||||
time.value = _timeStr;
|
||||
if (_type === 'fixed-media') {
|
||||
type.value = 'cloud';
|
||||
queryServiceRecords(_timeStr);
|
||||
} else {
|
||||
queryLocalRecords(_timeStr);
|
||||
type.value = 'local';
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const handleTimeLineChange = (times: any) => {
|
||||
if (times) {
|
||||
playNowTime.value = Number(times.startTime.valueOf());
|
||||
playTime.value = 0;
|
||||
url.value =
|
||||
type.value === 'local'
|
||||
? playBackApi.playbackLocal(
|
||||
times.deviceId,
|
||||
times.channelId,
|
||||
'mp4',
|
||||
moment(times.startTime).format('YYYY-MM-DD HH:mm:ss'),
|
||||
moment(times.endTime).format('YYYY-MM-DD HH:mm:ss'),
|
||||
)
|
||||
: playBackApi.playbackStart(times.deviceId);
|
||||
} else {
|
||||
url.value = '';
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import './index.less';
|
||||
</style>
|
||||
|
|
|
@ -0,0 +1,262 @@
|
|||
<!-- 播放器时间刻度 -->
|
||||
<template>
|
||||
<div class="time-line-warp">
|
||||
<div class="time-line-clock">
|
||||
<div
|
||||
v-for="item in Array.from(Array(25), (v, k) => k)"
|
||||
:key="item"
|
||||
style="width: 12px"
|
||||
>
|
||||
{{ item }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="time-line-content" ref="LineContent">
|
||||
<div class="time-line-progress">
|
||||
<div
|
||||
v-for="(item, index) in list"
|
||||
:key="`time_${index}`"
|
||||
@click="handleProgress($event, item)"
|
||||
:style="
|
||||
getLineItemStyle(
|
||||
item.startTime || item.mediaStartTime,
|
||||
item.endTime || item.mediaEndTime,
|
||||
)
|
||||
"
|
||||
></div>
|
||||
</div>
|
||||
<div id="btn" class="time-line-btn"></div>
|
||||
<div id="time" class="time-line">
|
||||
{{ moment(playTime || 0).format('HH:mm:ss') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { message } from 'ant-design-vue';
|
||||
import type { Moment } from 'moment';
|
||||
import moment from 'moment';
|
||||
import type { recordsItemType } from './typings';
|
||||
|
||||
export type TimeChangeType = {
|
||||
endTime: Moment;
|
||||
startTime: Moment;
|
||||
deviceId: string;
|
||||
channelId: string;
|
||||
};
|
||||
|
||||
interface Props {
|
||||
onChange: (times: TimeChangeType | undefined) => void;
|
||||
data: recordsItemType[];
|
||||
dateTime?: Moment;
|
||||
type: string;
|
||||
playStatus: number;
|
||||
playTime: number;
|
||||
server?: any;
|
||||
localToServer?: {
|
||||
endTime: number;
|
||||
startTime: number;
|
||||
};
|
||||
getPlayList?: (data: any) => void;
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
// 获取选中当天开始时间戳
|
||||
const startT = ref<number>(
|
||||
new Date(
|
||||
moment(props.dateTime).startOf('day').format('YYYY-MM-DD HH:mm:ss'),
|
||||
).getTime(),
|
||||
);
|
||||
// 获取选中当天结束时间戳
|
||||
const endT = ref<number>(
|
||||
new Date(
|
||||
moment(props.dateTime).endOf('day').format('YYYY-MM-DD HH:mm:ss'),
|
||||
).getTime(),
|
||||
);
|
||||
const list = ref<any[]>([]);
|
||||
const playTime = ref<number>(0);
|
||||
const LineContent = ref<HTMLDivElement>();
|
||||
// const LineContentSize = LineContent.value;
|
||||
const LineContentSize = ref({ width: 100 });
|
||||
|
||||
const setTimeAndPosition = (ob: number) => {
|
||||
const oBtn = document.getElementById('btn');
|
||||
const oTime = document.getElementById('time');
|
||||
|
||||
if (oBtn && oTime && LineContentSize.value.width) {
|
||||
oBtn.style.visibility = 'visible';
|
||||
oBtn.style.left = `${ob * LineContentSize.value.width}px`;
|
||||
oTime.style.visibility = 'visible';
|
||||
oTime.style.left = `${ob * LineContentSize.value.width - 15}px`;
|
||||
}
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.dateTime,
|
||||
(val: any) => {
|
||||
startT.value = new Date(
|
||||
moment(val).startOf('day').format('YYYY-MM-DD HH:mm:ss'),
|
||||
).getTime();
|
||||
},
|
||||
);
|
||||
|
||||
const onChange = (
|
||||
startTime: number,
|
||||
endTime: number,
|
||||
deviceId: string,
|
||||
channelId: string,
|
||||
) => {
|
||||
playTime.value = startTime;
|
||||
props.onChange({
|
||||
startTime: moment(startTime),
|
||||
endTime: moment(endTime),
|
||||
deviceId,
|
||||
channelId,
|
||||
});
|
||||
};
|
||||
|
||||
const playByStartTime = (time: any) => {
|
||||
const playNow = props.data.find((item) => {
|
||||
const startTime = item.startTime || item.mediaStartTime;
|
||||
return startTime === time;
|
||||
});
|
||||
|
||||
if (playNow) {
|
||||
const startTime = playNow.startTime || playNow.mediaStartTime;
|
||||
const endTime = playNow.endTime || playNow.mediaEndTime;
|
||||
const deviceId = props.type === 'local' ? playNow.deviceId : playNow.id;
|
||||
onChange(startTime, endTime, deviceId, playNow.channelId);
|
||||
}
|
||||
};
|
||||
playByStartTime(0);
|
||||
|
||||
const onNextPlay = () => {
|
||||
if (playTime.value) {
|
||||
// 查找下一个视频
|
||||
const nowIndex = props.data.findIndex((item) => {
|
||||
const startTime = item.startTime || item.mediaStartTime;
|
||||
return startTime === playTime.value;
|
||||
});
|
||||
// 是否为最后一个
|
||||
if (nowIndex !== props.data.length - 1) {
|
||||
const nextPlay = props.data[nowIndex + 1];
|
||||
const startTime = nextPlay.startTime || nextPlay.mediaStartTime;
|
||||
const endTime = nextPlay.endTime || nextPlay.mediaEndTime;
|
||||
const deviceId =
|
||||
props.type === 'local' ? nextPlay.deviceId : nextPlay.id;
|
||||
onChange(startTime, endTime, deviceId, nextPlay.channelId);
|
||||
}
|
||||
}
|
||||
};
|
||||
onNextPlay();
|
||||
|
||||
watch(
|
||||
() => props.data,
|
||||
(val: any) => {
|
||||
const { data, localToServer, type } = props;
|
||||
if (data && Array.isArray(data) && data.length > 0) {
|
||||
list.value = [...data];
|
||||
if (type === 'local') {
|
||||
// 播放第一个
|
||||
onChange(
|
||||
data[0].startTime,
|
||||
data[0].endTime,
|
||||
data[0].deviceId,
|
||||
data[0].channelId,
|
||||
);
|
||||
} else if (type === 'cloud') {
|
||||
// 是否从本地跳转到云端播放
|
||||
if (localToServer && Object.keys(localToServer).length > 0) {
|
||||
// 获取跳转播放段
|
||||
const playItem = data.find((item) => {
|
||||
return (
|
||||
item.mediaEndTime <= localToServer.endTime &&
|
||||
item.mediaStartTime >= localToServer.startTime
|
||||
);
|
||||
});
|
||||
if (playItem) {
|
||||
//播放片段
|
||||
onChange(
|
||||
playItem.mediaStartTime,
|
||||
playItem.mediaEndTime,
|
||||
playItem.id,
|
||||
playItem.channelId,
|
||||
);
|
||||
} else {
|
||||
props.onChange(undefined);
|
||||
message.error('没有可播放的视频资源');
|
||||
}
|
||||
} else {
|
||||
onChange(
|
||||
data[0].mediaStartTime,
|
||||
data[0].mediaEndTime,
|
||||
data[0].id,
|
||||
data[0].channelId,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else if (localToServer && localToServer.startTime) {
|
||||
// 本地跳转云端但是无资源
|
||||
props.onChange(undefined);
|
||||
message.error('没有可播放的视频资源');
|
||||
list.value = [];
|
||||
} else {
|
||||
// 啥都没有
|
||||
list.value = [];
|
||||
props.onChange(undefined);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const getLineItemStyle = (
|
||||
startTime: number,
|
||||
endTime: number,
|
||||
): { left: string; width: string } => {
|
||||
const start = startTime - startT.value > 0 ? startTime - startT.value : 0;
|
||||
const _width = LineContentSize.value.width!;
|
||||
const itemWidth = ((endTime - startTime) / (24 * 3600000)) * _width;
|
||||
return {
|
||||
left: `${(start / (24 * 3600000)) * _width}px`,
|
||||
width: `${itemWidth < 1 ? 1 : itemWidth}px`,
|
||||
};
|
||||
};
|
||||
|
||||
const playTimeChange = () => {
|
||||
if (
|
||||
props.playTime &&
|
||||
props.playTime >= startT.value &&
|
||||
props.playTime <= endT.value &&
|
||||
props.data &&
|
||||
props.data.length
|
||||
) {
|
||||
setTimeAndPosition((props.playTime - startT.value) / 3600000 / 24);
|
||||
}
|
||||
};
|
||||
watch(
|
||||
() => props.playTime,
|
||||
() => {
|
||||
playTimeChange();
|
||||
},
|
||||
);
|
||||
watch(
|
||||
() => startT.value,
|
||||
() => {
|
||||
playTimeChange();
|
||||
},
|
||||
);
|
||||
|
||||
const handleProgress = (event: any, item: any) => {
|
||||
const pos = LineContent.value?.getBoundingClientRect();
|
||||
if (pos && item.endTime) {
|
||||
const dt = event.clientX - pos.x;
|
||||
const start = (dt / pos.width) * 24 * 3600000 + startT.value;
|
||||
const _start = start < item.startTime ? item.startTime : start;
|
||||
onChange(_start, item.endTime, item.deviceId, item.channelId);
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
@import './index.less';
|
||||
</style>
|
Loading…
Reference in New Issue