Files
TakeoutSaaS.TenantUI/apps/web-antd/src/views/finance/transaction/composables/transaction-page/helpers.ts

198 lines
5.0 KiB
TypeScript
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.
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);
}