feat: 稿件详情处理
This commit is contained in:
@ -85,7 +85,7 @@
|
|||||||
<span class="cts num">{{ exactFormatTime(record[column.dataIndex]) }}</span>
|
<span class="cts num">{{ exactFormatTime(record[column.dataIndex]) }}</span>
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="column.dataIndex === 'cover'" #cell="{ record }">
|
<template v-else-if="column.dataIndex === 'cover'" #cell="{ record }">
|
||||||
<a-image :width="64" :height="64" :src="record.cover" class="!rounded-6px">
|
<a-image :width="64" :height="64" :src="record.cover" class="!rounded-6px" fit="cover">
|
||||||
<template #error>
|
<template #error>
|
||||||
<img :src="icon4" class="w-full h-full" />
|
<img :src="icon4" class="w-full h-full" />
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@ -1,7 +1,11 @@
|
|||||||
<script lang="jsx">
|
<script lang="jsx">
|
||||||
import { Button, Message as AMessage } from '@arco-design/web-vue';
|
import { Button, Message as AMessage, Spin } from '@arco-design/web-vue';
|
||||||
|
|
||||||
import { useRouter, useRoute } from 'vue-router';
|
import { useRouter, useRoute } from 'vue-router';
|
||||||
import { AuditStatus } from '@/views/creative-generation-workshop/manuscript/check-list/constants';
|
import { AuditStatus } from '@/views/creative-generation-workshop/manuscript/check-list/constants';
|
||||||
|
import { getWorksDetail } from '@/api/all/generationWorkshop';
|
||||||
|
import { EnumManuscriptType } from '@/views/creative-generation-workshop/manuscript/list/constants.ts';
|
||||||
|
import { convertVideoUrlToCoverUrl, exactFormatTime } from '@/utils/tools.ts';
|
||||||
|
|
||||||
const DEFAULT_SOURCE_INFO = {
|
const DEFAULT_SOURCE_INFO = {
|
||||||
title: '内容稿件列表',
|
title: '内容稿件列表',
|
||||||
@ -16,36 +20,66 @@ export default {
|
|||||||
const workId = ref(route.params.id);
|
const workId = ref(route.params.id);
|
||||||
const { source, audit_status } = route.query;
|
const { source, audit_status } = route.query;
|
||||||
|
|
||||||
const sourceInfo = computed(() => SOURCE_MAP.get(source) ?? DEFAULT_SOURCE_INFO);
|
|
||||||
console.log({ source });
|
|
||||||
|
|
||||||
// 视频播放相关状态
|
// 视频播放相关状态
|
||||||
const isPlaying = ref(false);
|
const isPlaying = ref(false);
|
||||||
const videoRef = ref(null);
|
const videoRef = ref(null);
|
||||||
const videoUrl = ref('');
|
const videoUrl = ref('');
|
||||||
const coverImageUrl = ref('');
|
const coverImageUrl = ref('');
|
||||||
const isVideoLoaded = ref(false);
|
const isVideoLoaded = ref(false);
|
||||||
const contentType = ref('video');
|
const dataSource = ref({});
|
||||||
|
const images = ref([]);
|
||||||
|
const loading = ref(false);
|
||||||
|
|
||||||
const isVideo = computed(() => contentType.value === 'video');
|
const isVideo = computed(() => dataSource.value.type === EnumManuscriptType.Video);
|
||||||
|
const sourceInfo = computed(() => SOURCE_MAP.get(source) ?? DEFAULT_SOURCE_INFO);
|
||||||
|
|
||||||
const onBack = () => {
|
const onBack = () => {
|
||||||
router.push({ name: sourceInfo.value.routeName });
|
router.push({ name: sourceInfo.value.routeName });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const initData = () => {
|
||||||
|
const [fileOne, ...fileOthers] = dataSource.value.files ?? [];
|
||||||
|
if (isVideo.value) {
|
||||||
|
videoUrl.value = fileOne;
|
||||||
|
coverImageUrl.value = convertVideoUrlToCoverUrl(fileOne);
|
||||||
|
} else {
|
||||||
|
coverImageUrl.value = fileOne;
|
||||||
|
images.value = fileOthers;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getData = async () => {
|
||||||
|
try {
|
||||||
|
loading.value = true;
|
||||||
|
const { code, data } = await getWorksDetail(workId.value);
|
||||||
|
if (code === 200) {
|
||||||
|
dataSource.value = data;
|
||||||
|
initData();
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const renderMainImg = () => {
|
const renderMainImg = () => {
|
||||||
|
if (!coverImageUrl.value) return null;
|
||||||
|
|
||||||
if (isVideo.value) {
|
if (isVideo.value) {
|
||||||
return (
|
return (
|
||||||
<div class="main-img-box mb-16px relative overflow-hidden cursor-pointer" onClick={togglePlay}>
|
<div class="main-video-box mb-16px relative overflow-hidden cursor-pointer" onClick={togglePlay}>
|
||||||
<video ref={videoRef} class="w-100% h-100% object-cover" onEnded={onVideoEnded}></video>
|
<video ref={videoRef} class="w-100% h-100% object-contain" onEnded={onVideoEnded}></video>
|
||||||
<img src={coverImageUrl.value} class="w-100% h-100% object-cover absolute z-0 top-0 left-0" />
|
{!isPlaying.value && (
|
||||||
|
<>
|
||||||
|
<img src={coverImageUrl.value} class="w-100% h-100% object-contain absolute z-0 top-0 left-0" />
|
||||||
<div v-show={!isPlaying.value} class="play-icon"></div>
|
<div v-show={!isPlaying.value} class="play-icon"></div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return (
|
return (
|
||||||
<div class="main-img-box mb-16px relative overflow-hidden cursor-pointer">
|
<div class="main-img-box mb-16px relative overflow-hidden cursor-pointer">
|
||||||
<img src={coverImageUrl.value} class="w-100% h-100% object-cover absolute z-0 top-0 left-0" />
|
<img src={coverImageUrl.value} class="w-100% h-100% object-contain absolute z-0 top-0 left-0" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -54,10 +88,10 @@ export default {
|
|||||||
const togglePlay = () => {
|
const togglePlay = () => {
|
||||||
if (!videoRef.value) return;
|
if (!videoRef.value) return;
|
||||||
|
|
||||||
|
console.log('togglePlay', videoRef.value);
|
||||||
if (isPlaying.value) {
|
if (isPlaying.value) {
|
||||||
videoRef.value.pause();
|
videoRef.value.pause();
|
||||||
} else {
|
} else {
|
||||||
// 首次播放时才加载视频
|
|
||||||
if (!isVideoLoaded.value) {
|
if (!isVideoLoaded.value) {
|
||||||
videoRef.value.src = videoUrl.value;
|
videoRef.value.src = videoUrl.value;
|
||||||
isVideoLoaded.value = true;
|
isVideoLoaded.value = true;
|
||||||
@ -101,10 +135,13 @@ export default {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// 4. 修改模板部分,根据contentType条件渲染
|
onMounted(() => {
|
||||||
|
workId && getData();
|
||||||
|
});
|
||||||
|
|
||||||
return () => (
|
return () => (
|
||||||
<>
|
<Spin loading={loading.value} class="manuscript-detail-wrap" size={50}>
|
||||||
<div class="manuscript-detail-wrap">
|
<div class="h-full w-full flex flex-col">
|
||||||
<div class="flex items-center mb-8px">
|
<div class="flex items-center mb-8px">
|
||||||
<span class="cts color-#4E5969 cursor-pointer" onClick={onBack}>
|
<span class="cts color-#4E5969 cursor-pointer" onClick={onBack}>
|
||||||
{sourceInfo.value.title}
|
{sourceInfo.value.title}
|
||||||
@ -114,38 +151,32 @@ export default {
|
|||||||
</div>
|
</div>
|
||||||
<div class="flex-1 overflow-y-auto bg-#fff rounded-8px border-1px border-#D7D7D9 border-solid py-32px">
|
<div class="flex-1 overflow-y-auto bg-#fff rounded-8px border-1px border-#D7D7D9 border-solid py-32px">
|
||||||
<div class="w-684px mx-auto flex flex-col items-center">
|
<div class="w-684px mx-auto flex flex-col items-center">
|
||||||
<p class="mb-8px cts bold !text-28px !lh-40px !color-#211F24">
|
<div class="flex justify-start flex-col w-full">
|
||||||
挖到宝了!这个平价好物让我素颜出门都自信✨挖到宝了!这个平价
|
<p class="mb-8px cts bold !text-28px !lh-40px !color-#211F24">{dataSource.value.title}</p>
|
||||||
|
<p class="cts !text-12px !color-#737478 mb-32px w-full text-left">
|
||||||
|
{exactFormatTime(dataSource.value.update_time)}修改
|
||||||
</p>
|
</p>
|
||||||
<p class="cts !text-12px !color-#737478 mb-32px w-full text-left">6月26日修改</p>
|
</div>
|
||||||
|
|
||||||
{renderMainImg()}
|
{renderMainImg()}
|
||||||
|
|
||||||
<p class="cts !color-#211F24 ">
|
<p class="cts !color-#211F24 ">{dataSource.value.content}</p>
|
||||||
谁懂啊!作为混干皮,每天素颜出门总被说 “气色好差”,直到被闺蜜按头安利这个 30 块的素颜霜 ——
|
|
||||||
质地像冰淇淋一样推开就化,完全不卡粉!带一点自然提亮,黄黑皮涂完像天生好皮肤,连遮瑕都省了~
|
|
||||||
最绝的是它还带轻微防晒值,早上洗完脸涂一层就能冲出门,懒人狂喜!我已经空罐 3
|
|
||||||
瓶了,现在同事都以为我每天早起化妆,其实我多睡了 20 分钟 hhh
|
|
||||||
(PS:油痘肌姐妹建议局部薄涂,后续补妆更服帖~)
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{/* 仅图片类型显示图片列表 */}
|
{/* 仅图片类型显示图片列表 */}
|
||||||
{!isVideo.value && (
|
{!isVideo.value && (
|
||||||
<div class="desc-img-wrap mt-40px">
|
<div class="desc-img-wrap mt-40px">
|
||||||
{new Array(5).fill(0).map((item, index) => (
|
{images.value.map((item, index) => (
|
||||||
<div class="desc-img-box" key={index}>
|
<div class="desc-img-box" key={index}>
|
||||||
<img src="" class="w-100% h-100%" />
|
<img src={item} class="w-100% h-100% object-contain" />
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
<div class="desc-img-box">
|
|
||||||
<img src="" class="w-100% h-100%" />
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex justify-end items-center px-16px py-20px w-full bg-#fff footer-row">{renderFooterRow()}</div>
|
<div class="flex justify-end items-center px-16px py-20px w-full bg-#fff footer-row">{renderFooterRow()}</div>
|
||||||
</>
|
</Spin>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
$footer-height: 68px;
|
$footer-height: 68px;
|
||||||
.manuscript-detail-wrap {
|
.manuscript-detail-wrap {
|
||||||
|
width: 100%;
|
||||||
height: calc(100% - 72px);
|
height: calc(100% - 72px);
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
.cts {
|
.cts {
|
||||||
color: #939499;
|
color: #939499;
|
||||||
font-family: $font-family-regular;
|
font-family: $font-family-regular;
|
||||||
@ -14,11 +13,15 @@ $footer-height: 68px;
|
|||||||
font-family: $font-family-medium;
|
font-family: $font-family-medium;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.main-video-box {
|
||||||
|
width: 320px;
|
||||||
|
height: auto;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
.main-img-box {
|
.main-img-box {
|
||||||
width: 320px;
|
width: 320px;
|
||||||
height: 472px;
|
height: auto;
|
||||||
background: #fff;
|
background: #fff;
|
||||||
object-fit: contain;
|
|
||||||
aspect-ratio: 3/4;
|
aspect-ratio: 3/4;
|
||||||
}
|
}
|
||||||
.desc-img-wrap {
|
.desc-img-wrap {
|
||||||
|
|||||||
@ -67,12 +67,18 @@ export default {
|
|||||||
const getData = async () => {
|
const getData = async () => {
|
||||||
const { code, data } = await getWorksDetail(workId.value);
|
const { code, data } = await getWorksDetail(workId.value);
|
||||||
if (code === 200) {
|
if (code === 200) {
|
||||||
|
const { type, files } = data;
|
||||||
const _data = { ...data, videoInfo: cloneDeep(INITIAL_VIDEO_INFO) };
|
const _data = { ...data, videoInfo: cloneDeep(INITIAL_VIDEO_INFO) };
|
||||||
|
|
||||||
|
if (type === EnumManuscriptType.Video && files.length) {
|
||||||
|
_data.videoInfo.uploadStatus = 'end';
|
||||||
|
}
|
||||||
dataSource.value = cloneDeep(_data);
|
dataSource.value = cloneDeep(_data);
|
||||||
remoteDataSource.value = cloneDeep(_data);
|
remoteDataSource.value = cloneDeep(_data);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const onChange = (val) => {
|
const onChange = (val) => {
|
||||||
|
console.log('onChange', val);
|
||||||
dataSource.value = val;
|
dataSource.value = val;
|
||||||
};
|
};
|
||||||
const onUpdateVideoInfo = (newVideoInfo) => {
|
const onUpdateVideoInfo = (newVideoInfo) => {
|
||||||
|
|||||||
@ -71,7 +71,7 @@
|
|||||||
{{ exactFormatTime(record[column.dataIndex]) }}
|
{{ exactFormatTime(record[column.dataIndex]) }}
|
||||||
</template>
|
</template>
|
||||||
<template v-else-if="column.dataIndex === 'cover'" #cell="{ record }">
|
<template v-else-if="column.dataIndex === 'cover'" #cell="{ record }">
|
||||||
<a-image :width="64" :height="64" :src="record.cover" class="!rounded-6px">
|
<a-image :width="64" :height="64" :src="record.cover" class="!rounded-6px" fit="cover">
|
||||||
<template #error>
|
<template #error>
|
||||||
<img :src="icon4" class="w-full h-full" />
|
<img :src="icon4" class="w-full h-full" />
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user