diff --git a/src/views/cms/cmsAd/components/Import.vue b/src/views/cms/cmsAd/components/Import.vue new file mode 100644 index 0000000..524aebc --- /dev/null +++ b/src/views/cms/cmsAd/components/Import.vue @@ -0,0 +1,219 @@ + + + + diff --git a/src/views/cms/cmsAd/components/search.vue b/src/views/cms/cmsAd/components/search.vue index b52f683..2c364ea 100644 --- a/src/views/cms/cmsAd/components/search.vue +++ b/src/views/cms/cmsAd/components/search.vue @@ -7,6 +7,10 @@ 添加 + 备份 + 恢复 (), {} ); @@ -50,6 +55,8 @@ (e: 'add'): void; (e: 'remove'): void; (e: 'batchMove'): void; + (e: 'backup'): void; + (e: 'restore'): void; }>(); // 表单数据 @@ -64,6 +71,16 @@ emit('add'); }; + // 备份 + const backup = () => { + emit('backup'); + }; + + // 恢复 + const restore = () => { + emit('restore'); + }; + // 按分类查询 const onCategoryId = (id: number) => { where.categoryId = id; diff --git a/src/views/cms/cmsAd/index.vue b/src/views/cms/cmsAd/index.vue index e04a76c..4d089e1 100644 --- a/src/views/cms/cmsAd/index.vue +++ b/src/views/cms/cmsAd/index.vue @@ -3,7 +3,7 @@ @@ -85,6 +91,7 @@ import { createVNode, ref } from 'vue'; import { message, Modal } from 'ant-design-vue'; import { ExclamationCircleOutlined } from '@ant-design/icons-vue'; + import { utils, writeFile } from 'xlsx'; import type { EleProTable } from 'ele-admin-pro'; import { toTreeData } from 'ele-admin-pro'; import { useI18n } from 'vue-i18n'; @@ -94,11 +101,18 @@ } from 'ele-admin-pro/es/ele-pro-table/types'; import Search from './components/search.vue'; import CmsAdEdit from './components/cmsAdEdit.vue'; - import { pageCmsAd, removeCmsAd, removeBatchCmsAd } from '@/api/cms/cmsAd'; + import Import from './components/Import.vue'; + import { + listCmsAd, + pageCmsAd, + removeBatchCmsAd, + removeCmsAd + } from '@/api/cms/cmsAd'; import type { CmsAd, CmsAdParam } from '@/api/cms/cmsAd/model'; import { CmsNavigation } from '@/api/cms/cmsNavigation/model'; import { listCmsNavigation } from '@/api/cms/cmsNavigation'; import { getPageTitle } from '@/utils/common'; + import { getTenantId } from '@/utils/domain'; // 表格实例 const tableRef = ref | null>(null); @@ -112,10 +126,16 @@ const showEdit = ref(false); // 是否显示批量移动弹窗 const showMove = ref(false); + // 是否显示导入备份弹窗 + const showImport = ref(false); // 栏目数据 const navigationList = ref(); // 加载状态 const loading = ref(true); + // 导出状态 + const exportLoading = ref(false); + // 记录最新搜索条件,供备份导出使用 + const lastWhere = ref({}); // 表格数据源 const datasource: DatasourceFunction = ({ @@ -189,6 +209,9 @@ /* 搜索 */ const reload = (where?: CmsAdParam) => { + if (where) { + lastWhere.value = { ...where }; + } selection.value = []; tableRef?.value?.reload({ where: where }); }; @@ -204,6 +227,123 @@ showMove.value = true; }; + /* 打开导入弹窗 */ + const openImport = () => { + showImport.value = true; + }; + + /* 备份导出 */ + const handleExport = async () => { + if (exportLoading.value) { + return; + } + exportLoading.value = true; + message.loading('正在准备导出数据...', 0); + + const array: (string | number)[][] = [ + [ + '广告ID', + '类型', + '唯一标识', + '栏目ID', + '栏目名称', + '广告位名称', + '宽', + '高', + '样式', + '图片数据', + '链接', + '排序号', + '备注', + '状态', + '语言', + '租户ID', + '商户ID' + ] + ]; + + try { + const where: CmsAdParam = { + ...(lastWhere.value ?? {}), + lang: locale.value || undefined + }; + const list = await listCmsAd(where); + if (!list || list.length === 0) { + message.destroy(); + message.warning('没有数据可以导出'); + exportLoading.value = false; + return; + } + + list.forEach((d: CmsAd) => { + const images = Array.isArray(d.imageList) + ? JSON.stringify(d.imageList) + : typeof d.images === 'string' + ? d.images + : JSON.stringify(d.images ?? []); + array.push([ + `${d.adId || ''}`, + `${d.type ?? ''}`, + `${d.code || ''}`, + `${d.categoryId ?? ''}`, + `${d.categoryName || ''}`, + `${d.name || ''}`, + `${d.width || ''}`, + `${d.height || ''}`, + `${d.style || ''}`, + `${images || ''}`, + `${d.path || ''}`, + `${d.sortNumber ?? ''}`, + `${d.comments || ''}`, + `${d.status ?? ''}`, + `${d.lang || ''}`, + `${d.tenantId ?? ''}`, + `${d.merchantId ?? ''}` + ]); + }); + + const sheetName = `bak_cms_ad_${getTenantId()}`; + const workbook = { + SheetNames: [sheetName], + Sheets: {} + } as any; + const sheet = utils.aoa_to_sheet(array); + workbook.Sheets[sheetName] = sheet; + sheet['!cols'] = [ + { wch: 10 }, // 广告ID + { wch: 8 }, // 类型 + { wch: 24 }, // 唯一标识 + { wch: 10 }, // 栏目ID + { wch: 18 }, // 栏目名称 + { wch: 24 }, // 广告位名称 + { wch: 10 }, // 宽 + { wch: 10 }, // 高 + { wch: 20 }, // 样式 + { wch: 60 }, // 图片数据(JSON) + { wch: 30 }, // 链接 + { wch: 10 }, // 排序号 + { wch: 24 }, // 备注 + { wch: 8 }, // 状态 + { wch: 10 }, // 语言 + { wch: 10 }, // 租户ID + { wch: 10 } // 商户ID + ]; + + message.destroy(); + message.loading('正在生成Excel文件...', 0); + setTimeout(() => { + writeFile(workbook, `${sheetName}.xlsx`); + exportLoading.value = false; + message.destroy(); + message.success(`成功导出 ${list.length} 条记录`); + }, 600); + } catch (e: any) { + exportLoading.value = false; + message.destroy(); + message.error(e?.message || '导出失败,请重试'); + } + }; + /* 删除单个 */ const remove = (row: CmsAd) => { const hide = message.loading('请求中..', 0);