import type { FinanceTransactionFilterState, FinanceTransactionListQueryPayload, FinanceTransactionQueryPayload, QuickDateRangeKey, } from '../../types'; /** * 文件职责:交易流水页面纯函数与数据转换工具。 */ import type { FinanceTransactionChannelFilter, FinanceTransactionPaymentFilter, FinanceTransactionTypeFilter, } from '#/api/finance'; function formatDate(date: Date) { const year = date.getFullYear(); const month = `${date.getMonth() + 1}`.padStart(2, '0'); const day = `${date.getDate()}`.padStart(2, '0'); return `${year}-${month}-${day}`; } function toDateOnly(date: Date) { return new Date(date.getFullYear(), date.getMonth(), date.getDate()); } function shiftDate(date: Date, dayOffset: number) { const next = new Date(date); next.setDate(next.getDate() + dayOffset); return next; } function normalizeType( value: FinanceTransactionTypeFilter, ): FinanceTransactionTypeFilter | undefined { return value === 'all' ? undefined : value; } function normalizeChannel( value: FinanceTransactionChannelFilter, ): FinanceTransactionChannelFilter | undefined { return value === 'all' ? undefined : value; } function normalizePayment( value: FinanceTransactionPaymentFilter, ): FinanceTransactionPaymentFilter | undefined { return value === 'all' ? undefined : value; } /** 获取今天日期字符串(yyyy-MM-dd)。 */ export function getTodayDateString() { return formatDate(new Date()); } /** 根据快捷日期键计算筛选起止日期。 */ export function resolveQuickRangeDateRange(value: QuickDateRangeKey) { const today = toDateOnly(new Date()); let start = today; let end = today; switch (value) { case '7d': { start = shiftDate(today, -6); break; } case '30d': { start = shiftDate(today, -29); break; } case 'month': { start = new Date(today.getFullYear(), today.getMonth(), 1); break; } case 'yesterday': { start = shiftDate(today, -1); end = start; break; } // No default } return { startDate: formatDate(start), endDate: formatDate(end), }; } /** 构建交易流水筛选请求。 */ export function buildFilterQueryPayload( storeId: string, filters: FinanceTransactionFilterState, ): FinanceTransactionQueryPayload { return { storeId, startDate: filters.startDate || undefined, endDate: filters.endDate || undefined, type: normalizeType(filters.type), channel: normalizeChannel(filters.channel), paymentMethod: normalizePayment(filters.paymentMethod), keyword: filters.keyword.trim() || undefined, }; } /** 构建交易流水列表请求。 */ export function buildListQueryPayload( storeId: string, filters: FinanceTransactionFilterState, page: number, pageSize: number, ): FinanceTransactionListQueryPayload { return { ...buildFilterQueryPayload(storeId, filters), page, pageSize, }; } /** 判断日期范围是否合法。 */ export function isDateRangeInvalid(filters: FinanceTransactionFilterState) { if (!filters.startDate || !filters.endDate) { return false; } return filters.startDate > filters.endDate; } /** 货币格式化(人民币)。 */ export function formatCurrency(value: number) { return new Intl.NumberFormat('zh-CN', { style: 'currency', currency: 'CNY', minimumFractionDigits: 2, maximumFractionDigits: 2, }).format(Number.isFinite(value) ? value : 0); } /** 交易金额(带符号)格式化。 */ export function formatSignedAmount(value: number, isIncome: boolean) { const normalized = Number.isFinite(value) ? value : 0; if (normalized === 0) { return formatCurrency(0); } if (normalized > 0 || isIncome) { return `+${formatCurrency(Math.abs(normalized))}`; } return `-${formatCurrency(Math.abs(normalized))}`; } /** 金额视觉色调。 */ export function resolveAmountToneClass(value: number, isIncome: boolean) { if (value > 0 || isIncome) { return 'income'; } if (value < 0) { return 'expense'; } return 'neutral'; } /** 交易类型标签颜色。 */ export function resolveTransactionTypeTagColor(type: string) { if (type === 'income') return 'green'; if (type === 'refund') return 'red'; if (type === 'stored_card_recharge') return 'blue'; if (type === 'point_redeem') return 'orange'; return 'default'; } function decodeBase64ToBlob(base64: string) { const binary = atob(base64); const bytes = new Uint8Array(binary.length); for (let index = 0; index < binary.length; index += 1) { bytes[index] = binary.codePointAt(index) ?? 0; } return new Blob([bytes], { type: 'text/csv;charset=utf-8;' }); } /** 下载 Base64 编码文件。 */ export function downloadBase64File( fileName: string, fileContentBase64: string, ) { const blob = decodeBase64ToBlob(fileContentBase64); const url = URL.createObjectURL(blob); const anchor = document.createElement('a'); anchor.href = url; anchor.download = fileName; anchor.click(); URL.revokeObjectURL(url); }