Commit 221c7fbe by lijiabin

【需求 17679】 perf: 优化首页头像展示、优化上传视频页面等

parent dd599e8f
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
<el-icon class="upload-icon"><VideoCamera /></el-icon> <el-icon class="upload-icon"><VideoCamera /></el-icon>
<div class="upload-text"> <div class="upload-text">
<p>拖拽视频文件到此处,或点击选择文件</p> <p>拖拽视频文件到此处,或点击选择文件</p>
<p class="upload-hint">支持 MP4、AVI、MOV 格式,文件大小不超过 500MB</p> <p class="upload-hint">支持 MP4、AVI、MOV 格式,文件大小不超过 {{ maxSize }}MB</p>
</div> </div>
</div> </div>
...@@ -82,7 +82,7 @@ interface VideoInfo { ...@@ -82,7 +82,7 @@ interface VideoInfo {
fileId?: string fileId?: string
} }
const { maxSize = 500, acceptFormats = ['mp4', 'avi', 'mov', 'wmv', 'flv'] } = const { maxSize = 1000, acceptFormats = ['mp4', 'avi', 'mov', 'wmv', 'flv'] } =
defineProps<UploadVideoProps>() defineProps<UploadVideoProps>()
const modelValue = defineModel<string>('modelValue', { required: true }) const modelValue = defineModel<string>('modelValue', { required: true })
......
...@@ -32,9 +32,10 @@ ...@@ -32,9 +32,10 @@
class="flex items-center cursor-pointer px-2 py-1 rounded transition-colors sm:px-3 sm:py-2 hover:shadow-lg duration-200" class="flex items-center cursor-pointer px-2 py-1 rounded transition-colors sm:px-3 sm:py-2 hover:shadow-lg duration-200"
@click="router.push('/userPage')" @click="router.push('/userPage')"
> >
<!-- 默认展示匿名头像 -->
<img <img
class="w-8 h-8 object-contain flex-shrink-0 rounded-full" class="w-8 h-8 object-contain flex-shrink-0 rounded-full"
:src="userInfo?.avatar" :src="userInfo?.hiddenAvatar"
alt="个人中心" alt="个人中心"
/> />
<span class="ml-2 text-sm text-gray-700 whitespace-nowrap hidden lg:inline" <span class="ml-2 text-sm text-gray-700 whitespace-nowrap hidden lg:inline"
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
<div class="relative group"> <div class="relative group">
<div <div
class="w-48 h-28 bg-gradient-to-br from-gray-100 to-gray-200 rounded-lg shadow-md hover:shadow-lg transition-all duration-300 cursor-pointer overflow-hidden" class="w-48 h-28 bg-gradient-to-br from-gray-100 to-gray-200 rounded-lg shadow-md hover:shadow-lg transition-all duration-300 cursor-pointer overflow-hidden"
@click="showCoverDialog = true" @click="handleOpenCoverDialog"
> >
<img <img
v-if="form.faceUrl" v-if="form.faceUrl"
...@@ -46,7 +46,9 @@ ...@@ -46,7 +46,9 @@
v-else v-else
class="w-full h-full flex items-center justify-center text-gray-400" class="w-full h-full flex items-center justify-center text-gray-400"
> >
<el-icon :size="32"><Picture /></el-icon> <el-icon :size="32">
<Picture />
</el-icon>
</div> </div>
<div <div
class="absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex items-center justify-center shadow-lg" class="absolute inset-0 bg-black/40 opacity-0 group-hover:opacity-100 transition-opacity duration-300 flex items-center justify-center shadow-lg"
...@@ -92,48 +94,56 @@ ...@@ -92,48 +94,56 @@
</el-form-item> </el-form-item>
</div> </div>
<div class="mb-8"> <template v-if="showSpecialInput">
<el-form-item prop="mainTagId"> <div class="mb-8">
<label class="block text-sm font-semibold text-gray-700 mb-3"> <el-form-item prop="mainTagId">
主标签 <label class="block text-sm font-semibold text-gray-700 mb-3">
<el-tooltip content="主标签最多添加一个" placement="top"> 主标签
<el-icon class="text-gray-400 cursor-help"><QuestionFilled /></el-icon> <el-tooltip content="主标签最多添加一个" placement="top">
</el-tooltip> <el-icon class="text-gray-400 cursor-help">
</label> <QuestionFilled />
<SelectTags class="w-full" v-model="form.mainTagId" :max-selected-tags="1" /> </el-icon>
</el-form-item> </el-tooltip>
</div> </label>
<SelectTags class="w-full" v-model="form.mainTagId" :max-selected-tags="1" />
<div class="mb-8"> </el-form-item>
<el-form-item prop="tagList"> </div>
<label class="block text-sm font-semibold text-gray-700 mb-3">
副标签
<el-tooltip content="副标签最多添加3个" placement="top">
<el-icon class="text-gray-400 cursor-help"><QuestionFilled /></el-icon>
</el-tooltip>
</label>
<SelectTags
class="w-full"
v-model="form.tagList as number[]"
:max-selected-tags="3"
:filter-tags-fn="filterTagsFn"
/>
</el-form-item>
</div>
<div class="mb-8"> <div class="mb-8">
<el-form-item prop="relateColumnId"> <el-form-item prop="tagList">
<label class="block text-sm font-semibold text-gray-700 mb-3"> 视频栏目选择 </label> <label class="block text-sm font-semibold text-gray-700 mb-3">
<el-select v-model="form.relateColumnId" placeholder="请选择视频栏目"> 副标签
<el-option <el-tooltip content="副标签最多添加3个" placement="top">
v-for="item in videoList" <el-icon class="text-gray-400 cursor-help">
:key="item.id" <QuestionFilled />
:label="item.title" </el-icon>
:value="item.id" </el-tooltip>
</label>
<SelectTags
class="w-full"
v-model="form.tagList as number[]"
:max-selected-tags="3"
:filter-tags-fn="filterTagsFn"
/> />
</el-select> </el-form-item>
</el-form-item> </div>
</div>
<div class="mb-8">
<el-form-item prop="relateColumnId">
<label class="block text-sm font-semibold text-gray-700 mb-3">
视频栏目选择
</label>
<el-select v-model="form.relateColumnId" placeholder="请选择视频栏目">
<el-option
v-for="item in videoList"
:key="item.id"
:label="item.title"
:value="item.id"
/>
</el-select>
</el-form-item>
</div>
</template>
</div> </div>
<div <div
...@@ -178,7 +188,9 @@ ...@@ -178,7 +188,9 @@
size="large" size="large"
class="w-full !border-gray-200 hover:!border-indigo-300 hover:!text-indigo-600 transition-all duration-200" class="w-full !border-gray-200 hover:!border-indigo-300 hover:!text-indigo-600 transition-all duration-200"
> >
<el-icon class="mr-2"><Document /></el-icon> <el-icon class="mr-2">
<Document />
</el-icon>
保存草稿 保存草稿
</el-button> </el-button>
<el-button <el-button
...@@ -187,7 +199,9 @@ ...@@ -187,7 +199,9 @@
class="w-full !bg-gradient-to-r !from-indigo-500 !to-purple-600 !border-none shadow-lg hover:shadow-xl transition-all duration-300" class="w-full !bg-gradient-to-r !from-indigo-500 !to-purple-600 !border-none shadow-lg hover:shadow-xl transition-all duration-300"
@click="handleSubmit" @click="handleSubmit"
> >
<el-icon class="mr-2"><Upload /></el-icon> <el-icon class="mr-2">
<Upload />
</el-icon>
立即发布 立即发布
</el-button> </el-button>
</div> </div>
...@@ -226,6 +240,21 @@ ...@@ -226,6 +240,21 @@
/> />
</div> </div>
</div> </div>
<div class="flex justify-end items-center gap-2">
<p class="text-sm text-gray-500">拖动进度条找到合适的画面,点击截取按钮生成封面</p>
<el-button type="primary" @click="captureFrame" :icon="Camera"> 截取当前帧 </el-button>
or
<el-button type="primary" @click="coverInputRef?.click()">
手动上传封面
<input
ref="coverInputRef"
class="hidden"
type="file"
accept="image/*"
@change="handleFileChange"
/>
</el-button>
</div>
<!-- 封面预览 --> <!-- 封面预览 -->
<div class="bg-gray-50 rounded-lg p-4"> <div class="bg-gray-50 rounded-lg p-4">
...@@ -234,18 +263,12 @@ ...@@ -234,18 +263,12 @@
<div class="relative w-60 h-34 bg-gray-200 rounded-lg overflow-hidden"> <div class="relative w-60 h-34 bg-gray-200 rounded-lg overflow-hidden">
<img v-if="form.faceUrl" :src="form.faceUrl" class="w-full h-full object-cover" /> <img v-if="form.faceUrl" :src="form.faceUrl" class="w-full h-full object-cover" />
<div v-else class="w-full h-full flex items-center justify-center text-gray-400"> <div v-else class="w-full h-full flex items-center justify-center text-gray-400">
<el-icon :size="40"><Picture /></el-icon> <el-icon :size="40">
<Picture />
</el-icon>
</div> </div>
<canvas ref="canvasRef" class="hidden" /> <canvas ref="canvasRef" class="hidden" />
</div> </div>
<div class="flex-1">
<el-button type="primary" @click="captureFrame" :icon="Camera">
截取当前帧
</el-button>
<p class="text-xs text-gray-500 mt-2">
拖动进度条找到合适的画面,点击截取按钮生成封面
</p>
</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -270,19 +293,26 @@ import { addOrUpdateArticle, uploadFile } from '@/api' ...@@ -270,19 +293,26 @@ import { addOrUpdateArticle, uploadFile } from '@/api'
import SelectTags from '@/components/common/SelectTags/index.vue' import SelectTags from '@/components/common/SelectTags/index.vue'
import type { TagItemDto, AddOrUpdateVideoDto } from '@/api' import type { TagItemDto, AddOrUpdateVideoDto } from '@/api'
import { Camera, Picture } from '@element-plus/icons-vue' import { Camera, Picture } from '@element-plus/icons-vue'
import { useVideoStore } from '@/stores' import { useVideoStore, useUserStore } from '@/stores'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
const videoStore = useVideoStore() const videoStore = useVideoStore()
const { videoList } = storeToRefs(videoStore) const { videoList } = storeToRefs(videoStore)
const userStore = useUserStore()
const { userInfo } = storeToRefs(userStore)
const showSpecialInput = computed(
() => userInfo.value?.isAdmin || userInfo.value?.isOfficialAccount,
)
const router = useRouter() const router = useRouter()
const formRef = useTemplateRef('formRef') const formRef = useTemplateRef('formRef')
const coverInputRef = useTemplateRef('coverInputRef')
const [form, resetData] = useResetData<AddOrUpdateVideoDto>({ const [form, resetData] = useResetData<AddOrUpdateVideoDto>({
videoUrl: '', videoUrl: '',
title: '视频标题', title: '',
type: ArticleTypeEnum.VIDEO, type: ArticleTypeEnum.VIDEO,
content: '', content: '',
mainTagId: '', mainTagId: '',
...@@ -305,6 +335,10 @@ const canvasRef = ref<HTMLCanvasElement>() ...@@ -305,6 +335,10 @@ const canvasRef = ref<HTMLCanvasElement>()
const videoDuration = ref(0) const videoDuration = ref(0)
const currentTime = ref(0) const currentTime = ref(0)
const handleOpenCoverDialog = () => {
if (!locationVideoBlolUrl.value) return ElMessage.warning('请先上传视频')
showCoverDialog.value = true
}
// 视频加载完成 // 视频加载完成
const onVideoLoaded = () => { const onVideoLoaded = () => {
if (videoRef.value) { if (videoRef.value) {
...@@ -435,6 +469,15 @@ const handleVideoChange = ({ ...@@ -435,6 +469,15 @@ const handleVideoChange = ({
} }
form.value.videoDuration = videoDuration form.value.videoDuration = videoDuration
} }
// 手动上传
const handleFileChange = async (e: Event) => {
const target = e.target as HTMLInputElement
const file = target.files?.[0]
if (!file) return
const { data } = await uploadFile(file)
form.value.faceUrl = data.data[0].filePath
}
</script> </script>
<style scoped> <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