From 966c25ba6e056dde4e8a9c1112fd2e3a1ae0098d Mon Sep 17 00:00:00 2001 From: "zangch@mesnac.com" Date: Thu, 26 Mar 2026 17:47:10 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E5=88=A0=E9=99=A4=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/composables/useEmsClearAll.ts | 35 ++++++++++++++++++ src/utils/dateReportUtils.ts | 61 +++++++++++++++++++++++++++++++ src/utils/export.ts | 39 ++++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 src/composables/useEmsClearAll.ts create mode 100644 src/utils/dateReportUtils.ts create mode 100644 src/utils/export.ts diff --git a/src/composables/useEmsClearAll.ts b/src/composables/useEmsClearAll.ts new file mode 100644 index 0000000..240a09f --- /dev/null +++ b/src/composables/useEmsClearAll.ts @@ -0,0 +1,35 @@ +import request from '@/utils/request'; + +export interface EmsClearAllConfig { + moduleKey: string; + entityName: string; + permission?: string; +} + +/** + * 这里把原先散落在 mixin 里的“一键清空”能力收敛成组合函数, + * 既保留老页面行为,也避免继续依赖仓库里缺失的 mixin 文件。 + */ +export function useEmsClearAll(clearAllConfig: Ref, refreshList: () => Promise | unknown) { + const { proxy } = getCurrentInstance() as ComponentInternalInstance; + + const handleClearAll = async () => { + const config = clearAllConfig.value; + if (!config?.moduleKey || !config.entityName) { + proxy?.$modal.msgError('清空配置缺失,无法执行操作'); + return; + } + + await proxy?.$modal.confirm(`是否确认清空全部${config.entityName}数据?此操作不可恢复!`); + await request({ + url: `/ems/common/clearAll/${config.moduleKey}`, + method: 'delete' + }); + proxy?.$modal.msgSuccess(`已清空${config.entityName}`); + await refreshList(); + }; + + return { + handleClearAll + }; +} diff --git a/src/utils/dateReportUtils.ts b/src/utils/dateReportUtils.ts new file mode 100644 index 0000000..204b40e --- /dev/null +++ b/src/utils/dateReportUtils.ts @@ -0,0 +1,61 @@ +const pad = (value: number): string => String(value).padStart(2, '0'); + +const formatDateTime = (date: Date): string => + `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`; + +const normalizeDate = (value: string | Date): Date => { + const date = value instanceof Date ? new Date(value) : new Date(String(value).replace(/-/g, '/')); + return Number.isNaN(date.getTime()) ? new Date() : date; +}; + +const iterateDates = (start: Date, end: Date, stepper: (date: Date) => void): string[] => { + const result: string[] = []; + const cursor = new Date(start); + + while (cursor.getTime() <= end.getTime()) { + result.push(formatDateTime(cursor)); + stepper(cursor); + } + + return result; +}; + +export const getHoursBetween = (startTime: string | Date, endTime: string | Date): string[] => { + const start = normalizeDate(startTime); + const end = normalizeDate(endTime); + start.setMinutes(0, 0, 0); + end.setMinutes(0, 0, 0); + + return iterateDates(start, end, (date) => date.setHours(date.getHours() + 1)); +}; + +export const getDatesBetween = (startTime: string | Date, endTime: string | Date): string[] => { + const start = normalizeDate(startTime); + const end = normalizeDate(endTime); + start.setHours(0, 0, 0, 0); + end.setHours(0, 0, 0, 0); + + return iterateDates(start, end, (date) => date.setDate(date.getDate() + 1)); +}; + +export const getMonthsBetween = (startTime: string | Date, endTime: string | Date): string[] => { + const start = normalizeDate(startTime); + const end = normalizeDate(endTime); + start.setDate(1); + start.setHours(0, 0, 0, 0); + end.setDate(1); + end.setHours(0, 0, 0, 0); + + return iterateDates(start, end, (date) => date.setMonth(date.getMonth() + 1)); +}; + +export const getYearsBetween = (startTime: string | Date, endTime: string | Date): string[] => { + const start = normalizeDate(startTime); + const end = normalizeDate(endTime); + start.setMonth(0, 1); + start.setHours(0, 0, 0, 0); + end.setMonth(0, 1); + end.setHours(0, 0, 0, 0); + + return iterateDates(start, end, (date) => date.setFullYear(date.getFullYear() + 1)); +}; diff --git a/src/utils/export.ts b/src/utils/export.ts new file mode 100644 index 0000000..a25e390 --- /dev/null +++ b/src/utils/export.ts @@ -0,0 +1,39 @@ +const escapeCell = (value: string): string => { + const normalized = value.replace(/"/g, '""').replace(/\r?\n/g, ' '); + return `"${normalized}"`; +}; + +/** + * 这里保留最小导出能力,优先满足 EMS 报表页在 Vue3 环境下可继续导出表格数据, + * 避免因为旧版工具文件缺失导致整页无法启动。 + */ +export const handleExport = (tableId: string, fileName: string, includeHidden = false): void => { + const table = document.getElementById(tableId) as HTMLTableElement | null; + if (!table) { + return; + } + + const rows = Array.from(table.querySelectorAll('tr')).map((row) => { + const cells = Array.from(row.querySelectorAll('th,td')).filter((cell) => { + if (includeHidden) { + return true; + } + return cell.offsetParent !== null; + }); + + return cells.map((cell) => escapeCell(cell.innerText.trim())).join(','); + }); + + const csvContent = `\uFEFF${rows.join('\r\n')}`; + const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' }); + const link = document.createElement('a'); + const url = URL.createObjectURL(blob); + + link.href = url; + link.download = `${fileName}.csv`; + link.style.display = 'none'; + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + URL.revokeObjectURL(url); +};