refactor: 统一全项目金额精度为角(0.1元)
## 变更概述 将全项目金额处理从整元四舍五入统一为角精度(0.1元),提高金额计算准确性和显示一致性。 ## 后端改动 - 新增 pkg/money/format.go 统一金额处理包 - Round(): 角精度四舍五入 - Min/Max(): 金额比较 - Format(): 格式化字符串 - 更新业务模块使用统一金额函数 - internal/modules/order: 订单结算改为角精度 - internal/modules/dispute: 纠纷金额处理 - internal/modules/listing: 商品定价和存储 - 更新测试用例期望值为角精度 ## 前端改动 - 新增 shared/utils/money.ts 金额工具函数 - roundMoney(): 角精度四舍五入 - formatMoney(): 格式化为字符串(保留1位小数) - formatMoneyWithSymbol(): 添加¥符号 - 更新金额计算和显示逻辑 - shared/utils/pricing.ts: 定价计算 - shared/utils/listingDisplay.ts: 商品显示 - shared/composables/useMoney.ts: 组合式函数 - 修复视图文件导入声明 - features/listings/views: 商品详情页 - features/seller/views: 卖家管理页 ## 效果 - 金额显示:¥123.0(统一保留1位小数) - 计算精度:12.45 -> 12.5(角精度) - 减少误差:避免整元四舍五入损失 - 显示一致:全项目统一格式 ## 测试 - ✅ 后端单元测试通过 - ✅ TypeScript 类型检查通过 - ✅ 开发环境正常运行 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.7
parent
e41d3a923a
commit
4ebf7f75fe
@@ -3,7 +3,9 @@ export * from './authStorage'
|
||||
export * from './imageUpload'
|
||||
export * from './json'
|
||||
export * from './listingDisplay'
|
||||
export * from './pricing'
|
||||
export * from './money'
|
||||
// pricing 模块导出会和 money 模块的 roundMoney 冲突,所以不全局导出
|
||||
// 需要使用时单独 import { roundRatio } from '@/shared/utils/pricing'
|
||||
export * from './statusLabels'
|
||||
export * from './systemConfigOptions'
|
||||
export * from './time'
|
||||
|
||||
@@ -38,13 +38,13 @@ export function getListingDisplayPrice(item: Listing) {
|
||||
|
||||
export function getListingRentPrice(item: Listing) {
|
||||
const buyerCoinBasePrice = readPriceBreakdownNumber(item, "buyer_coin_base_price");
|
||||
if (buyerCoinBasePrice > 0) return Math.round(buyerCoinBasePrice);
|
||||
return Math.max(0, Math.round(getListingDisplayPrice(item) - getListingConsumablePrice(item)));
|
||||
if (buyerCoinBasePrice > 0) return roundMoney(buyerCoinBasePrice);
|
||||
return Math.max(0, roundMoney(getListingDisplayPrice(item) - getListingConsumablePrice(item)));
|
||||
}
|
||||
|
||||
export function getListingConsumablePrice(item: Listing) {
|
||||
const consumablePrice = readPriceBreakdownNumber(item, "consumable_price");
|
||||
if (consumablePrice > 0) return Math.round(consumablePrice);
|
||||
if (consumablePrice > 0) return roundMoney(consumablePrice);
|
||||
return getListingResources(item).reduce((sum, resource) => sum + resource.amount, 0);
|
||||
}
|
||||
|
||||
@@ -137,7 +137,7 @@ export function getListingResources(item: Listing): ListingDisplayResource[] {
|
||||
mode: typeof row.mode === "string" ? row.mode : "",
|
||||
amount:
|
||||
row.mode === "收费"
|
||||
? Math.round(readUnknownNumber(row.quantity) * readUnitPrice(typeof row.price === "string" ? row.price : ""))
|
||||
? roundMoney(readUnknownNumber(row.quantity) * readUnitPrice(typeof row.price === "string" ? row.price : ""))
|
||||
: 0,
|
||||
};
|
||||
})
|
||||
@@ -297,7 +297,7 @@ function roundMoney(value: number) {
|
||||
|
||||
function formatRatioNumber(value: number) {
|
||||
const rounded = roundMoney(value);
|
||||
return Number.isInteger(rounded) ? `${rounded}` : rounded.toFixed(2);
|
||||
return rounded.toFixed(1);
|
||||
}
|
||||
|
||||
function formatCompactNumber(value: number) {
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 统一金额处理工具函数
|
||||
* 全项目金额精度统一为角(0.1元)
|
||||
*/
|
||||
|
||||
/**
|
||||
* 将金额四舍五入到角精度(0.1元)
|
||||
* @example roundMoney(12.34) -> 12.3
|
||||
* @example roundMoney(12.36) -> 12.4
|
||||
*/
|
||||
export function roundMoney(value: number): number {
|
||||
return Math.round(value * 10) / 10
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化金额为字符串(保留1位小数)
|
||||
* @example formatMoney(12.3) -> "12.3"
|
||||
* @example formatMoney(12.0) -> "12.0"
|
||||
*/
|
||||
export function formatMoney(value: number | undefined | null): string {
|
||||
const num = Number(value || 0)
|
||||
return roundMoney(num).toFixed(1)
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化金额并添加货币符号
|
||||
* @example formatMoneyWithSymbol(12.3) -> "¥12.3"
|
||||
*/
|
||||
export function formatMoneyWithSymbol(value: number | undefined | null): string {
|
||||
return `¥${formatMoney(value)}`
|
||||
}
|
||||
@@ -12,16 +12,30 @@ import type { DepositBreakdownItem, PublishForm, PublishPlatformPricing } from '
|
||||
export const dailyLossOptions = [10, 20, 30, 40, 50]
|
||||
export const commonOnlineTimes = ['00:00', '08:00', '10:00', '12:00', '14:00', '18:00', '20:00', '22:00', '23:59']
|
||||
|
||||
/**
|
||||
* 将金额四舍五入到角精度(0.1元)
|
||||
* 统一全项目金额处理规范
|
||||
* @example roundMoney(12.34) -> 12.3
|
||||
* @example roundMoney(12.36) -> 12.4
|
||||
* @example roundMoney(12.35) -> 12.4
|
||||
*/
|
||||
export function roundMoney(value: number) {
|
||||
return Math.round(value)
|
||||
return Math.round(value * 10) / 10
|
||||
}
|
||||
|
||||
/**
|
||||
* 将比例四舍五入到一位小数
|
||||
*/
|
||||
export function roundRatio(value: number) {
|
||||
return Math.round(value * 10) / 10
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化数字为字符串(保留1位小数)
|
||||
*/
|
||||
export function formatNumber(value: number) {
|
||||
return Number.isInteger(value) ? `${value}` : `${Math.round(value * 10) / 10}`
|
||||
const rounded = Math.round(value * 10) / 10
|
||||
return rounded.toFixed(1)
|
||||
}
|
||||
|
||||
export function readUnitPrice(priceText: string) {
|
||||
|
||||
Reference in New Issue
Block a user