feat: 积分商城-供应商-对账

This commit is contained in:
2026-09-03 18:06:07 +08:00
parent 750c36116d
commit 5c8fbddb2e
9 changed files with 1195 additions and 16 deletions
+1
View File
@@ -6,6 +6,7 @@ const suppliedServiceBaseUrl = String(process.env.SUPPLIED_SERVICE_BASE_URL || '
const addressRoutes = new Map([
['/supplierOpenApi/pointOrder/queryOrderInfo', '/supplierOpenApi/pointOrder/queryOrderInfo'],
['/supplierOpenApi/pointOrder/queryReconciliationInfo', '/supplierOpenApi/pointOrder/queryReconciliationInfo'],
['/supplierOpenApi/pointOrder/applyForInvoices', '/supplierOpenApi/pointOrder/applyForInvoices'],
['/supplierOpenApi/pointOrder/unReconciledMsg', '/supplierOpenApi/pointOrder/unReconciledMsg'],
['/supplierOpenApi/pointOrder/reconciliationResult', '/supplierOpenApi/pointOrder/reconciliationResult']
])
+12 -5
View File
@@ -20,6 +20,7 @@ const saveUser = data => {
export const useUserStore = defineStore('joyfulSelectionUser', {
state: () => ({
userId: '',
encryptedParam: '',
supplierIdentification: '',
supplierId: '',
supplierName: '',
@@ -58,10 +59,11 @@ export const useUserStore = defineStore('joyfulSelectionUser', {
this.loadUser()
}
const nextUserId = query.userId || ''
const encryptedParam = query.AplParmObjct || query.aplParmObjct || ''
if (nextUserId && nextUserId !== this.userId) {
this.userId = nextUserId
if (encryptedParam) {
this.encryptedParam = encryptedParam
this.userId = ''
this.pointsBalance = 0
}
if (!this.supplierIdentification) {
@@ -90,7 +92,10 @@ export const useUserStore = defineStore('joyfulSelectionUser', {
if (!this.loaded) {
this.loadUser()
}
if (!this.userId || !this.supplierIdentification || this.hasToken) {
if (!this.supplierIdentification || (!this.encryptedParam && this.hasToken)) {
return
}
if (!this.encryptedParam) {
return
}
if (this.loadingToken && bridgeTokenPromise) {
@@ -104,10 +109,12 @@ export const useUserStore = defineStore('joyfulSelectionUser', {
}
const data = await postFunction('supplier-token', {
userId: this.userId,
AplParmObjct: this.encryptedParam,
supplierIdentification: this.supplierIdentification
})
this.userId = data?.userId || ''
this.encryptedParam = ''
this.supplierId = data?.supplierId || this.supplierId
this.supplierName = data?.supplierName || this.supplierName
this.persistUser()
@@ -0,0 +1,551 @@
/*
Navicat Premium Dump SQL
Source Server : localhost
Source Server Type : MySQL
Source Server Version : 80046 (8.0.46)
Source Host : 127.0.0.1:10086
Source Schema : supplier_db
Target Server Type : MySQL
Target Server Version : 80046 (8.0.46)
File Encoding : 65001
Date: 02/09/2026 11:08:42
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for cartitem
-- ----------------------------
DROP TABLE IF EXISTS `cartitem`;
CREATE TABLE `cartitem` (
`id` int NOT NULL AUTO_INCREMENT,
`userId` int NOT NULL,
`productId` int NOT NULL,
`skuText` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
`quantity` int NOT NULL DEFAULT 1,
`createdAt` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` datetime(3) NOT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `CartItem_userId_productId_skuText_key`(`userId` ASC, `productId` ASC, `skuText` ASC) USING BTREE,
INDEX `CartItem_productId_fkey`(`productId` ASC) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of cartitem
-- ----------------------------
-- ----------------------------
-- Table structure for supplier_after_sale
-- ----------------------------
DROP TABLE IF EXISTS `supplier_after_sale`;
CREATE TABLE `supplier_after_sale` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '供应商售后单主键ID',
`serviceOrderId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '售后业务单号',
`supplierId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '供应商ID',
`userId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '用户ID',
`mainOrderId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '关联主单ID',
`subOrderId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '关联子单ID',
`serviceType` int NOT NULL COMMENT '售后类型:4退货,5换货',
`serviceState` int NOT NULL DEFAULT 0 COMMENT '售后状态:0商家待审核,1审核通过,2审核拒绝,3用户已寄回,4商家已收货,5已完成,6已取消',
`auditStatus` int NOT NULL DEFAULT 0 COMMENT '审核状态:0待审核,1审核通过,2审核拒绝',
`logisticsState` int NOT NULL DEFAULT 0 COMMENT '物流状态:0无物流,1待用户寄回,2用户已寄回,3商家已收货,4商家已发货,5用户已收货',
`amount` decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT '售后金额',
`reason` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '售后原因',
`auditRemark` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '审核备注',
`userLogisticsNo` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '用户寄回物流单号',
`userLogisticsCompany` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '用户寄回物流公司',
`merchantLogisticsNo` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '商家换货物流单号',
`merchantLogisticsCompany` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '商家换货物流公司',
`applyTime` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '申请时间',
`auditTime` datetime(3) NULL DEFAULT NULL COMMENT '审核时间',
`userShipTime` datetime(3) NULL DEFAULT NULL COMMENT '用户寄回时间',
`merchantReceiveTime` datetime(3) NULL DEFAULT NULL COMMENT '商家收货时间',
`merchantShipTime` datetime(3) NULL DEFAULT NULL COMMENT '商家发货时间',
`finishTime` datetime(3) NULL DEFAULT NULL COMMENT '完成时间',
`requestBody` json NULL COMMENT '原始业务请求体',
`createTime` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
`updateTime` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
`deleted` int NOT NULL DEFAULT 0 COMMENT '删除状态:0未删除,1已删除',
`reasonType` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
`problemDescription` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL,
`pickupMethod` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
`pickupName` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
`pickupMobile` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
`pickupAddress` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL,
`images` json NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `supplier_after_sale_serviceOrderId_key`(`serviceOrderId` ASC) USING BTREE,
INDEX `supplier_after_sale_supplierId_mainOrderId_idx`(`supplierId` ASC, `mainOrderId` ASC) USING BTREE,
INDEX `supplier_after_sale_supplierId_userId_idx`(`supplierId` ASC, `userId` ASC) USING BTREE,
INDEX `supplier_after_sale_subOrderId_idx`(`subOrderId` ASC) USING BTREE,
INDEX `supplier_after_sale_serviceType_serviceState_idx`(`serviceType` ASC, `serviceState` ASC) USING BTREE,
INDEX `supplier_after_sale_auditStatus_logisticsState_idx`(`auditStatus` ASC, `logisticsState` ASC) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '供应商退款售后流程表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of supplier_after_sale
-- ----------------------------
-- ----------------------------
-- Table structure for supplier_info
-- ----------------------------
DROP TABLE IF EXISTS `supplier_info`;
CREATE TABLE `supplier_info` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`supplierIdentification` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '供应商唯一标识',
`supplierId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '供应商ID',
`supplierName` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '供应商名称',
`clientId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '平台分配的客户端ID',
`clientSecret` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '平台分配的客户端密钥',
`supplierApiUrl` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '供应商开放接口地址',
`sroNo` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT 'BAB7服务商编号',
`createTime` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
`updateTime` datetime(3) NOT NULL COMMENT '更新时间',
`creator` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '创建人',
`updator` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '更新人',
`version` int NOT NULL DEFAULT 0 COMMENT '版本号',
`deleted` int NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `supplier_info_supplierIdentification_key`(`supplierIdentification` ASC) USING BTREE,
UNIQUE INDEX `supplier_info_supplierId_key`(`supplierId` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '供应商信息表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of supplier_info
-- ----------------------------
INSERT INTO `supplier_info` VALUES (1, 'joyful-selection', '99999999', '悦享优选', 'pmall_5f8c2d91a7b34e3db1c9f4e6a8d2b7c1', 'pmsec_8d7f4c1a9b3e6f2d5c8a1e7b9f4d6c2a3b8e1f5d9c7a6b4e2f1a8c3d6b9e7f', NULL, NULL, '2026-07-28 15:16:35.000', '2026-07-28 15:16:35.000', 'system', 'system', 0, 0);
-- ----------------------------
-- Table structure for supplier_invoice_info
-- ----------------------------
DROP TABLE IF EXISTS `supplier_invoice_info`;
CREATE TABLE `supplier_invoice_info` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '发票信息主键ID',
`invoiceBizId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '发票业务唯一ID,优先使用发票号或事件订单号',
`supplierId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '供应商ID',
`userId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '用户ID',
`mainOrderId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '关联主单ID',
`subOrderId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '关联子单ID',
`settlementId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '结算单号',
`invoiceCode` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '发票代码或纳税识别号',
`invoiceIds` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '发票号码列表,多个用英文逗号分隔',
`orderIds` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '关联订单号列表,多个用英文逗号分隔',
`invoiceStatus` int NOT NULL DEFAULT 0 COMMENT '发票状态:0已记录,1已申请,2已开票,3失败',
`fileId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '发票文件ID',
`filePath` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '发票文件路径',
`requestBody` json NULL COMMENT '原始业务请求体',
`createTime` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
`updateTime` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
`deleted` int NOT NULL DEFAULT 0 COMMENT '删除状态:0未删除,1已删除',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `supplier_invoice_info_invoiceBizId_key`(`invoiceBizId` ASC) USING BTREE,
INDEX `supplier_invoice_info_supplierId_mainOrderId_idx`(`supplierId` ASC, `mainOrderId` ASC) USING BTREE,
INDEX `supplier_invoice_info_settlementId_idx`(`settlementId` ASC) USING BTREE,
INDEX `supplier_invoice_info_invoiceCode_idx`(`invoiceCode` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '供应商发票信息表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of supplier_invoice_info
-- ----------------------------
INSERT INTO `supplier_invoice_info` VALUES (1, 'INV_ORD20260729134300_001', '99999999', '17a7f8ad3ee947b4a26175049a9c253d', 'ORD20260729134300', 'ORD20260729134300_001', NULL, NULL, 'INV_ORD20260729134300_001', 'ORD20260729134300_001', 2, NULL, NULL, '{\"time\": 1785303898394, \"amount\": 20.02, \"reason\": \"发票信息\", \"userId\": \"17a7f8ad3ee947b4a26175049a9c253d\", \"orderId\": \"ORD20260729134300_001\", \"orderIds\": \"ORD20260729134300_001\", \"orderType\": 11, \"invoiceIds\": \"INV_ORD20260729134300_001\", \"subOrderId\": \"ORD20260729134300_001\", \"supplierId\": \"99999999\", \"mainOrderId\": \"ORD20260729134300\", \"invoiceBizId\": \"INV_ORD20260729134300_001\"}', '2026-07-29 05:45:01.657', '2026-07-29 05:45:01.657', 0);
-- ----------------------------
-- Table structure for supplier_order_main
-- ----------------------------
DROP TABLE IF EXISTS `supplier_order_main`;
CREATE TABLE `supplier_order_main` (
`id` int NOT NULL AUTO_INCREMENT,
`orderId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '主订单ID',
`orderNumberId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '主订单编号',
`supplierId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '供应商ID',
`userId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '平台用户ID',
`aplName` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '应用名称',
`addressId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '收货地址ID',
`remark` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '订单备注',
`createTime` datetime(3) NULL DEFAULT NULL COMMENT '订单创建时间',
`updateTime` datetime(3) NULL DEFAULT NULL COMMENT '订单更新时间',
`deliveryTime` datetime(3) NULL DEFAULT NULL COMMENT '发货时间',
`orderFinishTime` datetime(3) NULL DEFAULT NULL COMMENT '订单完成时间',
`completeTime` datetime(3) NULL DEFAULT NULL COMMENT '交易完成时间',
`deliveryStatus` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '配送状态',
`freightCost` decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT '运费积分金额',
`wPayOrAPayFreightCost` decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT '微信或支付宝支付运费金额',
`refund` decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT '积分退款金额',
`wPayOrAPayRefund` decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT '微信或支付宝退款金额',
`logisticsOrderId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '物流单号',
`crrgBsnNm` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '承运商名称',
`orderState` int NOT NULL DEFAULT 0 COMMENT '订单状态:0待付款,1待发货,2待收货,3已取消,4已完成兼容旧值,5已完成,6换货,7退货,8废除',
`isSplit` tinyint NOT NULL DEFAULT 0 COMMENT '主单是否拆单:0未拆单,1已拆单',
`splitTime` datetime(3) NULL DEFAULT NULL COMMENT '主单拆单时间',
`totalPrice` decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT '订单总金额',
`wPayOrAPay` decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT '微信或支付宝支付金额',
`pointsPrice` decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT '积分支付金额',
`invoiceCode` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '发票编码',
`createAt` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '记录创建时间',
`updateAt` datetime(3) NOT NULL COMMENT '记录更新时间',
`deleted` int NOT NULL DEFAULT 0 COMMENT '删除状态:0未删除,1已删除',
`payTime` datetime NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `supplier_order_main_orderId_key`(`orderId` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '供应商主订单表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of supplier_order_main
-- ----------------------------
INSERT INTO `supplier_order_main` VALUES (1, 'ORD20260901165221', 'TR20260901165221752', '99999999', 'c281e124321c8db3a14f0a7c86046c3c', '积分商城', 'addr-1788252731181', '', '2026-09-01 08:52:21.752', '2026-09-01 08:55:56.487', '2026-09-01 08:55:23.144', NULL, '2026-09-01 08:55:56.487', '1', 0.00, 0.00, 0.00, 0.00, '20260901', '韵达快递', 5, 1, '2026-09-01 08:52:25.891', 10.01, 0.00, 10.01, NULL, '2026-09-01 08:52:21.766', '2026-09-01 08:55:56.526', 0, '2026-09-01 08:52:26');
-- ----------------------------
-- Table structure for supplier_order_operate_log
-- ----------------------------
DROP TABLE IF EXISTS `supplier_order_operate_log`;
CREATE TABLE `supplier_order_operate_log` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '订单操作日志主键ID',
`supplierId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '供应商ID',
`userId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '用户ID',
`mainOrderId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '主单ID',
`subOrderId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '子单ID',
`operateType` int NOT NULL COMMENT '操作类型:1创建待支付,2支付成功,3拆单,4取消主单,5取消子单,6取消已支付未拆单整单,7确认收货,8已完成,9退款,10换货,11废除子单,12发票信息',
`beforeState` int NULL DEFAULT NULL COMMENT '操作前订单状态',
`afterState` int NULL DEFAULT NULL COMMENT '操作后订单状态',
`beforeSplit` int NULL DEFAULT NULL COMMENT '操作前拆单状态:0未拆单,1已拆单',
`afterSplit` int NULL DEFAULT NULL COMMENT '操作后拆单状态:0未拆单,1已拆单',
`remark` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '操作备注',
`operator` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '操作人或系统标识',
`createTime` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
`deleted` int NOT NULL DEFAULT 0 COMMENT '删除状态:0未删除,1已删除',
PRIMARY KEY (`id`) USING BTREE,
INDEX `supplier_order_operate_log_supplierId_mainOrderId_idx`(`supplierId` ASC, `mainOrderId` ASC) USING BTREE,
INDEX `supplier_order_operate_log_subOrderId_idx`(`subOrderId` ASC) USING BTREE,
INDEX `supplier_order_operate_log_operateType_idx`(`operateType` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '供应商订单操作日志表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of supplier_order_operate_log
-- ----------------------------
INSERT INTO `supplier_order_operate_log` VALUES (1, '99999999', 'c281e124321c8db3a14f0a7c86046c3c', 'ORD20260901165221', 'ORD20260901165221_001', 7, 1, 2, NULL, NULL, NULL, 'api', '2026-09-01 08:55:23.165', 0);
INSERT INTO `supplier_order_operate_log` VALUES (2, '99999999', 'c281e124321c8db3a14f0a7c86046c3c', 'ORD20260901165221', 'ORD20260901165221_001', 8, 2, 5, NULL, NULL, '确认收货', 'system', '2026-09-01 08:55:56.515', 0);
-- ----------------------------
-- Table structure for supplier_order_product
-- ----------------------------
DROP TABLE IF EXISTS `supplier_order_product`;
CREATE TABLE `supplier_order_product` (
`id` int NOT NULL AUTO_INCREMENT,
`subOrderId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '所属子订单ID',
`sku` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '商品SKU编码',
`number` int NOT NULL COMMENT '商品购买数量',
`price` decimal(10, 2) NOT NULL COMMENT '商品成交单价',
`name` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '商品名称快照',
`taxRate` decimal(5, 4) NOT NULL DEFAULT 0.1300 COMMENT '商品税率快照',
`productImgUrl` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '商品图片地址',
`fileId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '平台文件ID或图片ID',
`filePath` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '文件存储路径',
`picInfo` json NULL COMMENT '商品图片列表快照,JSON数组',
`createAt` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '记录创建时间',
`updateAt` datetime(3) NOT NULL COMMENT '记录更新时间',
`deleted` int NOT NULL DEFAULT 0 COMMENT '删除状态:0未删除,1已删除',
PRIMARY KEY (`id`) USING BTREE,
INDEX `supplier_order_product_subOrderId_idx`(`subOrderId` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '供应商子订单商品表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of supplier_order_product
-- ----------------------------
INSERT INTO `supplier_order_product` VALUES (1, 'ORD20260901165221_001', '2-cream-standard', 1, 10.01, '手机壳', 0.1300, 'https://ts3.tc.mm.bing.net/th/id/OIP-C.MkmCbLoY2S4zqzMeHvCDMQHaHD?w=128&h=108&c=7&qlt=90&bgcl=f61537&r=0&o=6&dpr=1.3&pid=13.1', 'https://ts3.tc.mm.bing.net/th/id/OIP-C.MkmCbLoY2S4zqzMeHvCDMQHaHD?w=128&h=108&c=7&qlt=90&bgcl=f61537&r=0&o=6&dpr=1.3&pid=13.1', 'https://ts3.tc.mm.bing.net/th/id/OIP-C.MkmCbLoY2S4zqzMeHvCDMQHaHD?w=128&h=108&c=7&qlt=90&bgcl=f61537&r=0&o=6&dpr=1.3&pid=13.1', '[\"https://ts3.tc.mm.bing.net/th/id/OIP-C.MkmCbLoY2S4zqzMeHvCDMQHaHD?w=128&h=108&c=7&qlt=90&bgcl=f61537&r=0&o=6&dpr=1.3&pid=13.1\"]', '2026-09-01 08:52:21.780', '2026-09-01 08:52:21.780', 0);
-- ----------------------------
-- Table structure for supplier_order_push_log
-- ----------------------------
DROP TABLE IF EXISTS `supplier_order_push_log`;
CREATE TABLE `supplier_order_push_log` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '订单推送日志主键ID',
`supplierId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '供应商ID',
`userId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '用户ID',
`mainOrderId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '主单ID',
`orderId` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '推送订单ID,多个子单用英文逗号分隔',
`orderType` int NULL DEFAULT NULL COMMENT '推送事件类型:1取消主单,2拆单子单,3取消子单,7取消已支付未拆单整单',
`apiPath` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '推送接口路径',
`requestBody` json NULL COMMENT '推送请求体',
`responseBody` json NULL COMMENT '推送响应体',
`httpStatus` int NULL DEFAULT NULL COMMENT 'HTTP状态码',
`resultCode` int NULL DEFAULT NULL COMMENT '远程业务返回码',
`pushStatus` int NOT NULL DEFAULT 0 COMMENT '推送状态:0待推送,1推送成功,2推送失败',
`retryCount` int NOT NULL DEFAULT 0 COMMENT '重试次数',
`errorMessage` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '失败原因',
`lastPushTime` datetime(3) NULL DEFAULT NULL COMMENT '最后推送时间',
`nextRetryTime` datetime(3) NULL DEFAULT NULL COMMENT '下次重试时间',
`createTime` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
`updateTime` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
`deleted` int NOT NULL DEFAULT 0 COMMENT '删除状态:0未删除,1已删除',
PRIMARY KEY (`id`) USING BTREE,
INDEX `supplier_order_push_log_supplierId_mainOrderId_idx`(`supplierId` ASC, `mainOrderId` ASC) USING BTREE,
INDEX `supplier_order_push_log_orderType_pushStatus_idx`(`orderType` ASC, `pushStatus` ASC) USING BTREE,
INDEX `supplier_order_push_log_nextRetryTime_idx`(`nextRetryTime` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '供应商订单远程推送日志表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of supplier_order_push_log
-- ----------------------------
INSERT INTO `supplier_order_push_log` VALUES (1, '99999999', 'c281e124321c8db3a14f0a7c86046c3c', 'ORD20260901165221', 'ORD20260901165221_001', 6, '/pointOrder/pushOrderInfoMsg', '{\"time\": 1788252956480, \"userId\": \"c281e124321c8db3a14f0a7c86046c3c\", \"orderId\": \"ORD20260901165221_001\", \"orderType\": 6, \"supplierId\": \"99999999\", \"mainOrderId\": \"ORD20260901165221\"}', '{\"message\": \"成功\", \"resultCode\": 0}', 200, 0, 1, 0, NULL, '2026-09-01 08:55:56.601', NULL, '2026-09-01 08:55:56.534', '2026-09-01 08:55:56.604', 0);
-- ----------------------------
-- Table structure for supplier_order_sub
-- ----------------------------
DROP TABLE IF EXISTS `supplier_order_sub`;
CREATE TABLE `supplier_order_sub` (
`id` int NOT NULL AUTO_INCREMENT,
`orderId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '子订单ID',
`orderNumberId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '子订单编号',
`mainOrderId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '所属主订单ID',
`supplierId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '供应商ID',
`token` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '平台桥接访问令牌快照',
`userId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '平台用户ID',
`aplName` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '应用名称',
`addressId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '收货地址ID',
`remark` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '订单备注',
`createTime` datetime(3) NULL DEFAULT NULL COMMENT '订单创建时间',
`updateTime` datetime(3) NULL DEFAULT NULL COMMENT '订单更新时间',
`deliveryTime` datetime(3) NULL DEFAULT NULL COMMENT '发货时间',
`orderFinishTime` datetime(3) NULL DEFAULT NULL COMMENT '订单完成时间',
`completeTime` datetime(3) NULL DEFAULT NULL COMMENT '交易完成时间',
`deliveryStatus` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '配送状态',
`freightCost` decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT '运费积分金额',
`wPayOrAPayFreightCost` decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT '微信或支付宝支付运费金额',
`refund` decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT '积分退款金额',
`wPayOrAPayRefund` decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT '微信或支付宝退款金额',
`logisticsOrderId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '物流单号',
`crrgBsnNm` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '承运商名称',
`orderState` int NOT NULL DEFAULT 0 COMMENT '订单状态:0待付款,1待发货,2待收货,3已取消,4已完成兼容旧值,5已完成,6换货,7退货,8废除',
`totalPrice` decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT '子订单总金额',
`wPayOrAPay` decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT '微信或支付宝支付金额',
`pointsPrice` decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT '积分支付金额',
`invoiceCode` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '发票编码',
`createAt` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '记录创建时间',
`updateAt` datetime(3) NOT NULL COMMENT '记录更新时间',
`deleted` int NOT NULL DEFAULT 0 COMMENT '删除状态:0未删除,1已删除',
`payTime` datetime NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `supplier_order_sub_orderId_key`(`orderId` ASC) USING BTREE,
INDEX `supplier_order_sub_mainOrderId_idx`(`mainOrderId` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '供应商子订单表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of supplier_order_sub
-- ----------------------------
INSERT INTO `supplier_order_sub` VALUES (1, 'ORD20260901165221_001', 'TR20260901165221752_001', 'ORD20260901165221', '99999999', NULL, 'c281e124321c8db3a14f0a7c86046c3c', '积分商城', 'addr-1788252731181', '', '2026-09-01 08:52:21.752', '2026-09-01 08:55:56.487', '2026-09-01 08:55:23.144', '2026-09-01 08:55:56.487', '2026-09-01 08:55:56.487', '1', 0.00, 0.00, 0.00, 0.00, '20260901', '韵达快递', 5, 10.01, 0.00, 10.01, NULL, '2026-09-01 08:52:21.776', '2026-09-01 08:55:56.509', 0, '2026-09-01 08:52:26');
-- ----------------------------
-- Table structure for supplier_points_ledger
-- ----------------------------
DROP TABLE IF EXISTS `supplier_points_ledger`;
CREATE TABLE `supplier_points_ledger` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '积分流水主键ID',
`ledgerNo` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '流水号,业务唯一',
`supplierId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '供应商ID',
`userId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户ID',
`mainOrderId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '关联主单ID',
`subOrderId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '关联子单ID',
`bizType` int NOT NULL COMMENT '业务类型:1支付消费,2取消返还,3退货退款,4人工调整',
`direction` int NOT NULL COMMENT '流水方向:1增加,2扣减',
`points` decimal(10, 2) NOT NULL COMMENT '积分变动金额',
`beforePoints` decimal(10, 2) NULL DEFAULT NULL COMMENT '变动前积分余额',
`afterPoints` decimal(10, 2) NULL DEFAULT NULL COMMENT '变动后积分余额',
`remark` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '流水备注',
`createTime` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
`updateTime` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
`deleted` int NOT NULL DEFAULT 0 COMMENT '删除状态:0未删除,1已删除',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `supplier_points_ledger_ledgerNo_key`(`ledgerNo` ASC) USING BTREE,
INDEX `supplier_points_ledger_supplierId_userId_idx`(`supplierId` ASC, `userId` ASC) USING BTREE,
INDEX `supplier_points_ledger_mainOrderId_idx`(`mainOrderId` ASC) USING BTREE,
INDEX `supplier_points_ledger_subOrderId_idx`(`subOrderId` ASC) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '供应商用户积分消费流水表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of supplier_points_ledger
-- ----------------------------
-- ----------------------------
-- Table structure for supplier_product
-- ----------------------------
DROP TABLE IF EXISTS `supplier_product`;
CREATE TABLE `supplier_product` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '商品主键ID',
`sku` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '商品SKU编码',
`number` int NOT NULL DEFAULT 0 COMMENT '默认购买数量或导入数量',
`price` decimal(10, 2) NOT NULL COMMENT '商品销售价格',
`name` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '商品名称',
`taxRate` decimal(5, 4) NOT NULL DEFAULT 0.1300 COMMENT '商品税率',
`picInfo` json NULL COMMENT '商品图片列表,JSON数组',
`description` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '商品简短描述',
`detail` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '商品详情描述',
`originPrice` decimal(10, 2) NULL DEFAULT NULL COMMENT '商品原价',
`imageUrl` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '商品主图地址',
`categoryId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '商品分类ID',
`category` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '商品分类名称',
`tag` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '商品标签',
`sales` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '商品销量展示文案',
`stock` int NOT NULL DEFAULT 0 COMMENT '商品库存',
`sortOrder` int NOT NULL DEFAULT 0 COMMENT '排序值,越小越靠前',
`enabled` tinyint(1) NOT NULL DEFAULT 1 COMMENT '是否启用',
`deleted` int NOT NULL DEFAULT 0 COMMENT '删除状态:0未删除,1已删除',
`createdAt` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
`updatedAt` datetime(3) NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `supplier_product_sku_key`(`sku` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 25 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '供应商商品信息表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of supplier_product
-- ----------------------------
INSERT INTO `supplier_product` VALUES (1, 'SKU001', 2, 149.99, '蓝牙耳机', 0.1300, '[\"https://ts3.tc.mm.bing.net/th/id/OIP-C.im_WvX9bWGyvagEZp4Pz0AHaGX?w=142&h=108&c=7&qlt=90&bgcl=a01e15&r=0&o=6&dpr=1.3&pid=13.1\", \"https://ts3.tc.mm.bing.net/th/id/OIP-C.MkmCbLoY2S4zqzMeHvCDMQHaHD?w=128&h=108&c=7&qlt=90&bgcl=f61537&r=0&o=6&dpr=1.3&pid=13.1\"]', '轻盈佩戴,稳定连接,通勤运动都好用', '轻盈佩戴,稳定连接,通勤运动都好用。精选品质商品,适合积分商城兑换和日常福利采购场景。', 199.99, 'https://ts3.tc.mm.bing.net/th/id/OIP-C.im_WvX9bWGyvagEZp4Pz0AHaGX?w=142&h=108&c=7&qlt=90&bgcl=a01e15&r=0&o=6&dpr=1.3&pid=13.1', 'digitalAppliance', '数码家电', '积分兑换', '1.2万件', 180, 1, 1, 0, '2026-07-28 09:43:03.406', '2026-07-28 09:43:03.406');
INSERT INTO `supplier_product` VALUES (2, 'SKU002', 1, 10.01, '手机壳', 0.1300, '[\"https://ts3.tc.mm.bing.net/th/id/OIP-C.MkmCbLoY2S4zqzMeHvCDMQHaHD?w=128&h=108&c=7&qlt=90&bgcl=f61537&r=0&o=6&dpr=1.3&pid=13.1\", \"https://ts2.tc.mm.bing.net/th/id/OIP-C.CKSBSB33LwT9qJD_Yhb1mwHaKk?w=132&h=108&c=7&qlt=90&bgcl=2e287d&r=0&o=6&dpr=1.3&pid=13.1\"]', '防滑耐磨,贴合机身,日常保护更安心', '防滑耐磨,贴合机身,日常保护更安心。精选品质商品,适合积分商城兑换和日常福利采购场景。', 19.90, 'https://ts3.tc.mm.bing.net/th/id/OIP-C.MkmCbLoY2S4zqzMeHvCDMQHaHD?w=128&h=108&c=7&qlt=90&bgcl=f61537&r=0&o=6&dpr=1.3&pid=13.1', 'digitalAppliance', '数码家电', '赠品', '5632件', 187, 2, 1, 0, '2026-07-28 09:43:03.427', '2026-07-28 09:43:03.427');
INSERT INTO `supplier_product` VALUES (3, 'SKU003', 1, 99.00, '智能音箱 Pro', 0.1300, '[\"https://ts2.tc.mm.bing.net/th/id/OIP-C.CKSBSB33LwT9qJD_Yhb1mwHaKk?w=132&h=108&c=7&qlt=90&bgcl=2e287d&r=0&o=6&dpr=1.3&pid=13.1\", \"https://tse1-mm.cn.bing.net/th/id/OIP-C.StrDRqennoZNbzSPZapKZwHaEJ?w=286&h=180&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3\"]', '语音唤醒,沉浸音效,适合卧室和书房', '语音唤醒,沉浸音效,适合卧室和书房。精选品质商品,适合积分商城兑换和日常福利采购场景。', 139.00, 'https://ts2.tc.mm.bing.net/th/id/OIP-C.CKSBSB33LwT9qJD_Yhb1mwHaKk?w=132&h=108&c=7&qlt=90&bgcl=2e287d&r=0&o=6&dpr=1.3&pid=13.1', 'digitalAppliance', '数码家电', '热门推荐', '2.1万件', 194, 3, 1, 0, '2026-07-28 09:43:03.431', '2026-07-28 09:43:03.431');
INSERT INTO `supplier_product` VALUES (4, 'SKU004', 1, 129.00, '奶油白迷你烤箱', 0.1300, '[\"https://tse1-mm.cn.bing.net/th/id/OIP-C.StrDRqennoZNbzSPZapKZwHaEJ?w=286&h=180&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3\", \"https://tse3-mm.cn.bing.net/th/id/OIP-C.ynSetSr3z884UC6sEp4yiwHaEJ?w=331&h=186&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3\"]', '小巧不占地,早餐烘焙好帮手', '小巧不占地,早餐烘焙好帮手。精选品质商品,适合积分商城兑换和日常福利采购场景。', 169.00, 'https://tse1-mm.cn.bing.net/th/id/OIP-C.StrDRqennoZNbzSPZapKZwHaEJ?w=286&h=180&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3', 'homeLiving', '居家生活', '新品上架', '1.2万件', 201, 4, 1, 0, '2026-07-28 09:43:03.435', '2026-07-28 09:43:03.435');
INSERT INTO `supplier_product` VALUES (5, 'SKU005', 1, 69.90, '北欧陶瓷餐具套装', 0.1300, '[\"https://tse3-mm.cn.bing.net/th/id/OIP-C.ynSetSr3z884UC6sEp4yiwHaEJ?w=331&h=186&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3\", \"https://ts3.tc.mm.bing.net/th/id/OIP-C.im_WvX9bWGyvagEZp4Pz0AHaGX?w=142&h=108&c=7&qlt=90&bgcl=a01e15&r=0&o=6&dpr=1.3&pid=13.1\"]', '简约釉色,日常用餐更有仪式感', '简约釉色,日常用餐更有仪式感。精选品质商品,适合积分商城兑换和日常福利采购场景。', 99.90, 'https://tse3-mm.cn.bing.net/th/id/OIP-C.ynSetSr3z884UC6sEp4yiwHaEJ?w=331&h=186&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3', 'homeLiving', '居家生活', '品质精选', '6453件', 208, 5, 1, 0, '2026-07-28 09:43:03.438', '2026-07-28 09:43:03.438');
INSERT INTO `supplier_product` VALUES (6, 'SKU006', 1, 179.00, '纯棉舒适四件套', 0.1300, '[\"https://ts3.tc.mm.bing.net/th/id/OIP-C.im_WvX9bWGyvagEZp4Pz0AHaGX?w=142&h=108&c=7&qlt=90&bgcl=a01e15&r=0&o=6&dpr=1.3&pid=13.1\", \"https://ts3.tc.mm.bing.net/th/id/OIP-C.MkmCbLoY2S4zqzMeHvCDMQHaHD?w=128&h=108&c=7&qlt=90&bgcl=f61537&r=0&o=6&dpr=1.3&pid=13.1\"]', '柔软亲肤,安心睡眠,四季可用', '柔软亲肤,安心睡眠,四季可用。精选品质商品,适合积分商城兑换和日常福利采购场景。', 229.00, 'https://ts3.tc.mm.bing.net/th/id/OIP-C.im_WvX9bWGyvagEZp4Pz0AHaGX?w=142&h=108&c=7&qlt=90&bgcl=a01e15&r=0&o=6&dpr=1.3&pid=13.1', 'homeLiving', '居家生活', '积分兑换', '8321件', 215, 6, 1, 0, '2026-07-28 09:43:03.441', '2026-07-28 09:43:03.441');
INSERT INTO `supplier_product` VALUES (7, 'SKU007', 1, 99.90, '植萃保湿护肤礼盒', 0.1300, '[\"https://ts3.tc.mm.bing.net/th/id/OIP-C.MkmCbLoY2S4zqzMeHvCDMQHaHD?w=128&h=108&c=7&qlt=90&bgcl=f61537&r=0&o=6&dpr=1.3&pid=13.1\", \"https://ts2.tc.mm.bing.net/th/id/OIP-C.CKSBSB33LwT9qJD_Yhb1mwHaKk?w=132&h=108&c=7&qlt=90&bgcl=2e287d&r=0&o=6&dpr=1.3&pid=13.1\"]', '补水保湿,清爽不黏腻', '补水保湿,清爽不黏腻。精选品质商品,适合积分商城兑换和日常福利采购场景。', 139.90, 'https://ts3.tc.mm.bing.net/th/id/OIP-C.MkmCbLoY2S4zqzMeHvCDMQHaHD?w=128&h=108&c=7&qlt=90&bgcl=f61537&r=0&o=6&dpr=1.3&pid=13.1', 'beautyCare', '美妆个护', '礼盒精选', '4820件', 222, 7, 1, 0, '2026-07-28 09:43:03.443', '2026-07-28 09:43:03.443');
INSERT INTO `supplier_product` VALUES (8, 'SKU008', 1, 59.90, '香氛洗护旅行套装', 0.1300, '[\"https://ts2.tc.mm.bing.net/th/id/OIP-C.CKSBSB33LwT9qJD_Yhb1mwHaKk?w=132&h=108&c=7&qlt=90&bgcl=2e287d&r=0&o=6&dpr=1.3&pid=13.1\", \"https://tse1-mm.cn.bing.net/th/id/OIP-C.StrDRqennoZNbzSPZapKZwHaEJ?w=286&h=180&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3\"]', '温和清洁,清新留香,出行便携', '温和清洁,清新留香,出行便携。精选品质商品,适合积分商城兑换和日常福利采购场景。', 89.90, 'https://ts2.tc.mm.bing.net/th/id/OIP-C.CKSBSB33LwT9qJD_Yhb1mwHaKk?w=132&h=108&c=7&qlt=90&bgcl=2e287d&r=0&o=6&dpr=1.3&pid=13.1', 'beautyCare', '美妆个护', '新品上架', '7932件', 229, 8, 1, 0, '2026-07-28 09:43:03.446', '2026-07-28 09:43:03.446');
INSERT INTO `supplier_product` VALUES (9, 'SKU009', 1, 49.90, '便携补光化妆镜', 0.1300, '[\"https://tse1-mm.cn.bing.net/th/id/OIP-C.StrDRqennoZNbzSPZapKZwHaEJ?w=286&h=180&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3\", \"https://tse3-mm.cn.bing.net/th/id/OIP-C.ynSetSr3z884UC6sEp4yiwHaEJ?w=331&h=186&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3\"]', '高清镜面,柔光补妆,随身携带', '高清镜面,柔光补妆,随身携带。精选品质商品,适合积分商城兑换和日常福利采购场景。', 79.90, 'https://tse1-mm.cn.bing.net/th/id/OIP-C.StrDRqennoZNbzSPZapKZwHaEJ?w=286&h=180&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3', 'beautyCare', '美妆个护', '热门推荐', '3651件', 236, 9, 1, 0, '2026-07-28 09:43:03.450', '2026-07-28 09:43:03.450');
INSERT INTO `supplier_product` VALUES (10, 'SKU010', 1, 59.90, '橙意零食礼盒', 0.1300, '[\"https://tse3-mm.cn.bing.net/th/id/OIP-C.ynSetSr3z884UC6sEp4yiwHaEJ?w=331&h=186&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3\", \"https://ts3.tc.mm.bing.net/th/id/OIP-C.im_WvX9bWGyvagEZp4Pz0AHaGX?w=142&h=108&c=7&qlt=90&bgcl=a01e15&r=0&o=6&dpr=1.3&pid=13.1\"]', '精选零食组合,办公室分享刚刚好', '精选零食组合,办公室分享刚刚好。精选品质商品,适合积分商城兑换和日常福利采购场景。', 89.90, 'https://tse3-mm.cn.bing.net/th/id/OIP-C.ynSetSr3z884UC6sEp4yiwHaEJ?w=331&h=186&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3', 'foodDrink', '食品饮料', '礼盒精选', '6324件', 243, 10, 1, 0, '2026-07-28 09:43:03.453', '2026-07-28 09:43:03.453');
INSERT INTO `supplier_product` VALUES (11, 'SKU011', 1, 49.90, '咖啡随行杯组合', 0.1300, '[\"https://ts3.tc.mm.bing.net/th/id/OIP-C.im_WvX9bWGyvagEZp4Pz0AHaGX?w=142&h=108&c=7&qlt=90&bgcl=a01e15&r=0&o=6&dpr=1.3&pid=13.1\", \"https://ts3.tc.mm.bing.net/th/id/OIP-C.MkmCbLoY2S4zqzMeHvCDMQHaHD?w=128&h=108&c=7&qlt=90&bgcl=f61537&r=0&o=6&dpr=1.3&pid=13.1\"]', '锁温防漏,通勤随行更方便', '锁温防漏,通勤随行更方便。精选品质商品,适合积分商城兑换和日常福利采购场景。', 69.90, 'https://ts3.tc.mm.bing.net/th/id/OIP-C.im_WvX9bWGyvagEZp4Pz0AHaGX?w=142&h=108&c=7&qlt=90&bgcl=a01e15&r=0&o=6&dpr=1.3&pid=13.1', 'foodDrink', '食品饮料', '积分兑换', '3520件', 250, 11, 1, 0, '2026-07-28 09:43:03.456', '2026-07-28 09:43:03.456');
INSERT INTO `supplier_product` VALUES (12, 'SKU012', 1, 69.90, '下午茶点心礼盒', 0.1300, '[\"https://ts3.tc.mm.bing.net/th/id/OIP-C.MkmCbLoY2S4zqzMeHvCDMQHaHD?w=128&h=108&c=7&qlt=90&bgcl=f61537&r=0&o=6&dpr=1.3&pid=13.1\", \"https://ts2.tc.mm.bing.net/th/id/OIP-C.CKSBSB33LwT9qJD_Yhb1mwHaKk?w=132&h=108&c=7&qlt=90&bgcl=2e287d&r=0&o=6&dpr=1.3&pid=13.1\"]', '多种风味,一盒满足甜咸口味', '多种风味,一盒满足甜咸口味。精选品质商品,适合积分商城兑换和日常福利采购场景。', 99.90, 'https://ts3.tc.mm.bing.net/th/id/OIP-C.MkmCbLoY2S4zqzMeHvCDMQHaHD?w=128&h=108&c=7&qlt=90&bgcl=f61537&r=0&o=6&dpr=1.3&pid=13.1', 'foodDrink', '食品饮料', '品质精选', '4891件', 257, 12, 1, 0, '2026-07-28 09:43:03.459', '2026-07-28 09:43:03.459');
INSERT INTO `supplier_product` VALUES (13, 'SKU013', 1, 39.90, '安心儿童水杯', 0.1300, '[\"https://ts2.tc.mm.bing.net/th/id/OIP-C.CKSBSB33LwT9qJD_Yhb1mwHaKk?w=132&h=108&c=7&qlt=90&bgcl=2e287d&r=0&o=6&dpr=1.3&pid=13.1\", \"https://tse1-mm.cn.bing.net/th/id/OIP-C.StrDRqennoZNbzSPZapKZwHaEJ?w=286&h=180&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3\"]', '轻巧易握,防摔耐用,出门好携带', '轻巧易握,防摔耐用,出门好携带。精选品质商品,适合积分商城兑换和日常福利采购场景。', 59.90, 'https://ts2.tc.mm.bing.net/th/id/OIP-C.CKSBSB33LwT9qJD_Yhb1mwHaKk?w=132&h=108&c=7&qlt=90&bgcl=2e287d&r=0&o=6&dpr=1.3&pid=13.1', 'motherBaby', '母婴玩具', '新品上架', '4250件', 264, 13, 1, 0, '2026-07-28 09:43:03.462', '2026-07-28 09:43:03.462');
INSERT INTO `supplier_product` VALUES (14, 'SKU014', 1, 89.00, '益智积木套装', 0.1300, '[\"https://tse1-mm.cn.bing.net/th/id/OIP-C.StrDRqennoZNbzSPZapKZwHaEJ?w=286&h=180&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3\", \"https://tse3-mm.cn.bing.net/th/id/OIP-C.ynSetSr3z884UC6sEp4yiwHaEJ?w=331&h=186&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3\"]', '色彩柔和,锻炼动手能力', '色彩柔和,锻炼动手能力。精选品质商品,适合积分商城兑换和日常福利采购场景。', 129.00, 'https://tse1-mm.cn.bing.net/th/id/OIP-C.StrDRqennoZNbzSPZapKZwHaEJ?w=286&h=180&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3', 'motherBaby', '母婴玩具', '热门推荐', '2186件', 271, 14, 1, 0, '2026-07-28 09:43:03.465', '2026-07-28 09:43:03.465');
INSERT INTO `supplier_product` VALUES (15, 'SKU015', 1, 69.90, '柔光儿童夜灯', 0.1300, '[\"https://tse3-mm.cn.bing.net/th/id/OIP-C.ynSetSr3z884UC6sEp4yiwHaEJ?w=331&h=186&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3\", \"https://ts3.tc.mm.bing.net/th/id/OIP-C.im_WvX9bWGyvagEZp4Pz0AHaGX?w=142&h=108&c=7&qlt=90&bgcl=a01e15&r=0&o=6&dpr=1.3&pid=13.1\"]', '温和光线,陪伴睡前时光', '温和光线,陪伴睡前时光。精选品质商品,适合积分商城兑换和日常福利采购场景。', 99.90, 'https://tse3-mm.cn.bing.net/th/id/OIP-C.ynSetSr3z884UC6sEp4yiwHaEJ?w=331&h=186&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3', 'motherBaby', '母婴玩具', '品质精选', '3548件', 278, 15, 1, 0, '2026-07-28 09:43:03.469', '2026-07-28 09:43:03.469');
INSERT INTO `supplier_product` VALUES (16, 'SKU016', 1, 149.00, '大容量电脑背包', 0.1300, '[\"https://ts3.tc.mm.bing.net/th/id/OIP-C.im_WvX9bWGyvagEZp4Pz0AHaGX?w=142&h=108&c=7&qlt=90&bgcl=a01e15&r=0&o=6&dpr=1.3&pid=13.1\", \"https://ts3.tc.mm.bing.net/th/id/OIP-C.MkmCbLoY2S4zqzMeHvCDMQHaHD?w=128&h=108&c=7&qlt=90&bgcl=f61537&r=0&o=6&dpr=1.3&pid=13.1\"]', '分区收纳,通勤出行更轻松', '分区收纳,通勤出行更轻松。精选品质商品,适合积分商城兑换和日常福利采购场景。', 199.00, 'https://ts3.tc.mm.bing.net/th/id/OIP-C.im_WvX9bWGyvagEZp4Pz0AHaGX?w=142&h=108&c=7&qlt=90&bgcl=a01e15&r=0&o=6&dpr=1.3&pid=13.1', 'fashionBag', '服饰鞋包', '积分兑换', '1.6万件', 285, 16, 1, 0, '2026-07-28 09:43:03.472', '2026-07-28 09:43:03.472');
INSERT INTO `supplier_product` VALUES (17, 'SKU017', 1, 79.90, '轻巧通勤斜挎包', 0.1300, '[\"https://ts3.tc.mm.bing.net/th/id/OIP-C.MkmCbLoY2S4zqzMeHvCDMQHaHD?w=128&h=108&c=7&qlt=90&bgcl=f61537&r=0&o=6&dpr=1.3&pid=13.1\", \"https://ts2.tc.mm.bing.net/th/id/OIP-C.CKSBSB33LwT9qJD_Yhb1mwHaKk?w=132&h=108&c=7&qlt=90&bgcl=2e287d&r=0&o=6&dpr=1.3&pid=13.1\"]', '简洁百搭,日常出门更实用', '简洁百搭,日常出门更实用。精选品质商品,适合积分商城兑换和日常福利采购场景。', 109.90, 'https://ts3.tc.mm.bing.net/th/id/OIP-C.MkmCbLoY2S4zqzMeHvCDMQHaHD?w=128&h=108&c=7&qlt=90&bgcl=f61537&r=0&o=6&dpr=1.3&pid=13.1', 'fashionBag', '服饰鞋包', '新品上架', '5321件', 292, 17, 1, 0, '2026-07-28 09:43:03.475', '2026-07-28 09:43:03.475');
INSERT INTO `supplier_product` VALUES (18, 'SKU018', 1, 69.90, '柔软撞色丝巾礼盒', 0.1300, '[\"https://ts2.tc.mm.bing.net/th/id/OIP-C.CKSBSB33LwT9qJD_Yhb1mwHaKk?w=132&h=108&c=7&qlt=90&bgcl=2e287d&r=0&o=6&dpr=1.3&pid=13.1\", \"https://tse1-mm.cn.bing.net/th/id/OIP-C.StrDRqennoZNbzSPZapKZwHaEJ?w=286&h=180&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3\"]', '细腻亲肤,点亮日常穿搭', '细腻亲肤,点亮日常穿搭。精选品质商品,适合积分商城兑换和日常福利采购场景。', 99.90, 'https://ts2.tc.mm.bing.net/th/id/OIP-C.CKSBSB33LwT9qJD_Yhb1mwHaKk?w=132&h=108&c=7&qlt=90&bgcl=2e287d&r=0&o=6&dpr=1.3&pid=13.1', 'fashionBag', '服饰鞋包', '礼盒精选', '2680件', 299, 18, 1, 0, '2026-07-28 09:43:03.479', '2026-07-28 09:43:03.479');
INSERT INTO `supplier_product` VALUES (19, 'SKU019', 1, 49.90, '运动保温水杯', 0.1300, '[\"https://tse1-mm.cn.bing.net/th/id/OIP-C.StrDRqennoZNbzSPZapKZwHaEJ?w=286&h=180&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3\", \"https://tse3-mm.cn.bing.net/th/id/OIP-C.ynSetSr3z884UC6sEp4yiwHaEJ?w=331&h=186&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3\"]', '长效锁温,户外运动随行', '长效锁温,户外运动随行。精选品质商品,适合积分商城兑换和日常福利采购场景。', 79.90, 'https://tse1-mm.cn.bing.net/th/id/OIP-C.StrDRqennoZNbzSPZapKZwHaEJ?w=286&h=180&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3', 'sportsOutdoor', '运动户外', '热门推荐', '7342件', 306, 19, 1, 0, '2026-07-28 09:43:03.483', '2026-07-28 09:43:03.483');
INSERT INTO `supplier_product` VALUES (20, 'SKU020', 1, 99.00, '筋膜放松按摩仪 Mini', 0.1300, '[\"https://tse3-mm.cn.bing.net/th/id/OIP-C.ynSetSr3z884UC6sEp4yiwHaEJ?w=331&h=186&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3\", \"https://ts3.tc.mm.bing.net/th/id/OIP-C.im_WvX9bWGyvagEZp4Pz0AHaGX?w=142&h=108&c=7&qlt=90&bgcl=a01e15&r=0&o=6&dpr=1.3&pid=13.1\"]', '轻巧便携,缓解久坐酸胀', '轻巧便携,缓解久坐酸胀。精选品质商品,适合积分商城兑换和日常福利采购场景。', 149.00, 'https://tse3-mm.cn.bing.net/th/id/OIP-C.ynSetSr3z884UC6sEp4yiwHaEJ?w=331&h=186&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3', 'sportsOutdoor', '运动户外', '积分兑换', '3921件', 313, 20, 1, 0, '2026-07-28 09:43:03.486', '2026-07-28 09:43:03.486');
INSERT INTO `supplier_product` VALUES (21, 'SKU021', 1, 79.00, '户外露营灯', 0.1300, '[\"https://ts3.tc.mm.bing.net/th/id/OIP-C.im_WvX9bWGyvagEZp4Pz0AHaGX?w=142&h=108&c=7&qlt=90&bgcl=a01e15&r=0&o=6&dpr=1.3&pid=13.1\", \"https://ts3.tc.mm.bing.net/th/id/OIP-C.MkmCbLoY2S4zqzMeHvCDMQHaHD?w=128&h=108&c=7&qlt=90&bgcl=f61537&r=0&o=6&dpr=1.3&pid=13.1\"]', '多档照明,露营夜晚更安心', '多档照明,露营夜晚更安心。精选品质商品,适合积分商城兑换和日常福利采购场景。', 119.00, 'https://ts3.tc.mm.bing.net/th/id/OIP-C.im_WvX9bWGyvagEZp4Pz0AHaGX?w=142&h=108&c=7&qlt=90&bgcl=a01e15&r=0&o=6&dpr=1.3&pid=13.1', 'sportsOutdoor', '运动户外', '新品上架', '2568件', 320, 21, 1, 0, '2026-07-28 09:43:03.489', '2026-07-28 09:43:03.489');
INSERT INTO `supplier_product` VALUES (22, 'SKU022', 1, 59.90, '悦享精选礼包', 0.1300, '[\"https://ts3.tc.mm.bing.net/th/id/OIP-C.MkmCbLoY2S4zqzMeHvCDMQHaHD?w=128&h=108&c=7&qlt=90&bgcl=f61537&r=0&o=6&dpr=1.3&pid=13.1\", \"https://ts2.tc.mm.bing.net/th/id/OIP-C.CKSBSB33LwT9qJD_Yhb1mwHaKk?w=132&h=108&c=7&qlt=90&bgcl=2e287d&r=0&o=6&dpr=1.3&pid=13.1\"]', '多场景精选好物,福利兑换优选', '多场景精选好物,福利兑换优选。精选品质商品,适合积分商城兑换和日常福利采购场景。', 89.90, 'https://ts3.tc.mm.bing.net/th/id/OIP-C.MkmCbLoY2S4zqzMeHvCDMQHaHD?w=128&h=108&c=7&qlt=90&bgcl=f61537&r=0&o=6&dpr=1.3&pid=13.1', 'recommend', '精选推荐', '精选推荐', '8820件', 327, 22, 1, 0, '2026-07-28 09:43:03.492', '2026-07-28 09:43:03.492');
INSERT INTO `supplier_product` VALUES (23, 'SKU023', 1, 119.00, '品质生活组合装', 0.1300, '[\"https://ts2.tc.mm.bing.net/th/id/OIP-C.CKSBSB33LwT9qJD_Yhb1mwHaKk?w=132&h=108&c=7&qlt=90&bgcl=2e287d&r=0&o=6&dpr=1.3&pid=13.1\", \"https://tse1-mm.cn.bing.net/th/id/OIP-C.StrDRqennoZNbzSPZapKZwHaEJ?w=286&h=180&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3\"]', '居家、通勤、日用好物组合', '居家、通勤、日用好物组合。精选品质商品,适合积分商城兑换和日常福利采购场景。', 159.00, 'https://ts2.tc.mm.bing.net/th/id/OIP-C.CKSBSB33LwT9qJD_Yhb1mwHaKk?w=132&h=108&c=7&qlt=90&bgcl=2e287d&r=0&o=6&dpr=1.3&pid=13.1', 'recommend', '精选推荐', '热门推荐', '6902件', 334, 23, 1, 0, '2026-07-28 09:43:03.495', '2026-07-28 09:43:03.495');
INSERT INTO `supplier_product` VALUES (24, 'SKU024', 1, 39.90, '积分兑换惊喜盒', 0.1300, '[\"https://tse1-mm.cn.bing.net/th/id/OIP-C.StrDRqennoZNbzSPZapKZwHaEJ?w=286&h=180&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3\", \"https://tse3-mm.cn.bing.net/th/id/OIP-C.ynSetSr3z884UC6sEp4yiwHaEJ?w=331&h=186&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3\"]', '随机精选商品,兑换更有新鲜感', '随机精选商品,兑换更有新鲜感。精选品质商品,适合积分商城兑换和日常福利采购场景。', 69.90, 'https://tse1-mm.cn.bing.net/th/id/OIP-C.StrDRqennoZNbzSPZapKZwHaEJ?w=286&h=180&c=7&r=0&o=7&cb=thfc1falcon&dpr=1.3&pid=1.7&rm=3', 'recommend', '精选推荐', '限时秒杀', '5310件', 341, 24, 1, 0, '2026-07-28 09:43:03.498', '2026-07-28 09:43:03.498');
-- ----------------------------
-- Table structure for supplier_reconciliation_order
-- ----------------------------
DROP TABLE IF EXISTS `supplier_reconciliation_order`;
CREATE TABLE `supplier_reconciliation_order` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键',
`supplierId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '供应商ID',
`orderId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '子订单ID',
`mainOrderId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '主订单ID',
`userId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '用户ID',
`reconciliationStatus` tinyint NOT NULL DEFAULT 0 COMMENT '对账状态:0未对账,1对账成功,2对账异常',
`diffType` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '差异类型',
`diffReason` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '差异说明',
`platformTotalPrice` decimal(12, 2) NULL DEFAULT NULL COMMENT '平台订单总金额',
`platformCashAmount` decimal(12, 2) NULL DEFAULT NULL COMMENT '平台现金支付金额',
`platformPointsPrice` decimal(12, 2) NULL DEFAULT NULL COMMENT '平台积分支付金额',
`platformRefundPrice` decimal(12, 2) NULL DEFAULT NULL COMMENT '平台退款金额',
`supplierTotalPrice` decimal(12, 2) NULL DEFAULT NULL COMMENT '供应商订单总金额',
`supplierCashAmount` decimal(12, 2) NULL DEFAULT NULL COMMENT '供应商现金支付金额',
`supplierPointsPrice` decimal(12, 2) NULL DEFAULT NULL COMMENT '供应商积分支付金额',
`supplierRefundPrice` decimal(12, 2) NULL DEFAULT NULL COMMENT '供应商退款金额',
`reconciliationBatchNo` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '对账批次号',
`reconciliationTime` datetime(3) NULL DEFAULT NULL COMMENT '对账完成时间',
`resultPayload` json NULL COMMENT '对账回调原始结果',
`createAt` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updateAt` datetime(3) NOT NULL,
`deleted` int NOT NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `uk_supplier_order`(`supplierId` ASC, `orderId` ASC) USING BTREE,
INDEX `idx_supplier_status`(`supplierId` ASC, `reconciliationStatus` ASC) USING BTREE,
INDEX `idx_batch_no`(`reconciliationBatchNo` ASC) USING BTREE,
INDEX `idx_main_order`(`mainOrderId` ASC) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '供应商子订单对账结果表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of supplier_reconciliation_order
-- ----------------------------
-- ----------------------------
-- Table structure for supplier_refund_exchange
-- ----------------------------
DROP TABLE IF EXISTS `supplier_refund_exchange`;
CREATE TABLE `supplier_refund_exchange` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '售后记录主键ID',
`serviceOrderId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '退货/换货业务单号',
`supplierId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '供应商ID',
`userId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '用户ID',
`mainOrderId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '关联主单ID',
`subOrderId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '关联子单ID',
`serviceType` int NOT NULL COMMENT '售后类型:4退货,5换货',
`serviceState` int NOT NULL DEFAULT 0 COMMENT '售后状态:0已创建,1处理中,2已完成,3已取消',
`amount` decimal(10, 2) NOT NULL DEFAULT 0.00 COMMENT '售后金额',
`reason` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '售后原因',
`requestBody` json NULL COMMENT '原始业务请求体',
`createTime` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
`updateTime` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
`deleted` int NOT NULL DEFAULT 0 COMMENT '删除状态:0未删除,1已删除',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `supplier_refund_exchange_serviceOrderId_key`(`serviceOrderId` ASC) USING BTREE,
INDEX `supplier_refund_exchange_supplierId_mainOrderId_idx`(`supplierId` ASC, `mainOrderId` ASC) USING BTREE,
INDEX `supplier_refund_exchange_subOrderId_idx`(`subOrderId` ASC) USING BTREE,
INDEX `supplier_refund_exchange_serviceType_serviceState_idx`(`serviceType` ASC, `serviceState` ASC) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '供应商退货换货售后记录表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of supplier_refund_exchange
-- ----------------------------
-- ----------------------------
-- Table structure for supplier_user_address
-- ----------------------------
DROP TABLE IF EXISTS `supplier_user_address`;
CREATE TABLE `supplier_user_address` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '地址主键ID',
`addressId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '地址业务ID',
`supplierId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '供应商ID',
`userId` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '用户ID',
`name` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '收货人姓名',
`tel` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '收货人手机号',
`province` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '省',
`city` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '市',
`county` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '区县',
`addressDetail` text CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '详细地址',
`areaCode` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '地区编码',
`postalCode` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '邮政编码',
`isDefault` tinyint(1) NOT NULL DEFAULT 0 COMMENT '是否默认地址',
`createTime` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) COMMENT '创建时间',
`updateTime` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3) COMMENT '更新时间',
`deleted` int NOT NULL DEFAULT 0 COMMENT '删除状态:0未删除,1已删除',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `supplier_user_address_addressId_key`(`addressId` ASC) USING BTREE,
INDEX `supplier_user_address_supplierId_userId_idx`(`supplierId` ASC, `userId` ASC) USING BTREE,
INDEX `supplier_user_address_supplierId_userId_isDefault_idx`(`supplierId` ASC, `userId` ASC, `isDefault` ASC) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '供应商用户收货地址表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of supplier_user_address
-- ----------------------------
INSERT INTO `supplier_user_address` VALUES (1, 'addr-1785395646503', '99999999', 'b2397ac9a67f476c9833471d27709db1', '谌盼兮', '13545478393', '吉林省', '白山市', '临江市', '未来科技城', '220681', '430213', 1, '2026-07-30 07:14:06.541', '2026-07-30 07:29:34.829', 0);
INSERT INTO `supplier_user_address` VALUES (2, 'addr-1788252731181', '99999999', 'c281e124321c8db3a14f0a7c86046c3c', '谌盼兮', '19090230905', '湖北省', '武汉市', '洪山区', '中国地质大学', '420111', '430074', 1, '2026-09-01 08:52:11.226', '2026-09-01 08:52:11.226', 0);
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`mobile` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`nickname` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
`avatarUrl` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL,
`points` int NOT NULL DEFAULT 0,
`createdAt` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3),
`updatedAt` datetime(3) NOT NULL,
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `User_mobile_key`(`mobile` ASC) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user
-- ----------------------------
SET FOREIGN_KEY_CHECKS = 1;
@@ -16,6 +16,8 @@ import { orderListService } from '../services/order-list.service.js'
import { orderPushEventService, type OrderPushEventInput } from '../services/order-push-event.service.js'
import {
supplierOpenOrderService,
type SupplierInvoiceApplyRequest,
type SupplierInvoiceQueryRequest,
type SupplierOrderQueryRequest,
type SupplierReconciliationQueryRequest
} from '../services/supplier-open-order.service.js'
@@ -261,3 +263,37 @@ export const supplierReconciliationInfoController = withErrorBoundary(async (req
return Response.json(await supplierOpenOrderService.queryReconciliationInfo(body))
})
export const supplierInvoiceApplyController = withErrorBoundary(async (request: Request, _context: Context) => {
const methodResponse = guardMethod(request, ['POST'])
if (methodResponse) return methodResponse
let body: SupplierInvoiceApplyRequest
try {
body = supplierOpenOrderService.parseBody(await readJson<SupplierInvoiceApplyRequest>(request)) as SupplierInvoiceApplyRequest
} catch (error) {
return Response.json({
resultCode: 400,
message: error instanceof Error ? error.message : '请求参数解密失败'
})
}
return Response.json(await supplierOpenOrderService.applyForInvoices(body))
})
export const supplierInvoiceInfoController = withErrorBoundary(async (request: Request, _context: Context) => {
const methodResponse = guardMethod(request, ['POST'])
if (methodResponse) return methodResponse
let body: SupplierInvoiceQueryRequest
try {
body = supplierOpenOrderService.parseBody(await readJson<SupplierInvoiceQueryRequest>(request)) as SupplierInvoiceQueryRequest
} catch (error) {
return Response.json({
resultCode: 400,
message: error instanceof Error ? error.message : '请求参数解密失败'
})
}
return Response.json(await supplierOpenOrderService.queryInvoicesInfo(body))
})
@@ -10,7 +10,7 @@ type SupplierInfoRequest = {
}
type SupplierTokenRequest = {
userId?: string
AplParmObjct?: string
supplierIdentification?: string
}
@@ -39,10 +39,10 @@ export const supplierTokenController = withErrorBoundary(async (request: Request
if (methodResponse) return methodResponse
const body = await readJson<SupplierTokenRequest>(request)
const userId = String(body.userId || '').trim()
const encryptedParam = String(body.AplParmObjct || '').trim()
const supplierIdentification = String(body.supplierIdentification || '').trim().toLowerCase()
return toHttpResponse(await supplierService.warmSupplierToken(userId, supplierIdentification))
return toHttpResponse(await supplierService.warmSupplierToken(encryptedParam, supplierIdentification))
})
export const supplierPointsController = withErrorBoundary(async (request: Request, _context: Context) => {
+6
View File
@@ -33,6 +33,8 @@ import {
orderPayController,
orderPushEventController,
orderShipController,
supplierInvoiceApplyController,
supplierInvoiceInfoController,
supplierOrderInfoController,
supplierReconciliationInfoController
} from './controllers/order.controller.js'
@@ -107,6 +109,8 @@ const handlers: Record<string, FunctionHandler> = {
'merchant-product-delete': merchantProductDeleteController,
'supplier-debug-tokens': supplierDebugTokensController,
'supplier-info': supplierInfoController,
'supplier-invoice-apply': supplierInvoiceApplyController,
'supplier-invoice-info': supplierInvoiceInfoController,
'supplier-order-info': supplierOrderInfoController,
'supplier-reconciliation-info': supplierReconciliationInfoController,
'supplier-reconciliation-result': supplierReconciliationResultController,
@@ -200,6 +204,8 @@ router.all('/api/:name', async ctx => dispatch(ctx.params.name)(ctx))
router.all('/api/admin/:name', async ctx => dispatch(ctx.params.name)(ctx))
router.post('/supplierOpenApi/pointOrder/queryOrderInfo', dispatch('supplier-order-info'))
router.post('/supplierOpenApi/pointOrder/queryReconciliationInfo', dispatch('supplier-reconciliation-info'))
router.post('/supplierOpenApi/pointOrder/applyForInvoices', dispatch('supplier-invoice-apply'))
router.post('/supplierOpenApi/pointOrder/queryInvoicesInfo', dispatch('supplier-invoice-info'))
router.post('/supplierOpenApi/pointOrder/reconciliationResult', dispatch('supplier-reconciliation-result'))
router.post('/supplierOpenApi/pointOrder/unReconciledMsg', dispatch('supplier-unreconciled-msg'))
router.post('/supplierOpenApi/debug/tokens', dispatch('supplier-debug-tokens'))
@@ -2,6 +2,7 @@ import { supplierDao } from '../dao/supplier.dao.js'
import { orderDao } from '../dao/order.dao.js'
import { ORDER_EVENT_TYPE, ORDER_STATE } from '../constants/order.js'
import { logger } from '../utils/logger.js'
import { prisma } from '../utils/prisma.js'
import { sm4CbcDecrypt, verifySupplierOpenSignature } from '../utils/supplier-open-crypto.js'
export type SupplierOrderQueryRequest = {
@@ -11,6 +12,7 @@ export type SupplierOrderQueryRequest = {
orderId?: string
timestamp?: number
AplParmObjct?: string
RsrvFld1?: string
}
export type SupplierReconciliationQueryRequest = {
@@ -24,10 +26,51 @@ export type SupplierReconciliationQueryRequest = {
pageSize?: number
timestamp?: number
AplParmObjct?: string
RsrvFld1?: string
}
const parseBody = (body: SupplierOrderQueryRequest) => {
if (!body.AplParmObjct) return body
export type SupplierInvoiceApplyRequest = {
supplierId?: string
token?: string
settlementId?: string
orderIds?: string
orderNum?: number
orderTotalPrice?: number | string
invoiceDate?: string
invoiceTitle?: string
invoiceCode?: string
invoiceAddress?: string
invoiceContact?: string
invoiceNakedPrice?: number | string
invoiceTaxPrice?: number | string
invoiceType?: string
invoiceContent?: string
remark?: string
bankAccount?: string
registeredAddress?: string
bankName?: string
timestamp?: number
AplParmObjct?: string
RsrvFld1?: string
}
export type SupplierInvoiceQueryRequest = {
supplierId?: string
token?: string
settlementId?: string
timestamp?: number
AplParmObjct?: string
}
type SupplierOpenEncryptedRequest = {
AplParmObjct?: string
ApiParamObject?: string
RsrvFld1?: string
}
const parseBody = <T extends SupplierOpenEncryptedRequest>(body: T) => {
const encryptedData = body.AplParmObjct || body.ApiParamObject
if (!encryptedData) return body
const keyHex = process.env.SUPPLIER_OPEN_SM4_KEY_HEX || process.env.SM4CBC_KEY_HEX || ''
const ivHex = process.env.SUPPLIER_OPEN_SM4_IV_HEX || process.env.SM4CBC_IV_HEX || ''
@@ -35,7 +78,10 @@ const parseBody = (body: SupplierOrderQueryRequest) => {
throw new Error('供应商开放接口SM4配置缺失')
}
return JSON.parse(sm4CbcDecrypt(body.AplParmObjct, keyHex, ivHex)) as SupplierOrderQueryRequest
return {
...JSON.parse(sm4CbcDecrypt(encryptedData, keyHex, ivHex)),
RsrvFld1: body.RsrvFld1
} as T
}
const toText = (date?: Date | null) => {
@@ -223,5 +269,160 @@ export const supplierOpenOrderService = {
}))
return { resultCode: 0, message: '成功', totalPage, currentPage: page, orderInfos }
},
async applyForInvoices(body: SupplierInvoiceApplyRequest) {
const supplierId = String(body.supplierId || '').trim()
const token = String(body.token || '').trim()
const settlementId = String(body.settlementId || '').trim()
const orderIds = [...new Set(String(body.orderIds || '')
.split(',')
.map(item => item.trim())
.filter(Boolean))]
const orderNum = Number(body.orderNum || 0)
const orderTotalPrice = Number(body.orderTotalPrice)
const timestamp = Number(body.timestamp || 0)
logger.info('supplier open invoice apply', { supplierId, settlementId, orderCount: orderIds.length, timestamp })
if (!supplierId || !token || !timestamp || !settlementId || !orderIds.length) {
return { resultCode: 400, message: '供应商、结算单、订单或签名信息不能为空' }
}
if (!body.invoiceDate || !body.invoiceTitle || !body.invoiceCode || !body.invoiceAddress || !body.invoiceContact) {
return { resultCode: 400, message: '开票日期、抬头、纳税人识别号、地址和联系电话不能为空' }
}
if (!Number.isInteger(orderNum) || orderNum <= 0 || !Number.isFinite(orderTotalPrice) || orderTotalPrice < 0) {
return { resultCode: 400, message: '订单数量或订单总金额不正确' }
}
const supplier = await supplierDao.findActiveBySupplierId(supplierId)
if (!supplier) {
return { resultCode: 404, message: '供应商信息不存在' }
}
if (!verifySupplierOpenSignature(supplier.supplierId, String(body.RsrvFld1 || supplier.clientId), timestamp, token)) {
return { resultCode: 401, message: '签名无效或已过期' }
}
const orders = await orderDao.findOpenApiSubOrders(supplierId, orderIds)
if (orders.length !== orderIds.length || orderNum !== orderIds.length) {
return { resultCode: 400, message: '订单数量校验不通过' }
}
const actualTotalPrice = orders.reduce((total, order) => total + Number(order.totalPrice || 0), 0)
if (Math.abs(actualTotalPrice - orderTotalPrice) >= 0.01) {
return { resultCode: 400, message: '订单总金额校验不通过' }
}
const orderIdText = orderIds.join(',')
const firstOrder = orders[0]
await orderDao.transaction(async tx => {
await tx.supplierInvoiceInfo.upsert({
where: { invoiceBizId: settlementId },
update: {
supplierId,
userId: firstOrder?.userId || null,
mainOrderId: firstOrder?.mainOrderId || null,
subOrderId: firstOrder?.orderId || null,
settlementId,
invoiceCode: body.invoiceCode,
orderIds: orderIdText,
invoiceStatus: 1,
requestBody: JSON.parse(JSON.stringify(body)),
deleted: 0
},
create: {
invoiceBizId: settlementId,
supplierId,
userId: firstOrder?.userId || null,
mainOrderId: firstOrder?.mainOrderId || null,
subOrderId: firstOrder?.orderId || null,
settlementId,
invoiceCode: body.invoiceCode,
orderIds: orderIdText,
invoiceStatus: 1,
requestBody: JSON.parse(JSON.stringify(body))
}
})
})
return { resultCode: 0, message: '开票申请已受理' }
},
async queryInvoicesInfo(body: SupplierInvoiceQueryRequest) {
const supplierId = String(body.supplierId || '').trim()
const token = String(body.token || '').trim()
const settlementId = String(body.settlementId || '').trim()
const timestamp = Number(body.timestamp || 0)
if (!supplierId || !token || !timestamp || !settlementId) {
return { resultCode: 400, message: '供应商、结算单或签名信息不能为空' }
}
const supplier = await supplierDao.findActiveBySupplierId(supplierId)
if (!supplier) {
return { resultCode: 404, message: '供应商信息不存在' }
}
if (!verifySupplierOpenSignature(supplier.supplierId, supplier.clientId, timestamp, token)) {
return { resultCode: 401, message: '签名无效或已过期' }
}
const records = await prisma.supplierInvoiceInfo.findMany({
where: { supplierId, settlementId, deleted: 0 },
orderBy: { createTime: 'asc' }
})
const completedRecords = records.filter(item => item.invoiceStatus === 2)
const failedRecords = records.filter(item => item.invoiceStatus === 3)
const application = records.find(item => item.invoiceStatus === 1)
const applicationOrderIds = String(application?.orderIds || '')
const invoiceInfos = completedRecords.flatMap(record => {
const payload = record.requestBody && typeof record.requestBody === 'object'
? record.requestBody as Record<string, unknown>
: {}
const invoiceIds = String(record.invoiceIds || record.invoiceBizId)
.split(',')
.map(item => item.trim())
.filter(Boolean)
return invoiceIds.map(invoiceId => ({
invoiceId,
invoiceCode: record.invoiceCode || '',
invoiceDate: payload.invoiceDate || null,
invoiceNakeAmount: Number(payload.invoiceNakeAmount || payload.invoiceNakedPrice || 0),
invoiceTaxRate: Number(payload.invoiceTaxRate || 0),
invoiceTaxAmount: Number(payload.invoiceTaxAmount || payload.invoiceTaxPrice || 0),
invoiceAmount: Number(payload.invoiceAmount || 0),
invoiceType: Number(payload.invoiceType || 0),
url: payload.url || record.filePath || '',
imageEncode: payload.imageEncode || '',
fileType: payload.fileType || '',
checkCode: payload.checkCode || '',
invoiceAddress: payload.invoiceAddress || ''
}))
})
const completedOrderIds = completedRecords
.flatMap(item => String(item.orderIds || '').split(','))
.map(item => item.trim())
.filter(Boolean)
const sucOrderIds = completedRecords.length && !completedOrderIds.length
? applicationOrderIds.split(',').map(item => item.trim()).filter(Boolean)
: completedOrderIds
const failOrderIds = failedRecords.length ? applicationOrderIds : ''
const failMsg = failedRecords.length
? String((failedRecords[0].requestBody as Record<string, unknown> | null)?.failMsg || '开票失败')
: completedRecords.length ? '' : '发票尚未开具'
return {
resultCode: 0,
message: '成功',
getInvoiceInfo: {
bSuccess: completedRecords.length ? 0 : 1,
settlementId,
sucOrderIds: [...new Set(sucOrderIds)].join(','),
failOrderIds,
failMsg,
invoiceInfos
}
}
}
}
@@ -2,7 +2,7 @@ import { supplierDao } from '../dao/supplier.dao.js'
import { bridgeFetchWithAuth, findSupplierByIdentification, getBridgeApiBase, getBridgeToken, warmBridgeToken } from '../utils/bridge-auth.js'
import { sha256 } from '../utils/crypto.js'
import { logger } from '../utils/logger.js'
import { createSupplierOpenSignature } from '../utils/supplier-open-crypto.js'
import { createSupplierOpenSignature, sm4CbcDecrypt } from '../utils/supplier-open-crypto.js'
import { serviceFail, serviceOk } from '../types/service-result.js'
type BridgePointsResponse = {
@@ -33,11 +33,29 @@ export const supplierService = {
})
},
async warmSupplierToken(userId: string, supplierIdentification: string) {
logger.info('supplier token warmup', { userId, supplierIdentification })
async warmSupplierToken(encryptedParam: string, supplierIdentification: string) {
logger.info('supplier token warmup', { supplierIdentification })
if (!userId || !supplierIdentification) {
return serviceFail('用户信息和供应商唯一标识不能为空')
if (!encryptedParam || !supplierIdentification) {
return serviceFail('加密用户参数和供应商唯一标识不能为空')
}
const keyHex = process.env.SUPPLIER_OPEN_SM4_KEY_HEX || process.env.SM4CBC_KEY_HEX || ''
const ivHex = process.env.SUPPLIER_OPEN_SM4_IV_HEX || process.env.SM4CBC_IV_HEX || ''
if (!keyHex || !ivHex) {
return serviceFail('供应商开放接口SM4配置缺失', 500, 'SM4_CONFIG_MISSING')
}
let userId = ''
try {
const decrypted = sm4CbcDecrypt(encryptedParam.replace(/ /g, '+'), keyHex, ivHex)
const params = JSON.parse(decrypted) as { userId?: string }
userId = String(params.userId || '').trim()
} catch (error) {
return serviceFail('用户参数解密失败', 400, 'INVALID_USER_PARAM')
}
if (!userId) {
return serviceFail('用户信息不能为空', 400, 'USER_ID_MISSING')
}
const supplier = await findSupplierByIdentification(supplierIdentification).catch(error => error)
+359
View File
@@ -0,0 +1,359 @@
import { createHash } from 'node:crypto'
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
const PAGE_WIDTH = 842
const PAGE_HEIGHT = 595
const findFont = requestedPath => {
const candidates = [
requestedPath,
process.env.INVOICE_PDF_FONT_PATH,
'C:/Windows/Fonts/simhei.ttf',
'C:/Windows/Fonts/msyh.ttf',
'/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttf',
'/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf'
].filter(Boolean)
const fontPath = candidates.find(candidate => existsSync(candidate))
if (!fontPath) {
throw new Error('未找到可用字体,请通过 INVOICE_PDF_FONT_PATH 指定支持中文的 TTF 字体')
}
if (path.extname(fontPath).toLowerCase() !== '.ttf') {
throw new Error('模拟发票工具仅支持 TTF 字体')
}
return fontPath
}
const readTableDirectory = font => {
const tableCount = font.readUInt16BE(4)
const tables = new Map()
for (let index = 0; index < tableCount; index += 1) {
const offset = 12 + index * 16
tables.set(font.toString('ascii', offset, offset + 4), {
offset: font.readUInt32BE(offset + 8),
length: font.readUInt32BE(offset + 12)
})
}
return tables
}
const createGlyphMapper = font => {
const cmapTable = readTableDirectory(font).get('cmap')
if (!cmapTable) throw new Error('字体缺少 cmap 字符映射表')
const base = cmapTable.offset
const count = font.readUInt16BE(base + 2)
let format12Offset = null
let format4Offset = null
for (let index = 0; index < count; index += 1) {
const record = base + 4 + index * 8
const platformId = font.readUInt16BE(record)
const encodingId = font.readUInt16BE(record + 2)
const subtableOffset = base + font.readUInt32BE(record + 4)
const format = font.readUInt16BE(subtableOffset)
if (format === 12 && (platformId === 0 || (platformId === 3 && encodingId === 10))) {
format12Offset = subtableOffset
}
if (format === 4 && (platformId === 0 || platformId === 3)) {
format4Offset = subtableOffset
}
}
const fromFormat12 = codePoint => {
if (format12Offset === null) return 0
const groupCount = font.readUInt32BE(format12Offset + 12)
let low = 0
let high = groupCount - 1
while (low <= high) {
const middle = (low + high) >> 1
const group = format12Offset + 16 + middle * 12
const start = font.readUInt32BE(group)
const end = font.readUInt32BE(group + 4)
if (codePoint < start) high = middle - 1
else if (codePoint > end) low = middle + 1
else return font.readUInt32BE(group + 8) + codePoint - start
}
return 0
}
const fromFormat4 = codePoint => {
if (format4Offset === null || codePoint > 0xffff) return 0
const segmentCount = font.readUInt16BE(format4Offset + 6) / 2
const endCodes = format4Offset + 14
const startCodes = endCodes + segmentCount * 2 + 2
const deltas = startCodes + segmentCount * 2
const rangeOffsets = deltas + segmentCount * 2
for (let index = 0; index < segmentCount; index += 1) {
const end = font.readUInt16BE(endCodes + index * 2)
if (codePoint > end) continue
const start = font.readUInt16BE(startCodes + index * 2)
if (codePoint < start) return 0
const delta = font.readInt16BE(deltas + index * 2)
const rangeOffsetPosition = rangeOffsets + index * 2
const rangeOffset = font.readUInt16BE(rangeOffsetPosition)
if (rangeOffset === 0) return (codePoint + delta) & 0xffff
const glyphPosition = rangeOffsetPosition + rangeOffset + (codePoint - start) * 2
if (glyphPosition + 2 > font.length) return 0
const glyph = font.readUInt16BE(glyphPosition)
return glyph === 0 ? 0 : (glyph + delta) & 0xffff
}
return 0
}
return codePoint => fromFormat12(codePoint) || fromFormat4(codePoint)
}
const utf16Hex = value => {
const buffer = Buffer.from(value, 'utf16le')
buffer.swap16()
return buffer.toString('hex').toUpperCase()
}
const createPdfWriter = () => {
const objects = []
return {
add(body) {
objects.push(Buffer.isBuffer(body) ? body : Buffer.from(body, 'binary'))
return objects.length
},
save(outputPath) {
const header = Buffer.from('%PDF-1.7\n%\xFF\xFF\xFF\xFF\n', 'binary')
const chunks = [header]
const offsets = [0]
let cursor = header.length
objects.forEach((body, index) => {
offsets.push(cursor)
const prefix = Buffer.from(`${index + 1} 0 obj\n`, 'ascii')
const suffix = Buffer.from('\nendobj\n', 'ascii')
chunks.push(prefix, body, suffix)
cursor += prefix.length + body.length + suffix.length
})
const xrefOffset = cursor
const xref = [`xref\n0 ${objects.length + 1}\n`, '0000000000 65535 f \n']
for (let index = 1; index <= objects.length; index += 1) {
xref.push(`${String(offsets[index]).padStart(10, '0')} 00000 n \n`)
}
xref.push(`trailer\n<< /Size ${objects.length + 1} /Root 1 0 R >>\nstartxref\n${xrefOffset}\n%%EOF\n`)
chunks.push(Buffer.from(xref.join(''), 'ascii'))
mkdirSync(path.dirname(outputPath), { recursive: true })
writeFileSync(outputPath, Buffer.concat(chunks))
}
}
}
const streamObject = (dictionary, data) => Buffer.concat([
Buffer.from(`<< ${dictionary} /Length ${data.length} >>\nstream\n`, 'ascii'),
data,
Buffer.from('\nendstream', 'ascii')
])
const money = value => Number(value || 0).toFixed(2)
const chineseAmount = value => {
const digits = '零壹贰叁肆伍陆柒捌玖'
const units = ['', '拾', '佰', '仟', '万', '拾', '佰', '仟', '亿', '拾', '佰', '仟']
const amount = Math.max(Number(value || 0), 0)
const integer = Math.floor(amount)
const chars = String(integer).split('').reverse()
let result = ''
let pendingZero = false
chars.forEach((char, index) => {
const digit = Number(char)
if (digit === 0) {
pendingZero = result.length > 0
if (index === 4 || index === 8) result = units[index] + result
} else {
result = `${digits[digit]}${units[index]}${pendingZero ? '零' : ''}${result}`
pendingZero = false
}
})
const cents = Math.round((amount - integer) * 100)
const jiao = Math.floor(cents / 10)
const fen = cents % 10
return `${result || '零'}元${jiao ? `${digits[jiao]}角` : ''}${fen ? `${digits[fen]}分` : '整'}`
}
const normalizeInvoice = input => {
const digest = createHash('sha256').update(JSON.stringify(input)).digest('hex').toUpperCase()
const total = Number(input.orderTotalPrice || 0)
const taxRate = Number(input.taxRate ?? 0.13)
const naked = Number(input.invoiceNakedPrice ?? total / (1 + taxRate))
const tax = Number(input.invoiceTaxPrice ?? total - naked)
return {
...input,
invoiceDate: input.invoiceDate || new Date().toISOString().slice(0, 10),
invoiceNumber: input.invoiceNumber || digest.slice(0, 20),
checkCode: input.checkCode || digest.slice(20, 40),
sellerName: input.sellerName || '模拟积分商城供应商',
sellerTaxId: input.sellerTaxId || input.supplierId || 'SIMULATED-SUPPLIER',
sellerAddress: input.sellerAddress || '模拟供应商注册地址',
sellerContact: input.sellerContact || '400-000-0000',
invoiceContent: input.invoiceContent || '积分商城商品',
orderNum: Number(input.orderNum || 1),
total,
naked,
tax,
taxRate
}
}
export const generateMockInvoicePdf = (invoiceInput, outputPath, options = {}) => {
const invoice = normalizeInvoice(invoiceInput)
const fontPath = findFont(options.fontPath)
const font = readFileSync(fontPath)
const glyphFor = createGlyphMapper(font)
const glyphUnicode = new Map()
const commands = []
const encode = value => Array.from(String(value ?? '')).map(character => {
const glyph = glyphFor(character.codePointAt(0))
if (glyph && !glyphUnicode.has(glyph)) glyphUnicode.set(glyph, character)
return glyph.toString(16).padStart(4, '0')
}).join('').toUpperCase()
const text = (value, x, y, size = 10, color = '0 0 0') => {
commands.push(`BT /F1 ${size} Tf ${color} rg 1 0 0 1 ${x} ${y} Tm <${encode(value)}> Tj ET`)
}
const line = (x1, y1, x2, y2, width = 0.7, color = '0.45 0.12 0.12') => {
commands.push(`${color} RG ${width} w ${x1} ${y1} m ${x2} ${y2} l S`)
}
const rect = (x, y, width, height, color = '0.45 0.12 0.12') => {
commands.push(`${color} RG 0.7 w ${x} ${y} ${width} ${height} re S`)
}
const wrappedText = (value, x, y, maxChars, size = 9, lineHeight = 13) => {
const characters = Array.from(String(value || ''))
for (let index = 0; index < characters.length; index += maxChars) {
text(characters.slice(index, index + maxChars).join(''), x, y - index / maxChars * lineHeight, size)
}
}
commands.push('1 1 1 rg 0 0 842 595 re f')
text('增值税电子普通发票(模拟)', 280, 548, 22, '0.65 0.05 0.05')
line(274, 540, 568, 540, 1.2, '0.65 0.05 0.05')
text('仅供系统联调测试,禁止报销', 302, 522, 11, '0.75 0.1 0.1')
text(`发票号码:${invoice.invoiceNumber}`, 610, 555, 9)
text(`开票日期:${invoice.invoiceDate}`, 610, 538, 9)
text(`校验码:${invoice.checkCode}`, 610, 521, 9)
text(`结算单号:${invoice.settlementId || ''}`, 50, 521, 9)
rect(42, 188, 758, 320)
line(42, 414, 800, 414)
line(42, 320, 800, 320)
line(42, 280, 800, 280)
line(42, 226, 800, 226)
line(120, 414, 120, 508)
line(120, 320, 120, 414)
line(475, 414, 475, 508)
line(475, 320, 475, 414)
text('购买方', 68, 457, 12, '0.55 0.05 0.05')
text('销售方', 68, 365, 12, '0.55 0.05 0.05')
text('名称:', 132, 488, 9)
wrappedText(invoice.invoiceTitle, 180, 488, 26, 9)
text('纳税人识别号:', 132, 464, 9)
text(invoice.invoiceCode, 235, 464, 9)
text('地址、电话:', 487, 488, 9)
wrappedText(`${invoice.invoiceAddress || ''} ${invoice.invoiceContact || ''}`, 574, 488, 20, 8)
text('开户行及账号:', 487, 448, 9)
wrappedText(`${invoice.bankName || ''} ${invoice.bankAccount || ''}`, 574, 448, 20, 8)
text('名称:', 132, 395, 9)
text(invoice.sellerName, 180, 395, 9)
text('纳税人识别号:', 132, 371, 9)
text(invoice.sellerTaxId, 235, 371, 9)
text('地址、电话:', 487, 395, 9)
wrappedText(`${invoice.sellerAddress} ${invoice.sellerContact}`, 574, 395, 20, 8)
text('开户行及账号:', 487, 350, 9)
wrappedText(`${invoice.sellerBankName || '模拟银行'} ${invoice.sellerBankAccount || '0000000000000000'}`, 574, 350, 20, 8)
const columns = [42, 290, 382, 440, 495, 580, 655, 720, 800]
columns.slice(1, -1).forEach(x => line(x, 226, x, 320))
;['货物或应税劳务、服务名称', '规格型号', '单位', '数量', '单价', '金额', '税率', '税额'].forEach((label, index) => {
text(label, columns[index] + 7, 300, index === 0 ? 9 : 8)
})
wrappedText(`*商品*${invoice.invoiceContent}`, 50, 263, 28, 9)
text(invoice.invoiceType || '电子发票', 300, 263, 8)
text('项', 401, 263, 9)
text(invoice.orderNum, 458, 263, 9)
text(money(invoice.naked / invoice.orderNum), 503, 263, 8)
text(money(invoice.naked), 590, 263, 8)
text(`${(invoice.taxRate * 100).toFixed(0)}%`, 674, 263, 8)
text(money(invoice.tax), 730, 263, 8)
text('合计', 240, 203, 10)
text(`¥${money(invoice.naked)}`, 590, 203, 10)
text(`¥${money(invoice.tax)}`, 730, 203, 10)
text(`价税合计(大写):${chineseAmount(invoice.total)}`, 52, 164, 11)
text(`(小写):¥${money(invoice.total)}`, 600, 164, 11)
text(`订单号:${invoice.orderIds || ''}`, 52, 132, 8)
wrappedText(`备注:${invoice.remark || '模拟开票,仅用于开发与联调测试'}`, 52, 111, 70, 8)
text('收款人:模拟收款员', 52, 65, 9)
text('复核:模拟复核员', 285, 65, 9)
text('开票人:模拟开票员', 510, 65, 9)
text('销售方(章)', 682, 65, 9, '0.7 0.05 0.05')
commands.push('q 0.92 0.92 0.92 rg BT /F1 34 Tf 0.866 0.5 -0.5 0.866 235 170 Tm')
commands.push(`<${encode('模拟发票 禁止报销')}> Tj ET Q`)
commands.push('0.75 0.08 0.08 RG 2 w 798 88 m 798 111.196 779.196 130 756 130 c 732.804 130 714 111.196 714 88 c 714 64.804 732.804 46 756 46 c 779.196 46 798 64.804 798 88 c S')
const content = Buffer.from(commands.join('\n'), 'ascii')
const toUnicodeEntries = [...glyphUnicode.entries()].map(([glyph, character]) =>
`<${glyph.toString(16).padStart(4, '0').toUpperCase()}> <${utf16Hex(character)}>`)
const toUnicodeBlocks = []
for (let index = 0; index < toUnicodeEntries.length; index += 100) {
const entries = toUnicodeEntries.slice(index, index + 100)
toUnicodeBlocks.push(`${entries.length} beginbfchar`, ...entries, 'endbfchar')
}
const toUnicode = Buffer.from([
'/CIDInit /ProcSet findresource begin', '12 dict begin', 'begincmap',
'/CIDSystemInfo << /Registry (Adobe) /Ordering (UCS) /Supplement 0 >> def',
'/CMapName /MockInvoiceUnicode def', '/CMapType 2 def',
'1 begincodespacerange', '<0000> <FFFF>', 'endcodespacerange',
...toUnicodeBlocks,
'endcmap', 'CMapName currentdict /CMap defineresource pop', 'end', 'end'
].join('\n'), 'ascii')
const writer = createPdfWriter()
writer.add('<< /Type /Catalog /Pages 2 0 R >>')
writer.add('<< /Type /Pages /Kids [3 0 R] /Count 1 >>')
writer.add(`<< /Type /Page /Parent 2 0 R /MediaBox [0 0 ${PAGE_WIDTH} ${PAGE_HEIGHT}] /Resources << /Font << /F1 5 0 R >> >> /Contents 4 0 R >>`)
writer.add(streamObject('', content))
writer.add('<< /Type /Font /Subtype /Type0 /BaseFont /MockInvoiceFont /Encoding /Identity-H /DescendantFonts [6 0 R] /ToUnicode 9 0 R >>')
writer.add('<< /Type /Font /Subtype /CIDFontType2 /BaseFont /MockInvoiceFont /CIDSystemInfo << /Registry (Adobe) /Ordering (Identity) /Supplement 0 >> /FontDescriptor 7 0 R /DW 1000 /CIDToGIDMap /Identity >>')
writer.add('<< /Type /FontDescriptor /FontName /MockInvoiceFont /Flags 4 /FontBBox [-1000 -1000 3000 3000] /ItalicAngle 0 /Ascent 1000 /Descent -300 /CapHeight 800 /StemV 80 /FontFile2 8 0 R >>')
writer.add(streamObject(`/Length1 ${font.length}`, font))
writer.add(streamObject('', toUnicode))
writer.save(outputPath)
return outputPath
}
const parseArguments = argv => {
const options = {}
for (let index = 0; index < argv.length; index += 1) {
if (argv[index] === '--input') options.input = argv[++index]
else if (argv[index] === '--data') options.data = argv[++index]
else if (argv[index] === '--output') options.output = argv[++index]
else if (argv[index] === '--font') options.font = argv[++index]
}
return options
}
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
try {
const options = parseArguments(process.argv.slice(2))
if (!options.input && !options.data) {
throw new Error('请使用 --input <json文件> 或 --data <json字符串> 传入开票信息')
}
const input = options.input
? JSON.parse(readFileSync(path.resolve(options.input), 'utf8'))
: JSON.parse(options.data)
const defaultName = `mock-invoice-${String(input.settlementId || Date.now()).replace(/[^a-zA-Z0-9_-]/g, '_')}.pdf`
const outputPath = path.resolve(options.output || path.join('output', 'pdf', defaultName))
generateMockInvoicePdf(input, outputPath, { fontPath: options.font })
console.log(outputPath)
} catch (error) {
console.error(error instanceof Error ? error.message : String(error))
process.exitCode = 1
}
}