For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (
- [ ]) syntax for tracking.
Goal: 消除全栈所有 decimal/double 类型,使用整型(分/千分比)替代,前端统一做展示转换
架构: 分 4 阶段推进。P0 核心电商(Product/ProductOrder)→ P1 套餐/活动/服务(GuidePackage/Activity/ServiceContent)→ P2 支付/佣金/会员(PaymentOrder/Commission/Membership)→ P3 评分/配置/先天属性(Teacher rating/Energy ratio/Zodiac/Bazi)。数据库逐表迁移(新增 INT 列→迁移数据→删除旧 DECIMAL 列→重命名)。
核心原则:
1元 = 100),前端展示 (cents / 100).toFixed(2)23.5% = 235),前端展示 (permillage / 10) + '%'4.5 = 450),前端展示 (value / 100).toFixed(1)0.15 = 1500),计算时除以 10000Integer,前端做转换Tech Stack: Java 8, Spring Boot 2.7, MyBatis-Plus, MySQL 8.0, uni-app Vue 2
| 文件 | 操作 | 任务 | 优先级 |
|---|---|---|---|
Product.java |
修改 | T1 | P0 |
ProductDTO.java |
修改 | T1 | P0 |
ProductOrder.java |
修改 | T2 | P0 |
ProductOrderDTO.java |
修改 | T2 | P0 |
ProductOrderService.java |
修改 | T2 | P0 |
utils/format.js |
新建 | T3 | P0 |
| 前端价格展示位置(6 处) | 修改 | T3 | P0 |
DatabaseInitializer.java |
修改 | T4 | P0 |
AdminCommissionController.java |
修改 | T4 | P0 |
| SQL 迁移脚本 | 新增 | T4 | P0 |
Activity.java / ActivityDTO.java |
修改 | T5 | P1 |
ServiceContent.java / DTOs |
修改 | T5 | P1 |
GuidePackage.java / DTOs |
修改 | T5 | P1 |
| 套餐/服务相关 Service | 修改 | T5 | P1 |
PaymentOrder.java / PaymentOrderDTO.java |
修改 | T6 | P2 |
CommissionRecord.java / DTOs |
修改 | T6 | P2 |
CommissionService.java |
修改 | T6 | P2 |
WithdrawalRequest.java / WithdrawalService.java |
修改 | T6 | P2 |
MembershipLevel.java / MembershipService.java |
修改 | T6 | P2 |
Guide.java / Teacher.java rating |
修改 | T7 | P3 |
EnergyDimensionConfig.java / EnergySourceConfig.java |
修改 | T7 | P3 |
ZodiacConfig.java / BaziConfig.java / BloodTypeConfig.java |
修改 | T8 | P3 |
FamilyMemberAttributes.java |
修改 | T8 | P3 |
FamilyMemberAttributeService.java |
修改 | T8 | P3 |
Files:
Create: cfc-frontend/utils/format.js
[ ] Step 1: 创建 format.js
/**
* 金额格式化工具
* 后端统一使用整型(分)存储金额,前端在此转换展示
*/
/**
* 分 → 元,保留2位小数
* @param {number|null} cents 金额(分)
* @returns {string|null} "12.50" 或 null
*/
export function formatPrice(cents) {
if (cents == null || cents === undefined) return null
return (cents / 100).toFixed(2)
}
/**
* 分 → 元,带 ¥ 前缀
* @param {number|null} cents 金额(分)
* @returns {string} "¥12.50" 或 "登录查看"
*/
export function formatPriceWithSymbol(cents) {
if (cents == null || cents === undefined) return '登录查看'
return '¥' + (cents / 100).toFixed(2)
}
/**
* 千分比 → 百分比字符串
* @param {number|null} permillage 千分比(235 = 23.5%)
* @returns {string} "23.5%" 或 "--"
*/
export function formatRate(permillage) {
if (permillage == null || permillage === undefined) return '--'
return (permillage / 10) + '%'
}
/**
* 百分制评分 → 展示值
* @param {number|null} value 百分制(450 = 4.5分)
* @param {number} fixed 小数位数
* @returns {string} "4.5" 或 "--"
*/
export function formatScore(value, fixed) {
if (fixed === undefined) fixed = 1
if (value == null || value === undefined) return '--'
return (value / 100).toFixed(fixed)
}
[ ] Step 2: 编译验证
运行 lsp_diagnostics 确认无语法错误。
Files:
cfc-backend/src/main/java/com/etotem/cfc/entity/Product.javaModify: cfc-backend/src/main/java/com/etotem/cfc/dto/ProductDTO.java
[ ] Step 1: Product.java 字段类型修改
// 修改前
import java.math.BigDecimal;
// ...
private BigDecimal price;
private BigDecimal memberPrice;
private BigDecimal profitRate;
// 修改后 — 删除 import java.math.BigDecimal;
// ...
private Integer price; // 价格(分),展示时 /100
private Integer memberPrice; // 会员价(分)
private Integer profitRate; // 利润率(千分比),23.5% → 235
[ ] Step 2: ProductDTO.java 同步修改
// 删除 import java.math.BigDecimal;
private Integer price;
private Integer memberPrice;
private Integer profitRate;
检查 DTO 中的转换逻辑(如有 d.price = p.getPrice() 等),类型改为 Integer 后赋值不变(Integer → Integer 无需转换)。
[ ] Step 3: 编译验证
cd cfc-backend && mvn clean compile -q
预期:BUILD SUCCESS(仅改 entity + dto 无编译依赖错误)
Files:
cfc-backend/src/main/java/com/etotem/cfc/entity/ProductOrder.javacfc-backend/src/main/java/com/etotem/cfc/dto/ProductOrderDTO.javaModify: cfc-backend/src/main/java/com/etotem/cfc/service/ProductOrderService.java
[ ] Step 1: ProductOrder.java 字段类型修改
// 删除 import java.math.BigDecimal;
private Integer unitPrice; // 单价(分)
private Integer totalAmount; // 总价(分)
[ ] Step 2: ProductOrderDTO.java 同步修改
// 删除 import java.math.BigDecimal;
private Integer unitPrice;
private Integer totalAmount;
[ ] Step 3: ProductOrderService.java 计算逻辑更新
// 修改前 (约第65行):
order.setTotalAmount(product.getPrice().multiply(BigDecimal.valueOf(dto.getQuantity())));
// 修改后:
order.setUnitPrice(product.getPrice());
order.setTotalAmount(product.getPrice() * dto.getQuantity());
[ ] Step 4: 编译验证
cd cfc-backend && mvn clean compile -q
预期:BUILD SUCCESS
Files:
cfc-frontend/pages/index/index.vue(未登录态商品列表)cfc-frontend/components/DimensionProducts.vuecfc-frontend/pages/body/index.vue(如有直接价格渲染)cfc-frontend/pages/mind/index.vue(如有直接价格渲染)cfc-frontend/pages/action/index.vue(如有直接价格渲染)Modify: cfc-frontend/pages/shop/index.vue(商城价格)
[ ] Step 1: 在 utils/api.js 或相关位置引入 format 工具
在 main.js 中全局注册(或在各页面分别 import):
// main.js
import { formatPriceWithSymbol, formatPrice, formatRate } from '@/utils/format'
// 挂载到 Vue 原型,所有组件可通过 this.formatPriceWithSymbol() 访问
Vue.prototype.formatPriceWithSymbol = formatPriceWithSymbol
Vue.prototype.formatPrice = formatPrice
Vue.prototype.formatRate = formatRate
对所有前端文件中形如 ¥{{ item.price }} 的渲染,改为 {{ formatPriceWithSymbol(item.price) }}。
搜索清单(grep 查找 ¥{{ 或 ¥ 在 .vue 文件中):
grep -rn '¥' cfc-frontend/pages/ cfc-frontend/components/ --include='*.vue'
每个匹配位置都需修改:
<!-- 修改前 -->
<text class="product-price">¥{{ item.price }}</text>
<!-- 修改后 -->
<text class="product-price">{{ formatPriceWithSymbol(item.price) }}</text>
[ ] Step 3: 检查 v-if 条件
<!-- 修改前 — BigDecimal 用 v-if="item.price" 检查非零 -->
<view v-if="item.price">¥{{ item.price }}</view>
<!-- 修改后 — Integer 用 != null 检查,0 元商品显示 "¥0.00" 而不是隐藏 -->
<view v-if="item.price != null">{{ formatPriceWithSymbol(item.price) }}</view>
<!-- 会员价同理 -->
<text v-if="item.memberPrice != null">会员{{ formatPriceWithSymbol(item.memberPrice) }}</text>
[ ] Step 4: LSP 诊断
运行 lsp_diagnostics 确认无语法错误。
Files:
cfc-backend/.../controller/product/ProductController.javacfc-backend/.../config/DatabaseInitializer.javacfc-backend/.../controller/admin/AdminCommissionController.javaCreate: cfc-backend/src/main/resources/db/migration/V20260615__integer_price.sql
[ ] Step 1: ProductController 价格置 null 逻辑
// 游客隐藏价格逻辑不变,类型已改为 Integer
public Result<?> list(@RequestBody(required = false) Map<String, Object> params,
@RequestAttribute(value = "userId", required = false) Long userId) {
// ... 正常查询逻辑
List<ProductDTO> productList = ...;
if (userId == null) {
for (ProductDTO dto : productList) {
dto.setPrice(null);
dto.setMemberPrice(null);
}
}
return Result.success(productList);
}
类型可赋值 null,逻辑无需改动(只需确认编译通过)。
在 DatabaseInitializer.java 中找到种子数据插入(约第 982-986 行):
// 修改前:
insertProductSeed("亲子关系工作坊", "...", "activity", new java.math.BigDecimal("388.00"), "action", "all");
// 修改后: 388.00元 = 38800分
insertProductSeed("亲子关系工作坊", "...", "activity", 38800, "action", "all");
检查 insertProductSeed 方法签名,将参数类型从 java.math.BigDecimal 改为 Integer(或确认重载版本)。
// 方法签名修改前:
private void insertProductSeed(String name, String desc, String type, java.math.BigDecimal price, String domain, String budget) {
// 方法签名修改后:
private void insertProductSeed(String name, String desc, String type, Integer price, String domain, String budget) {
所有种子数据价格转换: | 原值 | 分 | |------|---| | 388.00 | 38800 | | 199.00 | 19900 | | 599.00 | 59900 | | 99.00 | 9900 | | 500.00 | 50000 |
[ ] Step 3: AdminCommissionController 整型化
// 修改前 (约第61-71行):
BigDecimal profitRate = params.get("profitRate") != null
? new BigDecimal(params.get("profitRate").toString())
: null;
if (productId == null || profitRate == null) {
return Result.error("productId和profitRate不能为空");
}
// ...
product.setProfitRate(profitRate);
// 修改后:
Integer profitRate = params.get("profitRate") != null
? Integer.valueOf(params.get("profitRate").toString())
: null;
if (productId == null || profitRate == null) {
return Result.error("productId和profitRate不能为空");
}
// ...
product.setProfitRate(profitRate);
[ ] Step 4: 数据库迁移 SQL
-- V20260615__integer_price.sql
-- ========================================
-- Phase 1: 核心电商表
-- ========================================
-- products: price, member_price, profit_rate
ALTER TABLE products
ADD COLUMN price_int INT DEFAULT 0 COMMENT '价格(分)',
ADD COLUMN member_price_int INT DEFAULT 0 COMMENT '会员价(分)',
ADD COLUMN profit_rate_int INT DEFAULT 0 COMMENT '利润率(千分比)';
UPDATE products SET price_int = ROUND(price * 100);
UPDATE products SET member_price_int = ROUND(member_price * 100);
UPDATE products SET profit_rate_int = ROUND(profit_rate * 10);
ALTER TABLE products
DROP COLUMN price,
DROP COLUMN member_price,
DROP COLUMN profit_rate;
ALTER TABLE products
CHANGE COLUMN price_int price INT DEFAULT 0 COMMENT '价格(分)',
CHANGE COLUMN member_price_int member_price INT DEFAULT 0 COMMENT '会员价(分)',
CHANGE COLUMN profit_rate_int profit_rate INT DEFAULT 0 COMMENT '利润率(千分比)';
-- product_orders: unit_price, total_amount
ALTER TABLE product_orders
ADD COLUMN unit_price_int INT DEFAULT 0 COMMENT '单价(分)',
ADD COLUMN total_amount_int INT DEFAULT 0 COMMENT '总价(分)';
UPDATE product_orders SET unit_price_int = ROUND(unit_price * 100);
UPDATE product_orders SET total_amount_int = ROUND(total_amount * 100);
ALTER TABLE product_orders
DROP COLUMN unit_price,
DROP COLUMN total_amount;
ALTER TABLE product_orders
CHANGE COLUMN unit_price_int unit_price INT DEFAULT 0 COMMENT '单价(分)',
CHANGE COLUMN total_amount_int total_amount INT DEFAULT 0 COMMENT '总价(分)';
[ ] Step 5: 编译验证
cd cfc-backend && mvn clean compile -q
预期:BUILD SUCCESS
Files:
cfc-backend/.../entity/Activity.java(price)cfc-backend/.../dto/ActivityDTO.java(price)cfc-backend/.../entity/ServiceContent.java(price)cfc-backend/.../entity/GuidePackage.java(price, commissionRate)cfc-backend/.../entity/GuidePackageTemplate.java(referencePrice, minPrice)cfc-backend/.../entity/TaskTemplatePackage.java(price, platformFee)cfc-backend/.../entity/Guide.java(commissionRate)cfc-backend/.../entity/GuideFamily.java(servicePrice)cfc-backend/.../entity/GuideApplication.java(paymentAmount)Modify: 相关 Controller/Service(调整 new BigDecimal() → Integer.valueOf())
[ ] Step 1: 实体字段逐类修改
每个实体执行同样的模式:
// Activity.java — 例
// 删除 import java.math.BigDecimal;
private Integer price; // 价格(分)
DTO 同步修改,注意 DTO 中的转换赋值不变(Integer ↔ Integer)。
搜索所有 Controller 中 new BigDecimal(params.get("price").toString()) 模式:
grep -rn 'new BigDecimal' cfc-backend/src/main/java/com/etotem/cfc/controller/
将每个匹配位置改为 Integer.valueOf() 或 Integer.parseInt():
// 修改前:
java.math.BigDecimal price = new java.math.BigDecimal(params.get("price").toString());
// 修改后:
Integer price = params.get("price") != null
? Integer.valueOf(params.get("price").toString())
: null;
搜索 Service 中使用 BigDecimal 进行金额计算的代码:
grep -rn '\.multiply\|\.divide\|\.add\|\.subtract\|new BigDecimal' cfc-backend/src/main/java/com/etotem/cfc/service/ --include='*.java'
需要重点调整的位置:
TaskTemplatePackageService.java:
// 修改前:
pkg.setPlatformFee(dto.getPrice().multiply(new BigDecimal("0.10")));
// 修改后: 平台服务费 = 价格 × 10%(结果以分存储)
pkg.setPlatformFee(dto.getPrice() * 10 / 100);
GuidePackageService.java:
// 方法签名:
// 旧: boolean addGuidePackage(Long guideId, Long packageId, BigDecimal price, BigDecimal commissionRate)
// 新: boolean addGuidePackage(Long guideId, Long packageId, Integer price, Integer commissionRate)
BindInviteService.java:
// 旧: gf.setServicePrice(BigDecimal.ZERO);
// 新:
gf.setServicePrice(0);
[ ] Step 4: 数据库迁移 SQL
-- Phase 2 SQL
-- activities.price
ALTER TABLE activity ADD COLUMN price_int INT DEFAULT 0;
UPDATE activity SET price_int = ROUND(price * 100);
ALTER TABLE activity DROP COLUMN price;
ALTER TABLE activity CHANGE COLUMN price_int price INT DEFAULT 0;
-- guide_packages.price, commission_rate
ALTER TABLE guide_packages ADD COLUMN price_int INT DEFAULT 0, ADD COLUMN commission_rate_int INT DEFAULT 0;
UPDATE guide_packages SET price_int = ROUND(price * 100), commission_rate_int = ROUND(commission_rate * 1000);
ALTER TABLE guide_packages DROP COLUMN price, DROP COLUMN commission_rate;
ALTER TABLE guide_packages CHANGE COLUMN price_int price INT DEFAULT 0, CHANGE COLUMN commission_rate_int commission_rate INT DEFAULT 0;
-- 后续表同理...
[ ] Step 5: 编译验证
cd cfc-backend && mvn clean compile -q
预期:BUILD SUCCESS
Files:
PaymentOrder.java, CommissionRecord.java, WithdrawalRequest.java, MembershipLevel.java, FamilyMembership.java, FinanceCheckin.java, InsurancePolicy.javaCommissionService.java(整型化全部计算逻辑)MembershipService.javaWithdrawalService.javaPackagePaymentService.javaPackagePurchaseService.java注意: Phase 3 涉及复杂的分佣计算(CommissionService 约 470 行,大量 BigDecimal 计算),改造风险较高。建议的改造策略:
- 所有金额字段改为整型(分)
- 百分比/费率字段改为万分比(1% = 100bps)
- 计算时:
amount * rate_bps / 10000(整型除法,避免精度问题)- 顺序:先改 Entity/DTO 保证编译通过 → 再逐个 Service 改造 → 最后改测试
按 Task 1/2 的模式,逐个文件将 BigDecimal 字段改为 Integer。
将浮动百分比改为 BPS(基点)模式:
// 旧模式:BigDecimal 乘除
private static final BigDecimal PROFIT_COMMISSION_RATE = new BigDecimal("0.30");
l1Amount = orderAmount.multiply(profitRate).divide(new BigDecimal("100"));
// 新模式:整型 BPS(基点)
private static final int PROFIT_COMMISSION_RATE_BPS = 3000; // 30%
// 分润 = 订单金额(分) × 利润率(千分比) × 佣金比例(bps) / 10000 / 1000
// 简化: l1Amount = orderAmount * profitRatePermillage * rateBps / 10000000
注意:CommissionService 的计算涉及多层乘除,整型化后需特别注意溢出(用
long中间值)。建议先在CommissionService.java中引入SafeMath辅助方法。
[ ] Step 3: 编译验证
cd cfc-backend && mvn clean compile -q
预期:BUILD SUCCESS
[ ] Step 4: 数据库迁移 SQL
-- Phase 3: payment_orders.amount
ALTER TABLE payment_orders ADD COLUMN amount_int INT DEFAULT 0;
UPDATE payment_orders SET amount_int = ROUND(amount * 100);
ALTER TABLE payment_orders DROP COLUMN amount;
ALTER TABLE payment_orders CHANGE COLUMN amount_int amount INT DEFAULT 0;
-- commission_records.order_amount, profit_rate, commission_amount
ALTER TABLE commission_records ADD COLUMN order_amount_int INT DEFAULT 0, ADD COLUMN profit_rate_int INT DEFAULT 0, ADD COLUMN commission_amount_int INT DEFAULT 0;
UPDATE commission_records SET order_amount_int = ROUND(order_amount * 100), profit_rate_int = ROUND(profit_rate * 1000), commission_amount_int = ROUND(commission_amount * 100);
ALTER TABLE commission_records DROP COLUMN order_amount, DROP COLUMN profit_rate, DROP COLUMN commission_amount;
ALTER TABLE commission_records CHANGE COLUMN order_amount_int order_amount INT DEFAULT 0, CHANGE COLUMN profit_rate_int profit_rate INT DEFAULT 0, CHANGE COLUMN commission_amount_int commission_amount INT DEFAULT 0;
-- 其他表同理...
Files:
Teacher.java, TeacherDTO.java(rating: 百分制整数, 4.5 = 450)EnergyDimensionConfig.java(weight: 万分比, 0.25 = 2500)EnergySourceConfig.java(ratio: 万分比)EnergyService.java(计算逻辑整型化)AssessmentPointsConfig.java(pointsValueYuan: 分)Modify: AssessmentService.java
[ ] Step 1: 实体字段整型化
// Teacher.java
// 旧: private java.math.BigDecimal rating; // 评分
// 新:
private Integer rating; // 评分(百分制),4.5分 → 450
// EnergyDimensionConfig.java
// 旧: private BigDecimal weight;
// 新:
private Integer weight; // 权重(万分比),0.25 → 2500
// EnergySourceConfig.java
// 旧: private BigDecimal ratio;
// 新:
private Integer ratio; // 比例(万分比)
// AssessmentPointsConfig.java
// 旧: private BigDecimal pointsValueYuan;
// 新:
private Integer pointsValueYuan; // 分值(分)
[ ] Step 2: EnergyService 计算逻辑重构
EnergyService.java 中的 resolveDimensionRatios 和 calculateAllocations 使用 BigDecimal 进行比例计算:
// 旧:
Map<Long, BigDecimal> ratios = ...; // <dimId, weight>
BigDecimal totalRatio = ratios.values().stream().reduce(BigDecimal.ZERO, BigDecimal::add);
BigDecimal share = BigDecimal.valueOf(total).multiply(entry.getValue()).divide(totalRatio, 0, RoundingMode.DOWN);
// 新:
Map<Long, Integer> ratios = ...; // <dimId, weight-in-permyriad>
long totalRatio = ratios.values().stream().mapToLong(Integer::longValue).sum();
long share = (long) total * entry.getValue() / totalRatio; // 整型运算
[ ] Step 3: 编译验证
cd cfc-backend && mvn clean compile -q
预期:BUILD SUCCESS
Files:
ZodiacConfig.java, BaziConfig.java, BloodTypeConfig.java(所有 BigDecimal → Integer 万分比)FamilyMemberAttributes.java(mindBaseScore/wisdomBaseScore: 百分制整数)Modify: FamilyMemberAttributeService.java(calcInnateScore 整型化)
[ ] Step 1: 配置实体整型化
// ZodiacConfig.java / BaziConfig.java / BloodTypeConfig.java
// 旧: private BigDecimal mindBase; // 基数 0.85
// 新:
private Integer mindBase; // 万分比基数,0.85 → 8500
private Integer wisdomBase; // 万分比
private Integer bodyModifier; // 万分比
private Integer actionModifier;
private Integer wealthModifier;
[ ] Step 2: FamilyMemberAttributeService 计算重构
calcInnateScore 方法中大量使用 BigDecimal 乘除:
// 旧:
BigDecimal bloodScore = BigDecimal.ZERO;
BigDecimal result = zodiacScore.multiply(BigDecimal.valueOf(0.5))
.add(baziScore.multiply(BigDecimal.valueOf(0.3)))
.add(bloodScore.multiply(BigDecimal.valueOf(0.2)));
// 新: 权重使用千分比,结果使用百分制整数
// zodiac占比50% = 500‰, bazi 30% = 300‰, blood 20% = 200‰
int result = (zodiacScore * 500 + baziScore * 300 + bloodScore * 200) / 1000;
[ ] Step 3: 编译验证
cd cfc-backend && mvn clean compile -q
预期:BUILD SUCCESS
| # | 验证项 | 预期 | 检查方法 |
|---|---|---|---|
| 1 | 后端编译 | BUILD SUCCESS | mvn clean compile -q |
| 2 | entity 中无 BigDecimal | 0 个 import java.math.BigDecimal | grep -r 'import java.math.BigDecimal' src/main/java/com/etotem/cfc/entity/ \| wc -l |
| 3 | dto 中无 BigDecimal | 0 个 import | grep -r 'import java.math.BigDecimal' src/main/java/com/etotem/cfc/dto/ \| wc -l |
| 4 | 前端无 ¥{{ 直接渲染 | 0 个匹配 | grep -rn '¥{{' cfc-frontend/pages/ cfc-frontend/components/ |
| 5 | 金额展示使用 formatPriceWithSymbol | 所有 ¥ 前缀位置使用函数 | 人工审查 |
| 6 | 数据库无 DECIMAL 列 | 0 个 DECIMAL | SHOW COLUMNS FROM products; 等 |
| 7 | 端到端价格展示 | 商品价格显示 ¥388.00 | 小程序截图对比 |
| 8 | 端到端游客价格 | 显示"登录查看" | 未登录状态浏览 |
执行以下命令确认最终清理状态:
# 后端全部 BigDecimal 引用(期望最终为 0)
grep -rn 'import java.math.BigDecimal' cfc-backend/src/main/java/ --include='*.java'
# 前端全部 ¥ 渲染(期望最终只剩通过 formatPriceWithSymbol 的调用)
grep -rn '¥' cfc-frontend/pages/ cfc-frontend/components/ --include='*.vue'
| 风险 | 影响范围 | 缓解措施 |
|---|---|---|
| Integer 溢出(金额*BPS 计算) | CommissionService | 中间值使用 long/Long,关键点加注释 |
| 精度损失(除不尽) | EnergyService 分配 | 大数优先分配,余数补到最大维度 |
| seed 数据价格不对 | DatabaseInitializer | 逐行双检(388.00→38800) |
| 前端漏改 | 所有 Tab 页 | grep ¥{{ + 人工审查 |
| 历史数据迁移失败 | 生产库 | 迁移前备份,执行后 SELECT 抽样对比 |