feat: 分享内容稿件

This commit is contained in:
rd
2025-08-01 15:03:16 +08:00
parent 568eeb33b4
commit a9bb9a45c0
11 changed files with 376 additions and 82 deletions

View File

@ -26,7 +26,6 @@ export const INITIAL_VIDEO_INFO = {
name: '',
size: '',
percent: 0,
poster: '',
time: '',
uploadSpeed: '0 KB/s',
startTime: 0,
@ -76,7 +75,6 @@ export default {
getVideoInfo(file)
.then(({ duration, firstFrame }) => {
console.log({ duration, firstFrame });
formData.value.videoInfo.poster = firstFrame;
formData.value.videoInfo.time = formatDuration(duration);
emit('updateVideoInfo', formData.value.videoInfo);

View File

@ -0,0 +1,40 @@
export const INITIAL_FORM = {
audit_status: '',
sort_column: undefined,
sort_order: undefined,
};
export const TABLE_COLUMNS = [
{
title: '序号',
dataIndex: 'uid',
width: 120,
fixed: 'left',
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{
title: '内容稿件标题',
dataIndex: 'title',
width: 220,
},
{
title: '审核状态',
dataIndex: 'audit_status',
width: 120,
},
{
title: '稿件类型',
dataIndex: 'type',
width: 120,
},
{
title: '最后修改时间',
dataIndex: 'last_modified_at',
width: 160,
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
];

View File

@ -0,0 +1,267 @@
<script lang="jsx">
import {
Input,
Table,
Modal,
TableColumn,
Checkbox,
Pagination,
Button,
Tooltip,
Notification,
} from '@arco-design/web-vue';
import CommonSelect from '@/components/common-select';
import TextOverTips from '@/components/text-over-tips';
import { INITIAL_FORM, TABLE_COLUMNS } from './constants';
import { formatTableField, exactFormatTime } from '@/utils/tools';
import { CHECK_STATUS, EnumManuscriptType } from '@/views/creative-generation-workshop/manuscript/list/constants';
import { useTableSelectionWithPagination } from '@/hooks/useTableSelectionWithPagination';
import { getWorksPage } from '@/api/all/generationWorkshop.ts';
import icon2 from '@/assets/img/creative-generation-workshop/icon-photo.png';
import icon3 from '@/assets/img/creative-generation-workshop/icon-video.png';
export default {
setup(props, { emit, expose }) {
const {
selectedRowKeys,
selectedRows,
dataSource,
pageInfo,
onPageChange,
onPageSizeChange,
rowSelection,
handleSelect,
handleSelectAll,
DEFAULT_PAGE_INFO,
} = useTableSelectionWithPagination({
onPageChange: () => {
getData();
},
onPageSizeChange: () => {
getData();
},
});
const visible = ref(false);
const query = ref(cloneDeep(INITIAL_FORM));
const tableRef = ref(null);
const reset = () => {
query.value = cloneDeep(INITIAL_FORM);
pageInfo.value = cloneDeep(DEFAULT_PAGE_INFO);
selectedRowKeys.value = [];
selectedRows.value = [];
dataSource.value = [];
};
const getData = async () => {
const { page, page_size } = pageInfo.value;
const { code, data } = await getWorksPage({
...query.value,
page,
page_size,
});
if (code === 200) {
dataSource.value = data?.data ?? [];
pageInfo.value.total = data.total;
}
};
const handleSearch = () => {
reload();
};
const reload = () => {
pageInfo.value.page = 1;
getData();
};
const open = () => {
getData();
visible.value = true;
};
const onClose = () => {
visible.value = false;
reset();
};
const renderColumn = () => {
return TABLE_COLUMNS.map((column) => (
<TableColumn
key={column.dataIndex}
data-index={column.dataIndex}
fixed={column.fixed}
width={column.width}
min-width={column.minWidth}
sortable={column.sortable}
align={column.align}
ellipsis
tooltip
v-slots={{
title: () => (
<div class="flex items-center">
<span class="cts mr-4px">{column.title}</span>
{column.tooltip && (
<Tooltip content={column.tooltip} position="top">
<IconQuestionCircle class="tooltip-icon color-#737478" size={16} />
</Tooltip>
)}
</div>
),
cell: ({ record }) => renderCell(record),
}}
/>
));
};
const onShare = () => {
console.log('onShare');
};
const handleSorterChange = (column, order) => {
query.value.sort_column = column;
query.value.sort_order = order === 'ascend' ? 'asc' : 'desc';
reload();
};
const getStatusInfo = (audit_status) => {
return CHECK_STATUS.find((v) => v.id === audit_status) ?? {};
};
expose({
open,
});
return () => (
<Modal
v-model:visible={visible.value}
title="分享内容稿件"
width="920px"
onClose={onClose}
modal-class="share-manuscript-modal"
v-slots={{
footer: () => (
<>
<Button size="large" onClick={onClose}>
取消
</Button>
<Button type="primary" class="ml-16px" size="large" onClick={onShare}>
分享
</Button>
</>
),
}}
>
<div class="filter-row-item mb-16px">
<span class="label mr-12px">审核状态</span>
<CommonSelect
placeholder="全部"
options={CHECK_STATUS}
v-model={query.value.audit_status}
class="!w-200px"
multiple={false}
onchange={handleSearch}
/>
</div>
<Table
ref={tableRef.value}
data={dataSource.value}
row-key="id"
column-resizable
row-selection={rowSelection.value}
selected-keys={selectedRowKeys.value}
pagination={false}
scroll={{ x: '100%' }}
class="flex-1 w-100% overflow-hidden"
bordered
onSorterChange={handleSorterChange}
onSelect={handleSelect}
onSelectAll={handleSelectAll}
v-slots={{
empty: () => <NoData />,
columns: () => (
<>
{TABLE_COLUMNS.map((column) => (
<TableColumn
key={column.dataIndex}
data-index={column.dataIndex}
fixed={column.fixed}
width={column.width}
min-width={column.minWidth}
sortable={column.sortable}
align={column.align}
ellipsis
tooltip
v-slots={{
title: () => (
<div class="flex items-center">
<span class="cts mr-4px">{column.title}</span>
{column.tooltip && (
<Tooltip content={column.tooltip} position="top">
<IconQuestionCircle class="tooltip-icon color-#737478" size={16} />
</Tooltip>
)}
</div>
),
cell: ({ record }) => {
if (column.dataIndex === 'audit_status') {
return (
<div
class="flex items-center w-fit h-28px px-8px rounded-2px"
style={{ backgroundColor: getStatusInfo(record.audit_status).backgroundColor }}
>
<span class="cts s1" style={{ color: getStatusInfo(record.audit_status).color }}>
{getStatusInfo(record.audit_status).name}
</span>
</div>
);
} else if (column.dataIndex === 'title') {
return <TextOverTips context={record.title} />;
} else if (column.dataIndex === 'type') {
return (
<div class="flex items-center">
<img
src={record.type === EnumManuscriptType.Image ? icon2 : icon3}
width="16"
height="16"
class="mr-4px"
/>
<span
class="cts"
class={record.type === EnumManuscriptType.Image ? '!color-#25C883' : '!color-#6D4CFE'}
>
{record.type === EnumManuscriptType.Image ? '图文' : '视频'}
</span>
</div>
);
} else if (column.dataIndex === 'last_modified_at') {
return exactFormatTime(record.last_modified_at, 'YYYY-MM-DD HH:mm:ss', 'YYYY-MM-DD HH:mm:ss');
} else {
return formatTableField(column, record, true);
}
},
}}
/>
))}
</>
),
}}
/>
{pageInfo.value.total > 0 && (
<div class="flex justify-end mt-16px">
<Pagination
total={pageInfo.value.total}
size="mini"
show-total
show-jumper
show-page-size
current={pageInfo.value.page}
page-size={pageInfo.value.page_size}
onChange={onPageChange}
onPageSizeChange={onPageSizeChange}
/>
</div>
)}
</Modal>
);
},
};
</script>
<style lang="scss">
@import './style.scss';
</style>

View File

@ -0,0 +1,17 @@
.share-manuscript-modal {
.filter-row-item {
.label {
color: var(--Text-1, #211f24);
font-family: $font-family-regular;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: 22px;
}
}
.arco-modal-body {
height: 464px;
display: flex;
flex-direction: column;
}
}

View File

@ -5,14 +5,14 @@ import CancelEditModal from './cancel-edit-modal.vue';
import { getWorksDetail, putWorksUpdate } from '@/api/all/generationWorkshop';
import { EnumManuscriptType } from '@/views/creative-generation-workshop/manuscript/list/constants.ts';
const INITIAL_DATA = {
title: '',
content: '',
type: EnumManuscriptType.Video,
// project_ids: [],
files: [],
videoInfo: cloneDeep(INITIAL_VIDEO_INFO),
};
// const INITIAL_DATA = {
// title: '',
// content: '',
// type: EnumManuscriptType.Video,
// // project_ids: [],
// files: [],
// videoInfo: cloneDeep(INITIAL_VIDEO_INFO),
// };
export default {
components: {
@ -41,6 +41,11 @@ export default {
const onSave = async (check = false) => {
formRef.value?.validate().then(async () => {
if (dataSource.value.videoInfo.uploadStatus === ENUM_UPLOAD_STATUS.UPLOADING) {
AMessage.warning('有视频正在上传中,请等待上传完成后再提交');
return;
}
const filteredWorks = omit(dataSource.value, 'videoInfo');
const { code, data } = await putWorksUpdate({ id: workId.value, ...filteredWorks });
if (code === 200) {
@ -62,8 +67,9 @@ export default {
const getData = async () => {
const { code, data } = await getWorksDetail(workId.value);
if (code === 200) {
dataSource.value = cloneDeep(data);
remoteDataSource.value = cloneDeep(data);
const _data = { ...data, videoInfo: cloneDeep(INITIAL_VIDEO_INFO) };
dataSource.value = cloneDeep(_data);
remoteDataSource.value = cloneDeep(_data);
}
};
const onChange = (val) => {
@ -76,7 +82,7 @@ export default {
router.push({ name: 'ManuscriptList' });
};
onMounted(() => {
init();
// init();
workId && getData();
});

View File

@ -18,11 +18,11 @@ export const TABLE_COLUMNS = [
dataIndex: 'title',
width: 240,
},
{
title: '所属项目',
dataIndex: 'projects',
width: 240,
},
// {
// title: '所属项目',
// dataIndex: 'projects',
// width: 240,
// },
{
title: '稿件类型',
dataIndex: 'type',
@ -43,7 +43,7 @@ export const TABLE_COLUMNS = [
},
{
title: '上传人员',
dataIndex: 'uploader.name',
dataIndex: 'uploader',
width: 180,
},
{
@ -56,7 +56,7 @@ export const TABLE_COLUMNS = [
},
{
title: '最后修改人员',
dataIndex: 'last_modifier.name',
dataIndex: 'last_modifier',
width: 180,
},
{

View File

@ -41,9 +41,6 @@
<template v-else-if="column.dataIndex === 'title'" #cell="{ record }">
<TextOverTips :context="record.title" :line="3" class="title" />
</template>
<template v-else-if="column.dataIndex === 'projects'" #cell="{ record }">
<TextOverTips :context="record.projects.map((item) => item).join('')" :line="3" />
</template>
<template v-else-if="column.dataIndex === 'audit_status'" #cell="{ record }">
<div
class="flex items-center w-fit h-28px px-8px rounded-2px"
@ -62,18 +59,19 @@
height="16"
class="mr-4px"
/>
<span
class="cts"
:class="record.type === EnumManuscriptType.Image ? '!color-#25C883' : '!color-#6D4CFE'"
>{{ record.type === EnumManuscriptType.Image ? '图文' : '视频' }}</span
>
<span class="cts" :class="record.type === EnumManuscriptType.Image ? '!color-#25C883' : '!color-#6D4CFE'">{{
record.type === EnumManuscriptType.Image ? '图文' : '视频'
}}</span>
</div>
</template>
<template v-else-if="['uploader', 'last_modifier'].includes(column.dataIndex)" #cell="{ record }">
{{ record[column.dataIndex].name || record[column.dataIndex].mobile }}
</template>
<template v-else-if="['updated_at', 'last_modified_at'].includes(column.dataIndex)" #cell="{ record }">
{{ exactFormatTime(record[column.dataIndex]) }}
</template>
<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" />
</template>
<template v-else-if="column.dataIndex === 'operation'" #cell="{ record }">
<div class="flex items-center">

View File

@ -38,6 +38,7 @@
<DeleteManuscriptModal ref="deleteManuscriptModalRef" />
<UploadManuscriptModal ref="uploadManuscriptModalRef" />
<ShareManuscriptModal ref="shareManuscriptModalRef" />
</div>
</template>
<script lang="jsx" setup>
@ -46,7 +47,8 @@ import { Button } from '@arco-design/web-vue';
import FilterBlock from './components/filter-block';
import ManuscriptTable from './components/manuscript-table';
import DeleteManuscriptModal from './components/manuscript-table/delete-manuscript-modal.vue';
import UploadManuscriptModal from './components/upload-manascript-modal';
import UploadManuscriptModal from './components/upload-manuscript-modal';
import ShareManuscriptModal from '../components/share-manuscript-modal';
import { useTableSelectionWithPagination } from '@/hooks/useTableSelectionWithPagination';
import { getWorksPage } from '@/api/all/generationWorkshop.ts';
@ -64,6 +66,7 @@ const query = ref(cloneDeep(INITIAL_QUERY));
const addManuscriptModalRef = ref(null);
const deleteManuscriptModalRef = ref(null);
const uploadManuscriptModalRef = ref(null);
const shareManuscriptModalRef = ref(null);
const getData = async () => {
const { page, page_size } = pageInfo.value;
@ -76,57 +79,6 @@ const getData = async () => {
dataSource.value = data?.data ?? [];
pageInfo.value.total = data.total;
}
dataSource.value = [
{
uid: 1,
id:1,
projects: ['内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1', '内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1'],
title: '内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1',
audit_status: EnumCheckStatus.Wait,
type: 0,
updated_at: 1753682671,
last_modified_at: 1753682671,
uploader: {
name: '1111'
},
last_modifier: {
name: '1111'
}
},
{
uid: 2,
id:2,
projects: ['内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1', '内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1'],
title: '内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1',
audit_status: EnumCheckStatus.Checking,
type: 1,
updated_at: 1753682672,
last_modified_at: 1753682672,
uploader: {
name: '1111'
},
last_modifier: {
name: '1111'
}
},
{
uid: 3,
id:3,
projects: ['内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1', '内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1'],
title: '内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1内容稿件1',
audit_status: EnumCheckStatus.Passed,
type: 1,
updated_at: 1753682673,
last_modified_at: 1753682673,
uploader: {
name: '1111'
},
last_modifier: {
name: '1111'
}
},
];
};
const handleSearch = () => {
reload();
@ -147,7 +99,7 @@ const handleSorterChange = (column, order) => {
};
const handleOpenAddProjectModal = () => {
console.log('handleOpenAddProjectModal');
shareManuscriptModalRef.value.open()
};
const openUploadModal = () => {
uploadManuscriptModalRef.value?.open();