From 8710da9383a12306eb79a3791714f0c9ac670f44 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sun, 17 May 2026 19:09:01 +0800 Subject: [PATCH] =?UTF-8?q?feat=EF=BC=88wms=EF=BC=89=EF=BC=9A=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=20wms=20=E5=B7=A5=E5=85=B7=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web-antd/src/views/wms/utils/format.ts | 153 ++++++++++++++++++++ apps/web-antd/src/views/wms/utils/order.ts | 12 ++ apps/web-ele/src/views/wms/utils/format.ts | 153 ++++++++++++++++++++ apps/web-ele/src/views/wms/utils/order.ts | 12 ++ 4 files changed, 330 insertions(+) create mode 100644 apps/web-antd/src/views/wms/utils/format.ts create mode 100644 apps/web-antd/src/views/wms/utils/order.ts create mode 100644 apps/web-ele/src/views/wms/utils/format.ts create mode 100644 apps/web-ele/src/views/wms/utils/order.ts diff --git a/apps/web-antd/src/views/wms/utils/format.ts b/apps/web-antd/src/views/wms/utils/format.ts new file mode 100644 index 000000000..e02b28e1b --- /dev/null +++ b/apps/web-antd/src/views/wms/utils/format.ts @@ -0,0 +1,153 @@ +/** + * WMS 展示格式化和表单配置 + */ + +type DecimalValue = null | number | string | undefined; + +/** 数量小数位 */ +export const QUANTITY_PRECISION = 2; +/** 金额小数位 */ +export const PRICE_PRECISION = 2; +/** 重量小数位 */ +export const WEIGHT_PRECISION = 3; +/** 长宽高小数位 */ +export const DIMENSION_PRECISION = 1; + +function isNullOrUndefined(value: unknown) { + return value === null || value === undefined; +} + +function toFiniteDecimal(value: DecimalValue) { + if (isNullOrUndefined(value)) { + return undefined; + } + if (typeof value === 'string' && value.trim() === '') { + return undefined; + } + const decimalValue = typeof value === 'string' ? Number(value) : value; + if (!Number.isFinite(decimalValue)) { + return undefined; + } + return decimalValue; +} + +function sumDecimal(list: T[], getter: (item: T) => DecimalValue) { + let sum = 0; + for (const item of list) { + const decimalValue = toFiniteDecimal(getter(item)); + if (decimalValue !== undefined) { + sum += decimalValue; + } + } + return sum; +} + +/** 格式化数量 */ +export function formatQuantity(value?: null | number | string) { + const decimalValue = toFiniteDecimal(value); + return decimalValue === undefined + ? '' + : decimalValue.toFixed(QUANTITY_PRECISION); +} + +/** 格式化金额 */ +export function formatPrice(value?: null | number | string) { + const decimalValue = toFiniteDecimal(value); + return decimalValue === undefined ? '' : decimalValue.toFixed(PRICE_PRECISION); +} + +/** 金额四舍五入 */ +export function roundPrice(value: number) { + return Number.isFinite(value) ? Number(value.toFixed(PRICE_PRECISION)) : undefined; +} + +/** 亏损数字样式 */ +export function getLossClass(value?: null | number | string) { + const decimalValue = toFiniteDecimal(value); + return decimalValue !== undefined && decimalValue < 0 ? 'text-red-500' : ''; +} + +/** 数量 * 单价,计算金额 */ +export function multiplyPrice(quantity?: number, price?: number) { + if ( + quantity === undefined || + quantity === null || + price === undefined || + price === null + ) { + return undefined; + } + return roundPrice(Number(quantity) * Number(price)); +} + +/** 金额 / 数量,反算单价 */ +export function dividePrice(totalPrice?: number, quantity?: number) { + if (totalPrice === undefined || totalPrice === null || !quantity) { + return undefined; + } + return roundPrice(Number(totalPrice) / Number(quantity)); +} + +/** 汇总数量 */ +export function sumQuantity(list: T[], getter: (item: T) => DecimalValue) { + return sumDecimal(list, getter); +} + +/** 汇总金额 */ +export function sumPrice(list: T[], getter: (item: T) => DecimalValue) { + return sumDecimal(list, getter); +} + +/** 格式化汇总数量 */ +export function formatSumQuantity( + list: T[], + getter: (item: T) => DecimalValue, +) { + return formatQuantity(sumQuantity(list, getter)); +} + +/** 格式化汇总金额 */ +export function formatSumPrice( + list: T[], + getter: (item: T) => DecimalValue, +) { + return formatPrice(sumPrice(list, getter)); +} + +/** 格式化重量 */ +export function formatWeight(value?: null | number | string) { + const decimalValue = toFiniteDecimal(value); + return decimalValue === undefined ? '' : decimalValue.toFixed(WEIGHT_PRECISION); +} + +/** 格式化长宽高 */ +export function formatDimension(value?: null | number | string) { + const decimalValue = toFiniteDecimal(value); + return decimalValue === undefined + ? '' + : decimalValue.toFixed(DIMENSION_PRECISION); +} + +/** 格式化长宽高组合 */ +export function formatDimensionText( + length?: null | number | string, + width?: null | number | string, + height?: null | number | string, +) { + if ( + !isNullOrUndefined(length) && + !isNullOrUndefined(width) && + !isNullOrUndefined(height) + ) { + return [formatDimension(length), formatDimension(width), formatDimension(height)].join( + ' * ', + ); + } + return [ + isNullOrUndefined(length) ? undefined : `长:${formatDimension(length)}`, + isNullOrUndefined(width) ? undefined : `宽:${formatDimension(width)}`, + isNullOrUndefined(height) ? undefined : `高:${formatDimension(height)}`, + ] + .filter(Boolean) + .join(' '); +} diff --git a/apps/web-antd/src/views/wms/utils/order.ts b/apps/web-antd/src/views/wms/utils/order.ts new file mode 100644 index 000000000..5f31136c3 --- /dev/null +++ b/apps/web-antd/src/views/wms/utils/order.ts @@ -0,0 +1,12 @@ +/** + * WMS 订单工具 + */ + +/** 生成业务单号:前缀 + 月日 + 4 位随机数 */ +export function generateOrderNo(prefix: string) { + const now = new Date(); + const month = String(now.getMonth() + 1).padStart(2, '0'); + const day = String(now.getDate()).padStart(2, '0'); + const randomNo = String(Math.floor(Math.random() * 10_000)).padStart(4, '0'); + return `${prefix}${month}${day}${randomNo}`; +} diff --git a/apps/web-ele/src/views/wms/utils/format.ts b/apps/web-ele/src/views/wms/utils/format.ts new file mode 100644 index 000000000..e02b28e1b --- /dev/null +++ b/apps/web-ele/src/views/wms/utils/format.ts @@ -0,0 +1,153 @@ +/** + * WMS 展示格式化和表单配置 + */ + +type DecimalValue = null | number | string | undefined; + +/** 数量小数位 */ +export const QUANTITY_PRECISION = 2; +/** 金额小数位 */ +export const PRICE_PRECISION = 2; +/** 重量小数位 */ +export const WEIGHT_PRECISION = 3; +/** 长宽高小数位 */ +export const DIMENSION_PRECISION = 1; + +function isNullOrUndefined(value: unknown) { + return value === null || value === undefined; +} + +function toFiniteDecimal(value: DecimalValue) { + if (isNullOrUndefined(value)) { + return undefined; + } + if (typeof value === 'string' && value.trim() === '') { + return undefined; + } + const decimalValue = typeof value === 'string' ? Number(value) : value; + if (!Number.isFinite(decimalValue)) { + return undefined; + } + return decimalValue; +} + +function sumDecimal(list: T[], getter: (item: T) => DecimalValue) { + let sum = 0; + for (const item of list) { + const decimalValue = toFiniteDecimal(getter(item)); + if (decimalValue !== undefined) { + sum += decimalValue; + } + } + return sum; +} + +/** 格式化数量 */ +export function formatQuantity(value?: null | number | string) { + const decimalValue = toFiniteDecimal(value); + return decimalValue === undefined + ? '' + : decimalValue.toFixed(QUANTITY_PRECISION); +} + +/** 格式化金额 */ +export function formatPrice(value?: null | number | string) { + const decimalValue = toFiniteDecimal(value); + return decimalValue === undefined ? '' : decimalValue.toFixed(PRICE_PRECISION); +} + +/** 金额四舍五入 */ +export function roundPrice(value: number) { + return Number.isFinite(value) ? Number(value.toFixed(PRICE_PRECISION)) : undefined; +} + +/** 亏损数字样式 */ +export function getLossClass(value?: null | number | string) { + const decimalValue = toFiniteDecimal(value); + return decimalValue !== undefined && decimalValue < 0 ? 'text-red-500' : ''; +} + +/** 数量 * 单价,计算金额 */ +export function multiplyPrice(quantity?: number, price?: number) { + if ( + quantity === undefined || + quantity === null || + price === undefined || + price === null + ) { + return undefined; + } + return roundPrice(Number(quantity) * Number(price)); +} + +/** 金额 / 数量,反算单价 */ +export function dividePrice(totalPrice?: number, quantity?: number) { + if (totalPrice === undefined || totalPrice === null || !quantity) { + return undefined; + } + return roundPrice(Number(totalPrice) / Number(quantity)); +} + +/** 汇总数量 */ +export function sumQuantity(list: T[], getter: (item: T) => DecimalValue) { + return sumDecimal(list, getter); +} + +/** 汇总金额 */ +export function sumPrice(list: T[], getter: (item: T) => DecimalValue) { + return sumDecimal(list, getter); +} + +/** 格式化汇总数量 */ +export function formatSumQuantity( + list: T[], + getter: (item: T) => DecimalValue, +) { + return formatQuantity(sumQuantity(list, getter)); +} + +/** 格式化汇总金额 */ +export function formatSumPrice( + list: T[], + getter: (item: T) => DecimalValue, +) { + return formatPrice(sumPrice(list, getter)); +} + +/** 格式化重量 */ +export function formatWeight(value?: null | number | string) { + const decimalValue = toFiniteDecimal(value); + return decimalValue === undefined ? '' : decimalValue.toFixed(WEIGHT_PRECISION); +} + +/** 格式化长宽高 */ +export function formatDimension(value?: null | number | string) { + const decimalValue = toFiniteDecimal(value); + return decimalValue === undefined + ? '' + : decimalValue.toFixed(DIMENSION_PRECISION); +} + +/** 格式化长宽高组合 */ +export function formatDimensionText( + length?: null | number | string, + width?: null | number | string, + height?: null | number | string, +) { + if ( + !isNullOrUndefined(length) && + !isNullOrUndefined(width) && + !isNullOrUndefined(height) + ) { + return [formatDimension(length), formatDimension(width), formatDimension(height)].join( + ' * ', + ); + } + return [ + isNullOrUndefined(length) ? undefined : `长:${formatDimension(length)}`, + isNullOrUndefined(width) ? undefined : `宽:${formatDimension(width)}`, + isNullOrUndefined(height) ? undefined : `高:${formatDimension(height)}`, + ] + .filter(Boolean) + .join(' '); +} diff --git a/apps/web-ele/src/views/wms/utils/order.ts b/apps/web-ele/src/views/wms/utils/order.ts new file mode 100644 index 000000000..5f31136c3 --- /dev/null +++ b/apps/web-ele/src/views/wms/utils/order.ts @@ -0,0 +1,12 @@ +/** + * WMS 订单工具 + */ + +/** 生成业务单号:前缀 + 月日 + 4 位随机数 */ +export function generateOrderNo(prefix: string) { + const now = new Date(); + const month = String(now.getMonth() + 1).padStart(2, '0'); + const day = String(now.getDate()).padStart(2, '0'); + const randomNo = String(Math.floor(Math.random() * 10_000)).padStart(4, '0'); + return `${prefix}${month}${day}${randomNo}`; +}