feat: 内容稿件列表、整理文件目录结构
This commit is contained in:
@ -108,7 +108,6 @@ provide('toggleDrawerMenu', () => {
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
$nav-size-height: 72px;
|
||||
$layout-max-width: 1100px;
|
||||
|
||||
.layout {
|
||||
@ -121,7 +120,7 @@ $layout-max-width: 1100px;
|
||||
left: 0;
|
||||
z-index: 100;
|
||||
width: 100%;
|
||||
height: $nav-size-height;
|
||||
height: $navbar-height;
|
||||
}
|
||||
.layout-sider {
|
||||
position: fixed;
|
||||
|
||||
@ -8,6 +8,9 @@ const route = useRoute();
|
||||
const routerKey = computed(() => {
|
||||
return route.path + Math.random();
|
||||
});
|
||||
const showFooter = computed(() => {
|
||||
return !(route.meta && route.meta.hideFooter);
|
||||
});
|
||||
/*** - end */
|
||||
</script>
|
||||
|
||||
@ -19,7 +22,7 @@ const routerKey = computed(() => {
|
||||
<component :is="Component" :key="route.fullPath" />
|
||||
</keep-alive>
|
||||
</transition>
|
||||
<view class="footer">
|
||||
<view class="footer" v-if="showFooter">
|
||||
<view>闽公网安备 352018502850842号 闽ICP备20250520582号 © 2025小题科技,All Rights Reserved.</view>
|
||||
<view>* 数据通过公开渠道获取,灵机进行统计分析</view>
|
||||
</view>
|
||||
|
||||
@ -12,7 +12,7 @@ const COMPONENTS: AppRouteRecordRaw[] = [
|
||||
locale: '内容稿件',
|
||||
icon: IconContentManuscript,
|
||||
requiresAuth: false,
|
||||
requireLogin: true,
|
||||
requireLogin: false,
|
||||
roles: ['*'],
|
||||
id: MENU_GROUP_IDS.CREATIVE_GENERATION_WORKSHOP_ID,
|
||||
},
|
||||
@ -23,21 +23,48 @@ const COMPONENTS: AppRouteRecordRaw[] = [
|
||||
meta: {
|
||||
locale: '内容稿件列表',
|
||||
requiresAuth: false,
|
||||
requireLogin: true,
|
||||
requireLogin: false,
|
||||
roles: ['*'],
|
||||
},
|
||||
component: () => import('@/views/creative-generation-workshop/manuscript/manuscript-list/index.vue'),
|
||||
component: () => import('@/views/creative-generation-workshop/manuscript/list/index.vue'),
|
||||
},
|
||||
{
|
||||
path: 'check',
|
||||
path: 'edit/:id',
|
||||
name: 'ManuscriptEdit',
|
||||
meta: {
|
||||
locale: '账号详情',
|
||||
requiresAuth: false,
|
||||
requireLogin: false,
|
||||
hideFooter: true,
|
||||
roles: ['*'],
|
||||
hideInMenu: true,
|
||||
activeMenu: 'ManuscriptList',
|
||||
},
|
||||
component: () => import('@/views/creative-generation-workshop/manuscript/edit/index.vue'),
|
||||
},
|
||||
{
|
||||
path: 'detail/:id',
|
||||
name: 'ManuscriptDetail',
|
||||
meta: {
|
||||
locale: '账号详情',
|
||||
requiresAuth: false,
|
||||
requireLogin: false,
|
||||
roles: ['*'],
|
||||
hideInMenu: true,
|
||||
activeMenu: 'ManuscriptList',
|
||||
},
|
||||
component: () => import('@/views/creative-generation-workshop/manuscript/detail/index.vue'),
|
||||
},
|
||||
{
|
||||
path: 'check-list',
|
||||
name: 'ManuscriptCheck',
|
||||
meta: {
|
||||
locale: '内容稿件审核',
|
||||
requiresAuth: false,
|
||||
requireLogin: true,
|
||||
requireLogin: false,
|
||||
roles: ['*'],
|
||||
},
|
||||
component: () => import('@/views/creative-generation-workshop/manuscript/manuscript-check/index.vue'),
|
||||
component: () => import('@/views/creative-generation-workshop/manuscript/check/index.vue'),
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
1
src/router/typeings.d.ts
vendored
1
src/router/typeings.d.ts
vendored
@ -14,6 +14,7 @@ declare module 'vue-router' {
|
||||
noAffix?: boolean; // if set true, the tag will not affix in the tab-bar
|
||||
ignoreCache?: boolean; // if set true, the page will not be cached
|
||||
hideSidebar?: boolean;
|
||||
hideFooter?: boolean;
|
||||
requireLogin?: boolean; // 是否需要登陆才能访问
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,9 +55,9 @@ export const MENU_LIST = [
|
||||
{
|
||||
name: '内容稿件',
|
||||
routeName: 'ManuscriptList',
|
||||
includeRouteNames: ['ManuscriptList', 'ManuscriptCheck'],
|
||||
}
|
||||
]
|
||||
includeRouteNames: ['ManuscriptList', 'ManuscriptCheck', 'ManuscriptEdit', 'ManuscriptDetail'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: MENU_GROUP_IDS.PROPERTY_ID,
|
||||
@ -101,9 +101,7 @@ export const MENU_LIST = [
|
||||
{
|
||||
name: '项目管理',
|
||||
routeName: 'ProjectList',
|
||||
includeRouteNames: [
|
||||
'ProjectList',
|
||||
],
|
||||
includeRouteNames: ['ProjectList'],
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@ -1,4 +1,7 @@
|
||||
|
||||
$navbar-height: 72px; // 头部高度
|
||||
$sidebar-width: 220px; // 侧边栏菜单宽度
|
||||
|
||||
// 汉字字体
|
||||
$font-family-regular: 'PingFangSC-Regular', 'Microsoft Yahei', Arial, sans-serif;
|
||||
$font-family-medium: 'PingFangSC-Medium', 'Microsoft Yahei', Arial, sans-serif;
|
||||
|
||||
@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<div class="manuscript-detail-wrap">
|
||||
<div class="bg-#fff rounded-8px border-1px border-#D7D7D9 border-solid mb-24px">详情</div>
|
||||
</div>
|
||||
</template>
|
||||
@ -0,0 +1,3 @@
|
||||
.manuscript-edit-wrap {
|
||||
|
||||
}
|
||||
248
src/views/creative-generation-workshop/manuscript/edit/index.vue
Normal file
248
src/views/creative-generation-workshop/manuscript/edit/index.vue
Normal file
@ -0,0 +1,248 @@
|
||||
<script lang="jsx">
|
||||
import {
|
||||
Modal,
|
||||
Form,
|
||||
FormItem,
|
||||
Input,
|
||||
RadioGroup,
|
||||
Radio,
|
||||
Upload,
|
||||
Button,
|
||||
Message as AMessage,
|
||||
Textarea,
|
||||
} from '@arco-design/web-vue';
|
||||
import TextOverTips from '@/components/text-over-tips';
|
||||
import CommonSelect from '@/components/common-select';
|
||||
|
||||
import { EnumManuscriptType } from '@/views/creative-generation-workshop/manuscript/list/constants';
|
||||
import { getProjectList } from '@/api/all/propertyMarketing';
|
||||
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 = 20) =>
|
||||
Array.from({ length: count }, (_, i) => ({
|
||||
id: `item-${i + 1}`,
|
||||
content: '挖到宝了!这个平价好物让我素颜出门都自信✨挖到宝了!这个平价好物让我素颜出门都自信✨',
|
||||
type: 1,
|
||||
}));
|
||||
|
||||
const INITIAL_FORM = {
|
||||
title: '',
|
||||
desc: '',
|
||||
project_ids: [],
|
||||
files: [],
|
||||
};
|
||||
|
||||
export default {
|
||||
setup(props, { emit, expose }) {
|
||||
const formRef = ref(null);
|
||||
const uploadRef = ref(null);
|
||||
const form = ref(cloneDeep(INITIAL_FORM));
|
||||
const projects = ref([]);
|
||||
|
||||
const rules = {
|
||||
title: [{ required: true, message: '请输入标题' }],
|
||||
};
|
||||
|
||||
const dataSource = generateMockData();
|
||||
const onCancel = () => {
|
||||
console.log('onCancel');
|
||||
};
|
||||
const onSubmit = () => {
|
||||
console.log('onSubmit');
|
||||
};
|
||||
const handleUpload = (option) => {
|
||||
console.log('handleUpload', option);
|
||||
const {
|
||||
fileItem: { file },
|
||||
} = option;
|
||||
|
||||
// 验证文件类型
|
||||
const allowedTypes = ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp'];
|
||||
if (!allowedTypes.includes(file.type)) {
|
||||
AMessage.error('只能上传图片文件!');
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证文件大小 (5MB)
|
||||
const maxSize = 5 * 1024 * 1024;
|
||||
if (file.size > maxSize) {
|
||||
AMessage.error('图片大小不能超过5MB!');
|
||||
return;
|
||||
}
|
||||
|
||||
// 验证文件数量
|
||||
if (form.value.files.length >= 18) {
|
||||
AMessage.error('最多只能上传18张图片!');
|
||||
return;
|
||||
}
|
||||
|
||||
// 模拟上传过程
|
||||
setTimeout(() => {
|
||||
const newFile = {
|
||||
id: Date.now(),
|
||||
name: file.name,
|
||||
url: URL.createObjectURL(file),
|
||||
size: file.size,
|
||||
type: file.type,
|
||||
};
|
||||
|
||||
form.value.files.push(newFile);
|
||||
console.log(form.value.files);
|
||||
AMessage.success('上传成功!');
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
const handleDeleteFile = (index) => {
|
||||
form.value.files.splice(index, 1);
|
||||
AMessage.success('删除成功!');
|
||||
};
|
||||
const renderLeft = () => {
|
||||
return (
|
||||
<Form ref={formRef} model={form.value} rules={rules} layout="vertical" auto-label-width>
|
||||
<FormItem label="标题" field="title" required>
|
||||
<Input v-model={form.value.title} placeholder="请输入标题" size="large" class="w-500px" />
|
||||
</FormItem>
|
||||
<FormItem label="作品描述" field="desc">
|
||||
<Textarea
|
||||
v-model={form.value.desc}
|
||||
placeholder="请输入作品描述"
|
||||
size="large"
|
||||
class="h-200px"
|
||||
show-word-limit
|
||||
max-length={1000}
|
||||
auto-size={{ minRows: 7, maxRows: 9 }}
|
||||
/>
|
||||
</FormItem>
|
||||
<FormItem
|
||||
field="files"
|
||||
v-slots={{
|
||||
label: () => (
|
||||
<div class="flex items-center">
|
||||
<span class="cts !color-#211F24 mr-4px">图片</span>
|
||||
<span class="cts mr-8px">{`(${form.value.files.length}/18)`}</span>
|
||||
<span class="cts">第一张为首图,支持拖拽排序</span>
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
>
|
||||
<div class="flex flex-col gap-16px">
|
||||
{/* 已上传的图片列表 */}
|
||||
{form.value.files.length > 0 && (
|
||||
<div class="grid grid-cols-4 gap-12px">
|
||||
{form.value.files.map((file, index) => (
|
||||
<div key={file.id} class="relative group">
|
||||
<img
|
||||
src={file.url}
|
||||
alt={file.name}
|
||||
class="w-full h-120px object-cover rounded-8px border-1px border-#E6E6E8"
|
||||
/>
|
||||
<div class="absolute top-8px right-8px opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
<icon-delete
|
||||
size="16"
|
||||
class="color-#fff cursor-pointer bg-#000 bg-opacity-50 rounded-full p-4px"
|
||||
onClick={() => handleDeleteFile(index)}
|
||||
/>
|
||||
</div>
|
||||
{index === 0 && (
|
||||
<div class="absolute top-8px left-8px">
|
||||
<span class="text-10px color-#fff bg-#6D4CFE px-4px py-2px rounded-4px">首图</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 上传按钮 */}
|
||||
{form.value.files.length < 18 && (
|
||||
<Upload
|
||||
ref={uploadRef}
|
||||
action="/"
|
||||
draggable
|
||||
custom-request={handleUpload}
|
||||
accept=".jpg,.jpeg,.png,.gif,.webp"
|
||||
show-file-list={false}
|
||||
multiple
|
||||
limit={18 - form.value.files.length}
|
||||
>
|
||||
{{
|
||||
'upload-button': () => (
|
||||
<div class="upload-box">
|
||||
<icon-plus size="14" class="mb-16px color-#3C4043" />
|
||||
<span class="cts !color-#211F24">上传图片</span>
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
</Upload>
|
||||
)}
|
||||
</div>
|
||||
</FormItem>
|
||||
<FormItem label="所属项目" field="project_ids">
|
||||
<CommonSelect
|
||||
v-model={form.value.project_ids}
|
||||
options={projects.value}
|
||||
placeholder="请选择所属项目"
|
||||
size="large"
|
||||
class="w-280px"
|
||||
/>
|
||||
</FormItem>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
const getProjects = async () => {
|
||||
const { code, data } = await getProjectList();
|
||||
if (code === 200) {
|
||||
projects.value = data;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
getProjects();
|
||||
});
|
||||
return () => (
|
||||
<>
|
||||
<div class="manuscript-edit-wrap bg-#fff rounded-8px border-1px border-#D7D7D9 border-solid flex">
|
||||
<div class="left flex-1 overflow-y-auto p-24px">{renderLeft()}</div>
|
||||
<div class="right pt-24px pb-12px flex flex-col">
|
||||
<div class="title flex items-center mb-24px px-24px">
|
||||
<div class="w-3px h-16px bg-#6D4CFE rounded-2px mr-8px"></div>
|
||||
<p class="cts bold !color-#211F24 !text-16px !lh-24px mr-8px">上传内容稿件列表</p>
|
||||
<p class="cts">共30个</p>
|
||||
</div>
|
||||
<div class="flex-1 px-24px overflow-y-auto">
|
||||
{dataSource.map((item) => (
|
||||
<div key={item.id} class="mb-12px px-8px py-12px flex flex-col rounded-8px bg-#F7F8FA">
|
||||
<TextOverTips context={item.content} line={1} class="cts bold color-#211F24 mb-8px" />
|
||||
<div class="flex items-center">
|
||||
<img
|
||||
src={item.type === EnumManuscriptType.Image ? icon1 : icon2}
|
||||
width="16"
|
||||
height="16"
|
||||
class="mr-4px"
|
||||
/>
|
||||
<span class={`cts ${item.type === EnumManuscriptType.Image ? '!color-#25C883' : '!color-#6D4CFE'}`}>
|
||||
{item.type === EnumManuscriptType.Image ? '图文' : '视频'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-end items-center px-16px py-20px w-full bg-#fff footer-row">
|
||||
<Button size="medium" type="outline" onClick={onCancel} class="mr-12px">
|
||||
取消上传
|
||||
</Button>
|
||||
<Button type="primary" size="medium" onClick={onSubmit}>
|
||||
批量上传
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
@import './style.scss';
|
||||
</style>
|
||||
@ -0,0 +1,61 @@
|
||||
$footer-height: 68px;
|
||||
.manuscript-edit-wrap {
|
||||
height: calc(100% - 72px);
|
||||
.cts {
|
||||
color: #939499;
|
||||
font-family: $font-family-regular;
|
||||
font-size: 14px;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 22px;
|
||||
&.bold {
|
||||
font-family: $font-family-medium;
|
||||
}
|
||||
}
|
||||
.left {
|
||||
.upload-box {
|
||||
display: flex;
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
padding: 24px 16px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 8px;
|
||||
border: 1px dashed var(--Border-1, #d7d7d9);
|
||||
background: var(--BG-200, #f2f3f5);
|
||||
}
|
||||
}
|
||||
.right {
|
||||
border-left: 1px solid var(--Border-2, #e6e6e8);
|
||||
width: 320px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.upload-box {
|
||||
display: flex;
|
||||
height: 120px;
|
||||
padding: 0 16px;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
border-radius: 8px;
|
||||
border: 1px dashed var(--Border-1, #d7d7d9);
|
||||
background: var(--BG-200, #f2f3f5);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
|
||||
&:hover {
|
||||
border-color: var(--Primary-6, #6D4CFE);
|
||||
background: var(--Primary-1, #f0f0ff);
|
||||
}
|
||||
}
|
||||
}
|
||||
.footer-row {
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: $sidebar-width;
|
||||
width: calc(100% - $sidebar-width);
|
||||
border-top: 1px solid #e6e6e8;
|
||||
height: $footer-height;
|
||||
}
|
||||
@ -62,7 +62,7 @@ export const TABLE_COLUMNS = [
|
||||
{
|
||||
title: '操作',
|
||||
dataIndex: 'operation',
|
||||
width: 160,
|
||||
width: 180,
|
||||
fixed: 'right'
|
||||
},
|
||||
];
|
||||
@ -56,10 +56,17 @@
|
||||
</template>
|
||||
<template v-else-if="column.dataIndex === 'budget'" #cell="{ record }">
|
||||
<div class="flex items-center">
|
||||
<img :src="record.budget === 1 ? icon2 : icon3" width="16" height="16" class="mr-4px" />
|
||||
<span class="cts" :class="record.budget === 1 ? '!color-#25C883' : '!color-#6D4CFE'">{{
|
||||
record.budget === 1 ? '图文' : '视频'
|
||||
}}</span>
|
||||
<img
|
||||
:src="record.budget === EnumManuscriptType.Image ? icon2 : icon3"
|
||||
width="16"
|
||||
height="16"
|
||||
class="mr-4px"
|
||||
/>
|
||||
<span
|
||||
class="cts"
|
||||
:class="record.budget === EnumManuscriptType.Image ? '!color-#25C883' : '!color-#6D4CFE'"
|
||||
>{{ record.budget === EnumManuscriptType.Image ? '图文' : '视频' }}</span
|
||||
>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="['create_at', 'last_create_at'].includes(column.dataIndex)" #cell="{ record }">
|
||||
@ -87,7 +94,7 @@
|
||||
import { ref } from 'vue';
|
||||
import { formatTableField, exactFormatTime } from '@/utils/tools';
|
||||
import { TABLE_COLUMNS } from './constants';
|
||||
import { CHECK_STATUS } from '@/views/creative-generation-workshop/manuscript/manuscript-list/constants';
|
||||
import { CHECK_STATUS, EnumManuscriptType } from '@/views/creative-generation-workshop/manuscript/list/constants';
|
||||
|
||||
import TextOverTips from '@/components/text-over-tips';
|
||||
|
||||
@ -0,0 +1,352 @@
|
||||
<script lang="jsx">
|
||||
import {
|
||||
Modal,
|
||||
Form,
|
||||
FormItem,
|
||||
Input,
|
||||
RadioGroup,
|
||||
Radio,
|
||||
Upload,
|
||||
Button,
|
||||
Message as AMessage,
|
||||
Textarea,
|
||||
} from '@arco-design/web-vue';
|
||||
|
||||
import TextOverTips from '@/components/text-over-tips';
|
||||
import icon1 from '@/assets/img/media-account/icon-feedback-fail.png';
|
||||
|
||||
// 状态枚举
|
||||
const TASK_STATUS = {
|
||||
DEFAULT: 1,
|
||||
LOADING: 2,
|
||||
FAILED: 3,
|
||||
SUCCESS: 4,
|
||||
};
|
||||
|
||||
const UPLOAD_TYPE = {
|
||||
LINK: 'link',
|
||||
LOCAL: 'local',
|
||||
HANDWRITE: 'handwrite',
|
||||
};
|
||||
|
||||
// 初始表单数据
|
||||
const INITIAL_FORM = {
|
||||
linkUrl: '',
|
||||
link: '',
|
||||
};
|
||||
|
||||
// 模拟数据生成
|
||||
const generateMockData = (count = 20) =>
|
||||
Array.from({ length: count }, (_, i) => ({
|
||||
id: `item-${i + 1}`,
|
||||
content: '挖到宝了!这个平价好物让我素颜出门都自信✨挖到宝了!这个平价好物让我素颜出门都自信✨',
|
||||
}));
|
||||
|
||||
export default {
|
||||
setup(props, { emit, expose }) {
|
||||
const update = inject('update');
|
||||
const router = useRouter();
|
||||
|
||||
// 响应式状态
|
||||
const visible = ref(false);
|
||||
const formRef = ref(null);
|
||||
const uploadType = ref(UPLOAD_TYPE.LINK);
|
||||
const taskStatus = ref(TASK_STATUS.DEFAULT);
|
||||
const form = ref(cloneDeep(INITIAL_FORM));
|
||||
const uploadList = ref([]);
|
||||
const totalCount = ref(0);
|
||||
|
||||
// 剪贴板功能
|
||||
const { copy } = useClipboard({ source: form.value.link });
|
||||
|
||||
const isLink = computed(() => uploadType.value === UPLOAD_TYPE.LINK);
|
||||
const isLocal = computed(() => uploadType.value === UPLOAD_TYPE.LOCAL);
|
||||
const isHandwrite = computed(() => uploadType.value === UPLOAD_TYPE.HANDWRITE);
|
||||
const isDefault = computed(() => taskStatus.value === TASK_STATUS.DEFAULT);
|
||||
|
||||
// 模态框标题
|
||||
const getTitle = () => {
|
||||
const titleMap = {
|
||||
[TASK_STATUS.DEFAULT]: '上传内容稿件',
|
||||
[TASK_STATUS.LOADING]: isLink.value ? '链接上传' : isLocal.value ? '本地批量上传' : '上传内容稿件',
|
||||
[TASK_STATUS.FAILED]: isLink.value ? '链接上传' : isLocal.value ? '本地批量上传' : '上传内容稿件',
|
||||
[TASK_STATUS.SUCCESS]: '上传内容稿件列表',
|
||||
};
|
||||
return titleMap[taskStatus.value];
|
||||
};
|
||||
|
||||
// 重置状态
|
||||
const reset = () => {
|
||||
formRef.value?.resetFields?.();
|
||||
uploadType.value = UPLOAD_TYPE.LINK;
|
||||
taskStatus.value = TASK_STATUS.DEFAULT;
|
||||
form.value = cloneDeep(INITIAL_FORM);
|
||||
uploadList.value = [];
|
||||
totalCount.value = 0;
|
||||
};
|
||||
|
||||
// 打开模态框
|
||||
const open = () => {
|
||||
visible.value = true;
|
||||
};
|
||||
|
||||
// 关闭模态框
|
||||
const onClose = () => {
|
||||
reset();
|
||||
visible.value = false;
|
||||
};
|
||||
|
||||
// 防抖提交
|
||||
const debouncedSubmit = debounce(async () => {
|
||||
if (isHandwrite.value) {
|
||||
handleHandwriteSubmit();
|
||||
return;
|
||||
}
|
||||
|
||||
taskStatus.value = TASK_STATUS.LOADING;
|
||||
|
||||
// 模拟上传过程
|
||||
setTimeout(() => {
|
||||
taskStatus.value = TASK_STATUS.SUCCESS;
|
||||
totalCount.value = 30;
|
||||
uploadList.value = generateMockData();
|
||||
}, 2000);
|
||||
}, 300);
|
||||
|
||||
// 提交处理
|
||||
const onSubmit = () => {
|
||||
debouncedSubmit();
|
||||
};
|
||||
|
||||
// 手写提交处理
|
||||
const handleHandwriteSubmit = () => {
|
||||
copy(form.value.link);
|
||||
AMessage.success('复制成功!');
|
||||
onClose();
|
||||
};
|
||||
|
||||
// 取消上传
|
||||
const onCancelUpload = () => {
|
||||
taskStatus.value = TASK_STATUS.DEFAULT;
|
||||
AMessage.info('已取消上传');
|
||||
};
|
||||
|
||||
// 文件上传处理
|
||||
const handleUpload = async (file) => {
|
||||
console.log('handleUpload', file);
|
||||
taskStatus.value = TASK_STATUS.LOADING;
|
||||
|
||||
setTimeout(() => {
|
||||
taskStatus.value = TASK_STATUS.SUCCESS;
|
||||
totalCount.value = 30;
|
||||
uploadList.value = generateMockData();
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
// 跳转编辑
|
||||
const goEdit = () => {
|
||||
router.push(`/manuscript/edit/1`);
|
||||
onClose();
|
||||
};
|
||||
|
||||
// 删除项目
|
||||
const onDelete = (item) => {
|
||||
console.log('onDelete', item);
|
||||
uploadList.value = uploadList.value.filter((i) => i.id !== item.id);
|
||||
totalCount.value = uploadList.value.length;
|
||||
AMessage.success('删除成功');
|
||||
};
|
||||
|
||||
// 下载模板
|
||||
const handleDownloadTemplate = async () => {
|
||||
AMessage.info('下载模板功能开发中...');
|
||||
};
|
||||
|
||||
// 渲染链接上传表单
|
||||
const renderLinkForm = () => (
|
||||
<FormItem label="链接地址">
|
||||
<Textarea
|
||||
v-model={form.value.linkUrl}
|
||||
size="large"
|
||||
placeholder="请输入..."
|
||||
autoSize={{ minRows: 5, maxRows: 8 }}
|
||||
/>
|
||||
</FormItem>
|
||||
);
|
||||
|
||||
// 渲染手写上传表单
|
||||
const renderHandwriteForm = () => (
|
||||
<FormItem label="上传链接">
|
||||
<Input v-model={form.value.link} placeholder="请输入..." size="large" />
|
||||
</FormItem>
|
||||
);
|
||||
|
||||
// 渲染本地上传表单
|
||||
const renderLocalForm = () => (
|
||||
<FormItem label="内容稿件">
|
||||
<div class="flex flex-col w-full">
|
||||
<Upload
|
||||
action="/"
|
||||
draggable
|
||||
customRequest={handleUpload}
|
||||
accept=".xlsx,.xls,.docx,.doc"
|
||||
show-file-list={false}
|
||||
>
|
||||
{{
|
||||
'upload-button': () => (
|
||||
<div class="upload-box">
|
||||
<icon-plus size="14" class="mb-16px" />
|
||||
<span class="text mb-4px">点击或拖拽文件到此处上传</span>
|
||||
<span class="tip">支持文档(文本+图), 视频批量上传</span>
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
</Upload>
|
||||
<div class="flex items-center cursor-pointer mt-8px" onClick={handleDownloadTemplate}>
|
||||
<icon-download size="14" class="mr-4px !color-#6D4CFE" />
|
||||
<span class="cts color-#6D4CFE">下载示例文档</span>
|
||||
</div>
|
||||
</div>
|
||||
</FormItem>
|
||||
);
|
||||
|
||||
// 渲染加载状态
|
||||
const renderLoadingState = () => (
|
||||
<div class="flex flex-col items-center justify-center rounded-8px bg-#F7F8FA h-208px">
|
||||
<icon-loading size="48" class="!color-#6D4CFE mb-16px" />
|
||||
<p class="tip !text-#768893">上传过程耗时可能较长,请耐心等待;</p>
|
||||
<p class="tip !text-#768893">刷新页面将会终止本次数据的上传,请谨慎操作</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
// 渲染失败状态
|
||||
const renderFailedState = () => (
|
||||
<div class="flex flex-col items-center justify-center rounded-8px bg-#F7F8FA h-208px">
|
||||
<img src={icon1} class="w-80px h-80px mb-16px" />
|
||||
<p class="text mb-4px">上传失败</p>
|
||||
<p class="tip !text-#768893">可能是网络不稳定导致,请检查网络后重试~</p>
|
||||
</div>
|
||||
);
|
||||
|
||||
// 渲染成功状态
|
||||
const renderSuccessState = () => (
|
||||
<div class="flex flex-col py-12px max-h-540px rounded-8px bg-#F7F8FA">
|
||||
<span class="tip mb-8px px-12px fs-14px !text-left">共 {totalCount.value} 个内容稿件</span>
|
||||
<div class="flex-1 overflow-y-auto overflow-x-hidden px-12px">
|
||||
{uploadList.value.map((item) => (
|
||||
<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 width="32" height="32" class="rounded-3px mr-8px" />
|
||||
<TextOverTips class="text" context={item.content} />
|
||||
</div>
|
||||
<icon-delete
|
||||
size="16px"
|
||||
class="color-#737478 cursor-pointer hover:!color-#211F24"
|
||||
onClick={() => onDelete(item)}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
// 渲染表单内容
|
||||
const renderFormContent = () => {
|
||||
const contentMap = {
|
||||
[TASK_STATUS.DEFAULT]: () => {
|
||||
const formMap = {
|
||||
[UPLOAD_TYPE.LINK]: renderLinkForm,
|
||||
[UPLOAD_TYPE.HANDWRITE]: renderHandwriteForm,
|
||||
[UPLOAD_TYPE.LOCAL]: renderLocalForm,
|
||||
};
|
||||
return formMap[uploadType.value]?.();
|
||||
},
|
||||
[TASK_STATUS.LOADING]: renderLoadingState,
|
||||
[TASK_STATUS.FAILED]: renderFailedState,
|
||||
[TASK_STATUS.SUCCESS]: renderSuccessState,
|
||||
};
|
||||
|
||||
return contentMap[taskStatus.value]?.();
|
||||
};
|
||||
|
||||
// 渲染底部按钮
|
||||
const renderFooterButtons = () => {
|
||||
const buttonMap = {
|
||||
[TASK_STATUS.LOADING]: () => (
|
||||
<Button type="primary" size="medium" onClick={onCancelUpload}>
|
||||
取消上传
|
||||
</Button>
|
||||
),
|
||||
[TASK_STATUS.DEFAULT]: () => (
|
||||
<>
|
||||
<Button size="medium" onClick={onClose}>
|
||||
取消
|
||||
</Button>
|
||||
<Button type="primary" size="medium" onClick={onSubmit}>
|
||||
{isHandwrite.value ? '复制链接' : '确认'}
|
||||
</Button>
|
||||
</>
|
||||
),
|
||||
[TASK_STATUS.FAILED]: () => (
|
||||
<>
|
||||
<Button size="medium" onClick={onClose}>
|
||||
取消
|
||||
</Button>
|
||||
<Button type="primary" size="medium" onClick={onClose}>
|
||||
重新上传
|
||||
</Button>
|
||||
</>
|
||||
),
|
||||
[TASK_STATUS.SUCCESS]: () => (
|
||||
<>
|
||||
<Button size="medium" onClick={onClose}>
|
||||
取消
|
||||
</Button>
|
||||
<Button type="primary" size="medium" onClick={goEdit}>
|
||||
确认
|
||||
</Button>
|
||||
</>
|
||||
),
|
||||
};
|
||||
|
||||
return buttonMap[taskStatus.value]?.();
|
||||
};
|
||||
|
||||
expose({ open });
|
||||
|
||||
return () => (
|
||||
<Modal
|
||||
v-model:visible={visible.value}
|
||||
title={getTitle()}
|
||||
modal-class="upload-manuscript-modal"
|
||||
width="500px"
|
||||
mask-closable={false}
|
||||
unmount-on-close
|
||||
onClose={onClose}
|
||||
footer={!(isDefault.value && isLocal.value)}
|
||||
v-slots={{
|
||||
footer: () => renderFooterButtons(),
|
||||
}}
|
||||
>
|
||||
<Form ref="formRef" model={form.value} layout="horizontal" auto-label-width>
|
||||
{isDefault.value && (
|
||||
<FormItem label="上传方式">
|
||||
<RadioGroup v-model={uploadType.value}>
|
||||
<Radio value={UPLOAD_TYPE.LINK}>链接上传</Radio>
|
||||
<Radio value={UPLOAD_TYPE.LOCAL}>本地上传</Radio>
|
||||
<Radio value={UPLOAD_TYPE.HANDWRITE}>手写上传</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
)}
|
||||
|
||||
{renderFormContent()}
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
@import './style.scss';
|
||||
</style>
|
||||
@ -58,7 +58,7 @@ import { getProjects } from '@/api/all/propertyMarketing';
|
||||
import {
|
||||
INITIAL_QUERY,
|
||||
EnumCheckStatus,
|
||||
} from '@/views/creative-generation-workshop/manuscript/manuscript-list/constants.ts';
|
||||
} from '@/views/creative-generation-workshop/manuscript/list/constants.ts';
|
||||
|
||||
const { dataSource, pageInfo, onPageChange, onPageSizeChange, resetPageInfo } = useTableSelectionWithPagination({
|
||||
onPageChange: () => {
|
||||
@ -1,320 +0,0 @@
|
||||
<script lang="jsx">
|
||||
import {
|
||||
Modal,
|
||||
Form,
|
||||
FormItem,
|
||||
Input,
|
||||
RadioGroup,
|
||||
Radio,
|
||||
Upload,
|
||||
Button,
|
||||
Tooltip,
|
||||
Message as AMessage,
|
||||
Textarea,
|
||||
} from '@arco-design/web-vue';
|
||||
import { useClipboard } from '@vueuse/core';
|
||||
|
||||
import TextOverTips from '@/components/text-over-tips';
|
||||
|
||||
import icon1 from '@/assets/img/media-account/icon-feedback-fail.png';
|
||||
|
||||
const INITIAL_FORM = {
|
||||
linkUrl: '',
|
||||
link: '',
|
||||
};
|
||||
const FORM_TASK_STATUS = {
|
||||
default: 1, // 默认状态,
|
||||
importLoading: 2, // 上传中
|
||||
importFailed: 3, // 上传失败
|
||||
importSuccess: 4, // 上传成功
|
||||
};
|
||||
|
||||
export default {
|
||||
setup(props, { emit, expose }) {
|
||||
const update = inject('update');
|
||||
const visible = ref(false);
|
||||
const formRef = ref(null);
|
||||
const uploadRef = ref(null);
|
||||
const uploadType = ref('link');
|
||||
const taskStatus = ref(FORM_TASK_STATUS.default);
|
||||
const form = ref(cloneDeep(INITIAL_FORM));
|
||||
|
||||
const { copy, copied, isSupported } = useClipboard({ source: form.value.link });
|
||||
|
||||
const isLink = computed(() => uploadType.value === 'link'); // 链接上传
|
||||
const isLocal = computed(() => uploadType.value === 'local'); // 本地上传
|
||||
const isHandwrite = computed(() => uploadType.value === 'handwrite'); // 手写上传
|
||||
|
||||
const isDefaultTask = computed(() => taskStatus.value === FORM_TASK_STATUS.default);
|
||||
const isImportLoadingTask = computed(() => taskStatus.value === FORM_TASK_STATUS.importLoading);
|
||||
const isImportFailedTask = computed(() => taskStatus.value === FORM_TASK_STATUS.importFailed);
|
||||
const isImportSuccessTask = computed(() => taskStatus.value === FORM_TASK_STATUS.importSuccess);
|
||||
|
||||
const open = () => {
|
||||
visible.value = true;
|
||||
};
|
||||
const reset = () => {
|
||||
formRef.value?.resetFields?.();
|
||||
uploadType.value = 'link';
|
||||
taskStatus.value = FORM_TASK_STATUS.default;
|
||||
form.value = cloneDeep(INITIAL_FORM);
|
||||
};
|
||||
const onClose = () => {
|
||||
reset();
|
||||
visible.value = false;
|
||||
};
|
||||
|
||||
const onSubmit = async () => {
|
||||
if (isHandwrite.value) {
|
||||
if (!isSupported) {
|
||||
AMessage.error('您的浏览器不支持复制,请手动复制!');
|
||||
}
|
||||
copy(form.value.link);
|
||||
if (!copied) {
|
||||
AMessage.error('复制失败,请手动复制!');
|
||||
}
|
||||
AMessage.success('复制成功!');
|
||||
onClose();
|
||||
return;
|
||||
}
|
||||
|
||||
taskStatus.value = FORM_TASK_STATUS.importLoading;
|
||||
setTimeout(() => {
|
||||
taskStatus.value = FORM_TASK_STATUS.importSuccess;
|
||||
}, 2000);
|
||||
};
|
||||
const onCancelUpload = () => {
|
||||
console.log('onCancelUpload');
|
||||
taskStatus.value = FORM_TASK_STATUS.default;
|
||||
// onClose()
|
||||
};
|
||||
|
||||
const handleUpload = async (file) => {
|
||||
console.log('handleUpload11111', file);
|
||||
taskStatus.value = FORM_TASK_STATUS.importLoading;
|
||||
setTimeout(() => {
|
||||
taskStatus.value = FORM_TASK_STATUS.importSuccess;
|
||||
}, 2000);
|
||||
};
|
||||
|
||||
const goEdit = () => {
|
||||
console.log('goEdit 去稿件编辑页面');
|
||||
};
|
||||
|
||||
const onDelete = (item) => {
|
||||
console.log('onDelete', item);
|
||||
};
|
||||
|
||||
const handleDownloadTemplate = async () => {
|
||||
// const { code, data } = await getPlacementAccountsTemplateUrl();
|
||||
// if (code === 200) {
|
||||
// window.open(data.download_url, '_blank');
|
||||
// }
|
||||
};
|
||||
const getLink = () => {
|
||||
return (
|
||||
<FormItem label="链接地址">
|
||||
<Textarea
|
||||
v-model={form.value.linkUrl}
|
||||
size="large"
|
||||
placeholder="请输入..."
|
||||
autoSize={{ minRows: 5, maxRows: 8 }}
|
||||
/>
|
||||
</FormItem>
|
||||
);
|
||||
};
|
||||
|
||||
const getHandwrite = () => {
|
||||
return (
|
||||
<FormItem label="上传链接">
|
||||
<Input v-model={form.value.link} placeholder="请输入..." size="large" />
|
||||
</FormItem>
|
||||
);
|
||||
};
|
||||
|
||||
const getLocal = () => {
|
||||
return (
|
||||
<FormItem label="内容稿件">
|
||||
<div class="flex flex-col w-full">
|
||||
<Upload
|
||||
ref="uploadRef"
|
||||
action="/"
|
||||
draggable
|
||||
customRequest={handleUpload}
|
||||
accept=".xlsx,.xls,.docx,.doc"
|
||||
show-file-list={false}
|
||||
>
|
||||
{{
|
||||
'upload-button': () => (
|
||||
<div class="upload-box">
|
||||
<icon-plus size="14" class="mb-16px" />
|
||||
<span class="text mb-4px">点击或拖拽文件到此处上传</span>
|
||||
<span class="tip">支持文档(文本+图), 视频批量上传</span>
|
||||
</div>
|
||||
),
|
||||
}}
|
||||
</Upload>
|
||||
<div class="flex items-center cursor-pointer mt-8px" onClick={handleDownloadTemplate}>
|
||||
<icon-download size="14" class="mr-4px !color-#6D4CFE" />
|
||||
<span class="cts color-#6D4CFE">下载示例文档</span>
|
||||
</div>
|
||||
</div>
|
||||
</FormItem>
|
||||
);
|
||||
};
|
||||
|
||||
const renderFormContent = () => {
|
||||
if (isDefaultTask.value) {
|
||||
if (isLink.value) {
|
||||
return getLink();
|
||||
}
|
||||
if (isHandwrite.value) {
|
||||
return getHandwrite();
|
||||
}
|
||||
if (isLocal.value) {
|
||||
return getLocal();
|
||||
}
|
||||
}
|
||||
|
||||
if (isImportLoadingTask.value) {
|
||||
return (
|
||||
<div class="flex flex-col items-center justify-center rounded-8px bg-#F7F8FA h-208px">
|
||||
<icon-loading size="48" class="!color-#6D4CFE mb-16px" />
|
||||
<p class="tip !text-#768893">上传过程耗时可能较长,请耐心等待;</p>
|
||||
<p class="tip !text-#768893">刷新页面将会终止本次数据的上传,请谨慎操作</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (isImportFailedTask.value) {
|
||||
return (
|
||||
<div class="flex flex-col items-center justify-center rounded-8px bg-#F7F8FA h-208px">
|
||||
<img src={icon1} class="w-80px h-80px mb-16px" />
|
||||
<p class="text mb-4px">上传失败</p>
|
||||
<p class="tip !text-#768893">可能是网络不稳定导致,请检查网络后重试~</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (isImportSuccessTask.value) {
|
||||
return (
|
||||
<div class="flex flex-col py-12px max-h-540px rounded-8px bg-#F7F8FA">
|
||||
<span class="tip mb-8px px-12px fs-14px !text-left">共 30 个内容稿件</span>
|
||||
<div class="flex-1 overflow-y-auto overflow-x-hidden px-12px">
|
||||
{new Array(20).fill(0).map((v) => (
|
||||
<div 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 width="32" height="32" class="rounded-3px mr-8px" />
|
||||
<TextOverTips
|
||||
class="text"
|
||||
context="挖到宝了!这个平价好物让我素颜出门都自信✨挖到宝了!这个平价好物让我素颜出门都自信✨"
|
||||
/>
|
||||
</div>
|
||||
<icon-delete
|
||||
size="16px"
|
||||
class="color-#737478 cursor-pointer hover:!color-#211F24"
|
||||
onClick={onDelete}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
const renderFooterBtn = () => {
|
||||
if (isImportLoadingTask.value) {
|
||||
return (
|
||||
<Button type="primary" size="medium" onClick={onCancelUpload}>
|
||||
取消上传
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
const getConfirmBtn = () => {
|
||||
if (isDefaultTask.value) {
|
||||
return (
|
||||
<Button type="primary" size="medium" onClick={onSubmit}>
|
||||
{isHandwrite.value ? '复制链接' : '确认'}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
if (isImportFailedTask.value) {
|
||||
return (
|
||||
<Button type="primary" size="medium" onClick={onClose}>
|
||||
重新上传
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
if (isImportSuccessTask.value) {
|
||||
return (
|
||||
<Button type="primary" size="medium" onClick={goEdit}>
|
||||
确认
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button size="medium" onClick={onClose}>
|
||||
取消
|
||||
</Button>
|
||||
{getConfirmBtn()}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const getTitle = () => {
|
||||
if (isDefaultTask.value) {
|
||||
return '上传内容稿件';
|
||||
} else if (isImportSuccessTask.value) {
|
||||
return '上传内容稿件列表';
|
||||
} else {
|
||||
if (isLink.value) {
|
||||
return '链接上传';
|
||||
}
|
||||
if (isLocal.value) {
|
||||
return '本地批量上传';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
expose({ open });
|
||||
|
||||
return () => (
|
||||
<Modal
|
||||
v-model:visible={visible.value}
|
||||
title={getTitle()}
|
||||
modal-class="upload-manuscript-modal"
|
||||
width="500px"
|
||||
mask-closable={false}
|
||||
unmount-on-close
|
||||
onClose={onClose}
|
||||
footer={!(isDefaultTask.value && isLocal.value)}
|
||||
v-slots={{
|
||||
footer: () => renderFooterBtn(),
|
||||
}}
|
||||
>
|
||||
<Form ref="formRef" model={form.value} layout="horizontal" auto-label-width>
|
||||
{isDefaultTask.value && (
|
||||
<FormItem label="上传方式">
|
||||
<RadioGroup v-model={uploadType.value}>
|
||||
<Radio value="link">链接上传</Radio>
|
||||
<Radio value="local">本地上传</Radio>
|
||||
<Radio value="handwrite">手写上传</Radio>
|
||||
</RadioGroup>
|
||||
</FormItem>
|
||||
)}
|
||||
|
||||
{renderFormContent()}
|
||||
</Form>
|
||||
</Modal>
|
||||
);
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<style lang="scss">
|
||||
@import './style.scss';
|
||||
</style>
|
||||
Reference in New Issue
Block a user