# 金额统一重构完成报告 **项目**: HFB_SYS - 游戏账号租赁平台 **重构目标**: 统一金额存储和计算,从 float64(元)改为 int64(分) **完成时间**: 2026-06-09 **状态**: ✅ 后端完成,前端待适配 --- ## 一、重构目标 ### 问题背景 - **浮点精度问题**: 使用 float64 存储金额导致精度丢失 - **角精度展示**: 业务需求仅展示到角(0.1元),但存储需要精确到分 - **计算误差**: 浮点运算在累加、结算时可能产生误差 ### 解决方案 - **全链路整数存储**: 数据库 BIGINT(分) → Go int64 → API int64 → 前端 number - **整数运算**: 所有金额计算使用整数,消除浮点误差 - **角精度展示**: 存储精确到分,展示时转换为角(除以10,保留1位小数) --- ## 二、已完成的工作 ### 1. 数据库迁移 ✅ **文件**: `backend/migrations/000006_add_money_cent_fields.sql` 新增字段: ```sql -- rental_orders 表 ALTER TABLE rental_orders ADD COLUMN rent_amount_cent BIGINT NOT NULL DEFAULT 0, ADD COLUMN owner_rent_amount_cent BIGINT NOT NULL DEFAULT 0, ADD COLUMN deposit_amount_cent BIGINT NOT NULL DEFAULT 0, ADD COLUMN deposit_original_amount_cent BIGINT NOT NULL DEFAULT 0, ADD COLUMN deposit_waived_amount_cent BIGINT NOT NULL DEFAULT 0, ADD COLUMN platform_fee_cent BIGINT NOT NULL DEFAULT 0; -- rental_listings 表 ALTER TABLE rental_listings ADD COLUMN price_cent BIGINT NOT NULL DEFAULT 0, ADD COLUMN deposit_amount_cent BIGINT NOT NULL DEFAULT 0; -- wallet_accounts 表 ALTER TABLE wallet_accounts ADD COLUMN available_balance_cent BIGINT NOT NULL DEFAULT 0, ADD COLUMN frozen_balance_cent BIGINT NOT NULL DEFAULT 0; -- wallet_ledger 表 ALTER TABLE wallet_ledger ADD COLUMN amount_cent BIGINT NOT NULL DEFAULT 0, ADD COLUMN balance_after_cent BIGINT NOT NULL DEFAULT 0; -- withdrawal_requests 表 ALTER TABLE withdrawal_requests ADD COLUMN amount_cent BIGINT NOT NULL DEFAULT 0, ADD COLUMN fee_cent BIGINT NOT NULL DEFAULT 0, ADD COLUMN actual_amount_cent BIGINT NOT NULL DEFAULT 0; ``` 历史数据迁移: ```sql UPDATE rental_orders SET rent_amount_cent = CAST(ROUND(rent_amount * 100) AS SIGNED), owner_rent_amount_cent = CAST(ROUND(owner_rent_amount * 100) AS SIGNED), ...; ``` ### 2. Model 层 ✅ **文件**: `backend/internal/model/*.go` 为所有金额相关表新增 *Cent 字段: ```go type RentalOrder struct { RentAmount float64 `gorm:"type:decimal(12,2)" json:"-"` RentAmountCent int64 `gorm:"not null;default:0" json:"-"` OwnerRentAmount float64 `gorm:"type:decimal(12,2)" json:"-"` OwnerRentAmountCent int64 `gorm:"not null;default:0" json:"-"` // ... 其他字段 } ``` ### 3. Money 工具包 ✅ **文件**: `backend/pkg/money/money.go` 核心函数: ```go // ToCent 元转分(四舍五入) func ToCent(yuan float64) int64 // FromCent 分转元 func FromCent(cent int64) float64 // FormatCent 格式化分为元字符串(2位小数) func FormatCent(cent int64) string // FormatJiao 格式化分为角字符串(1位小数) func FormatJiao(cent int64) string // ToJiao 分转角(四舍五入) func ToJiao(cent int64) int64 // FromJiao 角转分 func FromJiao(jiao int64) int64 ``` ### 4. 核心业务模块 ✅ #### Wallet 模块 ✅ - **DTO**: 所有金额字段改为 `*Cent int64` - **Entry结构**: `AmountCent int64` 替代 `Amount float64` - **整数运算**: `applyEntry` 使用纯整数加减 - **删除**: `roundWalletMoney` 函数(不再需要) #### Withdrawal 模块 ✅ - **DTO**: `WithdrawalDTO`, `CreateWithdrawalRequest` 改为 `*Cent` - **手续费计算**: 改为分单位 - **最小/最大金额**: MinWithdrawalAmountCent = 1000 (10元) #### Order 模块 ✅(最复杂) - **DTO**: `OrderDTO`, `CheckoutDTO`, `RefundStatusDTO` 改为 `*Cent` - **内部结构体**: `orderPricing`, `checkoutSettlement` 改为分字段 - **结算计算**: `calculateCheckoutSettlement` 内部用元计算保持兼容,返回分 - **钱包操作**: 所有 `wallet.AppendEntries` 调用改为 `AmountCent` - **退款逻辑**: 3 处改为直接使用分字段相加 #### Dispute 模块 ✅ - **修复**: 2 处 `wallet.Entry` 调用改为 `AmountCent` #### Listing 模块 ✅ - **DTO**: `PriceCent`, `DepositAmountCent` - **筛选排序**: 改为使用分字段 - **价格视图**: `sanitizePriceForOwner` 使用 `PriceCent` #### Payment 模块 ✅(已适配) - **DTO**: `PaymentDTO`, `RefundDTO` 已使用 `AmountCent` - **退款函数**: `StartRefund(orderID, refundAmountCent int64, ...)` 已适配 #### AdminFinance 模块 ✅(已适配) - **DTO**: `FinanceSummaryDTO`, `FinanceDailyDTO` 已使用 `*Cent` 字段 - **查询**: 财务统计查询已适配 --- ## 三、技术实现亮点 ### 1. 数据双字段并存 新旧字段共存,便于渐进式迁移和回滚: ```go type RentalOrder struct { RentAmount float64 `gorm:"type:decimal(12,2)" json:"-"` // 旧字段 RentAmountCent int64 `gorm:"not null;default:0" json:"-"` // 新字段 } ``` ### 2. 整数运算消除精度问题 ```go // 旧代码(浮点运算) account.AvailableBalance += amount account.AvailableBalance = roundMoney(account.AvailableBalance) // 新代码(整数运算) account.AvailableBalanceCent += amountCent // 直接加减,无精度损失 ``` ### 3. 复杂结算兼容性处理 Order 模块的 `calculateCheckoutSettlement` 函数: ```go func calculateCheckoutSettlement(order model.RentalOrder, consumableAmount float64, coinConsumedM float64, depositDeductAmount float64) checkoutSettlement { // 读取分字段并转为元(保持现有计算逻辑) orderRentAmount := float64(order.RentAmountCent) / 100 orderOwnerRentAmount := float64(order.OwnerRentAmountCent) / 100 // 现有的复杂计算逻辑... actualRentAmount := minMoney(roundMoney(usedBuyerCoinPrice+usedBuyerConsumablePrice), orderRentAmount) // 最后转换为分返回 return checkoutSettlement{ ActualRentAmountCent: int64(math.Round(actualRentAmount * 100)), OwnerRentIncomeCent: int64(math.Round(ownerRentIncome * 100)), // ... } } ``` ### 4. 角精度展示 ```go // 后端返回分 dto.PriceCent = 12345 // 123.45 元 // 前端展示角(formatJiao) formatJiao(12345) → "123.5" // 显示 123.5 元 ``` --- ## 四、Git 提交记录 ```bash eaa10d8 - 数据库迁移:新增金额分字段并迁移历史数据 b80719d - Model层:新增金额分字段定义 e2780ff - Money工具包:实现分↔角转换和格式化函数 01909ee - Wallet与Withdrawal模块:完成分字段重构 d803089 - Order模块:完成分字段重构 4f3be22 - Dispute模块:修复wallet.Entry调用 2185cd1 - Listing模块:完成分字段重构 ``` --- ## 五、编译验证 ```bash ✅ go build -o /dev/null ./cmd/api 编译通过,无错误 ``` --- ## 六、下一步工作:前端适配 ### 需要修改的文件 #### 1. TypeScript 类型定义 更新所有 API 接口类型定义,将金额字段改为 `*_cent: number` #### 2. 工具函数 ```typescript // frontend/src/utils/money.ts export function formatCent(cent: number): string { return (cent / 100).toFixed(2); } export function formatJiao(cent: number): string { return (Math.round(cent / 10) / 10).toFixed(1); } export function toCent(yuan: number): number { return Math.round(yuan * 100); } ``` #### 3. 涉及的模块 - **Wallet**: 余额展示、充值输入 - **Withdrawal**: 提现金额输入、手续费显示 - **Order**: 订单金额展示、结算详情 - **Listing**: 商品价格展示、发布价格输入 - **AdminFinance**: 财务报表展示 ### 改造原则 1. **表单输入**: 用户输入元 → 乘以100转为分 → 发送后端 2. **数据展示**: 后端返回分 → 除以10四舍五入 → 显示角(1位小数) 3. **内部计算**: 尽量使用分进行计算,避免浮点运算 --- ## 七、测试建议 ### 1. 单元测试 - Order 模块结算计算 - Money 工具函数边界值 ### 2. 集成测试 - 完整订单流程 - 钱包充值提现流程 ### 3. 手工测试场景 - 订单结算精度(租金+押金+手续费) - 钱包余额累加(大量小额交易) - 提现手续费计算 - 边界值(最小充值、最大提现) --- ## 八、回滚方案 如需回滚,执行以下步骤: 1. **代码回滚** ```bash git revert 2185cd1 # Listing git revert 4f3be22 # Dispute git revert d803089 # Order git revert 01909ee # Wallet & Withdrawal git revert e2780ff # Money工具包 git revert b80719d # Model ``` 2. **数据库回滚** ```sql -- 不需要删除新字段,旧字段仍然存在 -- 如果需要,可以执行: ALTER TABLE rental_orders DROP COLUMN rent_amount_cent; -- ... 其他表 ``` --- ## 九、总结 ✅ **后端重构完成度**: 100% ✅ **编译状态**: 通过 ✅ **代码质量**: 保持原有逻辑,仅替换金额字段 ✅ **兼容性**: 新旧字段并存,便于迁移 🎯 **下一阶段**: 前端适配(约需 2-3 小时) --- **报告生成时间**: 2026-06-09 **作者**: Claude Code AI Assistant