736a1b6ac6
按 Router used_quota 累计值与首次基线结算泥点 新增原子 checkpoint 事务及 llm_router_consume 钱包流水 同步额度查询校验、前端展示、生成绑定和技术文档
129 lines
3.9 KiB
TypeScript
129 lines
3.9 KiB
TypeScript
import type {
|
|
ProfileWalletLedgerEntry,
|
|
ProfileWalletLedgerResponse,
|
|
} from '../../../packages/shared/src/contracts/runtime';
|
|
|
|
const PLATFORM_WALLET_LEDGER_SOURCE_LABELS = {
|
|
new_user_registration_reward: '注册赠送',
|
|
points_recharge: '泥点充值',
|
|
invite_inviter_reward: '邀请奖励',
|
|
invite_invitee_reward: '填写邀请码奖励',
|
|
snapshot_sync: '账户同步',
|
|
membership_period_grant: '会员周期发放',
|
|
membership_period_reset: '会员周期重置',
|
|
daily_free_grant: '每日免费发放',
|
|
daily_free_reset: '每日免费重置',
|
|
asset_operation_consume: '资产操作消耗',
|
|
llm_router_consume: 'LLM 调用消耗',
|
|
asset_operation_refund: '资产操作退回',
|
|
recharge_refund_recovery: '充值退款追回',
|
|
redeem_code_reward: '兑换码奖励',
|
|
puzzle_author_incentive_claim: '拼图作者奖励',
|
|
daily_task_reward: '每日任务奖励',
|
|
} satisfies Record<ProfileWalletLedgerEntry['sourceType'], string>;
|
|
|
|
export type PlatformWalletLedgerEntryPresentation = {
|
|
amountLabel: string;
|
|
balanceLabel: string;
|
|
createdAt: string;
|
|
id: string;
|
|
isIncome: boolean;
|
|
sourceLabel: string;
|
|
};
|
|
|
|
export type PlatformWalletLedgerPresentation = {
|
|
balance: number;
|
|
balanceLabel: string;
|
|
entries: PlatformWalletLedgerEntryPresentation[];
|
|
};
|
|
|
|
function getPlatformWalletLedgerSourceLabel(
|
|
sourceType: string | null | undefined,
|
|
) {
|
|
const normalizedSourceType = sourceType?.trim() ?? '';
|
|
if (!normalizedSourceType) {
|
|
return '未知来源';
|
|
}
|
|
|
|
return (
|
|
PLATFORM_WALLET_LEDGER_SOURCE_LABELS[
|
|
normalizedSourceType as ProfileWalletLedgerEntry['sourceType']
|
|
] ?? normalizedSourceType
|
|
);
|
|
}
|
|
|
|
function buildPlatformWalletLedgerEntryPresentation(
|
|
entry: ProfileWalletLedgerEntry,
|
|
): PlatformWalletLedgerEntryPresentation {
|
|
return {
|
|
amountLabel:
|
|
entry.amountDelta > 0 ? `+${entry.amountDelta}` : `${entry.amountDelta}`,
|
|
balanceLabel: `余额 ${entry.balanceAfter}`,
|
|
createdAt: entry.createdAt,
|
|
id: entry.id,
|
|
isIncome: entry.amountDelta > 0,
|
|
sourceLabel: getPlatformWalletLedgerSourceLabel(entry.sourceType),
|
|
};
|
|
}
|
|
|
|
export function buildPlatformWalletLedgerPresentation(
|
|
ledger: ProfileWalletLedgerResponse | null,
|
|
fallbackBalance: number,
|
|
): PlatformWalletLedgerPresentation {
|
|
const entries = ledger?.entries ?? [];
|
|
const balance = entries[0]?.balanceAfter ?? fallbackBalance;
|
|
|
|
return {
|
|
balance,
|
|
balanceLabel: `${balance}泥点`,
|
|
entries: entries.map(buildPlatformWalletLedgerEntryPresentation),
|
|
};
|
|
}
|
|
|
|
export function formatPlatformRechargePrice(priceCents: number) {
|
|
const yuan = priceCents / 100;
|
|
return `¥${Number.isInteger(yuan) ? yuan.toFixed(0) : yuan.toFixed(2)}`;
|
|
}
|
|
|
|
function parsePlatformProfileDate(value: string) {
|
|
const normalized = value.trim();
|
|
const numericTimestamp = normalized.match(/^(-?\d+(?:\.\d+)?)(?:Z)?$/u);
|
|
if (numericTimestamp?.[1]) {
|
|
const rawTimestamp = Number(numericTimestamp[1]);
|
|
if (Number.isFinite(rawTimestamp)) {
|
|
const absoluteTimestamp = Math.abs(rawTimestamp);
|
|
const timestampMs =
|
|
absoluteTimestamp >= 1_000_000_000_000_000
|
|
? rawTimestamp / 1000
|
|
: absoluteTimestamp >= 1_000_000_000_000
|
|
? rawTimestamp
|
|
: absoluteTimestamp >= 1_000_000_000
|
|
? rawTimestamp * 1000
|
|
: Number.NaN;
|
|
const date = new Date(timestampMs);
|
|
if (!Number.isNaN(date.getTime())) {
|
|
return date;
|
|
}
|
|
}
|
|
}
|
|
|
|
const date = new Date(normalized);
|
|
return Number.isNaN(date.getTime()) ? null : date;
|
|
}
|
|
|
|
export function formatPlatformProfileTime(value: string | null) {
|
|
if (!value) {
|
|
return '未记录';
|
|
}
|
|
|
|
const date = parsePlatformProfileDate(value);
|
|
if (!date) {
|
|
return value;
|
|
}
|
|
|
|
const year = date.getUTCFullYear();
|
|
const month = String(date.getUTCMonth() + 1).padStart(2, '0');
|
|
const day = String(date.getUTCDate()).padStart(2, '0');
|
|
return `${year}-${month}-${day}`;
|
|
}
|