Files
hfb_sys/docs/金额统一重构完成报告.md
T
yml 86c080ae40 前端适配:Money工具函数和Wallet API类型更新
核心改造:
1. Money工具函数:新增formatCent、formatCentWithSymbol、yuanToCent等函数
2. Wallet API类型:WalletAccount和WalletLedger改为*_cent字段
3. API请求函数:rechargeWallet和startWalletRechargePayment自动转换元为分
4. 文档:生成完整的前端适配指南

技术细节:
- formatCent: 分转角并格式化(四舍五入到0.1元)
- yuanToCent: 元转分(用于表单提交)
- API函数自动处理转换,组件层面仍使用元
- 生成详细的适配指南供后续组件修改参考

下一步:
- 按照前端适配指南修改所有Vue组件
- 测试金额显示和计算精度
2026-06-09 14:07:55 +08:00

9.0 KiB
Raw Blame History

金额统一重构完成报告

项目: 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

新增字段:

-- 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;

历史数据迁移:

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 字段:

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

核心函数:

// 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. 数据双字段并存

新旧字段共存,便于渐进式迁移和回滚:

type RentalOrder struct {
    RentAmount      float64 `gorm:"type:decimal(12,2)" json:"-"`  // 旧字段
    RentAmountCent  int64   `gorm:"not null;default:0" json:"-"`  // 新字段
}

2. 整数运算消除精度问题

// 旧代码(浮点运算)
account.AvailableBalance += amount
account.AvailableBalance = roundMoney(account.AvailableBalance)

// 新代码(整数运算)
account.AvailableBalanceCent += amountCent  // 直接加减,无精度损失

3. 复杂结算兼容性处理

Order 模块的 calculateCheckoutSettlement 函数:

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. 角精度展示

// 后端返回分
dto.PriceCent = 12345  // 123.45 元

// 前端展示角(formatJiao
formatJiao(12345)  "123.5"  // 显示 123.5 元

四、Git 提交记录

eaa10d8 - 数据库迁移:新增金额分字段并迁移历史数据
b80719d - Model层:新增金额分字段定义
e2780ff - Money工具包:实现分↔角转换和格式化函数
01909ee - Wallet与Withdrawal模块:完成分字段重构
d803089 - Order模块:完成分字段重构
4f3be22 - Dispute模块:修复wallet.Entry调用
2185cd1 - Listing模块:完成分字段重构

五、编译验证

✅ go build -o /dev/null ./cmd/api
编译通过,无错误

六、下一步工作:前端适配

需要修改的文件

1. TypeScript 类型定义

更新所有 API 接口类型定义,将金额字段改为 *_cent: number

2. 工具函数

// 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. 代码回滚
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
  1. 数据库回滚
-- 不需要删除新字段,旧字段仍然存在
-- 如果需要,可以执行:
ALTER TABLE rental_orders DROP COLUMN rent_amount_cent;
-- ... 其他表

九、总结

后端重构完成度: 100%
编译状态: 通过
代码质量: 保持原有逻辑,仅替换金额字段
兼容性: 新旧字段并存,便于迁移

🎯 下一阶段: 前端适配(约需 2-3 小时)


报告生成时间: 2026-06-09
作者: Claude Code AI Assistant