Commit dd652a61 by lijiabin

【需求 20331】 feat: 支持编辑视频时回显视频相关信息

parent 5ce1af42
......@@ -44,8 +44,9 @@
<div class="video-details-text">
<p class="video-name">{{ videoInfo.name }}</p>
<p class="video-meta">
{{ formatFileSize(videoInfo.size) }} · {{ videoInfo.duration }} ·
{{ videoInfo.resolution }}
<span v-if="videoInfo.size"> {{ formatFileSize(videoInfo.size) }} </span> ·
<span v-if="videoInfo.duration"> {{ videoInfo.duration }} </span> ·
<span v-if="videoInfo.resolution"> {{ videoInfo.resolution }} </span>
</p>
</div>
</div>
......@@ -92,7 +93,6 @@ const {
acceptFormats = ['mp4', 'avi', 'mov', 'wmv', 'flv'],
btnClass = '',
} = defineProps<UploadVideoProps>()
console.log(btnClass, 'btnClass')
const modelValue = defineModel<string>('modelValue', { required: true })
const videoInfo = defineModel<VideoInfo | null>('videoInfo', { required: false, default: null })
......@@ -211,9 +211,38 @@ const cancelUpload = () => {
push.info('已取消上传')
}
// 编辑回显:当 modelValue 有值(父组件赋值)时,通过 getVideoMetadata 拉取元信息并展示
async function syncVideoInfoFromModel() {
const url = modelValue.value
if (!url || uploading.value) return
// 下面这种直接限制 新增视频 或者 编辑视频的二次上传
if (videoInfo.value?.url === url) return
let duration = '--'
let resolution = '--'
try {
const metadata = await getVideoMetadata(url)
duration = metadata.duration
resolution = metadata.resolution
} catch {
// 跨域或加载失败时使用占位
}
if (modelValue.value !== url) return
// 手动回显视频信息
videoInfo.value = {
url,
name: '已上传视频',
size: 0,
duration,
resolution,
}
}
watch(() => modelValue.value, syncVideoInfoFromModel, { immediate: true })
// 重新选择视频
const replaceVideo = () => {
videoInfo.value = null
modelValue.value = ''
uploadError.value = ''
uploadProgress.value = 0
currentFile.value = null
......
......@@ -99,3 +99,10 @@ export function formatSeconds(seconds: string | number) {
const res = dayjs.unix(Number(seconds)).endOf('day').unix()
return typeof seconds === 'number' ? res : res.toString()
}
// fetch远程oss链接转为 本地的blob链接
export function fetchOssBlob(url: string): Promise<string> {
return fetch(url)
.then((res) => res.blob())
.then((blob) => URL.createObjectURL(blob))
}
......@@ -472,7 +472,7 @@ onActivated(async () => {
console.log(route.query.id, '编辑 或者 草稿箱')
// 要编辑回显
const { data } = await getArticleDetail(route.query.id as string)
// 首先回显基础的信息
// 1首先回显基础的信息
// 标题 内容 主标签 副标签 所属栏目 是否推荐 是否同步同事吧 发布时间 发布状态
const {
id,
......@@ -500,34 +500,40 @@ onActivated(async () => {
id,
}
// 回显主副标签
// 2回显主副标签
form.value.mainTagId = tagIdList[0] ? String(tagIdList[0]) : ''
form.value.tagList = tagIdList.slice(1) || []
const { imgUrl, faceUrl } = data
// 3回显封面图内容图片 以及顶部 底部 视频等
const { imgUrl, faceUrl, articleVideoUrl } = data
if (type === ArticleTypeEnum.QUESTION || type === ArticleTypeEnum.PRACTICE) {
form.value.imgUrl = imgUrl
} else {
form.value.faceUrl = faceUrl
}
// 回显推送人员设置
if (articleVideoUrl) {
form.value.articleVideoUrl = articleVideoUrl
}
// 4回显推送人员设置
if (
(type === ArticleTypeEnum.COLUMN || type === ArticleTypeEnum.INTERVIEW) &&
userInfo.value.isOfficialAccount
) {
selectedDepts.value = data.pushList
.filter((item) => item.valueType === 1)
.map((item) => ({
id: item.valueId,
name: item.valueName,
}))
selectedUsers.value = data.pushList
.filter((item) => item.valueType === 2)
.map((item) => ({
id: item.valueId,
name: item.valueName,
}))
selectedDepts.value =
data.pushList
?.filter((item) => item.valueType === 1)
.map((item) => ({
id: item.valueId,
name: item.valueName,
})) || []
selectedUsers.value =
data.pushList
?.filter((item) => item.valueType === 2)
.map((item) => ({
id: item.valueId,
name: item.valueName,
})) || []
}
}
})
......
......@@ -273,6 +273,7 @@
width="800px"
:close-on-click-modal="false"
>
<!-- 这个用blob是因为 转为canvas 防止跨域污染 -->
<div v-if="locationVideoBlolUrl" class="space-y-6">
<!-- 视频预览 -->
<div class="relative">
......@@ -347,14 +348,16 @@
import UploadVideo from '@/components/common/UploadVideo/index.vue'
import { useResetData } from '@/hooks'
import { ArticleTypeEnum, ReleaseStatusTypeEnum, SendTypeEnum } from '@/constants'
import { addOrUpdateArticle, uploadFile } from '@/api'
import { addOrUpdateArticle, uploadFile, getArticleDetail } from '@/api'
import SelectTags from '@/components/common/SelectTags/index.vue'
import type { TagItemDto, AddOrUpdateVideoDto } from '@/api'
import { useVideoStore, useUserStore } from '@/stores'
import { storeToRefs } from 'pinia'
import { selectDepOrUser } from '@/utils'
import { selectDepOrUser, fetchOssBlob } from '@/utils'
import BackButton from '@/components/common/BackButton/index.vue'
import { push } from 'notivue'
const route = useRoute()
const videoStore = useVideoStore()
const { videoList } = storeToRefs(videoStore)
......@@ -600,21 +603,36 @@ onDeactivated(() => {
uploadVideoRef.value?.reset()
})
// const isEdit = computed(() => {
// return !!route.query.id
// })
// onActivated(async () => {
// resetPageData()
// if (isEdit.value) {
// const { data } = await getArticleDetail(route.query.id as string)
// form.value = {
// ...form.value,
// ...data,
// mainTagId:String( data.tagIdList?.[0]) || '',
// tagList: data.tagIdList?.slice(1) || [],
// }
// }
// })
// 处理编辑回显
onActivated(async () => {
if (route.query.id) {
const { data } = await getArticleDetail(route.query.id as string)
const blobUrl = await fetchOssBlob(data.videoUrl)
locationVideoBlolUrl.value = blobUrl
form.value = {
...form.value,
...data,
mainTagId: String(data.tagIdList?.[0]),
tagList: data.tagIdList?.slice(1),
}
// 回显推送的部门 这个后端没有返回相关数据 需要返回
console.log(data.pushList, 'data.pushList')
selectedDepts.value =
data.pushList
?.filter((item) => item.valueType === 1)
.map((item) => ({
id: item.valueId,
name: item.valueName,
})) || []
selectedUsers.value =
data.pushList
?.filter((item) => item.valueType === 2)
.map((item) => ({
id: item.valueId,
name: item.valueName,
})) || []
}
})
</script>
<style scoped>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment