add product
This commit is contained in:
+2
-38
@@ -1,15 +1,9 @@
|
||||
import type {
|
||||
CustomerPackageItem,
|
||||
CustomerPackageStatus,
|
||||
DeliveryOperationType,
|
||||
DeliveryStatus,
|
||||
FundOperationType,
|
||||
FundRecordStatus,
|
||||
GaoCustomerPackage,
|
||||
PackageConfigStatus,
|
||||
PaymentStatus,
|
||||
RefundStatus
|
||||
PackageConfigStatus
|
||||
} from "@/types/Package";
|
||||
import type { FundOperationType, FundRecordStatus } from "@/types/SalesOrder";
|
||||
|
||||
/** 生成套餐业务幂等请求号。每次新操作必须重新生成。 */
|
||||
export function createPackageRequestNo(): string {
|
||||
@@ -90,22 +84,6 @@ export function getCustomerPackageStatusText(status?: CustomerPackageStatus): st
|
||||
return ({ ACTIVE: "进行中", FULFILLED: "已履约", CANCELLED: "已取消" } as Record<string, string>)[status || ""] || "未知";
|
||||
}
|
||||
|
||||
export function getPaymentStatusText(status?: PaymentStatus): string {
|
||||
return ({ UNPAID: "未收款", PARTIALLY_PAID: "部分收款", PAID: "已收款" } as Record<string, string>)[status || ""] || "未知";
|
||||
}
|
||||
|
||||
export function getRefundStatusText(status?: RefundStatus): string {
|
||||
return ({ NOT_REQUIRED: "无需退款", PENDING: "待退款", REFUNDED: "已退款" } as Record<string, string>)[status || ""] || "未知";
|
||||
}
|
||||
|
||||
export function getDeliveryStatusText(status?: DeliveryStatus): string {
|
||||
return ({ PENDING: "待核销", VERIFIED: "已核销", REJECTED: "已拒绝", CANCELLED: "已撤销", REVOKED: "已冲正" } as Record<string, string>)[status || ""] || "未知";
|
||||
}
|
||||
|
||||
export function getDeliveryOperationText(type?: DeliveryOperationType): string {
|
||||
return type === "REVOKE" ? "发放冲正" : "正常发放";
|
||||
}
|
||||
|
||||
export function getFundOperationText(type?: FundOperationType): string {
|
||||
return ({ RECEIVE: "线下收款", REFUND: "退款", CONFIRM_NO_REFUND: "确认无需退款", REVOKE: "资金冲正" } as Record<string, string>)[type || ""] || "未知";
|
||||
}
|
||||
@@ -118,20 +96,6 @@ export function getPackageItemAvailableQuantity(item: CustomerPackageItem): stri
|
||||
return getPackageQuantityText(item.availableQuantity);
|
||||
}
|
||||
|
||||
/** 判断套餐是否存在可用于发放的已核销收款。免费套餐可直接发放。 */
|
||||
export function canCreatePackageDelivery(customerPackage?: Pick<GaoCustomerPackage, "saleAmount" | "paidAmount">): boolean {
|
||||
const saleAmount = customerPackage?.saleAmount || 0;
|
||||
const paidAmount = customerPackage?.paidAmount || 0;
|
||||
return saleAmount === 0 || 0 < paidAmount;
|
||||
}
|
||||
|
||||
/** 判断未付清套餐的发放操作是否必须由店长执行。 */
|
||||
export function isStoreManagerRequiredForPackageDelivery(customerPackage?: Pick<GaoCustomerPackage, "saleAmount" | "paidAmount">): boolean {
|
||||
const saleAmount = customerPackage?.saleAmount || 0;
|
||||
const paidAmount = customerPackage?.paidAmount || 0;
|
||||
return 0 < paidAmount && paidAmount < saleAmount;
|
||||
}
|
||||
|
||||
function toQuantityParts(value: number | string): { value: bigint; scale: number } | undefined {
|
||||
const normalized = normalizePackageQuantity(value);
|
||||
if (!normalized) {
|
||||
|
||||
+41
-9
@@ -45,6 +45,20 @@ export const permissionCodes = {
|
||||
update: "GAO:POINT_RULE:UPDATE",
|
||||
delete: "GAO:POINT_RULE:DELETE"
|
||||
},
|
||||
productCategory: {
|
||||
create: "GAO:PRODUCT_CATEGORY:CREATE",
|
||||
read: "GAO:PRODUCT_CATEGORY:READ",
|
||||
update: "GAO:PRODUCT_CATEGORY:UPDATE"
|
||||
},
|
||||
product: {
|
||||
create: "GAO:PRODUCT:CREATE",
|
||||
read: "GAO:PRODUCT:READ",
|
||||
update: "GAO:PRODUCT:UPDATE"
|
||||
},
|
||||
productStock: {
|
||||
create: "GAO:PRODUCT_STOCK:CREATE",
|
||||
read: "GAO:PRODUCT_STOCK:READ"
|
||||
},
|
||||
packageConfig: {
|
||||
create: "GAO:PACKAGE_CONFIG:CREATE",
|
||||
read: "GAO:PACKAGE_CONFIG:READ",
|
||||
@@ -57,11 +71,17 @@ export const permissionCodes = {
|
||||
cancel: "GAO:CUSTOMER_PACKAGE:CANCEL",
|
||||
priceOverride: "GAO:CUSTOMER_PACKAGE:PRICE_OVERRIDE"
|
||||
},
|
||||
packageDelivery: {
|
||||
create: "GAO:PACKAGE_DELIVERY:CREATE",
|
||||
read: "GAO:PACKAGE_DELIVERY:READ",
|
||||
verify: "GAO:PACKAGE_DELIVERY:VERIFY",
|
||||
revoke: "GAO:PACKAGE_DELIVERY:REVOKE"
|
||||
salesOrder: {
|
||||
create: "GAO:SALES_ORDER:CREATE",
|
||||
read: "GAO:SALES_ORDER:READ",
|
||||
cancel: "GAO:SALES_ORDER:CANCEL",
|
||||
priceOverride: "GAO:SALES_ORDER:PRICE_OVERRIDE"
|
||||
},
|
||||
orderFulfillment: {
|
||||
create: "GAO:ORDER_FULFILLMENT:CREATE",
|
||||
read: "GAO:ORDER_FULFILLMENT:READ",
|
||||
verify: "GAO:ORDER_FULFILLMENT:VERIFY",
|
||||
revoke: "GAO:ORDER_FULFILLMENT:REVOKE"
|
||||
},
|
||||
fundReceive: {
|
||||
create: "GAO:FUND_RECEIVE:CREATE",
|
||||
@@ -169,6 +189,14 @@ export const gaoStoreScopePermissionCodes = [
|
||||
permissionCodes.pointRule.read,
|
||||
permissionCodes.pointRule.update,
|
||||
permissionCodes.pointRule.delete,
|
||||
permissionCodes.productCategory.create,
|
||||
permissionCodes.productCategory.read,
|
||||
permissionCodes.productCategory.update,
|
||||
permissionCodes.product.create,
|
||||
permissionCodes.product.read,
|
||||
permissionCodes.product.update,
|
||||
permissionCodes.productStock.create,
|
||||
permissionCodes.productStock.read,
|
||||
permissionCodes.packageConfig.create,
|
||||
permissionCodes.packageConfig.read,
|
||||
permissionCodes.packageConfig.update,
|
||||
@@ -177,10 +205,14 @@ export const gaoStoreScopePermissionCodes = [
|
||||
permissionCodes.customerPackage.read,
|
||||
permissionCodes.customerPackage.cancel,
|
||||
permissionCodes.customerPackage.priceOverride,
|
||||
permissionCodes.packageDelivery.create,
|
||||
permissionCodes.packageDelivery.read,
|
||||
permissionCodes.packageDelivery.verify,
|
||||
permissionCodes.packageDelivery.revoke,
|
||||
permissionCodes.salesOrder.create,
|
||||
permissionCodes.salesOrder.read,
|
||||
permissionCodes.salesOrder.cancel,
|
||||
permissionCodes.salesOrder.priceOverride,
|
||||
permissionCodes.orderFulfillment.create,
|
||||
permissionCodes.orderFulfillment.read,
|
||||
permissionCodes.orderFulfillment.verify,
|
||||
permissionCodes.orderFulfillment.revoke,
|
||||
permissionCodes.fundReceive.create,
|
||||
permissionCodes.fundReceive.verify,
|
||||
permissionCodes.fundRecord.read,
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import type { ProductCategoryStatus, ProductStatus, ProductType, StockOperationType } from "@/types/Product";
|
||||
|
||||
/** 生成产品域写操作的幂等请求号。一次失败重试应复用调用方已经生成的请求号。 */
|
||||
export function createProductRequestNo(): string {
|
||||
return window.crypto.randomUUID();
|
||||
}
|
||||
|
||||
/** 将分转换成金额展示文本。金额不使用浮点数格式化。 */
|
||||
export function formatProductAmount(cents?: number | null): string {
|
||||
if (cents === undefined || cents === null) {
|
||||
return "未设置";
|
||||
}
|
||||
|
||||
const negative = cents < 0;
|
||||
const absolute = Math.abs(Math.trunc(cents));
|
||||
return `${negative ? "-" : ""}${Math.floor(absolute / 100)}.${String(absolute % 100).padStart(2, "0")}`;
|
||||
}
|
||||
|
||||
/** 将元金额输入精确转换为分。 */
|
||||
export function parseProductAmount(value: string): number | undefined {
|
||||
const text = value.trim();
|
||||
if (!/^\d+(?:\.\d{1,2})?$/.test(text)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const [yuanText, fenText = ""] = text.split(".");
|
||||
const cents = BigInt(yuanText) * 100n + BigInt(fenText.padEnd(2, "0") || "0");
|
||||
const result = Number(cents);
|
||||
return Number.isSafeInteger(result) ? result : undefined;
|
||||
}
|
||||
|
||||
/** 规范化最多三位小数的非负数量。 */
|
||||
export function normalizeProductQuantity(value: number | string): string | undefined {
|
||||
const text = String(value).trim();
|
||||
if (!/^\d+(?:\.\d{1,3})?$/.test(text)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const [integerText, fractionText = ""] = text.split(".");
|
||||
const integer = integerText.replace(/^0+(?=\d)/, "") || "0";
|
||||
const fraction = fractionText.replace(/0+$/, "");
|
||||
return fraction ? `${integer}.${fraction}` : integer;
|
||||
}
|
||||
|
||||
export function getProductTypeText(type?: ProductType): string {
|
||||
return ({ SERVICE: "服务", GOODS: "实物", CONSUMABLE: "消耗品" } as Record<string, string>)[type || ""] || "未知";
|
||||
}
|
||||
|
||||
export function getProductStatusText(status?: ProductStatus): string {
|
||||
return ({ ACTIVE: "启用", INACTIVE: "停用" } as Record<string, string>)[status || ""] || "未知";
|
||||
}
|
||||
|
||||
export function getProductStatusTheme(status?: ProductStatus): "success" | "warning" | "default" {
|
||||
return status === "ACTIVE" ? "success" : status === "INACTIVE" ? "warning" : "default";
|
||||
}
|
||||
|
||||
export function getProductCategoryStatusText(status?: ProductCategoryStatus): string {
|
||||
return ({ ACTIVE: "启用", INACTIVE: "停用" } as Record<string, string>)[status || ""] || "未知";
|
||||
}
|
||||
|
||||
export function getProductCategoryStatusTheme(status?: ProductCategoryStatus): "success" | "warning" | "default" {
|
||||
return status === "ACTIVE" ? "success" : status === "INACTIVE" ? "warning" : "default";
|
||||
}
|
||||
|
||||
export function getStockOperationText(type?: StockOperationType): string {
|
||||
return ({
|
||||
INITIAL_IN: "期初入库",
|
||||
MANUAL_IN: "手工入库",
|
||||
MANUAL_OUT: "手工出库",
|
||||
ORDER_RESERVE: "履约预占",
|
||||
ORDER_RELEASE: "履约释放预占",
|
||||
ORDER_OUT: "履约出库",
|
||||
ORDER_REVOKE: "履约冲正入库",
|
||||
STOCKTAKE_GAIN: "盘盈",
|
||||
STOCKTAKE_LOSS: "盘亏"
|
||||
} as Record<string, string>)[type || ""] || "未知操作";
|
||||
}
|
||||
|
||||
/** 将数量转换成稳定的展示文本,兼容后端 BigDecimal 字符串。 */
|
||||
export function getProductQuantityText(value?: number | string | null): string {
|
||||
if (value === undefined || value === null || value === "") {
|
||||
return "0";
|
||||
}
|
||||
return normalizeProductQuantity(value) || "0";
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import type { FulfillmentStatus, FulfillmentType } from "@/types/Fulfillment";
|
||||
import type { FundOperationType, FundRecordStatus, SalesOrderStatus, SalesOrderType, SalesPaymentStatus, SalesRefundStatus } from "@/types/SalesOrder";
|
||||
|
||||
export function getSalesOrderTypeText(type?: SalesOrderType): string {
|
||||
return type === "PACKAGE" ? "套餐订单" : type === "DIRECT_PRODUCT" ? "直接产品订单" : "未知订单";
|
||||
}
|
||||
export function getSalesOrderStatusText(status?: SalesOrderStatus): string {
|
||||
return ({ ACTIVE: "进行中", FULFILLED: "已履约", CANCELLED: "已取消" } as Record<string, string>)[status || ""] || "未知";
|
||||
}
|
||||
export function getSalesPaymentStatusText(status?: SalesPaymentStatus): string {
|
||||
return ({ UNPAID: "未收款", PARTIALLY_PAID: "部分收款", PAID: "已收款" } as Record<string, string>)[status || ""] || "未知";
|
||||
}
|
||||
export function getSalesRefundStatusText(status?: SalesRefundStatus): string {
|
||||
return ({ NOT_REQUIRED: "无需退款", PENDING: "待处理退款", REFUNDED: "已退款" } as Record<string, string>)[status || ""] || "未知";
|
||||
}
|
||||
export function getFundOperationText(type?: FundOperationType): string {
|
||||
return ({ RECEIVE: "线下收款", REFUND: "退款", CONFIRM_NO_REFUND: "确认无需退款", REVOKE: "资金冲正" } as Record<string, string>)[type || ""] || "未知";
|
||||
}
|
||||
export function getFundStatusText(status?: FundRecordStatus): string {
|
||||
return ({ PENDING: "待核销", VERIFIED: "已生效", REJECTED: "已拒绝", CANCELLED: "已撤销" } as Record<string, string>)[status || ""] || "未知";
|
||||
}
|
||||
export function getFulfillmentTypeText(type?: FulfillmentType): string {
|
||||
return type === "PACKAGE_ENTITLEMENT" ? "套餐权益" : type === "DIRECT_PRODUCT" ? "直接产品" : "未知来源";
|
||||
}
|
||||
export function getFulfillmentStatusText(status?: FulfillmentStatus): string {
|
||||
return ({ WAITING_STOCK: "等待库存", PENDING: "待核销", VERIFIED: "已核销", REJECTED: "已拒绝", CANCELLED: "已撤销", REVOKED: "已冲正" } as Record<string, string>)[status || ""] || "未知";
|
||||
}
|
||||
export function getStatusTheme(status?: string): "success" | "warning" | "danger" | "default" {
|
||||
if (["VERIFIED", "PAID", "FULFILLED"].includes(status || "")) return "success";
|
||||
if (["PENDING", "ACTIVE", "WAITING_STOCK"].includes(status || "")) return "warning";
|
||||
if (["REJECTED", "CANCELLED"].includes(status || "")) return "danger";
|
||||
return "default";
|
||||
}
|
||||
Reference in New Issue
Block a user