diff --git a/src/components/ExportCustomModal/index.vue b/src/components/ExportCustomModal/index.vue new file mode 100644 index 00000000..eb329347 --- /dev/null +++ b/src/components/ExportCustomModal/index.vue @@ -0,0 +1,458 @@ + + + + + diff --git a/src/i18n/locales/en-US.ts b/src/i18n/locales/en-US.ts index 086079c6..45602161 100644 --- a/src/i18n/locales/en-US.ts +++ b/src/i18n/locales/en-US.ts @@ -41,6 +41,11 @@ export default { columnSetText: 'Column Setting', columnSetTitle: 'Column Display / Sorting', sizeText: 'Density', + preview:'Preview', + exportCustom:'Custom Export', + exportColumns:'Column Definition', + resetToDefault:'Reset to default columns', + exportDefault:'Export', size: { default: 'Default', middle: 'Medium', diff --git a/src/i18n/locales/zh-CN.ts b/src/i18n/locales/zh-CN.ts index d5baaafd..eef4d3c0 100644 --- a/src/i18n/locales/zh-CN.ts +++ b/src/i18n/locales/zh-CN.ts @@ -41,6 +41,10 @@ export default { columnSetText: '列设置', columnSetTitle: '列展示/排序', sizeText: '密度', + exportCustom:'自定义导出', + exportColumns:'列定义', + resetToDefault:'重置为默认列', + exportDefault:'全部导出', size: { default: '默认', middle: '中等', diff --git a/src/views/dashboard/sgwcCDR/index.vue b/src/views/dashboard/sgwcCDR/index.vue index 6bd82c48..6a8ee626 100644 --- a/src/views/dashboard/sgwcCDR/index.vue +++ b/src/views/dashboard/sgwcCDR/index.vue @@ -22,6 +22,8 @@ import saveAs from 'file-saver'; import { useClipboard } from '@vueuse/core'; import dayjs, { type Dayjs } from 'dayjs'; import { dayjsRanges } from '@/hooks/useRangePicker'; +import ExportCustomModal from '@/components/ExportCustomModal/index.vue'; +import * as XLSX from 'xlsx'; const { copy } = useClipboard({ legacy: true }); const { t } = useI18n(); const ws = new WS(); @@ -397,9 +399,243 @@ function fnExportList() { }); } +/**自定义导出 - 先获取后端数据来确定可用列 */ +function fnExportCustom() { + if (modalState.confirmLoading || tablePagination.total === 0) return; + + modalState.confirmLoading = true; + const hide = message.loading(t('common.loading'), 0); + + // 先获取后端标准格式的完整数据 + const querys = toRaw(queryParams); + querys.pageNum = 1; + querys.pageSize = Math.min(tablePagination.total, 10); // 只获取前10条用于分析列结构 + querys.startTime = Number(querys.startTime); + querys.endTime = Number(querys.endTime); + + exportSGWCDataCDR(querys) + .then(res => { + if (res.code === RESULT_CODE_SUCCESS) { + // 解析后端Excel文件,获取可用的列 + parseExcelColumns(res.data); + } else { + message.error({ + content: `${res.msg}`, + duration: 3, + }); + } + }) + .catch(error => { + console.error('Export error:', error); + message.error({ + content: t('common.operateError'), + duration: 3, + }); + }) + .finally(() => { + hide(); + modalState.confirmLoading = false; + }); +} + +/**解析Excel获取可用的列信息 */ +function parseExcelColumns(excelBlob: Blob) { + const reader = new FileReader(); + reader.onload = function(e) { + try { + const data = new Uint8Array(e.target?.result as ArrayBuffer); + const workbook = XLSX.read(data, { type: 'array' }); + + // 获取第一个工作表 + const firstSheetName = workbook.SheetNames[0]; + const worksheet = workbook.Sheets[firstSheetName]; + + // 将工作表转换为JSON格式 + const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 }); + + if (jsonData.length === 0) { + message.error(t('common.noData')); + return; + } + + // 获取表头(第一行) + const headers = jsonData[0] as string[]; + const dataRows = jsonData.slice(1, 4); // 取前3行作为示例数据 + + // 构建可用列配置 + const availableColumns = headers.map((header, index) => ({ + key: `col_${index}`, + title: header, + originalTitle: header, + dataIndex: `col_${index}`, + columnIndex: index, + visible: true + })); + + exportAvailableColumns.value = availableColumns; + + // 构建示例数据 + const sampleData = dataRows.map((row: any) => { + const obj: any = { id: Math.random() }; + headers.forEach((header, index) => { + obj[`col_${index}`] = row[index] || ''; + }); + return obj; + }); + + exportSampleData.value = sampleData; + + // 打开自定义导出对话框 + exportCustomVisible.value = true; + + } catch (error) { + console.error('Parse Excel error:', error); + message.error(t('common.operateError')); + } + }; + + reader.readAsArrayBuffer(excelBlob); +} + +/**处理自定义导出确认 */ +function handleExportCustomConfirm(config: any[]) { + exportCustomConfig.value = config; + modalState.confirmLoading = true; + const hide = message.loading(t('common.loading'), 0); + + // 先获取后端标准格式的完整数据 + const querys = toRaw(queryParams); + querys.pageNum = 1; + querys.pageSize = tablePagination.total; + querys.startTime = Number(querys.startTime); + querys.endTime = Number(querys.endTime); + + exportSGWCDataCDR(querys) + .then(res => { + if (res.code === RESULT_CODE_SUCCESS) { + // 后端返回标准格式数据后,在前端进行自定义处理 + processCustomExport(res.data, config); + message.success({ + content: t('common.operateOk'), + duration: 3, + }); + } else { + message.error({ + content: `${res.msg}`, + duration: 3, + }); + } + }) + .catch(error => { + console.error('Export error:', error); + message.error({ + content: t('common.operateError'), + duration: 3, + }); + }) + .finally(() => { + hide(); + modalState.confirmLoading = false; + }); +} + +/**处理自定义导出 - 基于后端数据在前端自定义处理 */ +function processCustomExport(excelBlob: Blob, config: any[]) { + // 读取后端返回的Excel文件 + const reader = new FileReader(); + reader.onload = function(e) { + try { + const data = new Uint8Array(e.target?.result as ArrayBuffer); + const workbook = XLSX.read(data, { type: 'array' }); + + // 获取第一个工作表 + const firstSheetName = workbook.SheetNames[0]; + const worksheet = workbook.Sheets[firstSheetName]; + + // 将工作表转换为JSON格式 + const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 }); + + if (jsonData.length === 0) { + message.error(t('common.noData')); + return; + } + + // 获取表头(第一行) + const originalHeaders = jsonData[0] as string[]; + const dataRows = jsonData.slice(1); + + // 根据配置处理数据 + const processedData = processDataWithConfig(originalHeaders, dataRows, config); + + // 生成新的Excel文件 + generateCustomExcelFile(processedData); + + } catch (error) { + console.error('Process custom export error:', error); + message.error(t('common.operateError')); + } + }; + + reader.readAsArrayBuffer(excelBlob); +} + +/**根据配置处理数据 */ +function processDataWithConfig(originalHeaders: string[], dataRows: any[], config: any[]) { + // 获取可见的列配置 + const visibleColumns = config.filter(col => col.visible); + + // 处理表头 + const newHeaders = visibleColumns.map(col => col.title); + + // 处理数据行 - 使用columnIndex直接访问 + const newDataRows = dataRows.map(row => { + return visibleColumns.map(col => { + // 使用columnIndex字段直接访问对应列的数据 + const columnIndex = col.columnIndex; + return columnIndex !== undefined ? (row[columnIndex] || '') : ''; + }); + }); + + return { + headers: newHeaders, + data: newDataRows + }; +} + +/**生成自定义Excel文件 */ +function generateCustomExcelFile(processedData: { headers: string[], data: any[] }) { + // 创建工作簿 + const wb = XLSX.utils.book_new(); + + // 准备Excel数据 + const excelData = [processedData.headers, ...processedData.data]; + + // 创建工作表 + const ws = XLSX.utils.aoa_to_sheet(excelData); + + // 设置列宽 + const colWidths = processedData.headers.map(() => ({ wch: 20 })); + ws['!cols'] = colWidths; + + // 添加工作表到工作簿 + XLSX.utils.book_append_sheet(wb, ws, 'SGWC CDR'); + + // 生成Excel文件并下载 + const excelBuffer = XLSX.write(wb, { bookType: 'xlsx', type: 'array' }); + const blob = new Blob([excelBuffer], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }); + + saveAs(blob, `sgwc_cdr_custom_export_${Date.now()}.xlsx`); +} + /**实时数据开关 */ const realTimeData = ref(false); +/**自定义导出配置 */ +const exportCustomVisible = ref(false); +const exportCustomConfig = ref([]); +const exportAvailableColumns = ref([]); +const exportSampleData = ref([]); + /** * 实时数据 */ @@ -619,10 +855,25 @@ onBeforeUnmount(() => { {{ t('common.deleteText') }} - - - {{ t('common.export') }} - + + + + {{ t('common.export') }} + + + + @@ -830,6 +1081,14 @@ onBeforeUnmount(() => { + + +