feat: 上传稿件处理

This commit is contained in:
renxiaodong
2025-08-11 22:05:48 +08:00
parent 7a6e696fc3
commit ab87185a86
10 changed files with 5907 additions and 74 deletions

5778
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -29,7 +29,7 @@ const COMPONENTS: AppRouteRecordRaw[] = [
component: () => import('@/views/creative-generation-workshop/manuscript/list/index.vue'),
},
{
path: 'upload/:id',
path: 'upload',
name: 'ManuscriptUpload',
meta: {
locale: '稿件上传',

View File

@ -29,7 +29,7 @@ const COMPONENTS: AppRouteRecordRaw[] = [
component: () => import('@/views/creative-generation-workshop/manuscript-writer/list/index.vue'),
},
{
path: 'upload/:writerCode/:id',
path: 'upload/:writerCode',
name: 'WriterManuscriptUpload',
meta: {
locale: '稿件上传',

View File

@ -220,7 +220,6 @@ export default {
size="large"
show-word-limit
maxLength={1000}
show-word-limit
disabled={props.checkLoading}
/>
</FormItem>
@ -327,7 +326,7 @@ export default {
<div class="flex items-center mb-16px">
{RESULT_LIST.map((item, index) => (
<div class="flex flex-col justify-center items-center flex-1 result-item" key={index}>
<span class="s1" style={{ color: item.color }}>{`${aiReview.value?.[item.value]}${
<span class="s1" style={{ color: item.color }}>{`${aiReview.value?.[item.value] ?? '-'}${
item.suffix || ''
}`}</span>
<span class="cts mt-4px !lh-20px !text-12px !color-#737478">{item.label}</span>
@ -356,7 +355,7 @@ export default {
<div class="flex items-center mb-16px">
{RESULT_LIST.map((item, index) => (
<div class="flex flex-col justify-center items-center flex-1 result-item" key={index}>
<span class="s1" style={{ color: item.color }}>{`${aiReview.value?.[item.value]}${
<span class="s1" style={{ color: item.color }}>{`${aiReview.value?.[item.value] ?? '-'}${
item.suffix || ''
}`}</span>
<span class="cts mt-4px !lh-20px !text-12px !color-#737478">{item.label}</span>

View File

@ -12,6 +12,7 @@ import {
Textarea,
} from '@arco-design/web-vue';
import { getTemplateUrlWriter, postWorksByLinkWriter, postWorksByFileWriter } from '@/api/all/generationWorkshop-writer.ts';
import { slsWithCatch } from '@/utils/stroage.ts';
import TextOverTips from '@/components/text-over-tips';
import icon1 from '@/assets/img/media-account/icon-feedback-fail.png';
@ -39,6 +40,7 @@ export default {
setup(props, { emit, expose }) {
const update = inject('update');
const router = useRouter();
const route = useRoute();
// 响应式状态
const visible = ref(false);
@ -136,7 +138,8 @@ export default {
// 跳转编辑
const goUpload = () => {
router.push(`/writer/manuscript/upload/${route.params.writerCode}/1`);
slsWithCatch('writerWaitUploadWorks', JSON.stringify(works.value));
router.push(`/writer/manuscript/upload/${route.params.writerCode}`);
onClose();
};
@ -228,7 +231,7 @@ export default {
<div key={item.id} class="rounded-8px bg-#fff px-8px py-8px flex justify-between items-center mt-8px">
<div class="flex-1 overflow-hidden flex items-center mr-12px">
<img src={item.cover} width="32" height="32" class="rounded-3px mr-8px" />
<TextOverTips class="text" context={item.title} />
<TextOverTips class="text !text-left" context={item.title} />
</div>
<icon-delete
size="16px"

View File

@ -7,6 +7,7 @@ import UploadSuccessModal from './upload-success-modal.vue';
import { EnumManuscriptType } from '@/views/creative-generation-workshop/manuscript/list/constants';
import { postWorksBatchWriter } from '@/api/all/generationWorkshop-writer.ts';
import { glsWithCatch, rlsWithCatch, slsWithCatch } from '@/utils/stroage.ts';
import icon1 from '@/assets/img/creative-generation-workshop/icon-photo.png';
import icon2 from '@/assets/img/creative-generation-workshop/icon-video.png';
@ -72,29 +73,33 @@ export default {
});
};
const onSubmit = async (check) => {
const onSubmit = async (action) => {
uploadLoading.value = true;
const filteredWorks = map(works.value, (work) => omit(work, 'videoInfo'));
const { code, data } = await postWorksBatchWriter({ works: filteredWorks });
if (code === 200) {
uploadLoading.value = false;
if (check) {
if (action === 'batchUpload') {
uploadSuccessModal.value?.open(workId);
} else {
if (action === 'uploadAndCheck') {
slsWithCatch('writerManuscriptCheckIds', [workId]);
router.push({ path: `/writer/manuscript/check/${route.params.writerCode}` });
} else {
router.push({ path: `/writer/manuscript/list/${route.params.writerCode}` });
}
}
}
};
const onUpload = async (e, check = false) => {
console.log('onUpload', works.value);
const onUpload = async (action) => {
formRef.value
?.validate()
.then(() => {
return validateDataSource();
})
.then(() => {
onSubmit(check);
onSubmit(action);
})
.catch((err) => {
console.log('catch');
@ -102,8 +107,8 @@ export default {
});
};
const onUploadAndCheck = (e) => {
onUpload(e, true);
const syncLocalStorage = () => {
slsWithCatch('writerWaitUploadWorks', JSON.stringify(works.value ?? []));
};
const handleReValidate = () => {
@ -134,6 +139,8 @@ export default {
selectCardInfo.value = {};
}
}
syncLocalStorage();
};
const renderFooterRow = () => {
@ -143,7 +150,7 @@ export default {
<Button size="medium" type="outline" onClick={onCancel} class="mr-12px">
取消上传
</Button>
<Button type="primary" size="medium" onClick={onUpload} loading={uploadLoading.value}>
<Button type="primary" size="medium" onClick={() => onUpload('batchUpload')} loading={uploadLoading.value}>
{uploadLoading.value ? '批量上传' : '批量上传'}
</Button>
</>
@ -154,10 +161,21 @@ export default {
<Button size="medium" type="outline" onClick={onCancel} class="mr-12px">
取消上传
</Button>
<Button size="medium" type="outline" onClick={onUpload} class="mr-12px" loading={uploadLoading.value}>
<Button
size="medium"
type="outline"
onClick={() => onUpload('singleUpload')}
class="mr-12px"
loading={uploadLoading.value}
>
上传
</Button>
<Button type="primary" size="medium" onClick={onUploadAndCheck} loading={uploadLoading.value}>
<Button
type="primary"
size="medium"
onClick={() => onUpload('uploadAndCheck')}
loading={uploadLoading.value}
>
上传并审核
</Button>
</>
@ -165,8 +183,12 @@ export default {
}
};
const getData = () => {
works.value = generateMockData();
selectCardInfo.value = cloneDeep(works.value[0] ?? {});
const _works = JSON.parse(glsWithCatch('writerWaitUploadWorks') ?? '[]')?.map((item) => ({
...item,
videoInfo: item?.videoInfo ? cloneDeep(item.videoInfo) : cloneDeep(INITIAL_VIDEO_INFO),
}));
works.value = _works;
selectCardInfo.value = cloneDeep(_works[0] ?? {});
};
const getCardClass = (item) => {
if (selectCardInfo.value.id === item.id) {
@ -184,6 +206,8 @@ export default {
works.value[index] = cloneDeep(val);
}
selectCardInfo.value = val;
syncLocalStorage();
};
const onUpdateVideoInfo = (newVideoInfo) => {
const index = works.value.findIndex((v) => v.id === selectCardInfo.value.id);
@ -191,11 +215,16 @@ export default {
works.value[index].videoInfo = cloneDeep(newVideoInfo);
}
selectCardInfo.value.videoInfo = { ...selectCardInfo.value.videoInfo, ...newVideoInfo };
syncLocalStorage();
};
onMounted(() => {
getData();
});
onUnmounted(() => {
rlsWithCatch('writerWaitUploadWorks');
});
return () => (
<>

View File

@ -327,7 +327,7 @@ export default {
<div class="flex items-center mb-16px">
{RESULT_LIST.map((item, index) => (
<div class="flex flex-col justify-center items-center flex-1 result-item" key={index}>
<span class="s1" style={{ color: item.color }}>{`${aiReview.value?.[item.value]}${
<span class="s1" style={{ color: item.color }}>{`${aiReview.value?.[item.value] ?? '-'}${
item.suffix || ''
}`}</span>
<span class="cts mt-4px !lh-20px !text-12px !color-#737478">{item.label}</span>
@ -356,7 +356,7 @@ export default {
<div class="flex items-center mb-16px">
{RESULT_LIST.map((item, index) => (
<div class="flex flex-col justify-center items-center flex-1 result-item" key={index}>
<span class="s1" style={{ color: item.color }}>{`${aiReview.value?.[item.value]}${
<span class="s1" style={{ color: item.color }}>{`${aiReview.value?.[item.value] ?? '-'}${
item.suffix || ''
}`}</span>
<span class="cts mt-4px !lh-20px !text-12px !color-#737478">{item.label}</span>

View File

@ -77,7 +77,7 @@ export default {
path: `/explore/list/${data.code}`,
}).href;
copy(generateFullUrl(url));
AMessage.success('复制成功');
AMessage.success('链接已复制!');
emit('close');
}
} finally {

View File

@ -14,6 +14,7 @@ import {
import { useClipboard } from '@vueuse/core';
import { getWriterLinksGenerate, getTemplateUrl, postWorksByLink, postWorksByFile } from '@/api/all/generationWorkshop';
import { generateFullUrl } from '@/utils/tools';
import { slsWithCatch } from '@/utils/stroage.ts';
import TextOverTips from '@/components/text-over-tips';
import icon1 from '@/assets/img/media-account/icon-feedback-fail.png';
@ -86,7 +87,6 @@ export default {
path: `/writer/manuscript/list/${data.code}`,
}).href;
form.value.writerLink = generateFullUrl(url);
console.log('getWriterLinksGenerate -----writer-code---->', form.value.writerLink);
}
};
@ -144,9 +144,7 @@ export default {
// 文件上传处理
const handleUpload = async (option) => {
try {
taskStatus.value = TASK_STATUS.LOADING;
const {
fileItem: { file },
} = option;
@ -160,16 +158,14 @@ export default {
});
if (code === 200) {
taskStatus.value = TASK_STATUS.SUCCESS;
works.value = data;
}
} finally {
taskStatus.value = TASK_STATUS.DEFAULT;
works.value = data ? [data] : [];
}
};
// 跳转编辑
// 跳转上传页面
const goUpload = () => {
router.push(`/manuscript/upload/1`);
slsWithCatch('waitUploadWorks',JSON.stringify(works.value));
router.push(`/manuscript/upload`);
onClose();
};
@ -271,7 +267,7 @@ export default {
<div key={item.id} class="rounded-8px bg-#fff px-8px py-8px flex justify-between items-center mt-8px">
<div class="flex-1 overflow-hidden flex items-center mr-12px">
<img src={item.cover} width="32" height="32" class="rounded-3px mr-8px" />
<TextOverTips class="text" context={item.title} />
<TextOverTips class="text !text-left" context={item.title} />
</div>
<icon-delete
size="16px"

View File

@ -7,19 +7,20 @@ import UploadSuccessModal from './upload-success-modal.vue';
import { EnumManuscriptType } from '@/views/creative-generation-workshop/manuscript/list/constants';
import { postWorksBatch } from '@/api/all/generationWorkshop.ts';
import { glsWithCatch, rlsWithCatch, slsWithCatch } from '@/utils/stroage.ts';
import icon1 from '@/assets/img/creative-generation-workshop/icon-photo.png';
import icon2 from '@/assets/img/creative-generation-workshop/icon-video.png';
const generateMockData = (count = 4) =>
Array.from({ length: count }, (_, i) => ({
id: `${i + 1}`,
title: `标题${i + 1}`,
content: '挖到宝了!这个平价好物让我素颜出门都自信✨挖到宝了!这个平价好物让我素颜出门都自信✨',
type: i % 2 === 0 ? EnumManuscriptType.Image : EnumManuscriptType.Video,
files: [],
videoInfo: cloneDeep(INITIAL_VIDEO_INFO),
}));
// const generateMockData = (count = 4) =>
// Array.from({ length: count }, (_, i) => ({
// id: `${i + 1}`,
// title: `标题${i + 1}`,
// content: '挖到宝了!这个平价好物让我素颜出门都自信✨挖到宝了!这个平价好物让我素颜出门都自信✨',
// type: i % 2 === 0 ? EnumManuscriptType.Image : EnumManuscriptType.Video,
// files: [],
// videoInfo: cloneDeep(INITIAL_VIDEO_INFO),
// }));
export default {
components: {
@ -72,40 +73,46 @@ export default {
});
};
const onSubmit = async (check) => {
const onSubmit = async (action) => {
uploadLoading.value = true;
const filteredWorks = map(works.value, (work) => omit(work, 'videoInfo'));
const { code, data } = await postWorksBatch({ works: filteredWorks });
if (code === 200) {
uploadLoading.value = false;
if (check) {
if (action === 'batchUpload') {
uploadSuccessModal.value?.open(workId);
} else {
AMessage.success('上传成功');
if (action === 'uploadAndCheck') {
slsWithCatch('manuscriptCheckIds', [workId]);
router.push({ name: 'ManuscriptCheck' });
} else {
router.push({ name: 'ManuscriptList' });
}
}
}
};
const onUpload = async (e, check = false) => {
console.log('onUpload', works.value);
// 本地存储同步
const syncLocalStorage = () => {
slsWithCatch('waitUploadWorks', JSON.stringify(works.value ?? []));
};
const onUpload = async (action) => {
formRef.value
?.validate()
.then(() => {
return validateDataSource();
})
.then(() => {
onSubmit(check);
onSubmit(action);
})
.catch((err) => {
console.log('catch');
errorDataCards.value.push(err);
});
};
const onUploadAndCheck = (e) => {
onUpload(e, true);
};
const handleReValidate = () => {
formRef.value?.validate().then(() => {
deleteErrorCard(selectCardInfo.value);
@ -134,6 +141,8 @@ export default {
selectCardInfo.value = {};
}
}
syncLocalStorage();
};
const renderFooterRow = () => {
@ -143,8 +152,8 @@ export default {
<Button size="medium" type="outline" onClick={onCancel} class="mr-12px">
取消上传
</Button>
<Button type="primary" size="medium" onClick={onUpload} loading={uploadLoading.value}>
{uploadLoading.value ? '批量上传' : '批量上传'}
<Button type="primary" size="medium" onClick={() => onUpload('batchUpload')} loading={uploadLoading.value}>
{uploadLoading.value ? '批量上传中...' : '批量上传'}
</Button>
</>
);
@ -154,10 +163,21 @@ export default {
<Button size="medium" type="outline" onClick={onCancel} class="mr-12px">
取消上传
</Button>
<Button size="medium" type="outline" onClick={onUpload} class="mr-12px" loading={uploadLoading.value}>
<Button
size="medium"
type="outline"
onClick={() => onUpload('singleUpload')}
class="mr-12px"
loading={uploadLoading.value}
>
上传
</Button>
<Button type="primary" size="medium" onClick={onUploadAndCheck} loading={uploadLoading.value}>
<Button
type="primary"
size="medium"
onClick={() => onUpload('uploadAndCheck')}
loading={uploadLoading.value}
>
上传并审核
</Button>
</>
@ -165,8 +185,12 @@ export default {
}
};
const getData = () => {
works.value = generateMockData();
selectCardInfo.value = cloneDeep(works.value[0] ?? {});
const _works = JSON.parse(glsWithCatch('waitUploadWorks') ?? '[]')?.map((item) => ({
...item,
videoInfo: item?.videoInfo ? cloneDeep(item.videoInfo) : cloneDeep(INITIAL_VIDEO_INFO),
}));
works.value = _works;
selectCardInfo.value = cloneDeep(_works[0] ?? {});
};
const getCardClass = (item) => {
if (selectCardInfo.value.id === item.id) {
@ -184,6 +208,8 @@ export default {
works.value[index] = cloneDeep(val);
}
selectCardInfo.value = val;
syncLocalStorage();
};
const onUpdateVideoInfo = (newVideoInfo) => {
const index = works.value.findIndex((v) => v.id === selectCardInfo.value.id);
@ -191,12 +217,18 @@ export default {
works.value[index].videoInfo = cloneDeep(newVideoInfo);
}
selectCardInfo.value.videoInfo = { ...selectCardInfo.value.videoInfo, ...newVideoInfo };
syncLocalStorage();
};
onMounted(() => {
getData();
});
onUnmounted(() => {
rlsWithCatch('waitUploadWorks');
});
return () => (
<>
<div class="manuscript-upload-wrap bg-#fff rounded-8px border-1px border-#D7D7D9 border-solid flex">