feat: 内容审核表格初始化

This commit is contained in:
rd
2025-08-04 10:36:27 +08:00
parent 0b358cc19d
commit 29f4f22432
12 changed files with 403 additions and 94 deletions

View File

@ -53,3 +53,8 @@ export const putWorkAuditsAuditPass = (params = {}) => {
const { id: auditId, ...rest } = params as { id: string; [key: string]: any };
return Http.put(`/v1/work-audits/${auditId}/audit-pass`, rest);
};
// 生成分享链接
export const getWriterLinksGenerate = (params = {}) => {
return Http.get('/v1/writer-links/generate', params);
};

View File

@ -10,7 +10,7 @@
<span class="label">内容稿件标题</span>
<a-space size="medium">
<a-input
v-model="query.name"
v-model="query.title"
class="w-240px"
placeholder="请输入内容稿件标题"
size="medium"
@ -23,6 +23,57 @@
</a-input>
</a-space>
</div>
<div class="filter-row-item">
<span class="label">序号</span>
<a-space size="medium">
<a-input
v-model="query.uid"
class="w-160px"
placeholder="请输入序号"
size="medium"
allow-clear
@change="handleSearch"
>
<template #prefix>
<icon-search />
</template>
</a-input>
</a-space>
</div>
<div class="filter-row-item">
<span class="label">上传时间</span>
<a-range-picker
v-model="created_at"
size="medium"
allow-clear
format="YYYY-MM-DD"
class="w-280px"
@change="(value) => onDateChange(value, 'created_at')"
/>
</div>
<div class="filter-row-item">
<span class="label">审核平台</span>
<a-select v-model="query.audit_platform" size="medium" placeholder="全部" allow-clear @change="handleSearch">
<a-option
v-for="(item, index) in MEDIA_ACCOUNT_PLATFORMS"
:key="index"
:value="item.value"
:label="item.label"
>{{ item.label }}</a-option
>
</a-select>
</div>
<div class="filter-row-item">
<span class="label">审核时间</span>
<a-range-picker
v-model="audit_started_at"
size="medium"
allow-clear
format="YYYY-MM-DD"
class="w-280px"
@change="(value) => onDateChange(value, 'audit_started_at')"
/>
</div>
<div class="filter-row-item">
<a-button type="outline" class="mr-12px" size="medium" @click="handleSearch">
<template #icon>
@ -43,6 +94,7 @@
<script setup>
import { defineEmits, defineProps } from 'vue';
import { MEDIA_ACCOUNT_PLATFORMS } from '@/utils/platform';
const props = defineProps({
query: {
@ -52,6 +104,8 @@ const props = defineProps({
});
const emits = defineEmits('search', 'reset', 'update:query');
const created_at = ref([]);
const audit_started_at = ref([]);
const handleSearch = () => {
emits('update:query', props.query);
@ -60,7 +114,22 @@ const handleSearch = () => {
});
};
const onDateChange = (value, type) => {
if (!value) {
props.query[type] = [];
handleSearch();
return;
}
const [start, end] = value;
const FORMAT_DATE = 'YYYY-MM-DD HH:mm:ss';
props.query[type] = [dayjs(start).startOf('day').format(FORMAT_DATE), dayjs(end).endOf('day').format(FORMAT_DATE)];
handleSearch();
};
const handleReset = () => {
created_at.value = [];
emits('reset');
};
</script>

View File

@ -1,60 +0,0 @@
export const TABLE_COLUMNS = [
{
title: '序号',
dataIndex: 'index',
width: 120,
fixed: 'left',
},
{
title: '图片/视频',
dataIndex: 'picker',
width: 240,
},
{
title: '内容稿件标题',
dataIndex: 'name',
width: 240,
},
{
title: '所属项目',
dataIndex: 'name',
width: 240,
},
{
title: '稿件类型',
dataIndex: 'budget',
width: 180,
},
{
title: '上传时间',
dataIndex: 'create_at',
width: 180,
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{
title: '上传人员',
dataIndex: 'placement_account_count',
width: 180,
},
{
title: '最后修改时间',
dataIndex: 'last_create_at',
width: 180,
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{
title: '最后修改人员',
dataIndex: 'placement_account_count1',
width: 180,
},
{
title: '操作',
dataIndex: 'operation',
width: 160,
fixed: 'right'
},
];

View File

@ -20,7 +20,7 @@
<script setup>
import { ref } from 'vue';
import { deleteProject } from '@/api/all/propertyMarketing';
import { deleteWork } from '@/api/all/generationWorkshop';
import icon1 from '@/assets/img/media-account/icon-warn-1.png';
const update = inject('update');
@ -46,7 +46,7 @@ const open = (record) => {
};
async function onDelete() {
const { code } = await deleteProject(projectId.value);
const { code } = await deleteWork(projectId.value);
if (code === 200) {
AMessage.success('删除成功');
update()

View File

@ -11,11 +11,11 @@
@sorter-change="handleSorterChange"
>
<template #empty>
<NoData text="暂无项目"/>
<NoData text="暂无稿件" />
</template>
<template #columns>
<a-table-column
v-for="column in TABLE_COLUMNS"
v-for="column in tableColumns"
:key="column.dataIndex"
:data-index="column.dataIndex"
:fixed="column.fixed"
@ -38,14 +38,41 @@
<template v-if="column.dataIndex === 'create_at'" #cell="{ record }">
{{ exactFormatTime(record.create_at) }}
</template>
<template v-else-if="column.dataIndex === 'title'" #cell="{ record }">
<TextOverTips :context="record.title" :line="3" class="title" @click="onDetail(record)" />
</template>
<template v-else-if="column.dataIndex === 'type'" #cell="{ record }">
<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>
</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">
<template #error>
<img :src="icon4" class="w-full h-full" />
</template>
</a-image>
</template>
<template v-else-if="column.dataIndex === 'operation'" #cell="{ record }">
<div class="flex items-center">
<img class="mr-8px cursor-pointer" :src="icon1" width="14" height="14" @click="onDelete(record)" />
<a-button type="outline" size="mini" @click="onEdit(record)">分享</a-button>
<a-button type="outline" size="mini" @click="onEdit(record)">审核</a-button>
<a-button type="outline" size="mini" @click="onCheck(record)">审核</a-button>
</div>
</template>
<template v-else #cell="{ record }">
{{ formatTableField(column, record, true) }}
</template>
@ -57,17 +84,28 @@
<script setup>
import { ref } from 'vue';
import { formatTableField, exactFormatTime } from '@/utils/tools';
import { TABLE_COLUMNS } from './constants';
import { EnumManuscriptType } from '@/views/creative-generation-workshop/manuscript/list/constants';
import { AuditStatus } from '@/views/creative-generation-workshop/manuscript/check/constants';
import TextOverTips from '@/components/text-over-tips';
import icon1 from '@/assets/img/media-account/icon-delete.png';
import icon2 from '@/assets/img/creative-generation-workshop/icon-photo.png';
import icon3 from '@/assets/img/creative-generation-workshop/icon-video.png';
import icon4 from '@/assets/img/error-img.png';
const emits = defineEmits(['edit', 'sorterChange', 'delete']);
const router = useRouter();
const props = defineProps({
dataSource: {
type: Array,
default: () => [],
},
tableColumns: {
type: Array,
default: () => [],
},
});
const tableRef = ref(null);
@ -78,12 +116,13 @@ const handleSorterChange = (column, order) => {
const onDelete = (item) => {
emits('delete', item);
};
const onEdit = (item) => {
emits('edit', item);
const onCheck = (item) => {
router.push(`/manuscript/detail/${item.id}`);
};
const onDetail = (item) => {
console.log('onDetail')
router.push(`/manuscript/detail/${item.id}`);
};
</script>
<style scoped lang="scss">

View File

@ -7,4 +7,10 @@
font-weight: 400;
line-height: 22px;
}
:deep(.title) {
cursor: pointer;
&:hover {
color: #6d4cfe;
}
}
}

View File

@ -1,5 +1,224 @@
export const TABLE_COLUMNS1 = [
{
title: '序号',
dataIndex: 'uid',
width: 120,
fixed: 'left',
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{
title: '图片/视频',
dataIndex: 'cover',
width: 120,
},
{
title: '内容稿件标题',
dataIndex: 'title',
width: 300,
},
{
title: '稿件类型',
dataIndex: 'type',
width: 180,
},
{
title: '上传时间',
dataIndex: 'updated_at',
width: 180,
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{
title: '上传人员',
dataIndex: 'uploader',
width: 180,
},
{
title: '最后修改时间',
dataIndex: 'last_modified_at',
width: 180,
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{
title: '最后修改人员',
dataIndex: 'last_modifier',
width: 180,
},
{
title: '操作',
dataIndex: 'operation',
width: 180,
fixed: 'right',
},
];
export const TABLE_COLUMNS2 = [
{
title: '序号',
dataIndex: 'uid',
width: 120,
fixed: 'left',
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{
title: '图片/视频',
dataIndex: 'cover',
width: 120,
},
{
title: '内容稿件标题',
dataIndex: 'title',
width: 300,
},
{
title: '客户意见',
dataIndex: 'opinion',
width: 220,
},
{
title: '审核平台',
dataIndex: 'platform',
width: 120,
},
{
title: '合规程度',
dataIndex: 'platform',
width: 120,
},
{
title: '稿件类型',
dataIndex: 'type',
width: 180,
},
{
title: '审核时间',
dataIndex: 'last_modified_at',
width: 180,
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{
title: '最后修改时间',
dataIndex: 'last_modified_at',
width: 180,
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{
title: '修改人员',
dataIndex: 'last_modifier',
width: 180,
},
{
title: '操作',
dataIndex: 'operation',
width: 180,
fixed: 'right',
},
];
export const TABLE_COLUMNS3 = [
{
title: '序号',
dataIndex: 'uid',
width: 120,
fixed: 'left',
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{
title: '图片/视频',
dataIndex: 'cover',
width: 120,
},
{
title: '内容稿件标题',
dataIndex: 'title',
width: 300,
},
{
title: '客户意见',
dataIndex: 'title',
width: 120,
},
{
title: '审核平台',
dataIndex: 'platform',
width: 120,
},
{
title: '稿件类型',
dataIndex: 'type',
width: 180,
},
{
title: '通过时间',
dataIndex: 'last_modified_at',
width: 180,
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{
title: '最后修改时间',
dataIndex: 'last_modified_at',
width: 180,
sortable: {
sortDirections: ['ascend', 'descend'],
},
},
{
title: '修改人员',
dataIndex: 'last_modifier',
width: 180,
},
{
title: '操作',
dataIndex: 'operation',
width: 180,
fixed: 'right',
},
];
export enum AuditStatus {
Pending = '1',
Auditing = '2',
Passed = '3',
}
export const AUDIT_STATUS_LIST = [
{
label: '待审核',
value: AuditStatus.Pending,
tableColumns: TABLE_COLUMNS1,
},
{
label: '审核中',
value: AuditStatus.Auditing,
tableColumns: TABLE_COLUMNS2,
},
{
label: '已通过',
value: AuditStatus.Passed,
tableColumns: TABLE_COLUMNS3,
},
]
export const INITIAL_QUERY = {
name: '',
audit_status: AuditStatus.Pending,
title: '',
created_at: [],
audit_started_at: [],
audit_platform: '',
sort_column: undefined,
sort_order: undefined,
};

View File

@ -1,23 +1,19 @@
<template>
<div class="manuscript-check-wrap">
<div class="filter-wrap bg-#fff rounded-8px border-1px border-#D7D7D9 border-solid mb-16px">
<div class="top flex h-64px px-24px py-10px justify-between items-center">
<p class="text-18px font-400 lh-26px color-#211F24 title">内容审核列表</p>
<div class="flex items-center">
<a-button type="primary" size="medium" @click="handleOpenAddProjectModal">
<template #icon>
<icon-plus size="16"/>
</template>
<template #default>上传内容稿件</template>
</a-button>
</div>
</div>
<FilterBlock v-model:query="query" @search="handleSearch" @reset="handleReset" />
<a-tabs v-model="query.audit_status" @tab-click="handleTabClick">
<a-tab-pane title="待审核" v-for="item in AUDIT_STATUS_LIST" :key="item.value">{{ item.label }}</a-tab-pane>
<template #extra>
<a-button type="outline" size="medium" @click="handleOpenAddProjectModal">分享内容稿件</a-button>
</template>
</a-tabs>
<FilterBlock v-model:query="query" :audit_status="query.audit_status" @search="handleSearch" @reset="handleReset" />
</div>
<div
class="table-wrap bg-#fff rounded-8px border-1px border-#D7D7D9 border-solid px-24px py-24px flex-1 flex flex-col"
>
<ManuscriptCheckTable
:tableColumns="tableColumns"
:dataSource="dataSource"
@sorterChange="handleSorterChange"
@delete="handleDelete"
@ -48,11 +44,21 @@ import FilterBlock from './components/filter-block';
import ManuscriptCheckTable from './components/manuscript-check-table';
import DeleteManuscriptModal from './components/manuscript-check-table/delete-manuscript-modal.vue';
import { getWorkAuditsPage } from '@/api/all/generationWorkshop.ts';
import { useTableSelectionWithPagination } from '@/hooks/useTableSelectionWithPagination';
import { getProjects } from '@/api/all/propertyMarketing';
import { INITIAL_QUERY } from './constants';
import { INITIAL_QUERY, AUDIT_STATUS_LIST, TABLE_COLUMNS1, TABLE_COLUMNS2, TABLE_COLUMNS3 } from '@/views/creative-generation-workshop/manuscript/check/constants';
const { dataSource, pageInfo, onPageChange, onPageSizeChange, resetPageInfo } = useTableSelectionWithPagination({
const {
dataSource,
pageInfo,
onPageChange,
onPageSizeChange,
resetPageInfo,
selectedRowKeys,
selectedRows,
DEFAULT_PAGE_INFO,
} = useTableSelectionWithPagination({
onPageChange: () => {
getData();
},
@ -60,13 +66,14 @@ const { dataSource, pageInfo, onPageChange, onPageSizeChange, resetPageInfo } =
getData();
},
});
const tableColumns = ref([]);
const query = ref(cloneDeep(INITIAL_QUERY));
const addManuscriptModalRef = ref(null);
const deleteManuscriptModalRef = ref(null);
const getData = async () => {
const { page, page_size } = pageInfo.value;
const { code, data } = await getProjects({
const { code, data } = await getWorkAuditsPage({
...query.value,
page,
page_size,
@ -94,6 +101,16 @@ const handleSorterChange = (column, order) => {
reload();
};
const handleTabClick = (key) => {
dataSource.value = [];
selectedRowKeys.value = [];
selectedRows.value = [];
resetPageInfo();
query.value.audit_status = key;
tableColumns.value = AUDIT_STATUS_LIST.find((item) => item.value === key).tableColumns;
getData();
};
const handleOpenAddProjectModal = () => {
console.log('handleOpenAddProjectModal');
};
@ -107,11 +124,12 @@ const handleEdit = (item) => {
};
onMounted(() => {
tableColumns.value = TABLE_COLUMNS1;
getData();
});
provide('update', getData);
</script>
<style scoped lang="scss">
@import "./style.scss"
@import './style.scss';
</style>

View File

@ -3,11 +3,24 @@
display: flex;
flex-direction: column;
.filter-wrap {
:deep(.arco-tabs) {
.arco-tabs-tab {
height: 56px;
padding: 0 8px;
}
.arco-tabs-nav-extra {
padding-right: 24px;
}
.arco-tabs-content {
display: none;
}
}
.top {
.title {
font-family: $font-family-medium;
font-style: normal;
}
:deep(.arco-btn) {
.arco-btn-icon {
line-height: 16px;

View File

@ -18,7 +18,7 @@ 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 { getWorksPage, getWriterLinksGenerate } 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';
@ -218,7 +218,7 @@ export default {
if (column.dataIndex === 'audit_status') {
return (
<div
class="flex items-center w-fit h-28px px-8px rounded-2px"
class="flex items-center w-fit h-24px px-8px rounded-2px"
style={{ backgroundColor: getStatusInfo(record.audit_status).backgroundColor }}
>
<span class="cts s1" style={{ color: getStatusInfo(record.audit_status).color }}>

View File

@ -11,7 +11,7 @@ export const TABLE_COLUMNS = [
{
title: '图片/视频',
dataIndex: 'cover',
width: 240,
width: 120,
},
{
title: '内容稿件标题',

View File

@ -39,7 +39,7 @@
{{ exactFormatTime(record.create_at) }}
</template>
<template v-else-if="column.dataIndex === 'title'" #cell="{ record }">
<TextOverTips :context="record.title" :line="3" class="title" />
<TextOverTips :context="record.title" :line="3" class="title" @click="onDetail(record)" />
</template>
<template v-else-if="column.dataIndex === 'audit_status'" #cell="{ record }">
<div