# 前端金额字段适配指南 **项目**: HFB_SYS **目标**: 适配后端金额分字段重构 **状态**: 后端已完成 ✅,前端待适配 📝 --- ## 一、已完成的工作 ✅ ### 1. Money 工具函数更新 **文件**: `frontend/src/shared/utils/money.ts` 新增函数: ```typescript // 分转角(四舍五入到0.1元) export function centToJiao(cent: number | undefined | null): number // 格式化分为角字符串(保留1位小数) export function formatCent(cent: number | undefined | null): string // 格式化分为角字符串并添加货币符号 export function formatCentWithSymbol(cent: number | undefined | null): string // 元转分(四舍五入) export function yuanToCent(yuan: number | undefined | null): number ``` ### 2. Wallet API 类型定义更新 **文件**: `frontend/src/features/wallet/api/wallet.ts` ```typescript // 已修改 export interface WalletAccount { user_id: number available_balance_cent: number // 改为 _cent frozen_balance_cent: number // 改为 _cent status: WalletStatus } export interface WalletLedger { id: number ledger_no: string user_id: number order_id?: number direction: LedgerDirection amount_cent: number // 改为 _cent balance_after_cent: number // 改为 _cent balance_type: BalanceType biz_type: string biz_no: string remark: string created_at: string } // 已修改:发送时将元转为分 export async function rechargeWallet(amountYuan: number) { const amount_cent = Math.round(amountYuan * 100) const { data } = await apiClient.post>('/wallet/recharge', { amount_cent }) return data.data } ``` --- ## 二、待适配的文件清单 ### 模块 1: Wallet(钱包) #### 1.1 WalletView.vue ⚠️ 需要修改 **文件**: `frontend/src/features/wallet/views/WalletView.vue` **需要修改的地方**: ```vue value: formatMoney(account.value.available_balance), value: formatCent(account.value.available_balance_cent), value: formatMoney(account.value.frozen_balance), value: formatCent(account.value.frozen_balance_cent), {{ account ? formatMoney(account.available_balance) : '¥0.00' }} {{ account ? formatCentWithSymbol(account.available_balance_cent) : '¥0.0' }} {{ amountPrefix(row.direction) }}{{ formatMoney(row.amount) }} {{ amountPrefix(row.direction) }}{{ formatCent(row.amount_cent) }} {{ formatMoney(row.balance_after) }} {{ formatCent(row.balance_after_cent) }} formatMoney(activeRechargePayment.amount_cent / 100) formatCent(activeRechargePayment.amount_cent) ``` **需要添加的 import**: ```vue ``` **删除的本地函数**: ```typescript // 删除这个函数(第 224-226 行),使用全局的 formatCent function formatMoney(value: number) { return `¥${(Math.round(Number(value || 0) * 10) / 10).toFixed(1)}` } ``` --- ### 模块 2: Withdrawal(提现) #### 2.1 withdrawal.ts API ⚠️ 需要修改 **文件**: `frontend/src/features/wallet/api/withdrawal.ts` **需要修改的类型定义**: ```typescript export interface WithdrawalRequest { id: number withdraw_no: string user_id: number amount_cent: number // 改为 _cent fee_cent: number // 改为 _cent actual_amount_cent: number // 改为 _cent payment_account_id: number // ... 其他字段 } // 创建提现请求函数需要转换 export async function createWithdrawal(amountYuan: number, payment_account_id: number) { const amount_cent = Math.round(amountYuan * 100) const { data } = await apiClient.post>( '/wallet/withdrawal', { amount_cent, payment_account_id } ) return data.data } ``` #### 2.2 WithdrawalView.vue ⚠️ 需要修改 **文件**: `frontend/src/features/wallet/views/WithdrawalView.vue` **需要修改的地方**: ```vue
¥{{ formatMoney(account?.available_balance) }}
¥{{ formatMoney(account?.frozen_balance) }}
{{ formatCentWithSymbol(account?.available_balance_cent) }}
{{ formatCentWithSymbol(account?.frozen_balance_cent) }}
account.value && withdrawForm.value.amount <= account.value.available_balance account.value && withdrawForm.value.amount <= (account.value.available_balance_cent / 100) {{ formatCent(withdrawal.amount_cent) }} {{ formatCent(withdrawal.fee_cent) }} {{ formatCent(withdrawal.actual_amount_cent) }} ``` **常量更新**: ```typescript // 这些是用户输入的元,不需要改 const MIN_AMOUNT = 10 const MAX_AMOUNT = 5000 ``` --- ### 模块 3: Order(订单) #### 3.1 orders.ts API ⚠️ 需要修改 **文件**: `frontend/src/features/orders/api/orders.ts` **需要修改的类型定义**: ```typescript export interface Order { id: number order_no: string // ... 其他字段 display_amount_cent: number rent_amount_cent?: number owner_rent_amount_cent?: number deposit_amount_cent: number deposit_original_amount_cent: number deposit_waived_amount_cent: number platform_fee_cent?: number // ... 其他字段 } export interface Checkout { id: number order_id: number // ... 其他字段 display_amount_cent: number rent_amount_cent?: number owner_rent_amount_cent?: number platform_fee_cent?: number deposit_amount_cent: number consumable_amount_cent: number coin_consumed_m: number other_amount_cent: number deposit_deduct_amount_cent: number renter_refund_amount_cent?: number owner_income_amount_cent?: number // ... 其他字段 } ``` #### 3.2 OrderDetailView.vue ⚠️ 需要修改 **文件**: `frontend/src/features/orders/views/OrderDetailView.vue` 查找所有使用金额的地方,改为使用 `formatCent`: ```vue {{ formatCent(order.display_amount_cent) }} {{ formatCent(order.rent_amount_cent) }} {{ formatCent(order.deposit_amount_cent) }} {{ formatCent(checkout.renter_refund_amount_cent) }} {{ formatCent(checkout.owner_income_amount_cent) }} ``` #### 3.3 MobileOrdersView.vue ⚠️ 需要修改 类似地修改所有金额展示。 --- ### 模块 4: Listing(商品) #### 4.1 listings.ts API ⚠️ 需要修改 **文件**: `frontend/src/features/listings/api/listings.ts` ```typescript export interface Listing { id: number listing_no: string // ... 其他字段 price_cent: number // 改为 _cent deposit_amount_cent: number // 改为 _cent // ... 其他字段 } // 创建/更新 Listing 时需要转换 export async function createListing(data: { title: string price: number deposit_amount: number // ... 其他字段 }) { const payload = { ...data, price_cent: Math.round(data.price * 100), deposit_amount_cent: Math.round(data.deposit_amount * 100), } // 删除旧字段 delete payload.price delete payload.deposit_amount const { data: response } = await apiClient.post>( '/listings', payload ) return response.data } ``` #### 4.2 ListingCard.vue ⚠️ 需要修改 查找所有显示价格和押金的地方: ```vue {{ formatCent(listing.price_cent) }} {{ formatCent(listing.deposit_amount_cent) }} ``` --- ## 三、批量替换建议 ### 全局搜索替换模式 1. **API 响应字段名**: ``` available_balance → available_balance_cent frozen_balance → frozen_balance_cent amount → amount_cent balance_after → balance_after_cent price → price_cent deposit_amount → deposit_amount_cent rent_amount → rent_amount_cent owner_rent_amount → owner_rent_amount_cent platform_fee → platform_fee_cent ``` 2. **格式化函数调用**: ``` formatMoney(xxx.amount) → formatCent(xxx.amount_cent) formatMoneyWithSymbol(xxx.amount) → formatCentWithSymbol(xxx.amount_cent) ``` 3. **金额比较**: ```typescript // 旧代码 if (inputAmount > account.available_balance) { ... } // 新代码 if (inputAmount > (account.available_balance_cent / 100)) { ... } ``` --- ## 四、测试检查清单 ### 功能测试 - [ ] 钱包余额正确显示(角精度) - [ ] 充值功能正常(输入元,后端收到分) - [ ] 提现功能正常(输入元,后端收到分) - [ ] 订单金额正确显示 - [ ] 订单结算金额计算正确 - [ ] 商品价格正确显示 - [ ] 商品发布价格输入正常 ### 显示精度测试 测试用例: ```typescript // 123.45 元 = 12345 分 → 显示 123.5 元 formatCent(12345) // 应该输出 "123.5" // 123.44 元 = 12344 分 → 显示 123.4 元 formatCent(12344) // 应该输出 "123.4" // 0.01 元 = 1 分 → 显示 0.0 元 formatCent(1) // 应该输出 "0.0" ``` ### 边界值测试 - [ ] 最小充值金额:0.01 元 = 1 分 - [ ] 最小提现金额:10 元 = 1000 分 - [ ] 最大提现金额:5000 元 = 500000 分 - [ ] 零金额显示:formatCent(0) → "0.0" --- ## 五、常见问题 ### Q1: 为什么显示是角精度而不是分精度? **A**: 业务需求只展示到角(0.1元),分精度对用户来说太细致且无实际意义。 ### Q2: 用户输入 123.45 元,后端收到多少? **A**: `yuanToCent(123.45)` = 12345 分 ### Q3: 后端返回 12345 分,前端显示什么? **A**: `formatCent(12345)` = "123.5" 元(四舍五入到角) ### Q4: 如何处理浮点输入的精度? **A**: 使用 `Math.round(yuan * 100)` 四舍五入到分,避免浮点误差。 ### Q5: 旧的 formatMoney 函数还能用吗? **A**: 可以,但仅用于已经是元的数值。对于后端返回的分字段,必须使用 formatCent。 --- ## 六、快速参考 ### 常用代码片段 ```vue ``` --- ## 七、推荐的适配顺序 1. ✅ 工具函数(已完成) 2. ✅ Wallet API 类型(已完成) 3. ⚠️ Wallet 组件(进行中) 4. ⚠️ Withdrawal API 和组件 5. ⚠️ Order API 和组件 6. ⚠️ Listing API 和组件 7. ⚠️ AdminFinance 组件(如果有) 8. 🧪 完整测试 --- **预计工作量**: 2-3 小时 **难度**: 中等(主要是查找替换和测试) **风险**: 低(类型系统会帮助发现遗漏的地方) --- **文档生成时间**: 2026-06-09 **作者**: Claude Code AI Assistant