Files
lingji-work-fe/src/views/property-marketing/assignment-management/components/raw-material-drawer.vue
2025-09-24 17:27:57 +08:00

296 lines
8.6 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<a-drawer
title="原料库"
cancel-text="取消"
ok-text="确定"
placement="right"
:visible="visible"
@after-visible-change="onAfterVisibleChange"
@cancel="handleCancel"
width="904px"
class="task-drawer"
style="right: 481px"
>
<!-- 成品库表格 -->
<Table
:data-source="materialData"
bordered
:columns="columns"
:pagination="false"
row-key="id"
:row-selection="rowSelection"
>
<template #name="{ record }">
<div class="name-cell flex items-center">
<img
:src="record.type == 2 ? icon5 : record.cover"
alt="类型图标"
class="w-44px h-44px border-rounded-8px bg-#F0EDFF"
/>
<div class="flex flex-col ml-8px">
<span class="material-name">{{ record.name }}</span>
<span class="material-type">{{ record.uid }}</span>
</div>
</div>
</template>
<template #type="{ record }">
<div class="flex items-center">
<span>{{ getType(record.type) }}</span>
</div>
</template>
<template #origin="{ record }">
<span>{{ getOrigin(record.origin) }}</span>
</template>
<template #created_at="{ record }">
<div class="flex items-center">
{{ record.created_at ? dayjs(record.created_at * 1000).format('YYYY-MM-DD HH:mm:ss') : '-' }}
</div>
</template>
</Table>
<!-- 分页控件 -->
<div class="pagination-box">
<a-pagination
:total="pageInfo.total"
size="mini"
show-total
show-jumper
show-page-size
:current="pageInfo.page"
:page-size="pageInfo.page_size"
@change="onPageChange"
@page-size-change="onPageSizeChange"
/>
</div>
<!-- 底部操作栏 -->
<template #footer>
<div class="flex items-center justify-between">
<div class="flex items-center">
<div class="color-#737478 font-size-14px">已选择</div>
<div class="color-#737478 font-size-14px">{{ choseText }}</div>
<div v-for="item in choseImgArray" :key="item.id" class="ml-16px">
<img
:src="item.cover ? item.cover : icon4"
alt="选中的内容"
class="w-44px h-44px border-rounded-8px bg-#F0EDFF"
/>
</div>
<div
v-for="item in choseTextArray"
:key="item.id"
class="ml-16px bg-#F7F8FA h-44px overflow-hidden w-75px border-rounded-8px flex items-center"
>
<div class="whitespace-nowrap overflow-hidden text-ellipsis w-full px-2" :title="item.name">
{{ item.name }}
</div>
</div>
</div>
<div class="flex justify-end">
<Button @click="handleCancel">取消</Button>
<Button class="ml-16px" type="primary" @click="handleOk">确定</Button>
</div>
</div>
</template>
</a-drawer>
</template>
<script lang="ts" setup>
import { ref, watch, defineProps, defineEmits, watchEffect } from 'vue';
import { Table, Button, Pagination } from 'ant-design-vue';
import dayjs from 'dayjs';
import { useTableSelectionWithPagination } from '@/hooks/useTableSelectionWithPagination';
import { EnumManuscriptType } from '@/views/material-center/components/finished-products/manuscript/list/constants';
import { getRawMaterialsPage } from '@/api/all/generationWorkshop';
// 引入图片资源
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';
import { RawMaterialType } from '@/views/material-center/components/raw-material/constants';
import icon5 from '../../../../views/material-center/components/raw-material/img/icon-no-text.png';
// 定义Props
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
query: {
type: Object,
required: true,
default: () => ({
page: 1,
page_size: 10,
platforms: undefined,
operator_ids: undefined,
ids: [],
keyword: '',
audit_status: undefined,
type: undefined,
}),
},
});
// 辅助函数
const getType = (type: number): string => {
const typeMap = {
[RawMaterialType.Image]: '图片',
[RawMaterialType.Video]: '视频',
[RawMaterialType.Text]: '文本',
};
return typeMap[type] || '未知';
};
const getOrigin = (origin: number): string => {
const fromMap = {
0: '本地上传',
1: 'AI生成',
};
return fromMap[origin] || '未知';
};
// 定义Emits类型
const emit = defineEmits<{
(e: 'update:visible', value: boolean): void;
(
e: 'confirm',
data: {
selectedKeys: string[];
selectedData: any[];
choseText: string;
choseImgArray: any[];
selectedTexts: string[];
},
): void;
(e: 'cancel'): void;
}>();
// 内部状态管理
const materialData = ref([]);
const choseText = ref('');
const choseImgArray = ref([]);
const choseTextArray = ref([]);
// 表格列配置
const columns = ref([
{ title: '文件名称', dataIndex: 'name', width: 200, slots: { customRender: 'name' } },
{ title: '类型', dataIndex: 'type', width: 100, slots: { customRender: 'type' } },
{ title: '来源', dataIndex: 'origin', width: 100, slots: { customRender: 'origin' } },
{ title: '上传时间', dataIndex: 'created_at', width: 200, slots: { customRender: 'created_at' } },
]);
// 1. 先定义数据获取函数确保使用最新的query参数
const fetchProductData = async () => {
try {
// 使用主组件传递的最新查询参数
const params = { ...props.query };
console.log('成品库请求参数:', params); // 调试用
const res = await getRawMaterialsPage(params);
materialData.value = [];
pageInfo.value.total = res.data.total;
if (pageInfo.value.page === 1) {
materialData.value = res.data.data;
} else {
materialData.value = [...materialData.value, ...res.data.data];
}
} catch (error) {
console.error('获取成品库数据失败:', error);
}
};
// 2. 初始化表格选择逻辑
const { pageInfo, onPageChange, onPageSizeChange, rowSelection, selectedRowKeys } = useTableSelectionWithPagination({
rowKey: 'id',
onPageChange: fetchProductData,
onPageSizeChange: fetchProductData,
});
// 监听query参数变化当主组件传递的参数变化时重新请求数据
watchEffect(() => {
if (props.visible) {
console.log('成品库查询参数变化,重新加载数据');
fetchProductData();
}
});
// 监听选中项变化
watch(selectedRowKeys, (newKeys) => {
const filteredData = materialData.value.filter((item) => newKeys.includes(item.id));
const typeCount: Record<string, number> = {};
filteredData.forEach((item) => {
typeCount[item.type] = (typeCount[item.type] || 0) + 1;
});
choseText.value = Object.entries(typeCount)
.map(([type, count]) => {
const typeName = getType(Number(type));
return `${typeName}: ${count}`;
})
.join(' ');
choseImgArray.value = filteredData.filter((item) => [0, 1].includes(item.type));
choseTextArray.value = filteredData.filter((item) => [2].includes(item.type));
});
// 格式化审核状态显示
const getStatus = (status: number) => {
switch (status) {
case 0:
return '待审核';
case 1:
return '审核中';
case 2:
return '已通过';
case 3:
return '已拒绝';
default:
return '未知';
}
};
// 抽屉显示状态变化处理
const onAfterVisibleChange = (visible: boolean) => {
emit('after-visible-change', visible);
if (visible) {
// 当抽屉显示时,使用最新参数请求数据
fetchProductData();
} else {
// 关闭时清空数据
materialData.value = [];
selectedRowKeys.value = [];
choseText.value = '';
choseImgArray.value = [];
}
};
// 取消按钮处理
const handleCancel = () => {
console.log('取消');
emit('cancel');
};
// 确定按钮处理
const handleOk = () => {
const selectedData = materialData.value.filter((item) => selectedRowKeys.value.includes(item.id));
const selectedTexts = selectedData
.filter((item) => item.type === RawMaterialType.Text)
.map((item) => item.content || item.name);
emit('confirm', {
selectedKeys: selectedRowKeys.value,
selectedData,
choseText: choseText.value,
choseImgArray: choseImgArray.value,
selectedTexts: selectedTexts,
});
emit('update:visible', false);
};
</script>
<style scoped>
.pagination-box {
display: flex;
width: 100%;
padding: 16px 0;
justify-content: flex-end;
align-items: center;
}
</style>