统一 OMS DDL 到 db.sql,并新增采集插件草稿 API。

清理 sql/ 增量与种子脚本;E2E 不再依赖种子;PluginBrowserService 对接哪哪发「我的包裹」采集。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
zzh 2026-07-14 19:44:09 +08:00
parent 7e90112cbf
commit 600ab37594
58 changed files with 771 additions and 2806 deletions

644
db.sql
View File

@ -6,10 +6,49 @@
-- 2. The source spec references `t_sales_product_allocation_rule`, but no concrete table definition exists. The actual design stores
-- allocation scheme on `t_sales_product` and provider rows on `t_sales_product_allocation_provider`.
-- 3. `t_order` keeps SenderId/RecipientId/DeclarationId for compatibility with the original spec, while child tables also keep OrderId.
-- 4. Incremental `sql/migrate_*.sql` scripts are retired; this file is the single source of truth for OMS DDL.
-- 5. Data-permission tables (`user_org_perm` etc.) live here when RBAC and OMS share one MySQL database.
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
DROP TABLE IF EXISTS `data_perm_access_log`;
DROP TABLE IF EXISTS `data_perm_change_log`;
DROP TABLE IF EXISTS `data_perm_template_item`;
DROP TABLE IF EXISTS `data_perm_template`;
DROP TABLE IF EXISTS `data_perm_field_mask`;
DROP TABLE IF EXISTS `data_resource`;
DROP TABLE IF EXISTS `user_filter_rule`;
DROP TABLE IF EXISTS `role_filter_rule`;
DROP TABLE IF EXISTS `user_secret_perm`;
DROP TABLE IF EXISTS `role_secret_perm`;
DROP TABLE IF EXISTS `user_biz_perm`;
DROP TABLE IF EXISTS `role_biz_perm`;
DROP TABLE IF EXISTS `user_data_scope`;
DROP TABLE IF EXISTS `role_data_scope`;
DROP TABLE IF EXISTS `role_org_perm`;
DROP TABLE IF EXISTS `user_org_perm`;
DROP TABLE IF EXISTS `t_xhs_media`;
DROP TABLE IF EXISTS `t_xhs_ai_provider`;
DROP TABLE IF EXISTS `t_xhs_human_config`;
DROP TABLE IF EXISTS `t_xhs_skill`;
DROP TABLE IF EXISTS `t_xhs_analysis_session`;
DROP TABLE IF EXISTS `t_xhs_publish_record`;
DROP TABLE IF EXISTS `t_xhs_task`;
DROP TABLE IF EXISTS `t_xhs_agent`;
DROP TABLE IF EXISTS `C_inbound_box_line`;
DROP TABLE IF EXISTS `C_inbound_box`;
DROP TABLE IF EXISTS `C_inbound_notice`;
DROP TABLE IF EXISTS `C_parcel_item`;
DROP TABLE IF EXISTS `C_parcel`;
DROP TABLE IF EXISTS `C_inventory`;
DROP TABLE IF EXISTS `C_sku_platform_map`;
DROP TABLE IF EXISTS `C_sku`;
DROP TABLE IF EXISTS `C_bin_location`;
DROP TABLE IF EXISTS `t_sales_store_order_line`;
DROP TABLE IF EXISTS `t_sales_store_order`;
DROP TABLE IF EXISTS `t_sales_store`;
DROP TABLE IF EXISTS `t_customer_account_flow`;
DROP TABLE IF EXISTS `t_system_batch_email_record`;
DROP TABLE IF EXISTS `t_system_batch_email_account`;
DROP TABLE IF EXISTS `t_system_batch_email_template`;
@ -55,6 +94,7 @@ DROP TABLE IF EXISTS `t_order_task`;
DROP TABLE IF EXISTS `t_order_batch_job_item`;
DROP TABLE IF EXISTS `t_order_batch_job`;
DROP TABLE IF EXISTS `t_order_template`;
DROP TABLE IF EXISTS `t_order_exception_event`;
DROP TABLE IF EXISTS `t_order`;
CREATE TABLE `t_order` (
@ -92,6 +132,8 @@ CREATE TABLE `t_order` (
`PreviousOrderStatus` VARCHAR(32) NULL COMMENT '进入异常状态前的订单状态',
`WarehouseId` INT NULL COMMENT '仓库ID',
`CustomerId` INT NULL COMMENT '客户ID',
`OrganizationId` CHAR(36) NULL COMMENT '数据归属组织',
`SecretLevel` TINYINT NOT NULL DEFAULT 2 COMMENT '数据密级 1-4',
`SenderId` INT NULL COMMENT '发件人ID',
`RecipientId` INT NULL COMMENT '收件人ID',
`DeclarationId` INT NULL COMMENT '申报信息ID',
@ -124,7 +166,8 @@ CREATE TABLE `t_order` (
KEY `idx_ord_warehouse_status` (`WarehouseId`, `OrderStatus`),
KEY `idx_ord_sender` (`SenderId`),
KEY `idx_ord_recipient` (`RecipientId`),
KEY `idx_ord_declaration` (`DeclarationId`)
KEY `idx_ord_declaration` (`DeclarationId`),
KEY `idx_ord_org_secret_ctime` (`OrganizationId`, `SecretLevel`, `CreateTime`)
) COMMENT='订单表';
CREATE TABLE `t_order_template` (
@ -876,6 +919,7 @@ CREATE TABLE `t_customer` (
`Salesman` VARCHAR(32) NULL COMMENT '所属销售员账号',
`CustomerService` VARCHAR(32) NULL COMMENT '所属顾问',
`CustomerGroup` TINYINT NULL COMMENT '客户分组:0-普通客户,1-VIP1,2-VIP2,3-VIP3,4-VIP4,5-VIP5',
`OrganizationId` CHAR(36) NULL COMMENT '归属销售组织 FK organization.Id',
`LastLoginIp` VARCHAR(64) NULL COMMENT '最后在线IP',
`LastLoginTime` DATETIME NULL COMMENT '最后在线时间',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
@ -890,12 +934,14 @@ CREATE TABLE `t_customer` (
UNIQUE KEY `uk_cus_openid` (`WechatOpenid`),
KEY `idx_cus_parent_status` (`ParentCustomerId`, `Status`),
KEY `idx_cus_status_group` (`Status`, `CustomerGroup`),
KEY `idx_cus_sales_service` (`Salesman`, `CustomerService`)
KEY `idx_cus_sales_service` (`Salesman`, `CustomerService`),
KEY `idx_cus_organization` (`OrganizationId`)
) COMMENT='客户表';
CREATE TABLE `t_recharge_record` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键,自增,步长 1',
`CustomerId` INT NOT NULL COMMENT '客户ID(主账号/子账号关联主账号ID)',
`SecretLevel` TINYINT NOT NULL DEFAULT 3 COMMENT '数据密级 1-4',
`SerialNumber` VARCHAR(64) NOT NULL COMMENT '流水号',
`RechargeTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '充值提交时间',
`PayType` TINYINT NOT NULL COMMENT '支付方式:1-微信,2-支付宝',
@ -1139,9 +1185,307 @@ CREATE TABLE `t_warehouse_address` (
KEY `idx_wa_type` (`WarehouseType`)
) COMMENT='仓库地址表';
-- 小红书(LIKE AI → OMS)模块,详见 sql/migrate_t_xhs.sql 与设计文档 docs/小红书模块设计-063001.md
CREATE TABLE IF NOT EXISTS `t_xhs_agent` (
-- ---------------------------------------------------------------------------
-- 客户账户资金流水
-- ---------------------------------------------------------------------------
CREATE TABLE `t_customer_account_flow` (
`Id` int NOT NULL AUTO_INCREMENT,
`CustomerId` int NOT NULL COMMENT '客户 ID',
`SerialNumber` varchar(64) NOT NULL COMMENT '流水号',
`BizType` varchar(32) NOT NULL COMMENT '业务类型 recharge/orderPay',
`BizId` int DEFAULT NULL COMMENT '关联业务主键',
`BizNo` varchar(64) DEFAULT NULL COMMENT '关联业务单号',
`Amount` decimal(18,2) NOT NULL COMMENT '变动金额,正入账负出账',
`BalanceBefore` decimal(18,2) NOT NULL COMMENT '变动前余额',
`BalanceAfter` decimal(18,2) NOT NULL COMMENT '变动后余额',
`Currency` varchar(8) NOT NULL DEFAULT 'CNY' COMMENT '币种',
`Remark` varchar(512) DEFAULT NULL COMMENT '备注',
`IsDeleted` tinyint(1) NOT NULL DEFAULT '0',
`ConcurrencyStamp` char(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` int NOT NULL DEFAULT '0',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` int DEFAULT NULL,
`UpdateTime` datetime DEFAULT NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_customer_account_flow_serial` (`SerialNumber`),
KEY `idx_customer_account_flow_customer_time` (`CustomerId`, `CreateTime`),
KEY `idx_customer_account_flow_biz` (`BizType`, `BizId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='客户账户资金流水';
-- ---------------------------------------------------------------------------
-- 仓储模块(C_*)+ 店铺订单(t_sales_store*)
-- ---------------------------------------------------------------------------
CREATE TABLE `C_sku` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID → t_customer.Id',
`SkuCode` VARCHAR(64) NOT NULL COMMENT '库内SKU编码',
`SkuName` VARCHAR(256) NOT NULL COMMENT 'SKU名称',
`SkuImageUrl` VARCHAR(512) NULL COMMENT '图片URL',
`WeightG` DECIMAL(10,2) NULL COMMENT '重量(g)',
`LengthCm` DECIMAL(10,2) NULL COMMENT '长(cm)',
`WidthCm` DECIMAL(10,2) NULL COMMENT '宽(cm)',
`HeightCm` DECIMAL(10,2) NULL COMMENT '高(cm)',
`Remark` VARCHAR(512) NULL COMMENT '备注',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_c_sku_code` (`CustomerId`, `SkuCode`),
KEY `idx_c_sku_customer` (`CustomerId`, `IsDeleted`)
) COMMENT='仓储-SKU主数据';
CREATE TABLE `C_bin_location` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`WarehouseId` INT NOT NULL COMMENT '仓库ID → t_warehouse_address.Id',
`BinCode` VARCHAR(32) NOT NULL COMMENT '库位编码',
`BinName` VARCHAR(64) NULL COMMENT '库位展示名',
`ZoneCode` VARCHAR(32) NULL COMMENT '库区编码',
`IsEnabled` TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用:0-否,1-是',
`Remark` VARCHAR(512) NULL COMMENT '备注',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_c_bin_wh_code` (`WarehouseId`, `BinCode`),
KEY `idx_c_bin_warehouse` (`WarehouseId`, `IsEnabled`)
) COMMENT='仓储-库位主数据';
CREATE TABLE `C_inventory` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`WarehouseId` INT NOT NULL COMMENT '仓库ID',
`SkuId` INT NOT NULL COMMENT 'SKU ID → C_sku.Id',
`BinLocationId` INT NOT NULL COMMENT '库位ID → C_bin_location.Id',
`Qty` INT NOT NULL DEFAULT 0 COMMENT '可用库存数量',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_c_inventory` (`CustomerId`, `WarehouseId`, `SkuId`, `BinLocationId`),
KEY `idx_c_inv_sku_wh` (`CustomerId`, `SkuId`, `WarehouseId`)
) COMMENT='仓储-库存余额(按库位)';
CREATE TABLE `C_inbound_notice` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`WarehouseId` INT NOT NULL COMMENT '仓库ID',
`NoticeNo` VARCHAR(32) NOT NULL COMMENT '入库单号 IN+雪花',
`MarkReference` VARCHAR(64) NULL COMMENT '唛头参考号',
`InboundType` VARCHAR(16) NOT NULL DEFAULT 'normal' COMMENT 'normal/return',
`ReceiptStatus` VARCHAR(16) NOT NULL DEFAULT 'forecasted' COMMENT 'forecasted/received/completed',
`ExpectedArrivalTime` DATETIME NULL COMMENT '预计到货时间',
`ActualArrivalTime` DATETIME NULL COMMENT '实际到货时间',
`Remark` VARCHAR(512) NULL COMMENT '备注',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_c_inbound_notice_no` (`NoticeNo`),
KEY `idx_c_inbound_customer_status` (`CustomerId`, `ReceiptStatus`, `CreateTime`)
) COMMENT='仓储-入库预报主表';
CREATE TABLE `C_inbound_box` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`InboundNoticeId` INT NOT NULL COMMENT '入库预报ID → C_inbound_notice.Id',
`BoxSeqNo` VARCHAR(16) NOT NULL COMMENT '箱序号',
`MarkBoxNo` VARCHAR(64) NULL COMMENT '箱唛号/箱号',
`WeightG` DECIMAL(10,2) NULL COMMENT '箱重(g)',
`LengthCm` DECIMAL(10,2) NULL COMMENT '长(cm)',
`WidthCm` DECIMAL(10,2) NULL COMMENT '宽(cm)',
`HeightCm` DECIMAL(10,2) NULL COMMENT '高(cm)',
`IsReceived` TINYINT NOT NULL DEFAULT 0 COMMENT '是否已收货:0-否,1-是',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
KEY `idx_c_inbound_box_notice` (`InboundNoticeId`, `IsDeleted`)
) COMMENT='仓储-入库预报箱';
CREATE TABLE `C_inbound_box_line` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`InboundBoxId` INT NOT NULL COMMENT '入库箱ID → C_inbound_box.Id',
`SkuId` INT NOT NULL COMMENT 'SKU ID → C_sku.Id',
`SkuCode` VARCHAR(64) NOT NULL COMMENT '冗余SKU编码',
`PlannedQty` INT NOT NULL DEFAULT 0 COMMENT '计划入库数量',
`ReceivedQty` INT NULL COMMENT '实收数量',
`BinLocationId` INT NULL COMMENT '上架库位ID → C_bin_location.Id',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
KEY `idx_c_inbound_box_line_box` (`InboundBoxId`, `IsDeleted`),
KEY `idx_c_inbound_box_line_sku` (`SkuId`)
) COMMENT='仓储-入库箱内SKU行';
CREATE TABLE `C_parcel` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`WarehouseId` INT NOT NULL COMMENT '仓库ID',
`TrackingNo` VARCHAR(64) NOT NULL COMMENT '快递单号',
`CarrierName` VARCHAR(64) NULL COMMENT '快递公司',
`LifecycleStatus` VARCHAR(16) NOT NULL DEFAULT 'inTransit' COMMENT 'inTransit/arrived/stored',
`ArrivalTime` DATETIME NULL COMMENT '到仓时间',
`Remark` VARCHAR(512) NULL COMMENT '备注',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_c_parcel_tracking` (`CustomerId`, `TrackingNo`, `WarehouseId`),
KEY `idx_c_parcel_status` (`CustomerId`, `LifecycleStatus`)
) COMMENT='仓储-客户包裹';
CREATE TABLE `C_parcel_item` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`ParcelId` INT NOT NULL COMMENT '包裹ID → C_parcel.Id',
`ProductName` VARCHAR(512) NULL COMMENT '商品名称',
`Quantity` INT NOT NULL DEFAULT 0 COMMENT '数量',
`SkuId` INT NULL COMMENT '库内SKU ID → C_sku.Id',
`SkuCode` VARCHAR(64) NULL COMMENT '冗余SKU编码',
`BinLocationId` INT NULL COMMENT '上架库位ID',
`Remark` VARCHAR(512) NULL COMMENT '备注',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
KEY `idx_c_parcel_item_parcel` (`ParcelId`, `IsDeleted`)
) COMMENT='仓储-包裹明细';
CREATE TABLE `C_sku_platform_map` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`StoreId` INT NOT NULL COMMENT '店铺ID → t_sales_store.Id',
`PlatformSku` VARCHAR(128) NOT NULL COMMENT '平台listing SKU',
`SkuId` INT NOT NULL COMMENT '库内SKU ID → C_sku.Id',
`SkuCode` VARCHAR(64) NOT NULL COMMENT '冗余SKU编码',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_c_sku_map` (`StoreId`, `PlatformSku`),
KEY `idx_c_sku_map_customer` (`CustomerId`, `SkuId`)
) COMMENT='仓储-平台SKU映射';
-- ---------------------------------------------------------------------------
-- 订单域 — 店铺(t_sales_*,接口阶段使用)
-- ---------------------------------------------------------------------------
CREATE TABLE `t_sales_store` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`PlatformCode` VARCHAR(32) NOT NULL COMMENT 'lazada/shopee/tiktok/temu/manual',
`StoreNickname` VARCHAR(128) NOT NULL COMMENT '店铺昵称',
`PlatformStoreId` VARCHAR(64) NULL COMMENT '平台侧店铺ID',
`PlatformAccount` VARCHAR(128) NULL COMMENT '平台账号',
`SiteCountry` VARCHAR(8) NULL COMMENT '开户站点国家码',
`SellerId` VARCHAR(64) NULL COMMENT '平台卖家ID',
`AuthStatus` VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT 'active/expired/revoked',
`AuthTime` DATETIME NULL COMMENT '授权时间',
`TokenExpireTime` DATETIME NULL COMMENT 'AccessToken过期时间',
`RefreshExpireTime` DATETIME NULL COMMENT 'RefreshToken过期时间',
`AccessToken` VARCHAR(2048) NULL COMMENT 'AccessToken(加密存储)',
`RefreshToken` VARCHAR(2048) NULL COMMENT 'RefreshToken(加密存储)',
`TokenExtraJson` JSON NULL COMMENT '平台扩展Token信息',
`IsAutoFulfill` TINYINT NOT NULL DEFAULT 0 COMMENT '是否自动发货:0-否,1-是',
`Remark` VARCHAR(512) NULL COMMENT '备注',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
KEY `idx_sales_store_customer` (`CustomerId`, `IsDeleted`),
KEY `idx_sales_store_platform` (`CustomerId`, `PlatformCode`, `AuthStatus`)
) COMMENT='销售店铺授权';
CREATE TABLE `t_sales_store_order` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`StoreId` INT NOT NULL COMMENT '店铺ID → t_sales_store.Id',
`PlatformCode` VARCHAR(32) NOT NULL COMMENT '平台编码',
`PlatformOrderNo` VARCHAR(64) NOT NULL COMMENT '平台订单号',
`OrderCountry` VARCHAR(8) NULL COMMENT '订单国家',
`ItemCount` INT NULL COMMENT '商品行数',
`TotalAmount` DECIMAL(18,4) NULL COMMENT '订单总额',
`Currency` VARCHAR(8) NULL COMMENT '币种',
`PlatformOrderTime` DATETIME NULL COMMENT '平台下单时间',
`FulfillStatus` VARCHAR(32) NOT NULL DEFAULT 'pending' COMMENT '履约状态',
`PlatformStatus` VARCHAR(64) NULL COMMENT '平台原始状态码',
`PlatformStatusLabel` VARCHAR(128) NULL COMMENT '平台状态展示文案',
`ShippingLabelNo` VARCHAR(64) NULL COMMENT '面单号',
`ShippingLabelUrl` VARCHAR(512) NULL COMMENT '面单URL',
`IsMultiLabel` TINYINT NOT NULL DEFAULT 0 COMMENT '是否多面单',
`CustomTags` VARCHAR(512) NULL COMMENT '自定义标签',
`IsSuspended` TINYINT NOT NULL DEFAULT 0 COMMENT '是否搁置',
`WarehouseId` INT NULL COMMENT '发货仓库ID',
`LinkedOrderId` INT NULL COMMENT '关联小包订单 t_order.Id',
`LastSyncTime` DATETIME NULL COMMENT '最近同步时间',
`PlatformExtraJson` JSON NULL COMMENT '平台扩展字段',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_store_order_no` (`StoreId`, `PlatformOrderNo`),
KEY `idx_store_order_customer_status` (`CustomerId`, `FulfillStatus`, `PlatformOrderTime`)
) COMMENT='销售店铺订单';
CREATE TABLE `t_sales_store_order_line` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`StoreOrderId` INT NOT NULL COMMENT '店铺订单ID → t_sales_store_order.Id',
`PlatformLineId` VARCHAR(64) NULL COMMENT '平台行ID',
`PlatformSku` VARCHAR(128) NULL COMMENT '平台SKU',
`ProductName` VARCHAR(512) NULL COMMENT '商品名称',
`ProductImageUrl` VARCHAR(512) NULL COMMENT '商品图片',
`VariantText` VARCHAR(256) NULL COMMENT '规格属性',
`UnitPrice` DECIMAL(18,4) NULL COMMENT '单价',
`Quantity` INT NOT NULL DEFAULT 0 COMMENT '数量',
`Currency` VARCHAR(8) NULL COMMENT '币种',
`IsShipExcluded` TINYINT NOT NULL DEFAULT 0 COMMENT '是否拒绝发货',
`MappedSkuId` INT NULL COMMENT '映射库内SKU → C_sku.Id',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
KEY `idx_store_order_line_order` (`StoreOrderId`, `IsDeleted`)
) COMMENT='销售店铺订单明细';
-- 小红书(LIKE AI → OMS)模块,详见设计文档 docs/小红书模块设计-063001.md
CREATE TABLE `t_xhs_agent` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID → t_customer.Id',
`DeviceId` VARCHAR(64) NOT NULL COMMENT 'Agent 本机设备标识',
@ -1165,7 +1509,7 @@ CREATE TABLE IF NOT EXISTS `t_xhs_agent` (
KEY `idx_xhs_agent_customer` (`CustomerId`, `Status`)
) COMMENT='小红书本地 Agent 设备表';
CREATE TABLE IF NOT EXISTS `t_xhs_task` (
CREATE TABLE `t_xhs_task` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`AgentId` INT NULL COMMENT '指定执行的 Agent;NULL 表示任意在线 Agent',
@ -1195,7 +1539,7 @@ CREATE TABLE IF NOT EXISTS `t_xhs_task` (
KEY `idx_xhs_task_source` (`Source`, `SourceRefId`)
) COMMENT='小红书 Agent 任务队列表';
CREATE TABLE IF NOT EXISTS `t_xhs_publish_record` (
CREATE TABLE `t_xhs_publish_record` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`TaskId` INT NULL COMMENT '关联 t_xhs_task.Id',
@ -1224,7 +1568,7 @@ CREATE TABLE IF NOT EXISTS `t_xhs_publish_record` (
KEY `idx_xhs_publish_task` (`TaskId`)
) COMMENT='小红书发布记录表';
CREATE TABLE IF NOT EXISTS `t_xhs_analysis_session` (
CREATE TABLE `t_xhs_analysis_session` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`SessionName` VARCHAR(128) NULL COMMENT '用户备注名',
@ -1245,7 +1589,7 @@ CREATE TABLE IF NOT EXISTS `t_xhs_analysis_session` (
KEY `idx_xhs_analysis_customer` (`CustomerId`, `CreateTime`)
) COMMENT='小红书内容分析会话表';
CREATE TABLE IF NOT EXISTS `t_xhs_skill` (
CREATE TABLE `t_xhs_skill` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID;0 表示系统预置',
`ExternalId` VARCHAR(32) NOT NULL COMMENT '对外稳定 ID',
@ -1265,7 +1609,7 @@ CREATE TABLE IF NOT EXISTS `t_xhs_skill` (
KEY `idx_xhs_skill_customer` (`CustomerId`, `SortOrder`)
) COMMENT='小红书技能卡片表';
CREATE TABLE IF NOT EXISTS `t_xhs_human_config` (
CREATE TABLE `t_xhs_human_config` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`BehaviorJson` JSON NOT NULL COMMENT 'human_behavior 配置',
@ -1281,7 +1625,7 @@ CREATE TABLE IF NOT EXISTS `t_xhs_human_config` (
UNIQUE KEY `uk_xhs_human_customer` (`CustomerId`)
) COMMENT='小红书拟人行为与防封配置表';
CREATE TABLE IF NOT EXISTS `t_xhs_ai_provider` (
CREATE TABLE `t_xhs_ai_provider` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID;0 表示全局',
`ProviderKey` VARCHAR(32) NOT NULL COMMENT 'ai_chatgpt / ai_zhipu 等',
@ -1303,7 +1647,7 @@ CREATE TABLE IF NOT EXISTS `t_xhs_ai_provider` (
KEY `idx_xhs_ai_customer` (`CustomerId`, `Enabled`)
) COMMENT='小红书 AI 提供商配置表';
CREATE TABLE IF NOT EXISTS `t_xhs_media` (
CREATE TABLE `t_xhs_media` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`FileName` VARCHAR(256) NOT NULL COMMENT '原始文件名',
@ -1320,4 +1664,282 @@ CREATE TABLE IF NOT EXISTS `t_xhs_media` (
KEY `idx_xhs_media_customer` (`CustomerId`, `CreateTime`)
) COMMENT='小红书创作上传媒体表';
-- ---------------------------------------------------------------------------
-- 数据权限(RBAC 侧表;若与 OMS 分库,请只在 RBAC 库执行本段)
-- ---------------------------------------------------------------------------
CREATE TABLE `user_org_perm` (
`Id` CHAR(36) NOT NULL COMMENT '主键 GUID',
`UserId` CHAR(36) NOT NULL COMMENT 'FK user.Id',
`OrganizationId` CHAR(36) NOT NULL COMMENT 'FK organization.Id',
`OrgScope` TINYINT NOT NULL DEFAULT 2 COMMENT '1=仅本级 2=本级+所有下级',
`EffectiveTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '生效时间',
`ExpireTime` DATETIME NULL COMMENT '过期时间,NULL=永久',
`IsTemporary` TINYINT NOT NULL DEFAULT 0 COMMENT '是否临时授权:0否 1是',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
KEY `idx_user_org_perm_user` (`UserId`, `IsDeleted`),
KEY `idx_user_org_perm_org` (`OrganizationId`),
KEY `idx_user_org_perm_expire` (`ExpireTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户组织数据权限';
-- ---------------------------------------------------------------------------
-- 2. 角色组织权限(角色继承 / 模板绑定)
-- ---------------------------------------------------------------------------
CREATE TABLE `role_org_perm` (
`Id` CHAR(36) NOT NULL,
`RoleId` CHAR(36) NOT NULL COMMENT 'FK role.Id',
`OrganizationId` CHAR(36) NOT NULL,
`OrgScope` TINYINT NOT NULL DEFAULT 2,
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_role_org_perm` (`RoleId`, `OrganizationId`, `IsDeleted`),
KEY `idx_role_org_perm_role` (`RoleId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色组织数据权限';
-- ---------------------------------------------------------------------------
-- 3. 数据范围(个人/小组/部门/组织树/全局)
-- ---------------------------------------------------------------------------
CREATE TABLE `role_data_scope` (
`Id` CHAR(36) NOT NULL,
`RoleId` CHAR(36) NOT NULL,
`DataScope` TINYINT NOT NULL COMMENT '1个人 2小组 3部门 4组织树 5全局',
`DataResourceCode` VARCHAR(32) NULL COMMENT 'NULL=全局默认;Order/Customer/Recharge 等',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_role_data_scope` (`RoleId`, `DataResourceCode`, `IsDeleted`),
KEY `idx_role_data_scope_role` (`RoleId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色数据范围';
CREATE TABLE `user_data_scope` (
`Id` CHAR(36) NOT NULL,
`UserId` CHAR(36) NOT NULL,
`DataScope` TINYINT NOT NULL,
`DataResourceCode` VARCHAR(32) NULL,
`EffectiveTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`ExpireTime` DATETIME NULL,
`IsTemporary` TINYINT NOT NULL DEFAULT 0,
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_user_data_scope` (`UserId`, `DataResourceCode`, `IsDeleted`),
KEY `idx_user_data_scope_user` (`UserId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户数据范围(覆盖角色默认)';
-- ---------------------------------------------------------------------------
-- 4. 业务维度
-- ---------------------------------------------------------------------------
CREATE TABLE `role_biz_perm` (
`Id` CHAR(36) NOT NULL,
`RoleId` CHAR(36) NOT NULL,
`BizType` VARCHAR(32) NOT NULL COMMENT 'product_line/kpi_area/customer_group/warehouse/region',
`BizId` VARCHAR(64) NOT NULL COMMENT '业务主键字符串',
`BizName` VARCHAR(128) NULL COMMENT '冗余展示名',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`Id`),
KEY `idx_role_biz_perm_role` (`RoleId`, `BizType`),
KEY `idx_role_biz_perm_biz` (`BizType`, `BizId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色业务维度权限';
CREATE TABLE `user_biz_perm` (
`Id` CHAR(36) NOT NULL,
`UserId` CHAR(36) NOT NULL,
`BizType` VARCHAR(32) NOT NULL,
`BizId` VARCHAR(64) NOT NULL,
`BizName` VARCHAR(128) NULL,
`EffectiveTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`ExpireTime` DATETIME NULL,
`IsTemporary` TINYINT NOT NULL DEFAULT 0,
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`Id`),
KEY `idx_user_biz_perm_user` (`UserId`, `BizType`),
KEY `idx_user_biz_perm_biz` (`BizType`, `BizId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户业务维度权限';
-- ---------------------------------------------------------------------------
-- 5. 密级
-- ---------------------------------------------------------------------------
CREATE TABLE `role_secret_perm` (
`Id` CHAR(36) NOT NULL,
`RoleId` CHAR(36) NOT NULL,
`SecretLevel` TINYINT NOT NULL COMMENT '1公开 2内部 3机密 4绝密',
`DataResourceCode` VARCHAR(32) NULL,
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`Id`),
KEY `idx_role_secret_perm_role` (`RoleId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色密级权限';
CREATE TABLE `user_secret_perm` (
`Id` CHAR(36) NOT NULL,
`UserId` CHAR(36) NOT NULL,
`SecretLevel` TINYINT NOT NULL,
`DataResourceCode` VARCHAR(32) NULL,
`EffectiveTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`ExpireTime` DATETIME NULL,
`IsTemporary` TINYINT NOT NULL DEFAULT 0,
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`Id`),
KEY `idx_user_secret_perm_user` (`UserId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户密级权限';
-- ---------------------------------------------------------------------------
-- 6. 自定义过滤规则(JSON AST,禁止存 SQL)
-- ---------------------------------------------------------------------------
CREATE TABLE `role_filter_rule` (
`Id` CHAR(36) NOT NULL,
`RoleId` CHAR(36) NOT NULL,
`DataResourceCode` VARCHAR(32) NOT NULL,
`FilterContent` JSON NOT NULL COMMENT '过滤条件 AST',
`FilterHash` CHAR(64) NOT NULL COMMENT 'SHA256(FilterContent)',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_role_filter_rule` (`RoleId`, `DataResourceCode`, `IsDeleted`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色自定义过滤';
CREATE TABLE `user_filter_rule` (
`Id` CHAR(36) NOT NULL,
`UserId` CHAR(36) NOT NULL,
`DataResourceCode` VARCHAR(32) NOT NULL,
`FilterContent` JSON NOT NULL,
`FilterHash` CHAR(64) NOT NULL,
`EffectiveTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`ExpireTime` DATETIME NULL,
`IsTemporary` TINYINT NOT NULL DEFAULT 0,
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_user_filter_rule` (`UserId`, `DataResourceCode`, `IsDeleted`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户自定义过滤';
-- ---------------------------------------------------------------------------
-- 7. 数据资源注册(模块接入清单)
-- ---------------------------------------------------------------------------
CREATE TABLE `data_resource` (
`Id` CHAR(36) NOT NULL,
`Code` VARCHAR(32) NOT NULL COMMENT 'Order/Customer/Recharge/ChannelProduct/Xhs',
`Name` VARCHAR(64) NOT NULL,
`Description` VARCHAR(256) NULL,
`MainTable` VARCHAR(64) NULL COMMENT '主表名,如 t_order',
`OrgField` VARCHAR(64) NULL COMMENT '组织字段名',
`OwnerField` VARCHAR(64) NULL COMMENT '负责人字段名',
`SecretLevelField` VARCHAR(64) NULL DEFAULT 'SecretLevel',
`IsEnabled` TINYINT NOT NULL DEFAULT 1,
`SortOrder` INT NOT NULL DEFAULT 0,
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_data_resource_code` (`Code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据权限资源注册';
-- ---------------------------------------------------------------------------
-- 8. 字段脱敏配置
-- ---------------------------------------------------------------------------
CREATE TABLE `data_perm_field_mask` (
`Id` CHAR(36) NOT NULL,
`DataResourceCode` VARCHAR(32) NOT NULL,
`FieldName` VARCHAR(64) NOT NULL COMMENT 'DTO/表字段名',
`SecretLevel` TINYINT NOT NULL COMMENT '达到此密级才脱敏',
`MaskType` VARCHAR(32) NOT NULL DEFAULT 'partial' COMMENT 'partial/full/hide',
`MaskPattern` VARCHAR(128) NULL COMMENT '如 phone: 3,4 保留首尾',
`IsEnabled` TINYINT NOT NULL DEFAULT 1,
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_field_mask` (`DataResourceCode`, `FieldName`, `IsDeleted`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='字段级脱敏配置';
-- ---------------------------------------------------------------------------
-- 9. 权限模板
-- ---------------------------------------------------------------------------
CREATE TABLE `data_perm_template` (
`Id` CHAR(36) NOT NULL,
`Name` VARCHAR(64) NOT NULL,
`Code` VARCHAR(32) NOT NULL COMMENT '模板编码,如 SalesStaff',
`Description` VARCHAR(256) NULL,
`RoleCode` VARCHAR(64) NULL COMMENT '可选绑定 RBAC role.Code,分配角色时自动套用',
`IsBuiltIn` TINYINT NOT NULL DEFAULT 0 COMMENT '内置模板不可删',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_data_perm_template_code` (`Code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据权限模板';
CREATE TABLE `data_perm_template_item` (
`Id` CHAR(36) NOT NULL,
`TemplateId` CHAR(36) NOT NULL,
`DimensionType` VARCHAR(32) NOT NULL COMMENT 'org/data_scope/biz/secret/filter',
`ItemContent` JSON NOT NULL COMMENT '维度配置 JSON',
`SortOrder` INT NOT NULL DEFAULT 0,
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
PRIMARY KEY (`Id`),
KEY `idx_template_item_tpl` (`TemplateId`, `DimensionType`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据权限模板明细';
-- ---------------------------------------------------------------------------
-- 10. 审计
-- ---------------------------------------------------------------------------
CREATE TABLE `data_perm_change_log` (
`Id` BIGINT NOT NULL AUTO_INCREMENT,
`TargetType` VARCHAR(16) NOT NULL COMMENT 'user/role/template',
`TargetId` CHAR(36) NOT NULL,
`Action` VARCHAR(16) NOT NULL COMMENT 'create/update/delete/apply_template',
`BeforeJson` JSON NULL,
`AfterJson` JSON NULL,
`OperatorUserId` CHAR(36) NOT NULL COMMENT '操作人 user.Id',
`OperatorMapId` INT NULL COMMENT '操作人 mapId',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`Id`),
KEY `idx_perm_change_target` (`TargetType`, `TargetId`, `CreateTime`),
KEY `idx_perm_change_operator` (`OperatorUserId`, `CreateTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据权限配置变更日志';
CREATE TABLE `data_perm_access_log` (
`Id` BIGINT NOT NULL AUTO_INCREMENT,
`UserId` CHAR(36) NOT NULL,
`MapId` INT NULL,
`DataResourceCode` VARCHAR(32) NOT NULL,
`ApiPath` VARCHAR(256) NOT NULL,
`HttpMethod` VARCHAR(8) NOT NULL DEFAULT 'GET',
`AppliedScopeJson` JSON NULL COMMENT '生效五维快照',
`RowCount` INT NULL COMMENT '返回行数',
`ElapsedMs` INT NULL,
`ClientIp` VARCHAR(64) NULL,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`Id`),
KEY `idx_perm_access_user_time` (`UserId`, `CreateTime`),
KEY `idx_perm_access_resource` (`DataResourceCode`, `CreateTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据权限访问审计(可采样)';
SET FOREIGN_KEY_CHECKS = 1;

View File

@ -3,7 +3,7 @@
--
-- 注意:必须使用 DROP + CREATE,不能用 IF NOT EXISTS。
-- 若表已存在,IF NOT EXISTS 会跳过建表,表/字段注释不会写入。
-- 若表内已有业务数据,请勿执行本脚本,改用 sql/migrate_t_order_batch_job_comments.sql
-- 若表内已有业务数据,请勿直接 DROP;对照根目录 db.sql 中对应表定义手工补列。
SET FOREIGN_KEY_CHECKS = 0;

7
sql/README.md Normal file
View File

@ -0,0 +1,7 @@
# sql/
OMS / 共用库的建表脚本已统一到仓库根目录 `db.sql`。
- 新环境:直接执行 `db.sql`(会 DROP 后重建,勿在有生产数据的库上执行)
- 已有库:用 diff 对比 `db.sql` 与现库结构后手工 ALTER,不再维护 `migrate_*.sql`
- 数据权限表(`user_org_perm` 等)若 RBAC 与 OMS 分库,请只在 RBAC 库执行 `db.sql` 末尾对应段落

View File

@ -1,62 +0,0 @@
-- 数据权限表:诊断 CHAR(36) 非法 GUID
-- 症状:GET /rbac/data-perm/template/list → Could not parse CHAR(36) value as Guid: 1
-- 或其它 data-perm 接口同类报错
--
-- ⚠️ 在 API 实际连接的 RBAC 库执行(与 user/role/menu 同库)
SET @GUID_RE = '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$';
SELECT 'data_perm_template bad Id' AS section, t.`Id`, t.`Name`, t.`Code`, t.`CreateUserId`
FROM `data_perm_template` t
WHERE t.`Id` NOT REGEXP @GUID_RE;
SELECT 'data_perm_template_item bad Id/TemplateId' AS section, i.`Id`, i.`TemplateId`, i.`DimensionType`
FROM `data_perm_template_item` i
WHERE i.`Id` NOT REGEXP @GUID_RE
OR i.`TemplateId` NOT REGEXP @GUID_RE;
SELECT 'data_resource bad Id' AS section, r.`Id`, r.`Code`, r.`Name`
FROM `data_resource` r
WHERE r.`Id` NOT REGEXP @GUID_RE;
SELECT 'data_perm_field_mask bad Id' AS section, f.`Id`, f.`DataResourceCode`, f.`FieldName`
FROM `data_perm_field_mask` f
WHERE f.`Id` NOT REGEXP @GUID_RE;
SELECT 'user_org_perm bad Id/UserId/OrganizationId' AS section, p.`Id`, p.`UserId`, p.`OrganizationId`
FROM `user_org_perm` p
WHERE p.`Id` NOT REGEXP @GUID_RE
OR p.`UserId` NOT REGEXP @GUID_RE
OR p.`OrganizationId` NOT REGEXP @GUID_RE;
SELECT 'role_org_perm bad Id/RoleId/OrganizationId' AS section, p.`Id`, p.`RoleId`, p.`OrganizationId`
FROM `role_org_perm` p
WHERE p.`Id` NOT REGEXP @GUID_RE
OR p.`RoleId` NOT REGEXP @GUID_RE
OR p.`OrganizationId` NOT REGEXP @GUID_RE;
SELECT 'user_data_scope bad Id/UserId' AS section, p.`Id`, p.`UserId`, p.`DataResourceCode`
FROM `user_data_scope` p
WHERE p.`Id` NOT REGEXP @GUID_RE
OR p.`UserId` NOT REGEXP @GUID_RE;
SELECT 'role_data_scope bad Id/RoleId' AS section, p.`Id`, p.`RoleId`, p.`DataResourceCode`
FROM `role_data_scope` p
WHERE p.`Id` NOT REGEXP @GUID_RE
OR p.`RoleId` NOT REGEXP @GUID_RE;
SELECT 'data_perm_change_log bad TargetId' AS section, l.`Id`, l.`TargetType`, l.`TargetId`, l.`Action`
FROM `data_perm_change_log` l
WHERE l.`TargetId` NOT REGEXP @GUID_RE;
SELECT 'data_perm_access_log bad UserId' AS section, l.`Id`, l.`UserId`, l.`DataResourceCode`, l.`ApiPath`
FROM `data_perm_access_log` l
WHERE l.`UserId` NOT REGEXP @GUID_RE;
-- 常见脏值快捷统计
SELECT 'template Id=1' AS hint, COUNT(*) AS cnt FROM `data_perm_template` WHERE TRIM(`Id`) IN ('0', '1', '2');
SELECT 'template_item Id=1' AS hint, COUNT(*) AS cnt FROM `data_perm_template_item` WHERE TRIM(`Id`) IN ('0', '1', '2');
SELECT 'template dp prefix' AS hint, COUNT(*) AS cnt FROM `data_perm_template` WHERE `Id` LIKE 'dp%';
SELECT 'template dr prefix' AS hint, COUNT(*) AS cnt FROM `data_perm_template` WHERE `Id` LIKE 'dr%';
SELECT 'data_resource dr000001 prefix' AS hint, COUNT(*) AS cnt FROM `data_resource` WHERE `Id` LIKE 'dr000001-%';
SELECT 'field_mask fm000001 prefix' AS hint, COUNT(*) AS cnt FROM `data_perm_field_mask` WHERE `Id` LIKE 'fm000001-%';

View File

@ -1,56 +0,0 @@
-- RBAC 库:诊断所有 CHAR(36) / GUID 字段中的非法值(如 "0")
-- 症状:登录 / get-menu-tree → Could not parse CHAR(36) value as Guid: 0
--
-- ⚠️ 必须在 API 实际连接的 RBAC 库执行
-- 本地前端 dev(localhost:5173)默认代理到 http://api.nanafa.com/admin → 修本机库无效
SET @GUID_RE = '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$';
SELECT 'menu bad rows' AS section, m.`Id`, m.`Name`, m.`Route`, m.`PId`, m.`CreateUserId`, m.`UpdateUserId`, m.`ConcurrencyStamp`
FROM `menu` m
WHERE (m.`PId` IS NOT NULL AND m.`PId` NOT REGEXP @GUID_RE)
OR (m.`CreateUserId` IS NOT NULL AND m.`CreateUserId` NOT REGEXP @GUID_RE)
OR (m.`UpdateUserId` IS NOT NULL AND m.`UpdateUserId` NOT REGEXP @GUID_RE)
OR (m.`ConcurrencyStamp` IS NOT NULL AND m.`ConcurrencyStamp` NOT REGEXP @GUID_RE);
SELECT 'role bad rows' AS section, r.`Id`, r.`Code`, r.`Name`, r.`CreateUserId`, r.`UpdateUserId`, r.`ConcurrencyStamp`
FROM `role` r
WHERE (r.`CreateUserId` IS NOT NULL AND CAST(r.`CreateUserId` AS CHAR) NOT REGEXP @GUID_RE)
OR (r.`UpdateUserId` IS NOT NULL AND CAST(r.`UpdateUserId` AS CHAR) NOT REGEXP @GUID_RE)
OR (r.`ConcurrencyStamp` IS NOT NULL AND r.`ConcurrencyStamp` NOT REGEXP @GUID_RE);
SELECT 'user bad rows' AS section, u.`Id`, u.`Account`, u.`OrganizationId`, u.`ConcurrencyStamp`
FROM `user` u
WHERE (u.`OrganizationId` IS NOT NULL AND u.`OrganizationId` <> '' AND u.`OrganizationId` NOT REGEXP @GUID_RE)
OR (u.`ConcurrencyStamp` IS NOT NULL AND u.`ConcurrencyStamp` NOT REGEXP @GUID_RE);
SELECT 'user_role bad rows' AS section, ur.`Id`, ur.`UserId`, ur.`RoleId`
FROM `user_role` ur
WHERE (ur.`UserId` IS NOT NULL AND ur.`UserId` NOT REGEXP @GUID_RE)
OR (ur.`RoleId` IS NOT NULL AND ur.`RoleId` NOT REGEXP @GUID_RE);
SELECT 'role_permission bad rows' AS section, rp.`Id`, rp.`RoleId`, rp.`PermissionCode`, rp.`CreateUserId`
FROM `role_permission` rp
WHERE (rp.`RoleId` IS NOT NULL AND rp.`RoleId` NOT REGEXP @GUID_RE)
OR (rp.`CreateUserId` IS NOT NULL AND CAST(rp.`CreateUserId` AS CHAR) NOT REGEXP @GUID_RE);
SELECT 'user_role bad CreateUserId' AS section, ur.`Id`, ur.`UserId`, ur.`RoleId`, ur.`CreateUserId`
FROM `user_role` ur
WHERE ur.`CreateUserId` IS NOT NULL AND CAST(ur.`CreateUserId` AS CHAR) NOT REGEXP @GUID_RE;
SELECT 'organization bad rows' AS section, o.`Id`, o.`Name`, o.`ParentId`, o.`LeaderId`
FROM `organization` o
WHERE (o.`ParentId` IS NOT NULL AND o.`ParentId` <> '' AND o.`ParentId` NOT REGEXP @GUID_RE)
OR (o.`LeaderId` IS NOT NULL AND o.`LeaderId` <> '' AND o.`LeaderId` NOT REGEXP @GUID_RE)
OR (o.`ConcurrencyStamp` IS NOT NULL AND o.`ConcurrencyStamp` NOT REGEXP @GUID_RE);
-- 快速查 menu 里最常见的脏值(勿只查 Id 列)
SELECT 'menu CreateUserId=0' AS hint, COUNT(*) AS cnt FROM `menu` WHERE CAST(`CreateUserId` AS CHAR) = '0';
SELECT 'menu UpdateUserId=0' AS hint, COUNT(*) AS cnt FROM `menu` WHERE CAST(`UpdateUserId` AS CHAR) = '0';
SELECT 'menu PId=0' AS hint, COUNT(*) AS cnt FROM `menu` WHERE CAST(`PId` AS CHAR) = '0';
SELECT 'role_permission CreateUserId=0' AS hint, COUNT(*) AS cnt
FROM `role_permission` WHERE CAST(`CreateUserId` AS CHAR) = '0';
SELECT 'user_role CreateUserId=0' AS hint, COUNT(*) AS cnt
FROM `user_role` WHERE CAST(`CreateUserId` AS CHAR) = '0';

View File

@ -1,10 +0,0 @@
-- 数据权限审计菜单:accessLog → audit(与前端路由一致)
-- 若未执行过旧 seed 可跳过;已存在错误 Route/Component 时执行本脚本
UPDATE `menu`
SET
`Route` = '/system/dataPerm/audit',
`Component` = 'views/system/dataPerm/audit/index',
`UpdateTime` = NOW()
WHERE `Id` = 'da100001-0000-4000-8000-000000000004'
OR (`Route` = '/system/dataPerm/accessLog' AND `PermissionCode` = 'Rbac.DataPerm.Audit');

View File

@ -1,25 +0,0 @@
-- 修复 menu 表非法 GUID(Id/PId 含非十六进制字符,如 dp100001 中的 p)
-- 症状:登录 / get-menu-tree → Could not parse CHAR(36) value as Guid: dp100001-...
-- GUID 仅允许 0-9、a-f
--
-- ⚠️ 在 RBAC 库执行
SELECT 'before fix' AS stage, `Id`, `PId`, `Name`, `Route`, `PermissionCode`
FROM `menu`
WHERE `Id` LIKE 'dp100001-%'
OR `PId` LIKE 'dp100001-%';
-- 先改子节点 PId,再改 Id
UPDATE `menu`
SET `PId` = REPLACE(`PId`, 'dp100001-', 'da100001-')
WHERE `PId` LIKE 'dp100001-%';
UPDATE `menu`
SET `Id` = REPLACE(`Id`, 'dp100001-', 'da100001-')
WHERE `Id` LIKE 'dp100001-%';
SELECT 'after fix (should be empty)' AS stage, `Id`, `PId`, `Name`, `Route`
FROM `menu`
WHERE `Id` LIKE 'dp100001-%'
OR `PId` LIKE 'dp100001-%'
OR (`Id` NOT REGEXP '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$');

View File

@ -1,32 +0,0 @@
-- 修复 role_permission.CreateUserId = '0' 导致登录失败
-- 症状:POST /rbac/auth/login → Could not parse CHAR(36) value as Guid: 0
-- 原因:seed_data_perm_rbac_menu.sql 曾写入 CreateUserId = 0
--
-- ⚠️ 在 RBAC 库(fake_simple_admin 或 API 连接的 RBAC 库)执行
SET @ADMIN_USER_ID = (
SELECT `Id` FROM `user`
WHERE `Account` = 'admin' AND (`IsDeleted` = 0 OR `IsDeleted` IS NULL)
LIMIT 1
);
SET @ADMIN_USER_ID = IFNULL(
@ADMIN_USER_ID,
(SELECT `Id` FROM `user` WHERE `IsDeleted` = 0 OR `IsDeleted` IS NULL ORDER BY `CreateTime` LIMIT 1)
);
SELECT @ADMIN_USER_ID AS admin_user_id_used;
SELECT 'before fix' AS stage, rp.`Id`, rp.`RoleId`, rp.`PermissionCode`, rp.`CreateUserId`
FROM `role_permission` rp
WHERE CAST(rp.`CreateUserId` AS CHAR) = '0'
OR (rp.`CreateUserId` IS NOT NULL AND rp.`CreateUserId` NOT REGEXP '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$');
UPDATE `role_permission`
SET `CreateUserId` = @ADMIN_USER_ID
WHERE CAST(`CreateUserId` AS CHAR) = '0'
OR (`CreateUserId` IS NOT NULL AND `CreateUserId` NOT REGEXP '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$');
SELECT 'after fix (should be empty)' AS stage, rp.`Id`, rp.`RoleId`, rp.`PermissionCode`, rp.`CreateUserId`
FROM `role_permission` rp
WHERE CAST(rp.`CreateUserId` AS CHAR) = '0'
OR (rp.`CreateUserId` IS NOT NULL AND rp.`CreateUserId` NOT REGEXP '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$');

View File

@ -1,101 +0,0 @@
-- 修复 data_perm_* 表非法 GUID(如 Id='1'、dp/dr 前缀含非 hex 字符)
-- 症状:GET /rbac/data-perm/template/list → Could not parse CHAR(36) value as Guid: 1
--
-- ⚠️ 在 RBAC 库执行;执行前先跑 diagnose_data_perm_bad_guids.sql 确认脏数据
-- 若库中从未跑过 install_data_permission.sql,请先执行该脚本再跑本修复
SET @GUID_RE = '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$';
SELECT 'before fix — bad template rows' AS stage, t.`Id`, t.`Name`, t.`Code`
FROM `data_perm_template` t
WHERE t.`Id` NOT REGEXP @GUID_RE;
-- 1) 旧种子前缀 dp/dr → da(与 install_data_permission.sql 一致)
UPDATE `data_perm_template_item`
SET `TemplateId` = REPLACE(`TemplateId`, 'dp000001-', 'da000001-')
WHERE `TemplateId` LIKE 'dp000001-%';
UPDATE `data_perm_template_item`
SET `Id` = REPLACE(`Id`, 'dp200001-', 'da200001-')
WHERE `Id` LIKE 'dp200001-%';
UPDATE `data_perm_template_item`
SET `Id` = REPLACE(`Id`, 'dr200001-', 'da200001-')
WHERE `Id` LIKE 'dr200001-%';
UPDATE `data_perm_template`
SET `Id` = REPLACE(`Id`, 'dp000001-', 'da000001-')
WHERE `Id` LIKE 'dp000001-%';
UPDATE `data_perm_template`
SET `Id` = REPLACE(`Id`, 'dr000001-', 'da000001-')
WHERE `Id` LIKE 'dr000001-%';
UPDATE `data_resource`
SET `Id` = REPLACE(`Id`, 'dr000001-', 'da300001-')
WHERE `Id` LIKE 'dr000001-%';
UPDATE `data_resource`
SET `Id` = REPLACE(`Id`, 'dr300001-', 'da300001-')
WHERE `Id` LIKE 'dr300001-%';
UPDATE `data_resource`
SET `Id` = REPLACE(`Id`, 'dp300001-', 'da300001-')
WHERE `Id` LIKE 'dp300001-%';
UPDATE `data_perm_field_mask`
SET `Id` = REPLACE(`Id`, 'fm000001-', 'fa000001-')
WHERE `Id` LIKE 'fm000001-%';
-- 2) 删除无法自动映射的脏模板
DELETE FROM `data_perm_template_item`
WHERE `TemplateId` IN (
SELECT `Id` FROM (
SELECT `Id` FROM `data_perm_template` WHERE TRIM(`Id`) NOT REGEXP @GUID_RE
) AS bad_tpl
);
DELETE FROM `data_perm_template`
WHERE TRIM(`Id`) NOT REGEXP @GUID_RE;
-- 3) 重新插入内置模板(与 install_data_permission.sql §12 一致,可重复执行)
INSERT INTO `data_perm_template` (`Id`, `Name`, `Code`, `Description`, `RoleCode`, `IsBuiltIn`, `CreateUserId`, `CreateTime`) VALUES
('da000001-0000-4000-8000-000000000001', '普通销售', 'SalesStaff', '个人级+指定产品线+密级1-2', NULL, 1, 0, NOW()),
('da000001-0000-4000-8000-000000000002', '销售主管', 'SalesSupervisor', '部门级+全部产品线+密级1-3', NULL, 1, 0, NOW()),
('da000001-0000-4000-8000-000000000003', '分公司经理', 'BranchManager', '组织树级+密级1-3', NULL, 1, 0, NOW()),
('da000001-0000-4000-8000-000000000004', '总部产品经理', 'ProductManager', '全局级+单产品线+密级1-2', NULL, 1, 0, NOW()),
('da000001-0000-4000-8000-000000000005', '财务专员', 'FinanceStaff', '组织树级+密级含3-4', NULL, 1, 0, NOW()),
('da000001-0000-4000-8000-000000000006', '客服专员', 'CsStaff', '个人级+密级1-2', NULL, 1, 0, NOW())
ON DUPLICATE KEY UPDATE
`Name` = VALUES(`Name`),
`Description` = VALUES(`Description`),
`IsBuiltIn` = VALUES(`IsBuiltIn`);
INSERT INTO `data_perm_template_item` (`Id`, `TemplateId`, `DimensionType`, `ItemContent`, `SortOrder`) VALUES
('da200001-0000-4000-8000-000000000011', 'da000001-0000-4000-8000-000000000001', 'data_scope', '{"dataScope":1,"dataResourceCode":null}', 1),
('da200001-0000-4000-8000-000000000012', 'da000001-0000-4000-8000-000000000001', 'secret', '{"secretLevels":[1,2]}', 2),
('da200001-0000-4000-8000-000000000021', 'da000001-0000-4000-8000-000000000002', 'data_scope', '{"dataScope":3,"dataResourceCode":null}', 1),
('da200001-0000-4000-8000-000000000022', 'da000001-0000-4000-8000-000000000002', 'secret', '{"secretLevels":[1,2,3]}', 2),
('da200001-0000-4000-8000-000000000031', 'da000001-0000-4000-8000-000000000003', 'data_scope', '{"dataScope":4,"dataResourceCode":null}', 1),
('da200001-0000-4000-8000-000000000032', 'da000001-0000-4000-8000-000000000003', 'secret', '{"secretLevels":[1,2,3]}', 2),
('da200001-0000-4000-8000-000000000041', 'da000001-0000-4000-8000-000000000004', 'data_scope', '{"dataScope":5,"dataResourceCode":null}', 1),
('da200001-0000-4000-8000-000000000042', 'da000001-0000-4000-8000-000000000004', 'secret', '{"secretLevels":[1,2]}', 2),
('da200001-0000-4000-8000-000000000051', 'da000001-0000-4000-8000-000000000005', 'data_scope', '{"dataScope":4,"dataResourceCode":null}', 1),
('da200001-0000-4000-8000-000000000052', 'da000001-0000-4000-8000-000000000005', 'secret', '{"secretLevels":[1,2,3,4]}', 2),
('da200001-0000-4000-8000-000000000061', 'da000001-0000-4000-8000-000000000006', 'data_scope', '{"dataScope":1,"dataResourceCode":null}', 1),
('da200001-0000-4000-8000-000000000062', 'da000001-0000-4000-8000-000000000006', 'secret', '{"secretLevels":[1,2]}', 2)
ON DUPLICATE KEY UPDATE
`ItemContent` = VALUES(`ItemContent`),
`SortOrder` = VALUES(`SortOrder`);
SELECT 'after fix — bad template' AS stage, t.`Id`, t.`Name`, t.`Code`
FROM `data_perm_template` t
WHERE t.`Id` NOT REGEXP @GUID_RE;
SELECT 'after fix — bad data_resource' AS stage, r.`Id`, r.`Code`, r.`Name`
FROM `data_resource` r
WHERE r.`Id` NOT REGEXP @GUID_RE;
SELECT 'after fix — bad field_mask' AS stage, f.`Id`, f.`DataResourceCode`, f.`FieldName`
FROM `data_perm_field_mask` f
WHERE f.`Id` NOT REGEXP @GUID_RE;

View File

@ -1,95 +0,0 @@
-- RBAC 库:修复 GUID 脏数据(menu / role / user / organization 等)
-- 与 diagnose_rbac_bad_guids.sql 配套;修复后重新跑诊断应无结果
--
-- ⚠️ 在 API 实际连接的 RBAC 库执行(api.nanafa.com 对应库,不是本机 oms 除非 API 连本机)
SET @GUID_RE = '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$';
SET @ROOT_PID = '00000000-0000-0000-0000-000000000000';
SET @ADMIN_USER_ID = (
SELECT `Id` FROM `user`
WHERE `Account` = 'admin' AND (`IsDeleted` = 0 OR `IsDeleted` IS NULL)
LIMIT 1
);
SET @ADMIN_USER_ID = IFNULL(
@ADMIN_USER_ID,
(SELECT `Id` FROM `user` WHERE `IsDeleted` = 0 OR `IsDeleted` IS NULL ORDER BY `CreateTime` LIMIT 1)
);
SELECT @ADMIN_USER_ID AS admin_user_id_used;
-- ========== menu ==========
UPDATE `menu`
SET `CreateUserId` = @ADMIN_USER_ID
WHERE `CreateUserId` IS NOT NULL AND `CreateUserId` NOT REGEXP @GUID_RE;
UPDATE `menu`
SET `UpdateUserId` = @ADMIN_USER_ID
WHERE `UpdateUserId` IS NOT NULL AND `UpdateUserId` NOT REGEXP @GUID_RE;
UPDATE `menu`
SET `PId` = @ROOT_PID
WHERE `PId` IS NOT NULL AND `PId` NOT REGEXP @GUID_RE;
UPDATE `menu`
SET `ConcurrencyStamp` = UUID()
WHERE `ConcurrencyStamp` IS NOT NULL AND `ConcurrencyStamp` NOT REGEXP @GUID_RE;
-- 小红书种子菜单(精确 Id)
UPDATE `menu`
SET `CreateUserId` = @ADMIN_USER_ID,
`UpdateUserId` = @ADMIN_USER_ID
WHERE `Id` IN (
'a1b2c3d4-e5f6-7890-abcd-ef1234567801',
'a1b2c3d4-e5f6-7890-abcd-ef1234567802',
'a1b2c3d4-e5f6-7890-abcd-ef1234567803',
'a1b2c3d4-e5f6-7890-abcd-ef1234567804',
'a1b2c3d4-e5f6-7890-abcd-ef1234567805',
'a1b2c3d4-e5f6-7890-abcd-ef1234567806',
'a1b2c3d4-e5f6-7890-abcd-ef1234567807',
'a1b2c3d4-e5f6-7890-abcd-ef1234567808'
);
-- ========== role(若列为 CHAR(36) GUID)==========
UPDATE `role`
SET `CreateUserId` = @ADMIN_USER_ID
WHERE `CreateUserId` IS NOT NULL AND CAST(`CreateUserId` AS CHAR) NOT REGEXP @GUID_RE;
UPDATE `role`
SET `UpdateUserId` = @ADMIN_USER_ID
WHERE `UpdateUserId` IS NOT NULL AND CAST(`UpdateUserId` AS CHAR) NOT REGEXP @GUID_RE;
UPDATE `role`
SET `ConcurrencyStamp` = UUID()
WHERE `ConcurrencyStamp` IS NOT NULL AND `ConcurrencyStamp` NOT REGEXP @GUID_RE;
-- ========== user ==========
UPDATE `user`
SET `OrganizationId` = NULL
WHERE `OrganizationId` IS NOT NULL
AND `OrganizationId` <> ''
AND `OrganizationId` NOT REGEXP @GUID_RE;
UPDATE `user`
SET `ConcurrencyStamp` = UUID()
WHERE `ConcurrencyStamp` IS NOT NULL AND `ConcurrencyStamp` NOT REGEXP @GUID_RE;
-- ========== organization ==========
UPDATE `organization`
SET `ParentId` = NULL
WHERE `ParentId` IS NOT NULL AND `ParentId` <> '' AND `ParentId` NOT REGEXP @GUID_RE;
UPDATE `organization`
SET `LeaderId` = NULL
WHERE `LeaderId` IS NOT NULL AND `LeaderId` <> '' AND `LeaderId` NOT REGEXP @GUID_RE;
-- ========== role_permission / user_role(登录加载权限时会读 CreateUserId GUID)==========
UPDATE `role_permission`
SET `CreateUserId` = @ADMIN_USER_ID
WHERE `CreateUserId` IS NOT NULL AND CAST(`CreateUserId` AS CHAR) NOT REGEXP @GUID_RE;
UPDATE `user_role`
SET `CreateUserId` = @ADMIN_USER_ID
WHERE `CreateUserId` IS NOT NULL AND CAST(`CreateUserId` AS CHAR) NOT REGEXP @GUID_RE;
-- 修复后请再执行 diagnose_rbac_bad_guids.sql 确认无脏行

View File

@ -1,56 +0,0 @@
-- 修复 menu 表 CreateUserId / UpdateUserId 非法 GUID(如 "0")
-- 症状:登录或 GET /rbac/menu/get-menu-tree → Could not parse CHAR(36) value as Guid: 0
--
-- ⚠️ 在 RBAC 库执行(不是 OMS 业务库 fake_simple_admin)
-- ⚠️ WHERE 中禁止写 CreateUserId = 0(整数),会触发 1292 GUID 转数字错误
-- 1) 管理员 GUID:优先 admin 账号,否则取第一个用户
SET @ADMIN_USER_ID = (
SELECT `Id` FROM `user`
WHERE `Account` = 'admin' AND (`IsDeleted` = 0 OR `IsDeleted` IS NULL)
LIMIT 1
);
SET @ADMIN_USER_ID = IFNULL(
@ADMIN_USER_ID,
(SELECT `Id` FROM `user` WHERE `IsDeleted` = 0 OR `IsDeleted` IS NULL ORDER BY `CreateTime` LIMIT 1)
);
SELECT @ADMIN_USER_ID AS admin_user_id_used;
-- 2) 诊断:修复前查看脏数据
SELECT `Id`, `Name`, `Route`, `CreateUserId`, `UpdateUserId`
FROM `menu`
WHERE (`CreateUserId` IS NOT NULL AND `CreateUserId` NOT REGEXP '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$')
OR (`UpdateUserId` IS NOT NULL AND `UpdateUserId` NOT REGEXP '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$');
-- 3) 小红书种子菜单(按 Id 精确修复)
UPDATE `menu`
SET `CreateUserId` = @ADMIN_USER_ID,
`UpdateUserId` = @ADMIN_USER_ID
WHERE `Id` IN (
'a1b2c3d4-e5f6-7890-abcd-ef1234567801',
'a1b2c3d4-e5f6-7890-abcd-ef1234567802',
'a1b2c3d4-e5f6-7890-abcd-ef1234567803',
'a1b2c3d4-e5f6-7890-abcd-ef1234567804',
'a1b2c3d4-e5f6-7890-abcd-ef1234567805',
'a1b2c3d4-e5f6-7890-abcd-ef1234567806',
'a1b2c3d4-e5f6-7890-abcd-ef1234567807',
'a1b2c3d4-e5f6-7890-abcd-ef1234567808'
);
-- 4) 兜底:全表非法 GUID(字符串比较,勿用 = 0)
UPDATE `menu`
SET `CreateUserId` = @ADMIN_USER_ID
WHERE `CreateUserId` IS NOT NULL
AND `CreateUserId` NOT REGEXP '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$';
UPDATE `menu`
SET `UpdateUserId` = @ADMIN_USER_ID
WHERE `UpdateUserId` IS NOT NULL
AND `UpdateUserId` NOT REGEXP '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$';
-- 5) 修复后应无结果
SELECT `Id`, `Name`, `CreateUserId`, `UpdateUserId`
FROM `menu`
WHERE (`CreateUserId` IS NOT NULL AND `CreateUserId` NOT REGEXP '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$')
OR (`UpdateUserId` IS NOT NULL AND `UpdateUserId` NOT REGEXP '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$');

View File

@ -1,53 +0,0 @@
-- 修复小红书菜单层级与「启动服务」消失问题
-- RBAC 库执行
--
-- 原因:
-- 1. 一级「小红书」PId 必须为 00000000-0000-0000-0000-000000000000
-- 2. 一级目录 PermissionCode 必须为空字符串(列 NOT NULL,不可写 NULL;勿与「启动服务」同权限码)
SET @ROOT_PID = '00000000-0000-0000-0000-000000000000';
SET @XHS_PID = 'a1b2c3d4-e5f6-7890-abcd-ef1234567801';
-- 一级:小红书(目录,PermissionCode 空字符串)
UPDATE `menu`
SET `PId` = @ROOT_PID,
`PermissionCode` = '',
`Route` = '/xhs',
`Component` = NULL,
`Name` = '小红书',
`IsHidden` = 0,
`IsDeleted` = 0
WHERE `Id` = @XHS_PID;
-- 6 个子菜单挂到「小红书」下
UPDATE `menu`
SET `PId` = @XHS_PID,
`IsHidden` = 0,
`IsDeleted` = 0
WHERE `Id` IN (
'a1b2c3d4-e5f6-7890-abcd-ef1234567802', -- 启动服务
'a1b2c3d4-e5f6-7890-abcd-ef1234567803', -- 内容分析
'a1b2c3d4-e5f6-7890-abcd-ef1234567804', -- 爆款创作
'a1b2c3d4-e5f6-7890-abcd-ef1234567805', -- 发布记录
'a1b2c3d4-e5f6-7890-abcd-ef1234567806', -- 技能卡片
'a1b2c3d4-e5f6-7890-abcd-ef1234567807' -- 拟人设置
);
-- 诊断
SELECT `Name`, `Route`, `PId`, `PermissionCode`,
CASE
WHEN `Id` = @XHS_PID AND `PId` = @ROOT_PID AND (`PermissionCode` = '' OR `PermissionCode` IS NULL) THEN 'OK'
WHEN `PId` = @XHS_PID THEN 'OK-child'
ELSE 'CHECK'
END AS status
FROM `menu`
WHERE `Id` IN (
@XHS_PID,
'a1b2c3d4-e5f6-7890-abcd-ef1234567802',
'a1b2c3d4-e5f6-7890-abcd-ef1234567803',
'a1b2c3d4-e5f6-7890-abcd-ef1234567804',
'a1b2c3d4-e5f6-7890-abcd-ef1234567805',
'a1b2c3d4-e5f6-7890-abcd-ef1234567806',
'a1b2c3d4-e5f6-7890-abcd-ef1234567807'
)
ORDER BY `Order`;

View File

@ -1,349 +0,0 @@
-- 数据权限模块 — RBAC 侧表结构
-- 设计文档:E:\oms0414\docs\数据权限设计.md
-- 与 user / role / organization 同库;表名小写,与 Fake.Rbac 风格一致
-- 执行前请确认已存在 RBAC 基础表
-- ---------------------------------------------------------------------------
-- 1. 用户组织权限
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `user_org_perm` (
`Id` CHAR(36) NOT NULL COMMENT '主键 GUID',
`UserId` CHAR(36) NOT NULL COMMENT 'FK user.Id',
`OrganizationId` CHAR(36) NOT NULL COMMENT 'FK organization.Id',
`OrgScope` TINYINT NOT NULL DEFAULT 2 COMMENT '1=仅本级 2=本级+所有下级',
`EffectiveTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '生效时间',
`ExpireTime` DATETIME NULL COMMENT '过期时间,NULL=永久',
`IsTemporary` TINYINT NOT NULL DEFAULT 0 COMMENT '是否临时授权:0否 1是',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
KEY `idx_user_org_perm_user` (`UserId`, `IsDeleted`),
KEY `idx_user_org_perm_org` (`OrganizationId`),
KEY `idx_user_org_perm_expire` (`ExpireTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户组织数据权限';
-- ---------------------------------------------------------------------------
-- 2. 角色组织权限(角色继承 / 模板绑定)
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `role_org_perm` (
`Id` CHAR(36) NOT NULL,
`RoleId` CHAR(36) NOT NULL COMMENT 'FK role.Id',
`OrganizationId` CHAR(36) NOT NULL,
`OrgScope` TINYINT NOT NULL DEFAULT 2,
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_role_org_perm` (`RoleId`, `OrganizationId`, `IsDeleted`),
KEY `idx_role_org_perm_role` (`RoleId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色组织数据权限';
-- ---------------------------------------------------------------------------
-- 3. 数据范围(个人/小组/部门/组织树/全局)
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `role_data_scope` (
`Id` CHAR(36) NOT NULL,
`RoleId` CHAR(36) NOT NULL,
`DataScope` TINYINT NOT NULL COMMENT '1个人 2小组 3部门 4组织树 5全局',
`DataResourceCode` VARCHAR(32) NULL COMMENT 'NULL=全局默认;Order/Customer/Recharge 等',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_role_data_scope` (`RoleId`, `DataResourceCode`, `IsDeleted`),
KEY `idx_role_data_scope_role` (`RoleId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色数据范围';
CREATE TABLE IF NOT EXISTS `user_data_scope` (
`Id` CHAR(36) NOT NULL,
`UserId` CHAR(36) NOT NULL,
`DataScope` TINYINT NOT NULL,
`DataResourceCode` VARCHAR(32) NULL,
`EffectiveTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`ExpireTime` DATETIME NULL,
`IsTemporary` TINYINT NOT NULL DEFAULT 0,
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_user_data_scope` (`UserId`, `DataResourceCode`, `IsDeleted`),
KEY `idx_user_data_scope_user` (`UserId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户数据范围(覆盖角色默认)';
-- ---------------------------------------------------------------------------
-- 4. 业务维度
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `role_biz_perm` (
`Id` CHAR(36) NOT NULL,
`RoleId` CHAR(36) NOT NULL,
`BizType` VARCHAR(32) NOT NULL COMMENT 'product_line/kpi_area/customer_group/warehouse/region',
`BizId` VARCHAR(64) NOT NULL COMMENT '业务主键字符串',
`BizName` VARCHAR(128) NULL COMMENT '冗余展示名',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`Id`),
KEY `idx_role_biz_perm_role` (`RoleId`, `BizType`),
KEY `idx_role_biz_perm_biz` (`BizType`, `BizId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色业务维度权限';
CREATE TABLE IF NOT EXISTS `user_biz_perm` (
`Id` CHAR(36) NOT NULL,
`UserId` CHAR(36) NOT NULL,
`BizType` VARCHAR(32) NOT NULL,
`BizId` VARCHAR(64) NOT NULL,
`BizName` VARCHAR(128) NULL,
`EffectiveTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`ExpireTime` DATETIME NULL,
`IsTemporary` TINYINT NOT NULL DEFAULT 0,
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`Id`),
KEY `idx_user_biz_perm_user` (`UserId`, `BizType`),
KEY `idx_user_biz_perm_biz` (`BizType`, `BizId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户业务维度权限';
-- ---------------------------------------------------------------------------
-- 5. 密级
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `role_secret_perm` (
`Id` CHAR(36) NOT NULL,
`RoleId` CHAR(36) NOT NULL,
`SecretLevel` TINYINT NOT NULL COMMENT '1公开 2内部 3机密 4绝密',
`DataResourceCode` VARCHAR(32) NULL,
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`Id`),
KEY `idx_role_secret_perm_role` (`RoleId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色密级权限';
CREATE TABLE IF NOT EXISTS `user_secret_perm` (
`Id` CHAR(36) NOT NULL,
`UserId` CHAR(36) NOT NULL,
`SecretLevel` TINYINT NOT NULL,
`DataResourceCode` VARCHAR(32) NULL,
`EffectiveTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`ExpireTime` DATETIME NULL,
`IsTemporary` TINYINT NOT NULL DEFAULT 0,
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`Id`),
KEY `idx_user_secret_perm_user` (`UserId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户密级权限';
-- ---------------------------------------------------------------------------
-- 6. 自定义过滤规则(JSON AST,禁止存 SQL)
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `role_filter_rule` (
`Id` CHAR(36) NOT NULL,
`RoleId` CHAR(36) NOT NULL,
`DataResourceCode` VARCHAR(32) NOT NULL,
`FilterContent` JSON NOT NULL COMMENT '过滤条件 AST',
`FilterHash` CHAR(64) NOT NULL COMMENT 'SHA256(FilterContent)',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_role_filter_rule` (`RoleId`, `DataResourceCode`, `IsDeleted`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色自定义过滤';
CREATE TABLE IF NOT EXISTS `user_filter_rule` (
`Id` CHAR(36) NOT NULL,
`UserId` CHAR(36) NOT NULL,
`DataResourceCode` VARCHAR(32) NOT NULL,
`FilterContent` JSON NOT NULL,
`FilterHash` CHAR(64) NOT NULL,
`EffectiveTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`ExpireTime` DATETIME NULL,
`IsTemporary` TINYINT NOT NULL DEFAULT 0,
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_user_filter_rule` (`UserId`, `DataResourceCode`, `IsDeleted`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户自定义过滤';
-- ---------------------------------------------------------------------------
-- 7. 数据资源注册(模块接入清单)
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `data_resource` (
`Id` CHAR(36) NOT NULL,
`Code` VARCHAR(32) NOT NULL COMMENT 'Order/Customer/Recharge/ChannelProduct/Xhs',
`Name` VARCHAR(64) NOT NULL,
`Description` VARCHAR(256) NULL,
`MainTable` VARCHAR(64) NULL COMMENT '主表名,如 t_order',
`OrgField` VARCHAR(64) NULL COMMENT '组织字段名',
`OwnerField` VARCHAR(64) NULL COMMENT '负责人字段名',
`SecretLevelField` VARCHAR(64) NULL DEFAULT 'SecretLevel',
`IsEnabled` TINYINT NOT NULL DEFAULT 1,
`SortOrder` INT NOT NULL DEFAULT 0,
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_data_resource_code` (`Code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据权限资源注册';
-- ---------------------------------------------------------------------------
-- 8. 字段脱敏配置
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `data_perm_field_mask` (
`Id` CHAR(36) NOT NULL,
`DataResourceCode` VARCHAR(32) NOT NULL,
`FieldName` VARCHAR(64) NOT NULL COMMENT 'DTO/表字段名',
`SecretLevel` TINYINT NOT NULL COMMENT '达到此密级才脱敏',
`MaskType` VARCHAR(32) NOT NULL DEFAULT 'partial' COMMENT 'partial/full/hide',
`MaskPattern` VARCHAR(128) NULL COMMENT '如 phone: 3,4 保留首尾',
`IsEnabled` TINYINT NOT NULL DEFAULT 1,
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_field_mask` (`DataResourceCode`, `FieldName`, `IsDeleted`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='字段级脱敏配置';
-- ---------------------------------------------------------------------------
-- 9. 权限模板
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `data_perm_template` (
`Id` CHAR(36) NOT NULL,
`Name` VARCHAR(64) NOT NULL,
`Code` VARCHAR(32) NOT NULL COMMENT '模板编码,如 SalesStaff',
`Description` VARCHAR(256) NULL,
`RoleCode` VARCHAR(64) NULL COMMENT '可选绑定 RBAC role.Code,分配角色时自动套用',
`IsBuiltIn` TINYINT NOT NULL DEFAULT 0 COMMENT '内置模板不可删',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_data_perm_template_code` (`Code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据权限模板';
CREATE TABLE IF NOT EXISTS `data_perm_template_item` (
`Id` CHAR(36) NOT NULL,
`TemplateId` CHAR(36) NOT NULL,
`DimensionType` VARCHAR(32) NOT NULL COMMENT 'org/data_scope/biz/secret/filter',
`ItemContent` JSON NOT NULL COMMENT '维度配置 JSON',
`SortOrder` INT NOT NULL DEFAULT 0,
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
PRIMARY KEY (`Id`),
KEY `idx_template_item_tpl` (`TemplateId`, `DimensionType`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据权限模板明细';
-- ---------------------------------------------------------------------------
-- 10. 审计
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `data_perm_change_log` (
`Id` BIGINT NOT NULL AUTO_INCREMENT,
`TargetType` VARCHAR(16) NOT NULL COMMENT 'user/role/template',
`TargetId` CHAR(36) NOT NULL,
`Action` VARCHAR(16) NOT NULL COMMENT 'create/update/delete/apply_template',
`BeforeJson` JSON NULL,
`AfterJson` JSON NULL,
`OperatorUserId` CHAR(36) NOT NULL COMMENT '操作人 user.Id',
`OperatorMapId` INT NULL COMMENT '操作人 mapId',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`Id`),
KEY `idx_perm_change_target` (`TargetType`, `TargetId`, `CreateTime`),
KEY `idx_perm_change_operator` (`OperatorUserId`, `CreateTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据权限配置变更日志';
CREATE TABLE IF NOT EXISTS `data_perm_access_log` (
`Id` BIGINT NOT NULL AUTO_INCREMENT,
`UserId` CHAR(36) NOT NULL,
`MapId` INT NULL,
`DataResourceCode` VARCHAR(32) NOT NULL,
`ApiPath` VARCHAR(256) NOT NULL,
`HttpMethod` VARCHAR(8) NOT NULL DEFAULT 'GET',
`AppliedScopeJson` JSON NULL COMMENT '生效五维快照',
`RowCount` INT NULL COMMENT '返回行数',
`ElapsedMs` INT NULL,
`ClientIp` VARCHAR(64) NULL,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`Id`),
KEY `idx_perm_access_user_time` (`UserId`, `CreateTime`),
KEY `idx_perm_access_resource` (`DataResourceCode`, `CreateTime`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据权限访问审计(可采样)';
-- ---------------------------------------------------------------------------
-- 11. 种子:数据资源注册
-- ---------------------------------------------------------------------------
INSERT INTO `data_resource` (`Id`, `Code`, `Name`, `Description`, `MainTable`, `OrgField`, `OwnerField`, `SortOrder`) VALUES
('da300001-0000-4000-8000-000000000001', 'Order', '订单', '运营后台订单查询', 't_order', 'OrganizationId', 'CreateUserId', 10),
('da300001-0000-4000-8000-000000000002', 'Customer', '客户', '客户资料列表', 't_customer', 'OrganizationId', 'Salesman', 20),
('da300001-0000-4000-8000-000000000003', 'Recharge', '充值', '充值审核列表', 't_recharge_record', NULL, 'CreateUserId', 30),
('da300001-0000-4000-8000-000000000004', 'ChannelProduct', '销售产品', '渠道产品配置', 't_sales_product', NULL, NULL, 40),
('da300001-0000-4000-8000-000000000005', 'Xhs', '小红书', '小红书模块', NULL, NULL, NULL, 50)
ON DUPLICATE KEY UPDATE
`Name` = VALUES(`Name`),
`Description` = VALUES(`Description`),
`MainTable` = VALUES(`MainTable`),
`OrgField` = VALUES(`OrgField`),
`OwnerField` = VALUES(`OwnerField`);
-- ---------------------------------------------------------------------------
-- 12. 种子:内置权限模板(明细需按环境组织 Id 调整后再 apply)
-- ---------------------------------------------------------------------------
INSERT INTO `data_perm_template` (`Id`, `Name`, `Code`, `Description`, `RoleCode`, `IsBuiltIn`, `CreateUserId`, `CreateTime`) VALUES
('da000001-0000-4000-8000-000000000001', '普通销售', 'SalesStaff', '个人级+指定产品线+密级1-2', NULL, 1, 0, NOW()),
('da000001-0000-4000-8000-000000000002', '销售主管', 'SalesSupervisor', '部门级+全部产品线+密级1-3', NULL, 1, 0, NOW()),
('da000001-0000-4000-8000-000000000003', '分公司经理', 'BranchManager', '组织树级+密级1-3', NULL, 1, 0, NOW()),
('da000001-0000-4000-8000-000000000004', '总部产品经理', 'ProductManager', '全局级+单产品线+密级1-2', NULL, 1, 0, NOW()),
('da000001-0000-4000-8000-000000000005', '财务专员', 'FinanceStaff', '组织树级+密级含3-4', NULL, 1, 0, NOW()),
('da000001-0000-4000-8000-000000000006', '客服专员', 'CsStaff', '个人级+密级1-2', NULL, 1, 0, NOW())
ON DUPLICATE KEY UPDATE
`Name` = VALUES(`Name`),
`Description` = VALUES(`Description`);
INSERT INTO `data_perm_template_item` (`Id`, `TemplateId`, `DimensionType`, `ItemContent`, `SortOrder`) VALUES
-- 普通销售
('da200001-0000-4000-8000-000000000011', 'da000001-0000-4000-8000-000000000001', 'data_scope', '{"dataScope":1,"dataResourceCode":null}', 1),
('da200001-0000-4000-8000-000000000012', 'da000001-0000-4000-8000-000000000001', 'secret', '{"secretLevels":[1,2]}', 2),
-- 销售主管
('da200001-0000-4000-8000-000000000021', 'da000001-0000-4000-8000-000000000002', 'data_scope', '{"dataScope":3,"dataResourceCode":null}', 1),
('da200001-0000-4000-8000-000000000022', 'da000001-0000-4000-8000-000000000002', 'secret', '{"secretLevels":[1,2,3]}', 2),
-- 分公司经理
('da200001-0000-4000-8000-000000000031', 'da000001-0000-4000-8000-000000000003', 'data_scope', '{"dataScope":4,"dataResourceCode":null}', 1),
('da200001-0000-4000-8000-000000000032', 'da000001-0000-4000-8000-000000000003', 'secret', '{"secretLevels":[1,2,3]}', 2),
-- 总部产品经理
('da200001-0000-4000-8000-000000000041', 'da000001-0000-4000-8000-000000000004', 'data_scope', '{"dataScope":5,"dataResourceCode":null}', 1),
('da200001-0000-4000-8000-000000000042', 'da000001-0000-4000-8000-000000000004', 'secret', '{"secretLevels":[1,2]}', 2),
-- 财务专员
('da200001-0000-4000-8000-000000000051', 'da000001-0000-4000-8000-000000000005', 'data_scope', '{"dataScope":4,"dataResourceCode":null}', 1),
('da200001-0000-4000-8000-000000000052', 'da000001-0000-4000-8000-000000000005', 'secret', '{"secretLevels":[1,2,3,4]}', 2),
-- 客服专员
('da200001-0000-4000-8000-000000000061', 'da000001-0000-4000-8000-000000000006', 'data_scope', '{"dataScope":1,"dataResourceCode":null}', 1),
('da200001-0000-4000-8000-000000000062', 'da000001-0000-4000-8000-000000000006', 'secret', '{"secretLevels":[1,2]}', 2)
ON DUPLICATE KEY UPDATE
`ItemContent` = VALUES(`ItemContent`),
`SortOrder` = VALUES(`SortOrder`);
-- ---------------------------------------------------------------------------
-- 13. 种子:字段脱敏(Customer / Order)
-- ---------------------------------------------------------------------------
INSERT INTO `data_perm_field_mask` (`Id`, `DataResourceCode`, `FieldName`, `SecretLevel`, `MaskType`, `MaskPattern`) VALUES
('fa000001-0000-4000-8000-000000000001', 'Customer', 'Phone', 4, 'partial', 'phone'),
('fa000001-0000-4000-8000-000000000002', 'Customer', 'Email', 4, 'partial', 'email'),
('fa000001-0000-4000-8000-000000000003', 'Customer', 'Password', 1, 'hide', NULL),
('fa000001-0000-4000-8000-000000000004', 'Order', 'PayableAmount', 3, 'hide', NULL),
('fa000001-0000-4000-8000-000000000005', 'Order', 'CostAmount', 3, 'hide', NULL),
('fa000001-0000-4000-8000-000000000006', 'Order', 'ProfitAmount', 4, 'hide', NULL)
ON DUPLICATE KEY UPDATE
`SecretLevel` = VALUES(`SecretLevel`),
`MaskType` = VALUES(`MaskType`);

View File

@ -1,219 +0,0 @@
-- 小红书模块:建表 + 业务种子数据(在 OMS 库 fake_simple_admin / oms 执行)
-- 执行顺序:本文件 → seed_xhs_rbac_menu.sql(RBAC 库 menu 表)→ seed_xhs_role_permissions.sql
--
-- Navicat:选中 OMS 业务库后运行本文件
-- ========== 1. 建表 migrate_t_xhs.sql ==========
-- (内容与 migrate_t_xhs.sql 相同,便于一键安装)
CREATE TABLE IF NOT EXISTS `t_xhs_agent` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID → t_customer.Id',
`DeviceId` VARCHAR(64) NOT NULL COMMENT 'Agent 本机设备标识',
`DeviceName` VARCHAR(128) NULL COMMENT '用户自定义名称',
`AgentVersion` VARCHAR(32) NULL COMMENT 'Agent 版本号',
`BridgePort` INT NOT NULL DEFAULT 9333 COMMENT 'Bridge WebSocket 端口',
`Status` VARCHAR(16) NOT NULL DEFAULT 'offline' COMMENT 'online/offline',
`EngineRunning` TINYINT NOT NULL DEFAULT 0 COMMENT 'Bridge 引擎是否运行',
`ExtensionConnected` TINYINT NOT NULL DEFAULT 0 COMMENT 'Chrome 扩展是否连上 Bridge',
`XhsLoggedIn` TINYINT NOT NULL DEFAULT 0 COMMENT '小红书是否已登录',
`LastHeartbeatTime` DATETIME NULL COMMENT '最后心跳时间',
`LastError` VARCHAR(512) NULL COMMENT '最近一次 Agent 上报错误摘要',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_xhs_agent_device` (`DeviceId`),
KEY `idx_xhs_agent_customer` (`CustomerId`, `Status`)
) COMMENT='小红书本地 Agent 设备表';
CREATE TABLE IF NOT EXISTS `t_xhs_task` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`AgentId` INT NULL COMMENT '指定执行的 Agent;NULL 表示任意在线 Agent',
`TaskType` VARCHAR(32) NOT NULL COMMENT '任务类型',
`ToolName` VARCHAR(64) NULL COMMENT 'LIKE AI 工具名',
`Priority` INT NOT NULL DEFAULT 0 COMMENT '越大越优先',
`Status` VARCHAR(16) NOT NULL DEFAULT 'pending' COMMENT 'pending/claimed/running/succeeded/failed/cancelled',
`ArgumentsJson` JSON NOT NULL COMMENT '工具参数 JSON',
`ProgressText` VARCHAR(512) NULL COMMENT '执行过程摘要',
`ResultJson` JSON NULL COMMENT '成功时结构化结果',
`ErrorMessage` VARCHAR(1024) NULL COMMENT '失败原因',
`Source` VARCHAR(32) NOT NULL DEFAULT 'web' COMMENT 'web/schedule/skill',
`SourceRefId` VARCHAR(64) NULL COMMENT '来源关联 ID',
`ScheduledTime` DATETIME NULL COMMENT '计划执行时间',
`ClaimedAt` DATETIME NULL COMMENT 'Agent 认领时间',
`StartedAt` DATETIME NULL COMMENT '开始执行',
`FinishedAt` DATETIME NULL COMMENT '结束时间',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()),
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
KEY `idx_xhs_task_poll` (`CustomerId`, `Status`, `ScheduledTime`, `Priority`),
KEY `idx_xhs_task_agent` (`AgentId`, `Status`),
KEY `idx_xhs_task_source` (`Source`, `SourceRefId`)
) COMMENT='小红书 Agent 任务队列表';
CREATE TABLE IF NOT EXISTS `t_xhs_publish_record` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`TaskId` INT NULL COMMENT '关联 t_xhs_task.Id',
`ToolName` VARCHAR(64) NOT NULL COMMENT 'publish_content / publish_with_video',
`Title` VARCHAR(256) NOT NULL COMMENT '笔记标题',
`ContentPreview` VARCHAR(512) NULL COMMENT '正文摘要',
`ContentFull` TEXT NULL COMMENT '完整正文',
`MediaJson` JSON NULL COMMENT '图片/视频 URL 列表',
`TagsJson` JSON NULL COMMENT '标签数组',
`Visibility` VARCHAR(32) NULL COMMENT '可见范围',
`Status` VARCHAR(16) NOT NULL DEFAULT 'draft' COMMENT 'draft/scheduled/publishing/succeeded/failed/cancelled',
`Success` TINYINT NULL COMMENT '最终是否成功',
`ResultSummary` VARCHAR(1024) NULL COMMENT 'Agent 回传结果摘要',
`ScheduledTime` DATETIME NULL COMMENT '定时发布时间',
`PublishedTime` DATETIME NULL COMMENT '实际发布完成时间',
`SkillId` INT NULL COMMENT '若来自技能卡片',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()),
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
KEY `idx_xhs_publish_customer_time` (`CustomerId`, `CreateTime`),
KEY `idx_xhs_publish_status_sched` (`CustomerId`, `Status`, `ScheduledTime`),
KEY `idx_xhs_publish_task` (`TaskId`)
) COMMENT='小红书发布记录表';
CREATE TABLE IF NOT EXISTS `t_xhs_analysis_session` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`SessionName` VARCHAR(128) NULL COMMENT '用户备注名',
`AnalysisType` VARCHAR(32) NOT NULL COMMENT 'home_feed/search/my_feeds/feed_detail',
`Keyword` VARCHAR(128) NULL COMMENT '搜索关键词',
`TaskId` INT NULL COMMENT '采集任务 ID',
`FeedsJson` JSON NULL COMMENT '采集笔记列表',
`SelectedFeedId` VARCHAR(64) NULL COMMENT '当前选中笔记 ID',
`AiAnalysisMarkdown` MEDIUMTEXT NULL COMMENT 'AI 分析结果',
`SkillId` INT NULL COMMENT '技能配方 ID',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()),
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
KEY `idx_xhs_analysis_customer` (`CustomerId`, `CreateTime`)
) COMMENT='小红书内容分析会话表';
CREATE TABLE IF NOT EXISTS `t_xhs_skill` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID;0 表示系统预置',
`ExternalId` VARCHAR(32) NOT NULL COMMENT '对外稳定 ID',
`Title` VARCHAR(256) NOT NULL COMMENT '技能名称',
`SkillType` VARCHAR(32) NOT NULL DEFAULT 'ai_create' COMMENT '技能类型',
`PresetId` VARCHAR(64) NULL COMMENT '内置预设标识',
`RecipeJson` JSON NOT NULL COMMENT '配方 JSON',
`SortOrder` INT NOT NULL DEFAULT 0 COMMENT '排序',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()),
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_xhs_skill_external` (`CustomerId`, `ExternalId`),
KEY `idx_xhs_skill_customer` (`CustomerId`, `SortOrder`)
) COMMENT='小红书技能卡片表';
CREATE TABLE IF NOT EXISTS `t_xhs_human_config` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`BehaviorJson` JSON NOT NULL COMMENT 'human_behavior 配置',
`GuardJson` JSON NOT NULL COMMENT 'human_guard 配置',
`Version` INT NOT NULL DEFAULT 1 COMMENT '配置版本',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()),
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_xhs_human_customer` (`CustomerId`)
) COMMENT='小红书拟人行为与防封配置表';
CREATE TABLE IF NOT EXISTS `t_xhs_ai_provider` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID;0 表示全局',
`ProviderKey` VARCHAR(32) NOT NULL COMMENT 'ai_chatgpt / ai_zhipu 等',
`ProviderType` VARCHAR(32) NOT NULL COMMENT 'chatgpt/doubao/deepseek/zhipu',
`DisplayName` VARCHAR(64) NOT NULL COMMENT '展示名',
`BaseUrl` VARCHAR(512) NOT NULL COMMENT 'API Base URL',
`ApiKeyEnc` VARCHAR(512) NULL COMMENT 'API Key(暂明文,后续可加密)',
`ApiSecretEnc` VARCHAR(512) NULL COMMENT 'Secret/模型名',
`IsDefault` TINYINT NOT NULL DEFAULT 0 COMMENT '是否默认',
`Enabled` TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()),
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_xhs_ai_provider` (`CustomerId`, `ProviderKey`),
KEY `idx_xhs_ai_customer` (`CustomerId`, `Enabled`)
) COMMENT='小红书 AI 提供商配置表';
CREATE TABLE IF NOT EXISTS `t_xhs_media` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`FileName` VARCHAR(256) NOT NULL COMMENT '原始文件名',
`StoragePath` VARCHAR(512) NOT NULL COMMENT '相对路径',
`PublicUrl` VARCHAR(512) NOT NULL COMMENT '对外 HTTPS URL',
`MimeType` VARCHAR(64) NULL COMMENT 'MIME',
`FileSizeBytes` BIGINT NULL COMMENT '字节数',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
KEY `idx_xhs_media_customer` (`CustomerId`, `CreateTime`)
) COMMENT='小红书创作上传媒体表';
-- ========== 2. 种子 seed_xhs_skills + seed_xhs_ai_providers ==========
INSERT INTO `t_xhs_skill` (
`CustomerId`, `ExternalId`, `Title`, `SkillType`, `PresetId`, `RecipeJson`, `SortOrder`,
`IsDeleted`, `CreateUserId`, `CreateTime`
) VALUES
(0, '5a9d3c012d50', '数字型/疑问型 · 物流知识 · 图文', 'ai_create', NULL,
'{"formula":["emotion","utility","visual","social"],"title_types":["number","question"],"body":{"domain":"物流知识","content_type":"干货教程","emotion":"生活场景","social":"知识炫耀"},"image_modes":["cover_impact"],"video_modes":[],"notes":"讲解9610的简易申报和汇总申报,退税,以及申报要求"}',
1, 0, 0, NOW()),
(0, '7dd58bfe4770', '效率工具 · 干货教程(新号)', 'ai_create', 'efficiency_tutorial',
'{"formula":["emotion","utility","visual","social"],"title_types":["number","question"],"body":{"domain":"效率工具","content_type":"干货教程","emotion":"焦虑共鸣","social":"价值传递"},"image_modes":["cover_impact","step_cards"],"video_modes":[],"notes":"话题示例:笔记工具提升效率"}',
2, 0, 0, NOW()),
(0, '3f6ed9f62afd', '职场发展 · 经验分享', 'ai_create', 'career_experience',
'{"formula":["emotion","utility","social"],"title_types":["story","compare"],"body":{"domain":"职场发展","content_type":"经验分享","emotion":"理想生活","social":"身份标签"},"image_modes":["cover_impact","lifestyle"],"video_modes":[],"notes":"话题示例:职场人际关系"}',
3, 0, 0, NOW()),
(0, '61a4d4febada', '情感共鸣 · 真实场景', 'ai_create', 'emotional_relatable',
'{"formula":["emotion","social"],"title_types":["story","question"],"body":{"domain":"情感共鸣","content_type":"经验分享","emotion":"生活场景","social":"情感支持"},"image_modes":["lifestyle"],"video_modes":["vlog_clip"],"notes":"让读者觉得这也太真实了"}',
4, 0, 0, NOW()),
(0, 'ec62cc03eea9', '避坑指南 · 观点表达', 'ai_create', 'pitfall_opinion',
'{"formula":["emotion","utility","visual","social"],"title_types":["number"],"body":{"domain":"职场发展","content_type":"避坑指南","emotion":"吐槽宣泄","social":"观点表达"},"image_modes":["info_chart"],"video_modes":["talking_head"],"notes":"话题示例:避坑指南"}',
5, 0, 0, NOW())
ON DUPLICATE KEY UPDATE `Title` = VALUES(`Title`), `RecipeJson` = VALUES(`RecipeJson`);
INSERT INTO `t_xhs_ai_provider` (
`CustomerId`, `ProviderKey`, `ProviderType`, `DisplayName`, `BaseUrl`,
`ApiKeyEnc`, `ApiSecretEnc`, `IsDefault`, `Enabled`,
`IsDeleted`, `CreateUserId`, `CreateTime`
) VALUES
(0, 'ai_zhipu', 'zhipu', '智谱 AI', 'https://open.bigmodel.cn/api/paas/v4', NULL, 'glm-4-flash', 1, 0, 0, 0, NOW()),
(0, 'ai_deepseek', 'deepseek', 'DeepSeek', 'https://api.deepseek.com/v1', NULL, 'deepseek-chat', 0, 0, 0, 0, NOW()),
(0, 'ai_chatgpt', 'chatgpt', 'OpenAI', 'https://api.openai.com/v1', NULL, 'gpt-4o-mini', 0, 0, 0, 0, NOW())
ON DUPLICATE KEY UPDATE `DisplayName` = VALUES(`DisplayName`), `BaseUrl` = VALUES(`BaseUrl`);

View File

@ -1,3 +0,0 @@
-- 移除卖价/买价主表「收费时机」字段(已由件重尺阶段触发算价,不再配置 ChargingTime)
ALTER TABLE `t_sales_product_price` DROP COLUMN IF EXISTS `ChargingTime`;
ALTER TABLE `t_service_channel_price` DROP COLUMN IF EXISTS `ChargingTime`;

View File

@ -1,62 +0,0 @@
-- OMS 业务表 — 数据权限 P1 扩展字段
-- 设计文档:E:\oms0414\docs\数据权限设计.md §4.8
-- 可重复执行(information_schema 判断)
-- t_customer.OrganizationId
SET @db = DATABASE();
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 't_customer' AND COLUMN_NAME = 'OrganizationId') = 0,
'ALTER TABLE `t_customer` ADD COLUMN `OrganizationId` CHAR(36) NULL COMMENT ''归属销售组织 FK organization.Id'' AFTER `CustomerGroup`',
'SELECT ''skip t_customer.OrganizationId'' AS msg'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 't_customer' AND INDEX_NAME = 'idx_cus_organization') = 0,
'ALTER TABLE `t_customer` ADD KEY `idx_cus_organization` (`OrganizationId`)',
'SELECT ''skip idx_cus_organization'' AS msg'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- t_order.OrganizationId + SecretLevel
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 't_order' AND COLUMN_NAME = 'OrganizationId') = 0,
'ALTER TABLE `t_order` ADD COLUMN `OrganizationId` CHAR(36) NULL COMMENT ''数据归属组织'' AFTER `CustomerId`',
'SELECT ''skip t_order.OrganizationId'' AS msg'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 't_order' AND COLUMN_NAME = 'SecretLevel') = 0,
'ALTER TABLE `t_order` ADD COLUMN `SecretLevel` TINYINT NOT NULL DEFAULT 2 COMMENT ''数据密级 1-4'' AFTER `OrganizationId`',
'SELECT ''skip t_order.SecretLevel'' AS msg'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 't_order' AND INDEX_NAME = 'idx_ord_org_secret_ctime') = 0,
'ALTER TABLE `t_order` ADD KEY `idx_ord_org_secret_ctime` (`OrganizationId`, `SecretLevel`, `CreateTime`)',
'SELECT ''skip idx_ord_org_secret_ctime'' AS msg'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- t_recharge_record.SecretLevel(P2 预置,可跳过)
SET @sql = IF(
(SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 't_recharge_record' AND COLUMN_NAME = 'SecretLevel') = 0,
'ALTER TABLE `t_recharge_record` ADD COLUMN `SecretLevel` TINYINT NOT NULL DEFAULT 3 COMMENT ''数据密级 1-4'' AFTER `CustomerId`',
'SELECT ''skip t_recharge_record.SecretLevel'' AS msg'
);
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- 历史订单 OrganizationId 回填:取自客户归属组织(有则更新)
UPDATE `t_order` o
INNER JOIN `t_customer` c ON c.`Id` = o.`CustomerId` AND c.`IsDeleted` = 0
SET o.`OrganizationId` = c.`OrganizationId`
WHERE o.`OrganizationId` IS NULL
AND c.`OrganizationId` IS NOT NULL;

View File

@ -1,10 +0,0 @@
-- RBAC 用户扩展:电话、工号、微信号、微信二维码
-- 执行前请确认当前库为 RBAC 库(含 `user` 表)
ALTER TABLE `user`
ADD COLUMN `Phone` VARCHAR(32) NULL COMMENT '电话' AFTER `Avatar`,
ADD COLUMN `EmployeeNo` VARCHAR(16) NULL COMMENT '工号(NE+4位)' AFTER `Phone`,
ADD COLUMN `WechatId` VARCHAR(64) NULL COMMENT '微信号' AFTER `EmployeeNo`,
ADD COLUMN `WechatQrCode` LONGTEXT NULL COMMENT '微信二维码' AFTER `WechatId`;
CREATE UNIQUE INDEX `IX_user_EmployeeNo` ON `user` (`EmployeeNo`);

View File

@ -1,18 +0,0 @@
-- t_auto_trigger 规则名与优先级(可重复执行)
-- 在 OMS 业务库执行:mysql -h<host> -u<user> -p<db> < migrate_t_auto_trigger_rule_meta.sql
SET @db = DATABASE();
SET @exist := (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 't_auto_trigger' AND COLUMN_NAME = 'RuleName');
SET @sql := IF(@exist = 0,
'ALTER TABLE `t_auto_trigger` ADD COLUMN `RuleName` VARCHAR(128) NULL COMMENT ''规则名称'' AFTER `Status`',
'SELECT ''skip RuleName''');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @exist := (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 't_auto_trigger' AND COLUMN_NAME = 'Priority');
SET @sql := IF(@exist = 0,
'ALTER TABLE `t_auto_trigger` ADD COLUMN `Priority` INT NOT NULL DEFAULT 100 COMMENT ''优先级,数值越小越先执行'' AFTER `RuleName`',
'SELECT ''skip Priority''');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;

View File

@ -1,24 +0,0 @@
-- 客户账户资金流水
CREATE TABLE IF NOT EXISTS `t_customer_account_flow` (
`Id` int NOT NULL AUTO_INCREMENT,
`CustomerId` int NOT NULL COMMENT '客户 ID',
`SerialNumber` varchar(64) NOT NULL COMMENT '流水号',
`BizType` varchar(32) NOT NULL COMMENT '业务类型 recharge/orderPay',
`BizId` int DEFAULT NULL COMMENT '关联业务主键',
`BizNo` varchar(64) DEFAULT NULL COMMENT '关联业务单号',
`Amount` decimal(18,2) NOT NULL COMMENT '变动金额,正入账负出账',
`BalanceBefore` decimal(18,2) NOT NULL COMMENT '变动前余额',
`BalanceAfter` decimal(18,2) NOT NULL COMMENT '变动后余额',
`Currency` varchar(8) NOT NULL DEFAULT 'CNY' COMMENT '币种',
`Remark` varchar(512) DEFAULT NULL COMMENT '备注',
`IsDeleted` tinyint(1) NOT NULL DEFAULT '0',
`ConcurrencyStamp` char(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` int NOT NULL DEFAULT '0',
`CreateTime` datetime NOT NULL,
`UpdateUserId` int DEFAULT NULL,
`UpdateTime` datetime DEFAULT NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_customer_account_flow_serial` (`SerialNumber`),
KEY `idx_customer_account_flow_customer_time` (`CustomerId`, `CreateTime`),
KEY `idx_customer_account_flow_biz` (`BizType`, `BizId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='客户账户资金流水';

View File

@ -1,8 +0,0 @@
-- 已执行旧版 migrate_t_customer_account_flow.sql 的库补 ConcurrencyStamp(与 AggregateRoot 实体对齐)
-- 勿在 ALTER 中使用 DEFAULT(UUID()),复制环境会报 Error 1674
ALTER TABLE `t_customer_account_flow`
ADD COLUMN `ConcurrencyStamp` char(36) NOT NULL DEFAULT '' COMMENT '并发戳' AFTER `IsDeleted`;
UPDATE `t_customer_account_flow`
SET `ConcurrencyStamp` = UUID()
WHERE `ConcurrencyStamp` = '';

View File

@ -1,19 +0,0 @@
-- 渠道-问题模板
CREATE TABLE IF NOT EXISTS `t_issue_template` (
`Id` BIGINT NOT NULL AUTO_INCREMENT,
`OrganizationId` CHAR(36) NULL COMMENT '归属组织 GUID;NULL=平台通用',
`IssueType` VARCHAR(32) NOT NULL COMMENT '问题类型 code',
`Title` VARCHAR(128) NOT NULL COMMENT '问题标题',
`Content` TEXT NOT NULL COMMENT '问题内容',
`NotifyMethod` VARCHAR(64) NOT NULL COMMENT '通知方式,逗号分隔',
`Status` TINYINT NOT NULL DEFAULT 1 COMMENT '0-禁用 1-启用',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL,
`CreateTime` DATETIME NOT NULL,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
KEY `idx_issue_tpl_org_type` (`OrganizationId`, `IssueType`, `IsDeleted`),
KEY `idx_issue_tpl_status` (`Status`, `IsDeleted`)
) COMMENT='渠道-问题模板';

View File

@ -1,8 +0,0 @@
-- 已执行旧版 migrate_t_issue_template.sql 的库补 ConcurrencyStamp(与 AggregateRoot 实体对齐)
-- 勿在 ALTER 中使用 DEFAULT(UUID()),复制环境会报 Error 1674
ALTER TABLE `t_issue_template`
ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '' COMMENT '并发戳' AFTER `IsDeleted`;
UPDATE `t_issue_template`
SET `ConcurrencyStamp` = UUID()
WHERE `ConcurrencyStamp` = '';

View File

@ -1,46 +0,0 @@
-- 订单批量任务表:补表注释/字段注释(不删表、不丢数据)
-- 适用于已执行旧版 order_batch_job_tables.sql(IF NOT EXISTS)的库
ALTER TABLE `t_order_batch_job` COMMENT='订单批量异步任务表';
ALTER TABLE `t_order_batch_job`
MODIFY COLUMN `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键,自增,步长 1',
MODIFY COLUMN `Action` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '批量操作类型:pay/pre-declare/intercept/parcel-create 等',
MODIFY COLUMN `Status` VARCHAR(32) NOT NULL DEFAULT 'pending' COMMENT '任务状态:pending/running/completed/failed/cancelled',
MODIFY COLUMN `Total` INT NOT NULL DEFAULT 0 COMMENT '子项总数',
MODIFY COLUMN `SuccessCount` INT NOT NULL DEFAULT 0 COMMENT '成功数',
MODIFY COLUMN `FailCount` INT NOT NULL DEFAULT 0 COMMENT '失败数',
MODIFY COLUMN `CustomerId` INT NULL COMMENT '客户ID',
MODIFY COLUMN `PayloadJson` JSON NULL COMMENT '任务级扩展参数(JSON)',
MODIFY COLUMN `RequestId` VARCHAR(64) NULL COMMENT '请求幂等ID',
MODIFY COLUMN `StartedAt` DATETIME NULL COMMENT '开始执行时间',
MODIFY COLUMN `FinishedAt` DATETIME NULL COMMENT '结束时间',
MODIFY COLUMN `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
MODIFY COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
MODIFY COLUMN `CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
MODIFY COLUMN `CreateTime` DATETIME NOT NULL COMMENT '创建时间',
MODIFY COLUMN `UpdateUserId` INT NULL COMMENT '更新人',
MODIFY COLUMN `UpdateTime` DATETIME NULL COMMENT '更新时间';
ALTER TABLE `t_order_batch_job_item` COMMENT='订单批量异步任务明细表';
ALTER TABLE `t_order_batch_job_item`
MODIFY COLUMN `Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键,自增,步长 1',
MODIFY COLUMN `JobId` INT NOT NULL COMMENT '批量任务ID',
MODIFY COLUMN `OrderId` INT NOT NULL COMMENT '订单ID',
MODIFY COLUMN `ServiceNo` VARCHAR(64) NULL COMMENT '运单号',
MODIFY COLUMN `Action` VARCHAR(64) NOT NULL DEFAULT '' COMMENT '子项操作类型,通常与任务 Action 一致',
MODIFY COLUMN `Status` VARCHAR(32) NOT NULL DEFAULT 'pending' COMMENT '子项状态:pending/running/success/failed/cancelled',
MODIFY COLUMN `MessageId` VARCHAR(128) NULL COMMENT 'RabbitMQ 消息ID,用于幂等与去重',
MODIFY COLUMN `FailReason` TEXT NULL COMMENT '失败原因',
MODIFY COLUMN `PayloadJson` TEXT NULL COMMENT '子项入参快照(JSON)',
MODIFY COLUMN `ResultJson` TEXT NULL COMMENT '子项执行结果快照(JSON)',
MODIFY COLUMN `RetryCount` INT NOT NULL DEFAULT 0 COMMENT '系统重试次数',
MODIFY COLUMN `StartedAt` DATETIME NULL COMMENT '开始执行时间',
MODIFY COLUMN `FinishedAt` DATETIME NULL COMMENT '结束时间',
MODIFY COLUMN `IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
MODIFY COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
MODIFY COLUMN `CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
MODIFY COLUMN `CreateTime` DATETIME NOT NULL COMMENT '创建时间',
MODIFY COLUMN `UpdateUserId` INT NULL COMMENT '更新人',
MODIFY COLUMN `UpdateTime` DATETIME NULL COMMENT '更新时间';

View File

@ -1,23 +0,0 @@
-- 已执行旧版 order_batch_job_tables.sql 的库:补 ConcurrencyStamp / PayloadJson / ResultJson
-- 若列已存在,对应 ALTER 会报错,跳过即可
-- 补列完成后执行 sql/migrate_t_order_batch_job_comments.sql 写入表/字段注释
ALTER TABLE `t_order_batch_job`
ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '' COMMENT '并发戳' AFTER `IsDeleted`;
UPDATE `t_order_batch_job`
SET `ConcurrencyStamp` = UUID()
WHERE `ConcurrencyStamp` = '';
ALTER TABLE `t_order_batch_job_item`
ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '' COMMENT '并发戳' AFTER `IsDeleted`;
UPDATE `t_order_batch_job_item`
SET `ConcurrencyStamp` = UUID()
WHERE `ConcurrencyStamp` = '';
ALTER TABLE `t_order_batch_job_item`
ADD COLUMN `PayloadJson` TEXT NULL COMMENT '子项入参快照(JSON)' AFTER `FailReason`;
ALTER TABLE `t_order_batch_job_item`
ADD COLUMN `ResultJson` TEXT NULL COMMENT '子项执行结果快照(JSON)' AFTER `PayloadJson`;

View File

@ -1,9 +0,0 @@
-- t_order 增加收件国家中文名称
ALTER TABLE `t_order`
ADD COLUMN `ConsigneeCountryName` VARCHAR(64) NULL COMMENT '国家中文名称' AFTER `ConsigneeCountry`;
-- 历史数据:按二字码回填中文名
UPDATE `t_order` o
INNER JOIN `t_country` c ON c.`CountryCode` = o.`ConsigneeCountry`
SET o.`ConsigneeCountryName` = c.`ChineseName`
WHERE o.`ConsigneeCountryName` IS NULL OR o.`ConsigneeCountryName` = '';

View File

@ -1,6 +0,0 @@
-- 订单下游对接字段(排货确认渠道时固化,供 itfx 预报/轨迹使用)
ALTER TABLE `t_order`
ADD COLUMN `DownstreamSupplierCode` VARCHAR(64) NULL COMMENT '下游 API 服务商编码 supplierCode' AFTER `ChannelCode`,
ADD COLUMN `DownstreamAppKey` VARCHAR(128) NULL COMMENT '下游 itfx 应用 AppKey' AFTER `DownstreamSupplierCode`,
ADD COLUMN `DownstreamAppId` INT NULL COMMENT '下游 itfx 应用 Id' AFTER `DownstreamAppKey`,
ADD COLUMN `ChannelForecastCode` VARCHAR(128) NULL COMMENT '渠道预报编码 ForecastCode' AFTER `DownstreamAppId`;

View File

@ -1,27 +0,0 @@
-- 订单异常事件审计表
CREATE TABLE IF NOT EXISTS `t_order_exception_event` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`OrderId` INT NOT NULL COMMENT '订单Id',
`EventType` VARCHAR(32) NOT NULL COMMENT 'mark_problematic/mark_claimed/handle_processed',
`FromStatus` VARCHAR(32) NULL COMMENT '变更前OrderStatus',
`ToStatus` VARCHAR(32) NULL COMMENT '变更后OrderStatus',
`FromHandleStatus` VARCHAR(16) NULL COMMENT '变更前HandleStatus',
`ToHandleStatus` VARCHAR(16) NULL COMMENT '变更后HandleStatus',
`IssueType` VARCHAR(32) NULL COMMENT '问题类型',
`Title` VARCHAR(128) NULL COMMENT '标题快照',
`Content` TEXT NULL COMMENT '内容快照',
`IssueTemplateId` INT NULL COMMENT '模板Id',
`NotifyMethod` VARCHAR(64) NULL COMMENT '通知方式快照',
`ClaimType` VARCHAR(32) NULL COMMENT '理赔类型',
`ClaimAmount` DECIMAL(18,4) NULL COMMENT '索赔金额',
`ClaimCurrency` VARCHAR(16) NULL COMMENT '索赔币种',
`ClaimReason` VARCHAR(512) NULL COMMENT '理赔原因',
`Remark` VARCHAR(512) NULL COMMENT '操作备注',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '操作人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '操作时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
KEY `idx_oee_order_time` (`OrderId`, `CreateTime`)
) COMMENT='订单异常事件表';

View File

@ -1,14 +0,0 @@
-- 问题件 / 理赔件快照字段
ALTER TABLE `t_order`
ADD COLUMN `IssueType` VARCHAR(32) NULL COMMENT '问题类型' AFTER `HandleStatus`,
ADD COLUMN `IssueTitle` VARCHAR(128) NULL COMMENT '问题标题' AFTER `IssueType`,
ADD COLUMN `IssueContent` TEXT NULL COMMENT '问题内容' AFTER `IssueTitle`,
ADD COLUMN `IssueTemplateId` INT NULL COMMENT '问题模板Id' AFTER `IssueContent`,
ADD COLUMN `IssueRemark` VARCHAR(512) NULL COMMENT '问题备注' AFTER `IssueTemplateId`,
ADD COLUMN `IssueTime` DATETIME NULL COMMENT '标记问题件时间' AFTER `IssueRemark`,
ADD COLUMN `ClaimType` VARCHAR(32) NULL COMMENT '理赔类型' AFTER `IssueTime`,
ADD COLUMN `ClaimAmount` DECIMAL(18,4) NULL COMMENT '索赔金额' AFTER `ClaimType`,
ADD COLUMN `ClaimCurrency` VARCHAR(16) NULL COMMENT '索赔币种' AFTER `ClaimAmount`,
ADD COLUMN `ClaimReason` VARCHAR(512) NULL COMMENT '理赔原因' AFTER `ClaimCurrency`,
ADD COLUMN `ClaimTime` DATETIME NULL COMMENT '创建理赔件时间' AFTER `ClaimReason`,
ADD COLUMN `PreviousOrderStatus` VARCHAR(32) NULL COMMENT '进入异常状态前的订单状态' AFTER `ClaimTime`;

View File

@ -1,12 +0,0 @@
-- 问题件 / 已理赔 子状态:pending-待处理 processed-已处理
ALTER TABLE `t_order`
ADD COLUMN `HandleStatus` VARCHAR(16) NULL DEFAULT 'pending' COMMENT '处理子状态:pending/processed' AFTER `OrderStatus`;
UPDATE `t_order`
SET `HandleStatus` = 'pending'
WHERE `HandleStatus` IS NULL
AND `OrderStatus` IN ('problematic', 'claimed');
UPDATE `t_order`
SET `HandleStatus` = NULL
WHERE `OrderStatus` NOT IN ('problematic', 'claimed');

View File

@ -1,7 +0,0 @@
-- 订单表增加是否已支付字段,并按历史 PayTime 回填
ALTER TABLE `t_order`
ADD COLUMN `IsPaid` TINYINT NOT NULL DEFAULT 0 COMMENT '是否已支付:0-否,1-是' AFTER `PayTime`;
UPDATE `t_order`
SET `IsPaid` = 1
WHERE `PayTime` IS NOT NULL;

View File

@ -1,44 +0,0 @@
-- t_order / t_order_fee 小包预报计费字段补齐(可重复执行)
-- 在 OMS 业务库执行,例如:mysql -h<host> -u<user> -p<db> < migrate_t_order_parcel_columns.sql
SET @db = DATABASE();
-- t_order.ExportCustomsMode
SET @exist := (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 't_order' AND COLUMN_NAME = 'ExportCustomsMode');
SET @sql := IF(@exist = 0,
'ALTER TABLE `t_order` ADD COLUMN `ExportCustomsMode` VARCHAR(32) NULL COMMENT ''出口报关方式'' AFTER `CargoAttribute`',
'SELECT ''skip ExportCustomsMode''');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- t_order.PredeclareFailReason
SET @exist := (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 't_order' AND COLUMN_NAME = 'PredeclareFailReason');
SET @sql := IF(@exist = 0,
'ALTER TABLE `t_order` ADD COLUMN `PredeclareFailReason` VARCHAR(512) NULL COMMENT ''预报失败原因'' AFTER `IsRemote`',
'SELECT ''skip PredeclareFailReason''');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- t_order.SalesProductRulesVersion
SET @exist := (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 't_order' AND COLUMN_NAME = 'SalesProductRulesVersion');
SET @sql := IF(@exist = 0,
'ALTER TABLE `t_order` ADD COLUMN `SalesProductRulesVersion` VARCHAR(64) NULL COMMENT ''销售产品规则快照版本'' AFTER `PredeclareFailReason`',
'SELECT ''skip SalesProductRulesVersion''');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- t_order.SalesProductPriceVersion
SET @exist := (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 't_order' AND COLUMN_NAME = 'SalesProductPriceVersion');
SET @sql := IF(@exist = 0,
'ALTER TABLE `t_order` ADD COLUMN `SalesProductPriceVersion` VARCHAR(64) NULL COMMENT ''销售产品价格快照版本'' AFTER `SalesProductRulesVersion`',
'SELECT ''skip SalesProductPriceVersion''');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
-- t_order_fee.ChargingStage
SET @exist := (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 't_order_fee' AND COLUMN_NAME = 'ChargingStage');
SET @sql := IF(@exist = 0,
'ALTER TABLE `t_order_fee` ADD COLUMN `ChargingStage` VARCHAR(16) NULL COMMENT ''计费阶段:forecast/inbound/outbound'' AFTER `PriceEffectiveTime`',
'SELECT ''skip ChargingStage''');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;

View File

@ -1,11 +0,0 @@
-- t_order 预报失败原因(可重复执行)
-- 在 OMS 业务库执行:mysql -h<host> -u<user> -p<db> < migrate_t_order_predeclare_fail_reason.sql
SET @db = DATABASE();
SET @exist := (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 't_order' AND COLUMN_NAME = 'PredeclareFailReason');
SET @sql := IF(@exist = 0,
'ALTER TABLE `t_order` ADD COLUMN `PredeclareFailReason` VARCHAR(512) NULL COMMENT ''预报失败原因'' AFTER `IsRemote`',
'SELECT ''skip PredeclareFailReason''');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;

View File

@ -1,12 +0,0 @@
-- 下单模板:自定义映射与样例文件
ALTER TABLE `t_order_template`
ADD COLUMN `StandardTemplateKey` VARCHAR(64) NULL COMMENT '映射所依据的标准模板 TemplateKey' AFTER `TemplateKey`,
ADD COLUMN `MappingStatus` VARCHAR(16) NULL COMMENT 'draft/ready;标准模板为 ready' AFTER `StandardTemplateKey`,
ADD COLUMN `SourceFileName` VARCHAR(256) NULL COMMENT '客户上传样例文件名' AFTER `MappingStatus`,
ADD COLUMN `SourceFilePath` VARCHAR(512) NULL COMMENT '样例文件相对路径 /uploads/...' AFTER `SourceFileName`,
ADD COLUMN `SourceHeadersJson` TEXT NULL COMMENT '客户 Excel 表头 JSON 数组' AFTER `SourceFilePath`,
ADD COLUMN `ColumnMappingJson` TEXT NULL COMMENT '标准字段与客户列映射 JSON' AFTER `SourceHeadersJson`;
UPDATE `t_order_template`
SET `MappingStatus` = 'ready'
WHERE `Type` = 'standard' AND (`MappingStatus` IS NULL OR `MappingStatus` = '');

View File

@ -1,13 +0,0 @@
-- 出库记录表补齐件重尺、销售产品、目的国、服务渠道字段(与 t_inbound_record 对齐)
ALTER TABLE `t_outbound_record`
ADD COLUMN `Weight` DECIMAL(10,2) NULL COMMENT '实重(kg)' AFTER `WaybillNo`,
ADD COLUMN `Length` DECIMAL(10,2) NULL COMMENT '长(cm)' AFTER `Weight`,
ADD COLUMN `Width` DECIMAL(10,2) NULL COMMENT '宽(cm)' AFTER `Length`,
ADD COLUMN `Height` DECIMAL(10,2) NULL COMMENT '高(cm)' AFTER `Width`,
ADD COLUMN `SalesProductId` INT NULL COMMENT '销售产品ID' AFTER `Height`,
ADD COLUMN `DestinationCountry` VARCHAR(8) NULL COMMENT '目的国' AFTER `SalesProductId`,
ADD COLUMN `ServiceChannelId` INT NULL COMMENT '服务渠道ID' AFTER `DestinationCountry`;
ALTER TABLE `t_outbound_record`
ADD KEY `idx_out_product_time` (`SalesProductId`, `OperateTime`),
ADD KEY `idx_out_channel_time` (`ServiceChannelId`, `OperateTime`);

View File

@ -1,4 +0,0 @@
-- 销售产品表增加对客说明 Markdown 字段
ALTER TABLE `t_sales_product`
ADD COLUMN `CustomerGuideMarkdown` MEDIUMTEXT NULL COMMENT '对客说明 Markdown' AFTER `PreStorageScript`;

View File

@ -1,54 +0,0 @@
-- 批量发送邮件:模板与 SMTP 账号配置
CREATE TABLE IF NOT EXISTS `t_system_batch_email_template` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`OwnerUserId` INT NOT NULL DEFAULT 0 COMMENT '所属 RBAC 用户 Id',
`TemplateName` VARCHAR(128) NOT NULL COMMENT '模板名称',
`Subject` VARCHAR(512) NOT NULL DEFAULT '' COMMENT '邮件主题',
`Content` TEXT NOT NULL COMMENT '邮件正文',
`SortOrder` INT NOT NULL DEFAULT 0 COMMENT '排序',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_batch_email_tpl_owner_name` (`OwnerUserId`, `TemplateName`),
KEY `idx_batch_email_tpl_owner` (`OwnerUserId`, `SortOrder`, `Id`)
) COMMENT='批量发送邮件模板';
CREATE TABLE IF NOT EXISTS `t_system_batch_email_account` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`OwnerUserId` INT NOT NULL DEFAULT 0 COMMENT '所属 RBAC 用户 Id',
`SmtpUsername` VARCHAR(256) NOT NULL COMMENT 'SMTP 账号',
`SmtpPassword` VARCHAR(512) NOT NULL COMMENT 'SMTP 密码/授权码',
`ServerType` VARCHAR(32) NOT NULL DEFAULT 'qiye' COMMENT 'SMTP 类型',
`FromName` VARCHAR(128) NULL COMMENT '发件人显示名',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_batch_email_account_owner` (`OwnerUserId`)
) COMMENT='批量发送邮件 SMTP 账号配置';
CREATE TABLE IF NOT EXISTS `t_system_batch_email_record` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`OwnerUserId` INT NOT NULL DEFAULT 0 COMMENT '所属 RBAC 用户 Id',
`ToEmail` VARCHAR(256) NOT NULL COMMENT '收件邮箱',
`Subject` VARCHAR(512) NOT NULL DEFAULT '' COMMENT '邮件主题',
`Content` TEXT NOT NULL COMMENT '邮件正文',
`SendTime` DATETIME NOT NULL COMMENT '发送时间',
`Sender` VARCHAR(128) NOT NULL DEFAULT '' COMMENT '发送人',
`SenderEmail` VARCHAR(256) NULL COMMENT '发件邮箱',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
KEY `idx_batch_email_record_owner_time` (`OwnerUserId`, `SendTime`, `Id`)
) COMMENT='批量发送邮件记录';

View File

@ -1,21 +0,0 @@
-- 系统其他配置表(含 OMS 小包轨迹服务配置)
CREATE TABLE IF NOT EXISTS `t_system_other_config` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键,自增,步长 1',
`ConfigCode` VARCHAR(64) NOT NULL COMMENT '配置编码,如 track_service',
`ConfigName` VARCHAR(128) NOT NULL COMMENT '配置名称',
`Enabled` TINYINT NOT NULL DEFAULT 0 COMMENT '是否启用:0-否,1-是',
`BaseUrl` VARCHAR(512) NULL COMMENT '服务地址',
`AppKey` VARCHAR(128) NULL COMMENT 'AppKey',
`AppSecret` VARCHAR(256) NULL COMMENT 'AppSecret',
`TimeoutSeconds` INT NOT NULL DEFAULT 30 COMMENT '超时秒数',
`Remark` VARCHAR(512) NULL COMMENT '备注',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_system_other_config_code` (`ConfigCode`),
KEY `idx_system_other_config_enabled` (`Enabled`, `Id`)
) COMMENT='系统其他配置表';

View File

@ -1,5 +0,0 @@
-- 微信公众号 access_token 持久化(仅 wechat_mp 使用,不对前端展示)
ALTER TABLE `t_system_other_config`
ADD COLUMN `AccessToken` VARCHAR(512) NULL COMMENT '微信 access_token(运行时缓存)' AFTER `Remark`,
ADD COLUMN `AccessTokenExpiresIn` INT NOT NULL DEFAULT 0 COMMENT '微信 access_token 有效期秒数 expires_in' AFTER `AccessToken`,
ADD COLUMN `AccessTokenUpdatedAt` DATETIME NULL COMMENT '微信 access_token 最近刷新时间' AFTER `AccessTokenExpiresIn`;

View File

@ -1,6 +0,0 @@
-- 仓库地址表移除客服电话、客服微信及二维码字段
ALTER TABLE `t_warehouse_address`
DROP COLUMN `ServicePhone`,
DROP COLUMN `ServiceWechat`,
DROP COLUMN `ServiceWechatFiles`;

View File

@ -1,181 +0,0 @@
-- 小红书(LIKE AI → OMS)模块表结构
-- 设计文档:E:\oms0414\docs\小红书模块设计-063001.md
CREATE TABLE IF NOT EXISTS `t_xhs_agent` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID → t_customer.Id',
`DeviceId` VARCHAR(64) NOT NULL COMMENT 'Agent 本机设备标识',
`DeviceName` VARCHAR(128) NULL COMMENT '用户自定义名称',
`AgentVersion` VARCHAR(32) NULL COMMENT 'Agent 版本号',
`BridgePort` INT NOT NULL DEFAULT 9333 COMMENT 'Bridge WebSocket 端口',
`Status` VARCHAR(16) NOT NULL DEFAULT 'offline' COMMENT 'online/offline',
`EngineRunning` TINYINT NOT NULL DEFAULT 0 COMMENT 'Bridge 引擎是否运行',
`ExtensionConnected` TINYINT NOT NULL DEFAULT 0 COMMENT 'Chrome 扩展是否连上 Bridge',
`XhsLoggedIn` TINYINT NOT NULL DEFAULT 0 COMMENT '小红书是否已登录',
`LastHeartbeatTime` DATETIME NULL COMMENT '最后心跳时间',
`LastError` VARCHAR(512) NULL COMMENT '最近一次 Agent 上报错误摘要',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_xhs_agent_device` (`DeviceId`),
KEY `idx_xhs_agent_customer` (`CustomerId`, `Status`)
) COMMENT='小红书本地 Agent 设备表';
CREATE TABLE IF NOT EXISTS `t_xhs_task` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`AgentId` INT NULL COMMENT '指定执行的 Agent;NULL 表示任意在线 Agent',
`TaskType` VARCHAR(32) NOT NULL COMMENT '任务类型',
`ToolName` VARCHAR(64) NULL COMMENT 'LIKE AI 工具名',
`Priority` INT NOT NULL DEFAULT 0 COMMENT '越大越优先',
`Status` VARCHAR(16) NOT NULL DEFAULT 'pending' COMMENT 'pending/claimed/running/succeeded/failed/cancelled',
`ArgumentsJson` JSON NOT NULL COMMENT '工具参数 JSON',
`ProgressText` VARCHAR(512) NULL COMMENT '执行过程摘要',
`ResultJson` JSON NULL COMMENT '成功时结构化结果',
`ErrorMessage` VARCHAR(1024) NULL COMMENT '失败原因',
`Source` VARCHAR(32) NOT NULL DEFAULT 'web' COMMENT 'web/schedule/skill',
`SourceRefId` VARCHAR(64) NULL COMMENT '来源关联 ID',
`ScheduledTime` DATETIME NULL COMMENT '计划执行时间',
`ClaimedAt` DATETIME NULL COMMENT 'Agent 认领时间',
`StartedAt` DATETIME NULL COMMENT '开始执行',
`FinishedAt` DATETIME NULL COMMENT '结束时间',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()),
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
KEY `idx_xhs_task_poll` (`CustomerId`, `Status`, `ScheduledTime`, `Priority`),
KEY `idx_xhs_task_agent` (`AgentId`, `Status`),
KEY `idx_xhs_task_source` (`Source`, `SourceRefId`)
) COMMENT='小红书 Agent 任务队列表';
CREATE TABLE IF NOT EXISTS `t_xhs_publish_record` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`TaskId` INT NULL COMMENT '关联 t_xhs_task.Id',
`ToolName` VARCHAR(64) NOT NULL COMMENT 'publish_content / publish_with_video',
`Title` VARCHAR(256) NOT NULL COMMENT '笔记标题',
`ContentPreview` VARCHAR(512) NULL COMMENT '正文摘要',
`ContentFull` TEXT NULL COMMENT '完整正文',
`MediaJson` JSON NULL COMMENT '图片/视频 URL 列表',
`TagsJson` JSON NULL COMMENT '标签数组',
`Visibility` VARCHAR(32) NULL COMMENT '可见范围',
`Status` VARCHAR(16) NOT NULL DEFAULT 'draft' COMMENT 'draft/scheduled/publishing/succeeded/failed/cancelled',
`Success` TINYINT NULL COMMENT '最终是否成功',
`ResultSummary` VARCHAR(1024) NULL COMMENT 'Agent 回传结果摘要',
`ScheduledTime` DATETIME NULL COMMENT '定时发布时间',
`PublishedTime` DATETIME NULL COMMENT '实际发布完成时间',
`SkillId` INT NULL COMMENT '若来自技能卡片',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()),
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
KEY `idx_xhs_publish_customer_time` (`CustomerId`, `CreateTime`),
KEY `idx_xhs_publish_status_sched` (`CustomerId`, `Status`, `ScheduledTime`),
KEY `idx_xhs_publish_task` (`TaskId`)
) COMMENT='小红书发布记录表';
CREATE TABLE IF NOT EXISTS `t_xhs_analysis_session` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`SessionName` VARCHAR(128) NULL COMMENT '用户备注名',
`AnalysisType` VARCHAR(32) NOT NULL COMMENT 'home_feed/search/my_feeds/feed_detail',
`Keyword` VARCHAR(128) NULL COMMENT '搜索关键词',
`TaskId` INT NULL COMMENT '采集任务 ID',
`FeedsJson` JSON NULL COMMENT '采集笔记列表',
`SelectedFeedId` VARCHAR(64) NULL COMMENT '当前选中笔记 ID',
`AiAnalysisMarkdown` MEDIUMTEXT NULL COMMENT 'AI 分析结果',
`SkillId` INT NULL COMMENT '技能配方 ID',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()),
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
KEY `idx_xhs_analysis_customer` (`CustomerId`, `CreateTime`)
) COMMENT='小红书内容分析会话表';
CREATE TABLE IF NOT EXISTS `t_xhs_skill` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID;0 表示系统预置',
`ExternalId` VARCHAR(32) NOT NULL COMMENT '对外稳定 ID',
`Title` VARCHAR(256) NOT NULL COMMENT '技能名称',
`SkillType` VARCHAR(32) NOT NULL DEFAULT 'ai_create' COMMENT '技能类型',
`PresetId` VARCHAR(64) NULL COMMENT '内置预设标识',
`RecipeJson` JSON NOT NULL COMMENT '配方 JSON',
`SortOrder` INT NOT NULL DEFAULT 0 COMMENT '排序',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()),
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_xhs_skill_external` (`CustomerId`, `ExternalId`),
KEY `idx_xhs_skill_customer` (`CustomerId`, `SortOrder`)
) COMMENT='小红书技能卡片表';
CREATE TABLE IF NOT EXISTS `t_xhs_human_config` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`BehaviorJson` JSON NOT NULL COMMENT 'human_behavior 配置',
`GuardJson` JSON NOT NULL COMMENT 'human_guard 配置',
`Version` INT NOT NULL DEFAULT 1 COMMENT '配置版本',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()),
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_xhs_human_customer` (`CustomerId`)
) COMMENT='小红书拟人行为与防封配置表';
CREATE TABLE IF NOT EXISTS `t_xhs_ai_provider` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID;0 表示全局',
`ProviderKey` VARCHAR(32) NOT NULL COMMENT 'ai_chatgpt / ai_zhipu 等',
`ProviderType` VARCHAR(32) NOT NULL COMMENT 'chatgpt/doubao/deepseek/zhipu',
`DisplayName` VARCHAR(64) NOT NULL COMMENT '展示名',
`BaseUrl` VARCHAR(512) NOT NULL COMMENT 'API Base URL',
`ApiKeyEnc` VARCHAR(512) NULL COMMENT 'API Key(暂明文,后续可加密)',
`ApiSecretEnc` VARCHAR(512) NULL COMMENT 'Secret/模型名',
`IsDefault` TINYINT NOT NULL DEFAULT 0 COMMENT '是否默认',
`Enabled` TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()),
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_xhs_ai_provider` (`CustomerId`, `ProviderKey`),
KEY `idx_xhs_ai_customer` (`CustomerId`, `Enabled`)
) COMMENT='小红书 AI 提供商配置表';
CREATE TABLE IF NOT EXISTS `t_xhs_media` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`FileName` VARCHAR(256) NOT NULL COMMENT '原始文件名',
`StoragePath` VARCHAR(512) NOT NULL COMMENT '相对路径',
`PublicUrl` VARCHAR(512) NOT NULL COMMENT '对外 HTTPS URL',
`MimeType` VARCHAR(64) NULL COMMENT 'MIME',
`FileSizeBytes` BIGINT NULL COMMENT '字节数',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
KEY `idx_xhs_media_customer` (`CustomerId`, `CreateTime`)
) COMMENT='小红书创作上传媒体表';

View File

@ -1,275 +0,0 @@
-- 仓储模块 + 店铺订单表结构(v0.3)
-- 设计文档:E:\oms0414\docs\仓储模块设计方案.md
-- 仓储表前缀:C_ ;店铺表前缀:t_sales_
-- 幂等:CREATE TABLE IF NOT EXISTS
-- ---------------------------------------------------------------------------
-- 仓储域(C_*)
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `C_sku` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID → t_customer.Id',
`SkuCode` VARCHAR(64) NOT NULL COMMENT '库内SKU编码',
`SkuName` VARCHAR(256) NOT NULL COMMENT 'SKU名称',
`SkuImageUrl` VARCHAR(512) NULL COMMENT '图片URL',
`WeightG` DECIMAL(10,2) NULL COMMENT '重量(g)',
`LengthCm` DECIMAL(10,2) NULL COMMENT '长(cm)',
`WidthCm` DECIMAL(10,2) NULL COMMENT '宽(cm)',
`HeightCm` DECIMAL(10,2) NULL COMMENT '高(cm)',
`Remark` VARCHAR(512) NULL COMMENT '备注',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_c_sku_code` (`CustomerId`, `SkuCode`),
KEY `idx_c_sku_customer` (`CustomerId`, `IsDeleted`)
) COMMENT='仓储-SKU主数据';
CREATE TABLE IF NOT EXISTS `C_bin_location` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`WarehouseId` INT NOT NULL COMMENT '仓库ID → t_warehouse_address.Id',
`BinCode` VARCHAR(32) NOT NULL COMMENT '库位编码',
`BinName` VARCHAR(64) NULL COMMENT '库位展示名',
`ZoneCode` VARCHAR(32) NULL COMMENT '库区编码',
`IsEnabled` TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用:0-否,1-是',
`Remark` VARCHAR(512) NULL COMMENT '备注',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_c_bin_wh_code` (`WarehouseId`, `BinCode`),
KEY `idx_c_bin_warehouse` (`WarehouseId`, `IsEnabled`)
) COMMENT='仓储-库位主数据';
CREATE TABLE IF NOT EXISTS `C_inventory` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`WarehouseId` INT NOT NULL COMMENT '仓库ID',
`SkuId` INT NOT NULL COMMENT 'SKU ID → C_sku.Id',
`BinLocationId` INT NOT NULL COMMENT '库位ID → C_bin_location.Id',
`Qty` INT NOT NULL DEFAULT 0 COMMENT '可用库存数量',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_c_inventory` (`CustomerId`, `WarehouseId`, `SkuId`, `BinLocationId`),
KEY `idx_c_inv_sku_wh` (`CustomerId`, `SkuId`, `WarehouseId`)
) COMMENT='仓储-库存余额(按库位)';
CREATE TABLE IF NOT EXISTS `C_inbound_notice` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`WarehouseId` INT NOT NULL COMMENT '仓库ID',
`NoticeNo` VARCHAR(32) NOT NULL COMMENT '入库单号 IN+雪花',
`MarkReference` VARCHAR(64) NULL COMMENT '唛头参考号',
`InboundType` VARCHAR(16) NOT NULL DEFAULT 'normal' COMMENT 'normal/return',
`ReceiptStatus` VARCHAR(16) NOT NULL DEFAULT 'forecasted' COMMENT 'forecasted/received/completed',
`ExpectedArrivalTime` DATETIME NULL COMMENT '预计到货时间',
`ActualArrivalTime` DATETIME NULL COMMENT '实际到货时间',
`Remark` VARCHAR(512) NULL COMMENT '备注',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_c_inbound_notice_no` (`NoticeNo`),
KEY `idx_c_inbound_customer_status` (`CustomerId`, `ReceiptStatus`, `CreateTime`)
) COMMENT='仓储-入库预报主表';
CREATE TABLE IF NOT EXISTS `C_inbound_box` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`InboundNoticeId` INT NOT NULL COMMENT '入库预报ID → C_inbound_notice.Id',
`BoxSeqNo` VARCHAR(16) NOT NULL COMMENT '箱序号',
`MarkBoxNo` VARCHAR(64) NULL COMMENT '箱唛号/箱号',
`WeightG` DECIMAL(10,2) NULL COMMENT '箱重(g)',
`LengthCm` DECIMAL(10,2) NULL COMMENT '长(cm)',
`WidthCm` DECIMAL(10,2) NULL COMMENT '宽(cm)',
`HeightCm` DECIMAL(10,2) NULL COMMENT '高(cm)',
`IsReceived` TINYINT NOT NULL DEFAULT 0 COMMENT '是否已收货:0-否,1-是',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
KEY `idx_c_inbound_box_notice` (`InboundNoticeId`, `IsDeleted`)
) COMMENT='仓储-入库预报箱';
CREATE TABLE IF NOT EXISTS `C_inbound_box_line` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`InboundBoxId` INT NOT NULL COMMENT '入库箱ID → C_inbound_box.Id',
`SkuId` INT NOT NULL COMMENT 'SKU ID → C_sku.Id',
`SkuCode` VARCHAR(64) NOT NULL COMMENT '冗余SKU编码',
`PlannedQty` INT NOT NULL DEFAULT 0 COMMENT '计划入库数量',
`ReceivedQty` INT NULL COMMENT '实收数量',
`BinLocationId` INT NULL COMMENT '上架库位ID → C_bin_location.Id',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
KEY `idx_c_inbound_box_line_box` (`InboundBoxId`, `IsDeleted`),
KEY `idx_c_inbound_box_line_sku` (`SkuId`)
) COMMENT='仓储-入库箱内SKU行';
CREATE TABLE IF NOT EXISTS `C_parcel` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`WarehouseId` INT NOT NULL COMMENT '仓库ID',
`TrackingNo` VARCHAR(64) NOT NULL COMMENT '快递单号',
`CarrierName` VARCHAR(64) NULL COMMENT '快递公司',
`LifecycleStatus` VARCHAR(16) NOT NULL DEFAULT 'inTransit' COMMENT 'inTransit/arrived/stored',
`ArrivalTime` DATETIME NULL COMMENT '到仓时间',
`Remark` VARCHAR(512) NULL COMMENT '备注',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_c_parcel_tracking` (`CustomerId`, `TrackingNo`, `WarehouseId`),
KEY `idx_c_parcel_status` (`CustomerId`, `LifecycleStatus`)
) COMMENT='仓储-客户包裹';
CREATE TABLE IF NOT EXISTS `C_parcel_item` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`ParcelId` INT NOT NULL COMMENT '包裹ID → C_parcel.Id',
`ProductName` VARCHAR(512) NULL COMMENT '商品名称',
`Quantity` INT NOT NULL DEFAULT 0 COMMENT '数量',
`SkuId` INT NULL COMMENT '库内SKU ID → C_sku.Id',
`SkuCode` VARCHAR(64) NULL COMMENT '冗余SKU编码',
`BinLocationId` INT NULL COMMENT '上架库位ID',
`Remark` VARCHAR(512) NULL COMMENT '备注',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
KEY `idx_c_parcel_item_parcel` (`ParcelId`, `IsDeleted`)
) COMMENT='仓储-包裹明细';
CREATE TABLE IF NOT EXISTS `C_sku_platform_map` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`StoreId` INT NOT NULL COMMENT '店铺ID → t_sales_store.Id',
`PlatformSku` VARCHAR(128) NOT NULL COMMENT '平台listing SKU',
`SkuId` INT NOT NULL COMMENT '库内SKU ID → C_sku.Id',
`SkuCode` VARCHAR(64) NOT NULL COMMENT '冗余SKU编码',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_c_sku_map` (`StoreId`, `PlatformSku`),
KEY `idx_c_sku_map_customer` (`CustomerId`, `SkuId`)
) COMMENT='仓储-平台SKU映射';
-- ---------------------------------------------------------------------------
-- 订单域 — 店铺(t_sales_*,接口阶段使用)
-- ---------------------------------------------------------------------------
CREATE TABLE IF NOT EXISTS `t_sales_store` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`PlatformCode` VARCHAR(32) NOT NULL COMMENT 'lazada/shopee/tiktok/temu/manual',
`StoreNickname` VARCHAR(128) NOT NULL COMMENT '店铺昵称',
`PlatformStoreId` VARCHAR(64) NULL COMMENT '平台侧店铺ID',
`PlatformAccount` VARCHAR(128) NULL COMMENT '平台账号',
`SiteCountry` VARCHAR(8) NULL COMMENT '开户站点国家码',
`SellerId` VARCHAR(64) NULL COMMENT '平台卖家ID',
`AuthStatus` VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT 'active/expired/revoked',
`AuthTime` DATETIME NULL COMMENT '授权时间',
`TokenExpireTime` DATETIME NULL COMMENT 'AccessToken过期时间',
`RefreshExpireTime` DATETIME NULL COMMENT 'RefreshToken过期时间',
`AccessToken` VARCHAR(2048) NULL COMMENT 'AccessToken(加密存储)',
`RefreshToken` VARCHAR(2048) NULL COMMENT 'RefreshToken(加密存储)',
`TokenExtraJson` JSON NULL COMMENT '平台扩展Token信息',
`IsAutoFulfill` TINYINT NOT NULL DEFAULT 0 COMMENT '是否自动发货:0-否,1-是',
`Remark` VARCHAR(512) NULL COMMENT '备注',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
KEY `idx_sales_store_customer` (`CustomerId`, `IsDeleted`),
KEY `idx_sales_store_platform` (`CustomerId`, `PlatformCode`, `AuthStatus`)
) COMMENT='销售店铺授权';
CREATE TABLE IF NOT EXISTS `t_sales_store_order` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID',
`StoreId` INT NOT NULL COMMENT '店铺ID → t_sales_store.Id',
`PlatformCode` VARCHAR(32) NOT NULL COMMENT '平台编码',
`PlatformOrderNo` VARCHAR(64) NOT NULL COMMENT '平台订单号',
`OrderCountry` VARCHAR(8) NULL COMMENT '订单国家',
`ItemCount` INT NULL COMMENT '商品行数',
`TotalAmount` DECIMAL(18,4) NULL COMMENT '订单总额',
`Currency` VARCHAR(8) NULL COMMENT '币种',
`PlatformOrderTime` DATETIME NULL COMMENT '平台下单时间',
`FulfillStatus` VARCHAR(32) NOT NULL DEFAULT 'pending' COMMENT '履约状态',
`PlatformStatus` VARCHAR(64) NULL COMMENT '平台原始状态码',
`PlatformStatusLabel` VARCHAR(128) NULL COMMENT '平台状态展示文案',
`ShippingLabelNo` VARCHAR(64) NULL COMMENT '面单号',
`ShippingLabelUrl` VARCHAR(512) NULL COMMENT '面单URL',
`IsMultiLabel` TINYINT NOT NULL DEFAULT 0 COMMENT '是否多面单',
`CustomTags` VARCHAR(512) NULL COMMENT '自定义标签',
`IsSuspended` TINYINT NOT NULL DEFAULT 0 COMMENT '是否搁置',
`WarehouseId` INT NULL COMMENT '发货仓库ID',
`LinkedOrderId` INT NULL COMMENT '关联小包订单 t_order.Id',
`LastSyncTime` DATETIME NULL COMMENT '最近同步时间',
`PlatformExtraJson` JSON NULL COMMENT '平台扩展字段',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_store_order_no` (`StoreId`, `PlatformOrderNo`),
KEY `idx_store_order_customer_status` (`CustomerId`, `FulfillStatus`, `PlatformOrderTime`)
) COMMENT='销售店铺订单';
CREATE TABLE IF NOT EXISTS `t_sales_store_order_line` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`StoreOrderId` INT NOT NULL COMMENT '店铺订单ID → t_sales_store_order.Id',
`PlatformLineId` VARCHAR(64) NULL COMMENT '平台行ID',
`PlatformSku` VARCHAR(128) NULL COMMENT '平台SKU',
`ProductName` VARCHAR(512) NULL COMMENT '商品名称',
`ProductImageUrl` VARCHAR(512) NULL COMMENT '商品图片',
`VariantText` VARCHAR(256) NULL COMMENT '规格属性',
`UnitPrice` DECIMAL(18,4) NULL COMMENT '单价',
`Quantity` INT NOT NULL DEFAULT 0 COMMENT '数量',
`Currency` VARCHAR(8) NULL COMMENT '币种',
`IsShipExcluded` TINYINT NOT NULL DEFAULT 0 COMMENT '是否拒绝发货',
`MappedSkuId` INT NULL COMMENT '映射库内SKU → C_sku.Id',
`IsDeleted` TINYINT NOT NULL DEFAULT 0 COMMENT '软删除:0-否,1-是',
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()) COMMENT '并发戳',
`CreateUserId` INT NOT NULL DEFAULT 0 COMMENT '创建人',
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`UpdateUserId` INT NULL COMMENT '更新人',
`UpdateTime` DATETIME NULL COMMENT '更新时间',
PRIMARY KEY (`Id`),
KEY `idx_store_order_line_order` (`StoreOrderId`, `IsDeleted`)
) COMMENT='销售店铺订单明细';

View File

@ -1,50 +0,0 @@
-- 已执行旧版 migrate_warehouse_module.sql 的库补 ConcurrencyStamp(与 AggregateRoot 实体对齐)
-- 勿在 ALTER 中使用 DEFAULT(UUID()),复制环境会报 Error 1674
ALTER TABLE `C_sku`
ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '' COMMENT '并发戳' AFTER `IsDeleted`;
UPDATE `C_sku` SET `ConcurrencyStamp` = UUID() WHERE `ConcurrencyStamp` = '';
ALTER TABLE `C_bin_location`
ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '' COMMENT '并发戳' AFTER `IsDeleted`;
UPDATE `C_bin_location` SET `ConcurrencyStamp` = UUID() WHERE `ConcurrencyStamp` = '';
ALTER TABLE `C_inventory`
ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '' COMMENT '并发戳' AFTER `IsDeleted`;
UPDATE `C_inventory` SET `ConcurrencyStamp` = UUID() WHERE `ConcurrencyStamp` = '';
ALTER TABLE `C_inbound_notice`
ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '' COMMENT '并发戳' AFTER `IsDeleted`;
UPDATE `C_inbound_notice` SET `ConcurrencyStamp` = UUID() WHERE `ConcurrencyStamp` = '';
ALTER TABLE `C_inbound_box`
ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '' COMMENT '并发戳' AFTER `IsDeleted`;
UPDATE `C_inbound_box` SET `ConcurrencyStamp` = UUID() WHERE `ConcurrencyStamp` = '';
ALTER TABLE `C_inbound_box_line`
ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '' COMMENT '并发戳' AFTER `IsDeleted`;
UPDATE `C_inbound_box_line` SET `ConcurrencyStamp` = UUID() WHERE `ConcurrencyStamp` = '';
ALTER TABLE `C_parcel`
ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '' COMMENT '并发戳' AFTER `IsDeleted`;
UPDATE `C_parcel` SET `ConcurrencyStamp` = UUID() WHERE `ConcurrencyStamp` = '';
ALTER TABLE `C_parcel_item`
ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '' COMMENT '并发戳' AFTER `IsDeleted`;
UPDATE `C_parcel_item` SET `ConcurrencyStamp` = UUID() WHERE `ConcurrencyStamp` = '';
ALTER TABLE `C_sku_platform_map`
ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '' COMMENT '并发戳' AFTER `IsDeleted`;
UPDATE `C_sku_platform_map` SET `ConcurrencyStamp` = UUID() WHERE `ConcurrencyStamp` = '';
ALTER TABLE `t_sales_store`
ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '' COMMENT '并发戳' AFTER `IsDeleted`;
UPDATE `t_sales_store` SET `ConcurrencyStamp` = UUID() WHERE `ConcurrencyStamp` = '';
ALTER TABLE `t_sales_store_order`
ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '' COMMENT '并发戳' AFTER `IsDeleted`;
UPDATE `t_sales_store_order` SET `ConcurrencyStamp` = UUID() WHERE `ConcurrencyStamp` = '';
ALTER TABLE `t_sales_store_order_line`
ADD COLUMN `ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT '' COMMENT '并发戳' AFTER `IsDeleted`;
UPDATE `t_sales_store_order_line` SET `ConcurrencyStamp` = UUID() WHERE `ConcurrencyStamp` = '';

View File

@ -1,31 +0,0 @@
-- 微信公众号配置(t_system_other_config)
-- 字段映射:AppKey=AppId,AppSecret=Secret,Remark=Token,BaseUrl=OAuthRedirectBase
-- 请在管理端「系统 → 其他配置」填写真实 AppId / AppSecret / Token,勿将密钥提交到 Git。
INSERT INTO `t_system_other_config` (
`ConfigCode`,
`ConfigName`,
`Enabled`,
`BaseUrl`,
`AppKey`,
`AppSecret`,
`Remark`,
`TimeoutSeconds`,
`IsDeleted`,
`CreateUserId`
)
SELECT
'wechat_mp',
'微信公众号',
1,
'https://oms.nanafa.com',
'',
'',
'',
30,
0,
0
FROM DUAL
WHERE NOT EXISTS (
SELECT 1 FROM `t_system_other_config` WHERE `ConfigCode` = 'wechat_mp' AND `IsDeleted` = 0
);

View File

@ -1,39 +0,0 @@
-- 与 migrate_t_order_parcel_columns.sql 相同,保留此文件名便于按文档引用
-- t_order / t_order_fee 小包预报计费字段补齐(可重复执行)
SET @db = DATABASE();
SET @exist := (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 't_order' AND COLUMN_NAME = 'ExportCustomsMode');
SET @sql := IF(@exist = 0,
'ALTER TABLE `t_order` ADD COLUMN `ExportCustomsMode` VARCHAR(32) NULL COMMENT ''出口报关方式'' AFTER `CargoAttribute`',
'SELECT ''skip ExportCustomsMode''');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @exist := (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 't_order' AND COLUMN_NAME = 'PredeclareFailReason');
SET @sql := IF(@exist = 0,
'ALTER TABLE `t_order` ADD COLUMN `PredeclareFailReason` VARCHAR(512) NULL COMMENT ''预报失败原因'' AFTER `IsRemote`',
'SELECT ''skip PredeclareFailReason''');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @exist := (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 't_order' AND COLUMN_NAME = 'SalesProductRulesVersion');
SET @sql := IF(@exist = 0,
'ALTER TABLE `t_order` ADD COLUMN `SalesProductRulesVersion` VARCHAR(64) NULL COMMENT ''销售产品规则快照版本'' AFTER `PredeclareFailReason`',
'SELECT ''skip SalesProductRulesVersion''');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @exist := (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 't_order' AND COLUMN_NAME = 'SalesProductPriceVersion');
SET @sql := IF(@exist = 0,
'ALTER TABLE `t_order` ADD COLUMN `SalesProductPriceVersion` VARCHAR(64) NULL COMMENT ''销售产品价格快照版本'' AFTER `SalesProductRulesVersion`',
'SELECT ''skip SalesProductPriceVersion''');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
SET @exist := (SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = @db AND TABLE_NAME = 't_order_fee' AND COLUMN_NAME = 'ChargingStage');
SET @sql := IF(@exist = 0,
'ALTER TABLE `t_order_fee` ADD COLUMN `ChargingStage` VARCHAR(16) NULL COMMENT ''计费阶段:forecast/inbound/outbound'' AFTER `PriceEffectiveTime`',
'SELECT ''skip ChargingStage''');
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;

View File

@ -1,117 +0,0 @@
-- 数据权限管理 — RBAC 菜单与权限码种子
-- 前端路由:/system/dataPerm/users、/system/dataPerm/templates、/system/dataPerm/audit
-- PermissionCode 须在 PermissionDefinitionProvider 注册后方能分配
SET @ADMIN_USER_ID = (
SELECT `Id` FROM `user`
WHERE `Account` = 'admin' AND (`IsDeleted` = 0 OR `IsDeleted` IS NULL)
LIMIT 1
);
SET @ADMIN_USER_ID = IFNULL(@ADMIN_USER_ID, '08de4226-3fd4-4a5c-83e5-70e164b15f2f');
SET @ROOT_PID = '00000000-0000-0000-0000-000000000000';
-- 查找「系统管理」父菜单(若无则挂根)
SET @SYSTEM_PID = (
SELECT `Id` FROM `menu`
WHERE (`Route` = '/system' OR `Name` = '系统管理')
AND (`IsDeleted` = 0 OR `IsDeleted` IS NULL)
ORDER BY `Order`
LIMIT 1
);
SET @SYSTEM_PID = IFNULL(@SYSTEM_PID, @ROOT_PID);
INSERT INTO `menu` (
`Id`, `PId`, `Name`, `PermissionCode`, `Type`, `Icon`, `Route`, `Component`, `Order`,
`IsHidden`, `IsCached`, `Description`, `IsDeleted`,
`ConcurrencyStamp`, `CreateUserId`, `CreateTime`, `UpdateUserId`, `UpdateTime`
) VALUES
(
'da100001-0000-4000-8000-000000000001',
@SYSTEM_PID,
'数据权限',
'Rbac.DataPerm',
1,
'icon-safe',
'/system/dataPerm',
NULL,
90,
0, 1, '多维数据权限配置', 0,
UUID(), @ADMIN_USER_ID, NOW(), @ADMIN_USER_ID, NOW()
),
(
'da100001-0000-4000-8000-000000000002',
'da100001-0000-4000-8000-000000000001',
'用户数据权限',
'Rbac.DataPerm.Query',
1,
NULL,
'/system/dataPerm/users',
'views/system/dataPerm/users/index',
1,
0, 1, NULL, 0,
UUID(), @ADMIN_USER_ID, NOW(), @ADMIN_USER_ID, NOW()
),
(
'da100001-0000-4000-8000-000000000003',
'da100001-0000-4000-8000-000000000001',
'权限模板',
'Rbac.DataPerm.Template',
1,
NULL,
'/system/dataPerm/templates',
'views/system/dataPerm/templates/index',
2,
0, 1, NULL, 0,
UUID(), @ADMIN_USER_ID, NOW(), @ADMIN_USER_ID, NOW()
),
(
'da100001-0000-4000-8000-000000000004',
'da100001-0000-4000-8000-000000000001',
'访问审计',
'Rbac.DataPerm.Audit',
1,
NULL,
'/system/dataPerm/audit',
'views/system/dataPerm/audit/index',
3,
0, 0, NULL, 0,
UUID(), @ADMIN_USER_ID, NOW(), @ADMIN_USER_ID, NOW()
),
(
'da100001-0000-4000-8000-000000000005',
'da100001-0000-4000-8000-000000000002',
'保存用户权限',
'Rbac.DataPerm.Update',
2,
NULL,
NULL,
NULL,
1,
0, 0, NULL, 0,
UUID(), @ADMIN_USER_ID, NOW(), @ADMIN_USER_ID, NOW()
)
ON DUPLICATE KEY UPDATE
`Name` = VALUES(`Name`),
`PId` = VALUES(`PId`),
`PermissionCode` = VALUES(`PermissionCode`),
`Route` = VALUES(`Route`),
`Component` = VALUES(`Component`),
`Order` = VALUES(`Order`);
-- 超管角色分配数据权限(若存在 Admin 角色)
INSERT INTO `role_permission` (`Id`, `RoleId`, `PermissionCode`, `CreateUserId`, `CreateTime`)
SELECT UUID(), r.`Id`, p.`Code`, @ADMIN_USER_ID, NOW()
FROM `role` r
CROSS JOIN (
SELECT 'Rbac.DataPerm' AS Code UNION ALL
SELECT 'Rbac.DataPerm.Query' UNION ALL
SELECT 'Rbac.DataPerm.Update' UNION ALL
SELECT 'Rbac.DataPerm.Template' UNION ALL
SELECT 'Rbac.DataPerm.Audit'
) p
WHERE r.`Code` = 'Admin'
AND (r.`IsDeleted` = 0 OR r.`IsDeleted` IS NULL)
AND NOT EXISTS (
SELECT 1 FROM `role_permission` rp
WHERE rp.`RoleId` = r.`Id` AND rp.`PermissionCode` = p.`Code`
);

View File

@ -1,149 +0,0 @@
-- E2E 订单全链路测试主数据(固定 ID 段 900x / 99001)
-- 前置:已执行 db.sql;库中已有 t_country.US
-- 用法:mysql ... oms_test < sql/seed_e2e_order_lifecycle.sql
-- RBAC 批量任务菜单/权限:sql/seed_order_lab_rbac_menu.sql + sql/seed_order_lab_role_permissions.sql
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- 清理旧 E2E 数据(子表优先)
DELETE FROM `t_sales_product_allocation_provider` WHERE `SalesProductId` = 9001;
DELETE FROM `t_sales_product_price_detail` WHERE `PriceId` = 9001;
DELETE FROM `t_sales_product_price_factor` WHERE `PriceId` = 9001;
DELETE FROM `t_sales_product_price` WHERE `Id` = 9001;
DELETE FROM `t_service_channel_price_detail` WHERE `PriceId` = 9001;
DELETE FROM `t_service_channel_price_factor` WHERE `PriceId` = 9001;
DELETE FROM `t_service_channel_price` WHERE `Id` = 9001;
DELETE FROM `t_sales_product` WHERE `Id` = 9001;
DELETE FROM `t_service_channel` WHERE `Id` = 9001;
DELETE FROM `t_weight_rounding_info` WHERE `RoundingId` = 9001;
DELETE FROM `t_weight_rounding` WHERE `Id` = 9001;
DELETE FROM `t_weight_rule_info` WHERE `RuleId` = 9001;
DELETE FROM `t_weight_rule` WHERE `Id` = 9001;
DELETE FROM `t_kpi_area_info` WHERE `AreaId` = 9001;
DELETE FROM `t_kpi_area` WHERE `Id` = 9001;
DELETE FROM `t_warehouse_address` WHERE `Id` = 9001;
DELETE FROM `t_customer` WHERE `Id` = 99001;
-- 仓库
INSERT INTO `t_warehouse_address` (
`Id`, `WarehouseName`, `WarehouseType`, `Recipient`, `ContactPhone`, `ShippingAddress`,
`IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
) VALUES (
9001, 'E2E测试仓', 'main', 'E2E', '0755-00000000', '深圳市南山区测试路1号',
0, UUID(), 0, NOW()
);
-- 价格分区(美西 → US)
INSERT INTO `t_kpi_area` (
`Id`, `AppKey`, `AreaType`, `Name`, `SystemName`,
`IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
) VALUES (
9001, 'oms', 'warning', '美西', 'E2E-US-WEST',
0, UUID(), 0, NOW()
);
INSERT INTO `t_kpi_area_info` (
`AreaId`, `CountryCode`, `CountryName`, `IsDeleted`, `CreateUserId`, `CreateTime`
) VALUES (
9001, 'US', '美国', 0, 0, NOW()
);
-- 计重规则 / 进位
INSERT INTO `t_weight_rule` (
`Id`, `AppKey`, `Name`, `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
) VALUES (
9001, 'oms', 'E2E计重规则', 0, UUID(), 0, NOW()
);
INSERT INTO `t_weight_rule_info` (
`RuleId`, `Client`, `Condition`, `BillableWeight`, `VolumetricFactor`,
`IsDeleted`, `CreateUserId`, `CreateTime`
) VALUES (
9001, '全部', 'gw>=vw', 'gw', '6000', 0, 0, NOW()
);
INSERT INTO `t_weight_rounding` (
`Id`, `AppKey`, `Name`, `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
) VALUES (
9001, 'oms', 'E2E进位', 0, UUID(), 0, NOW()
);
INSERT INTO `t_weight_rounding_info` (
`RoundingId`, `StartValue`, `EndValue`, `Public`, `IsDeleted`, `CreateUserId`, `CreateTime`
) VALUES (
9001, 0, 30, '0.5', 0, 0, NOW()
);
-- 服务渠道 + 买价
INSERT INTO `t_service_channel` (
`Id`, `ChannelCode`, `ChannelName`, `IsActive`,
`IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
) VALUES (
9001, 'E2E-CH-01', 'E2E测试渠道', 1,
0, UUID(), 0, NOW()
);
INSERT INTO `t_service_channel_price` (
`Id`, `ServiceChannelId`, `SerialNumber`, `Status`, `PriceName`, `CostItem`, `CostUnit`, `Currency`,
`IsDeleted`, `CreateUserId`, `CreateTime`
) VALUES (
9001, 9001, 1, 1, 'E2E买价', 'freight', 'kg', 'CNY',
0, 0, NOW()
);
INSERT INTO `t_service_channel_price_detail` (
`PriceId`, `FactorValuesJson`, `CalculationFormula`, `CalculatedValue`,
`IsDeleted`, `CreateUserId`, `CreateTime`
) VALUES (
9001,
'{"分区":"美西","货物类型":"普货","首重":"1","首重价":"10","续重单位":"0.5","续重价":"4"}',
'续单价', NULL,
0, 0, NOW()
);
-- 销售产品 + 卖价 + 排货
INSERT INTO `t_sales_product` (
`Id`, `ProductCode`, `ProductName`, `ProductGroup`, `PriceAreaId`, `WeightRuleId`, `WeightRoundingId`,
`IsActive`, `Scheme`, `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
) VALUES (
9001, 'E2E-SP-01', 'E2E测试产品', '专线', 9001, 9001, 9001,
1, 'costLowest', 0, UUID(), 0, NOW()
);
INSERT INTO `t_sales_product_price` (
`Id`, `SalesProductId`, `SerialNumber`, `Status`, `PriceName`, `CostItem`, `CostUnit`, `Currency`,
`IsDeleted`, `CreateUserId`, `CreateTime`
) VALUES (
9001, 9001, 1, 1, 'E2E卖价', 'freight', 'kg', 'CNY',
0, 0, NOW()
);
INSERT INTO `t_sales_product_price_detail` (
`PriceId`, `FactorValuesJson`, `CalculationFormula`, `CalculatedValue`,
`IsDeleted`, `CreateUserId`, `CreateTime`
) VALUES (
9001,
'{"分区":"美西","货物类型":"普货","首重":"1","首重价":"18","续重单位":"0.5","续重价":"6"}',
'续单价', NULL,
0, 0, NOW()
);
INSERT INTO `t_sales_product_allocation_provider` (
`SalesProductId`, `SerialNumber`, `ProviderName`, `ServiceChannelId`, `Weight`,
`IsDeleted`, `CreateUserId`, `CreateTime`
) VALUES (
9001, 1, 'E2E渠道商', 9001, 100,
0, 0, NOW()
);
-- 客户(密码明文 e2e123 → MD5)
INSERT INTO `t_customer` (
`Id`, `UserId`, `CustomerCode`, `CustomerName`, `Email`, `Phone`, `Balance`,
`Status`, `Password`, `IsDeleted`, `ConcurrencyStamp`, `CreateUserId`, `CreateTime`
) VALUES (
99001, 1, 'E2E001', 'E2E测试客户', 'e2e99001@test.local', '19900009901', 50000.00,
1, '5df3e7decfd8323014e399401de7d82f', 0, UUID(), 0, NOW()
);
SET FOREIGN_KEY_CHECKS = 1;

View File

@ -1,54 +0,0 @@
-- 订单批量任务 RBAC 菜单(Fake.Rbac menu 表)
-- 执行库:RBAC 库(与 seed_xhs_rbac_menu.sql 相同)
-- 幂等:可重复执行
SET @ADMIN_USER_ID = (
SELECT `Id` FROM `user`
WHERE `Account` = 'admin' AND (`IsDeleted` = 0 OR `IsDeleted` IS NULL)
LIMIT 1
);
SET @ADMIN_USER_ID = IFNULL(
@ADMIN_USER_ID,
'08de4226-3fd4-4a5c-83e5-70e164b15f2f'
);
SET @ORDER_PID = (
SELECT `Id` FROM `menu`
WHERE `Route` = '/order' AND `IsDeleted` = 0
ORDER BY `Order`
LIMIT 1
);
SET @ORDER_PID = IFNULL(@ORDER_PID, '00000000-0000-0000-0000-000000000000');
INSERT INTO `menu` (
`Id`, `PId`, `Name`, `PermissionCode`, `Type`, `Icon`, `Route`, `Component`, `Order`,
`IsHidden`, `IsCached`, `Description`, `IsDeleted`,
`ConcurrencyStamp`, `CreateUserId`, `CreateTime`, `UpdateUserId`, `UpdateTime`
) VALUES (
'b1b2c3d4-e5f6-7890-abcd-ef1234567901',
@ORDER_PID,
'批量任务',
'Order.BatchJobs',
1,
NULL,
'/order/batchJobs',
'views/order/batchJobs/index',
4,
0, 1, '订单 RabbitMQ 批量任务治理', 0,
UUID(), @ADMIN_USER_ID, NOW(), @ADMIN_USER_ID, NOW()
)
ON DUPLICATE KEY UPDATE
`Name` = VALUES(`Name`),
`PId` = VALUES(`PId`),
`PermissionCode` = VALUES(`PermissionCode`),
`Route` = VALUES(`Route`),
`Component` = VALUES(`Component`),
`Order` = VALUES(`Order`),
`Description` = VALUES(`Description`),
`CreateUserId` = VALUES(`CreateUserId`),
`UpdateUserId` = VALUES(`UpdateUserId`);
-- 清理已废弃的链路演练菜单
UPDATE `menu`
SET `IsDeleted` = 1, `UpdateTime` = NOW(), `UpdateUserId` = @ADMIN_USER_ID
WHERE `Route` = '/order/lifecycleLab' AND `IsDeleted` = 0;

View File

@ -1,31 +0,0 @@
-- 为 Admin / Customer 角色追加批量任务权限(幂等)
-- RBAC 库执行;执行后登录用户需重新获取 token 或刷新权限缓存
SET @ADMIN_USER_ID = (
SELECT `Id` FROM `user`
WHERE `Account` = 'admin' AND (`IsDeleted` = 0 OR `IsDeleted` IS NULL)
LIMIT 1
);
SET @ADMIN_USER_ID = IFNULL(
@ADMIN_USER_ID,
'08de4226-3fd4-4a5c-83e5-70e164b15f2f'
);
INSERT INTO `role_permission` (`Id`, `RoleId`, `PermissionCode`, `CreateUserId`, `CreateTime`)
SELECT UUID(), r.`Id`, p.`Code`, @ADMIN_USER_ID, NOW()
FROM `role` r
CROSS JOIN (
SELECT 'Order.BatchJobs.Query' AS `Code` UNION ALL
SELECT 'Order.BatchJobs.View' UNION ALL
SELECT 'Order.BatchJobs.Retry' UNION ALL
SELECT 'Order.BatchJobs.Cancel'
) p
WHERE r.`Code` IN ('Admin', 'Customer')
AND NOT EXISTS (
SELECT 1 FROM `role_permission` rp
WHERE rp.`RoleId` = r.`Id` AND rp.`PermissionCode` = p.`Code`
);
-- 清理已废弃的链路演练权限
DELETE FROM `role_permission`
WHERE `PermissionCode` LIKE 'Order.LifecycleLab.%';

View File

@ -1,20 +0,0 @@
-- 标准模板:专线小包模板
INSERT INTO `t_order_template` (
`Name`, `Type`, `TemplateKey`, `StandardTemplateKey`, `MappingStatus`,
`CustomerId`, `IsDeleted`, `CreateUserId`, `CreateTime`
)
SELECT
'专线小包模板',
'standard',
'dedicated_small_parcel_v1',
'dedicated_small_parcel_v1',
'ready',
NULL,
0,
0,
NOW()
FROM DUAL
WHERE NOT EXISTS (
SELECT 1 FROM `t_order_template`
WHERE `Type` = 'standard' AND `TemplateKey` = 'dedicated_small_parcel_v1' AND `IsDeleted` = 0
);

View File

@ -1,45 +0,0 @@
-- ???? + ????/?? RBAC ??????
-- RBAC ?????????????????????
SET @ADMIN_USER_ID = (
SELECT `Id` FROM `user`
WHERE `Account` = 'admin' AND (`IsDeleted` = 0 OR `IsDeleted` IS NULL)
LIMIT 1
);
SET @ADMIN_USER_ID = IFNULL(
@ADMIN_USER_ID,
'08de4226-3fd4-4a5c-83e5-70e164b15f2f'
);
INSERT INTO `role_permission` (`Id`, `RoleId`, `PermissionCode`, `CreateUserId`, `CreateTime`)
SELECT UUID(), r.`Id`, p.`Code`, @ADMIN_USER_ID, NOW()
FROM `role` r
CROSS JOIN (
SELECT 'Warehouse.Sku.Query' AS `Code` UNION ALL
SELECT 'Warehouse.Sku.Save' UNION ALL
SELECT 'Warehouse.Sku.Delete' UNION ALL
SELECT 'Warehouse.Inventory.Query' UNION ALL
SELECT 'Warehouse.Inventory.Relocate' UNION ALL
SELECT 'Warehouse.BinLocation.Query' UNION ALL
SELECT 'Warehouse.BinLocation.Save' UNION ALL
SELECT 'Warehouse.Parcel.Query' UNION ALL
SELECT 'Warehouse.Parcel.Save' UNION ALL
SELECT 'Warehouse.Parcel.Delete' UNION ALL
SELECT 'Warehouse.InboundNotice.Query' UNION ALL
SELECT 'Warehouse.InboundNotice.Save' UNION ALL
SELECT 'Warehouse.InboundNotice.ConfirmReceive' UNION ALL
SELECT 'Warehouse.InboundNotice.Delete' UNION ALL
SELECT 'Order.PlatformStore.Query' UNION ALL
SELECT 'Order.PlatformStore.Save' UNION ALL
SELECT 'Order.PlatformStore.Delete' UNION ALL
SELECT 'Order.PlatformStore.Auth' UNION ALL
SELECT 'Order.PlatformStoreOrder.Query' UNION ALL
SELECT 'Order.PlatformStoreOrder.MatchInventory' UNION ALL
SELECT 'Order.PlatformStoreOrder.ToggleSuspend' UNION ALL
SELECT 'Order.PlatformStoreOrder.Delete'
) p
WHERE r.`Code` IN ('Admin', 'Customer')
AND NOT EXISTS (
SELECT 1 FROM `role_permission` rp
WHERE rp.`RoleId` = r.`Id` AND rp.`PermissionCode` = p.`Code`
);

View File

@ -1,36 +0,0 @@
-- 小红书 AI 提供商模板(CustomerId=0 全局,需填入 ApiKeyEnc / ApiSecretEnc 后启用)
-- ApiSecretEnc 字段存模型名,如 glm-4-flash / deepseek-chat / gpt-4o-mini
--
-- 若报 1146 Table doesn't exist:请先执行 migrate_t_xhs.sql
CREATE TABLE IF NOT EXISTS `t_xhs_ai_provider` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID;0 表示全局',
`ProviderKey` VARCHAR(32) NOT NULL COMMENT 'ai_chatgpt / ai_zhipu 等',
`ProviderType` VARCHAR(32) NOT NULL COMMENT 'chatgpt/doubao/deepseek/zhipu',
`DisplayName` VARCHAR(64) NOT NULL COMMENT '展示名',
`BaseUrl` VARCHAR(512) NOT NULL COMMENT 'API Base URL',
`ApiKeyEnc` VARCHAR(512) NULL COMMENT 'API Key(暂明文,后续可加密)',
`ApiSecretEnc` VARCHAR(512) NULL COMMENT 'Secret/模型名',
`IsDefault` TINYINT NOT NULL DEFAULT 0 COMMENT '是否默认',
`Enabled` TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()),
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_xhs_ai_provider` (`CustomerId`, `ProviderKey`),
KEY `idx_xhs_ai_customer` (`CustomerId`, `Enabled`)
) COMMENT='小红书 AI 提供商配置表';
INSERT INTO `t_xhs_ai_provider` (
`CustomerId`, `ProviderKey`, `ProviderType`, `DisplayName`, `BaseUrl`,
`ApiKeyEnc`, `ApiSecretEnc`, `IsDefault`, `Enabled`,
`IsDeleted`, `CreateUserId`, `CreateTime`
) VALUES
(0, 'ai_zhipu', 'zhipu', '智谱 AI', 'https://open.bigmodel.cn/api/paas/v4', NULL, 'glm-4-flash', 1, 0, 0, 0, NOW()),
(0, 'ai_deepseek', 'deepseek', 'DeepSeek', 'https://api.deepseek.com/v1', NULL, 'deepseek-chat', 0, 0, 0, 0, NOW()),
(0, 'ai_chatgpt', 'chatgpt', 'OpenAI', 'https://api.openai.com/v1', NULL, 'gpt-4o-mini', 0, 0, 0, 0, NOW())
ON DUPLICATE KEY UPDATE `DisplayName` = VALUES(`DisplayName`), `BaseUrl` = VALUES(`BaseUrl`);

View File

@ -1,97 +0,0 @@
-- 小红书模块 RBAC 菜单种子(Fake.Rbac menu 表)
-- 设计文档:E:\oms0414\docs\小红书模块设计-063001.md
--
-- 注意:本环境 menu.CreateUserId / UpdateUserId 为 CHAR(36) GUID,不可写整数 0
-- 若已误插入导致 get-menu-tree 报错,先执行 fix_xhs_menu_bad_guids.sql
SET @ADMIN_USER_ID = (
SELECT `Id` FROM `user`
WHERE `Account` = 'admin' AND (`IsDeleted` = 0 OR `IsDeleted` IS NULL)
LIMIT 1
);
SET @ADMIN_USER_ID = IFNULL(
@ADMIN_USER_ID,
'08de4226-3fd4-4a5c-83e5-70e164b15f2f'
);
SET @ROOT_PID = '00000000-0000-0000-0000-000000000000';
-- 一级:小红书(目录节点,PermissionCode 留空字符串;子菜单各自绑权限)
INSERT INTO `menu` (
`Id`, `PId`, `Name`, `PermissionCode`, `Type`, `Icon`, `Route`, `Component`, `Order`,
`IsHidden`, `IsCached`, `Description`, `IsDeleted`,
`ConcurrencyStamp`, `CreateUserId`, `CreateTime`, `UpdateUserId`, `UpdateTime`
) VALUES (
'a1b2c3d4-e5f6-7890-abcd-ef1234567801',
@ROOT_PID,
'小红书',
'',
1,
'icon-fire',
'/xhs',
NULL,
4,
0, 0, 'LIKE AI 小红书自动化', 0,
UUID(), @ADMIN_USER_ID, NOW(), @ADMIN_USER_ID, NOW()
) ON DUPLICATE KEY UPDATE
`Name` = VALUES(`Name`),
`PId` = VALUES(`PId`),
`PermissionCode` = VALUES(`PermissionCode`),
`Route` = VALUES(`Route`),
`Component` = VALUES(`Component`),
`CreateUserId` = VALUES(`CreateUserId`),
`UpdateUserId` = VALUES(`UpdateUserId`);
INSERT INTO `menu` (
`Id`, `PId`, `Name`, `PermissionCode`, `Type`, `Icon`, `Route`, `Component`, `Order`,
`IsHidden`, `IsCached`, `Description`, `IsDeleted`,
`ConcurrencyStamp`, `CreateUserId`, `CreateTime`, `UpdateUserId`, `UpdateTime`
) VALUES
('a1b2c3d4-e5f6-7890-abcd-ef1234567802', 'a1b2c3d4-e5f6-7890-abcd-ef1234567801', '启动服务', 'Xhs.Agent.Query', 1, NULL, '/xhs/startService', 'views/xhs/startService/index', 1, 0, 1, NULL, 0, UUID(), @ADMIN_USER_ID, NOW(), @ADMIN_USER_ID, NOW()),
('a1b2c3d4-e5f6-7890-abcd-ef1234567803', 'a1b2c3d4-e5f6-7890-abcd-ef1234567801', '内容分析', 'Xhs.Analysis.Use', 1, NULL, '/xhs/analysis', 'views/xhs/analysis/index', 2, 0, 1, NULL, 0, UUID(), @ADMIN_USER_ID, NOW(), @ADMIN_USER_ID, NOW()),
('a1b2c3d4-e5f6-7890-abcd-ef1234567804', 'a1b2c3d4-e5f6-7890-abcd-ef1234567801', '爆款创作', 'Xhs.Creation.Use', 1, NULL, '/xhs/creation', 'views/xhs/creation/index', 3, 0, 1, NULL, 0, UUID(), @ADMIN_USER_ID, NOW(), @ADMIN_USER_ID, NOW()),
('a1b2c3d4-e5f6-7890-abcd-ef1234567805', 'a1b2c3d4-e5f6-7890-abcd-ef1234567801', '发布记录', 'Xhs.Publish.Query', 1, NULL, '/xhs/publishHistory', 'views/xhs/publishHistory/index', 4, 0, 1, NULL, 0, UUID(), @ADMIN_USER_ID, NOW(), @ADMIN_USER_ID, NOW()),
('a1b2c3d4-e5f6-7890-abcd-ef1234567806', 'a1b2c3d4-e5f6-7890-abcd-ef1234567801', '技能卡片', 'Xhs.Skills.Query', 1, NULL, '/xhs/skills', 'views/xhs/skills/index', 5, 0, 1, NULL, 0, UUID(), @ADMIN_USER_ID, NOW(), @ADMIN_USER_ID, NOW()),
('a1b2c3d4-e5f6-7890-abcd-ef1234567807', 'a1b2c3d4-e5f6-7890-abcd-ef1234567801', '拟人设置', 'Xhs.HumanSettings.Save', 1, NULL, '/xhs/humanSettings', 'views/xhs/humanSettings/index', 6, 0, 1, NULL, 0, UUID(), @ADMIN_USER_ID, NOW(), @ADMIN_USER_ID, NOW())
ON DUPLICATE KEY UPDATE
`Name` = VALUES(`Name`),
`PId` = VALUES(`PId`),
`Route` = VALUES(`Route`),
`Component` = VALUES(`Component`),
`Order` = VALUES(`Order`),
`CreateUserId` = VALUES(`CreateUserId`),
`UpdateUserId` = VALUES(`UpdateUserId`);
-- AI 助手:挂在「系统管理」下(Route=/system);若不存在则挂根节点
SET @SYSTEM_PID = (
SELECT `Id` FROM `menu`
WHERE `Route` = '/system' AND `IsDeleted` = 0
ORDER BY `Order`
LIMIT 1
);
SET @AI_ASSISTANT_PID = IFNULL(@SYSTEM_PID, @ROOT_PID);
INSERT INTO `menu` (
`Id`, `PId`, `Name`, `PermissionCode`, `Type`, `Icon`, `Route`, `Component`, `Order`,
`IsHidden`, `IsCached`, `Description`, `IsDeleted`,
`ConcurrencyStamp`, `CreateUserId`, `CreateTime`, `UpdateUserId`, `UpdateTime`
) VALUES (
'a1b2c3d4-e5f6-7890-abcd-ef1234567808',
@AI_ASSISTANT_PID,
'AI 助手',
'Xhs.Ai.Use',
1,
NULL,
'/system/xhsAiAssistant',
'views/system/xhsAiAssistant/index',
99,
0, 1, '小红书 AI 助手(系统菜单)', 0,
UUID(), @ADMIN_USER_ID, NOW(), @ADMIN_USER_ID, NOW()
) ON DUPLICATE KEY UPDATE
`Name` = VALUES(`Name`),
`PId` = VALUES(`PId`),
`Route` = VALUES(`Route`),
`Component` = VALUES(`Component`),
`CreateUserId` = VALUES(`CreateUserId`),
`UpdateUserId` = VALUES(`UpdateUserId`);
-- 权限分配见 sql/seed_xhs_role_permissions.sql(或重启 API 由 XhsRolePermissionSeedContributor 自动合并)

View File

@ -1,61 +0,0 @@
-- 为客户 / Admin 角色批量追加小红书权限(幂等,可重复执行)
-- RBAC 库执行
-- ⚠️ 本环境 role_permission.CreateUserId 为 CHAR(36) GUID,不可写整数 0(登录会报 Guid: 0)
SET @ADMIN_USER_ID = (
SELECT `Id` FROM `user`
WHERE `Account` = 'admin' AND (`IsDeleted` = 0 OR `IsDeleted` IS NULL)
LIMIT 1
);
SET @ADMIN_USER_ID = IFNULL(
@ADMIN_USER_ID,
'00000000-0000-0000-0000-000000000001'
);
INSERT INTO `role_permission` (`Id`, `RoleId`, `PermissionCode`, `CreateUserId`, `CreateTime`)
SELECT UUID(), r.`Id`, p.`Code`, @ADMIN_USER_ID, NOW()
FROM `role` r
CROSS JOIN (
SELECT 'Xhs.Agent.Query' AS `Code` UNION ALL
SELECT 'Xhs.Agent.Control' UNION ALL
SELECT 'Xhs.Analysis.Use' UNION ALL
SELECT 'Xhs.Creation.Use' UNION ALL
SELECT 'Xhs.Publish.Query' UNION ALL
SELECT 'Xhs.Publish.Cancel' UNION ALL
SELECT 'Xhs.Skills.Query' UNION ALL
SELECT 'Xhs.Skills.Save' UNION ALL
SELECT 'Xhs.Skills.Run' UNION ALL
SELECT 'Xhs.HumanSettings.Save' UNION ALL
SELECT 'Xhs.Ai.Use' UNION ALL
SELECT 'Xhs.Ai.Save'
) p
WHERE r.`Code` = 'Customer'
AND NOT EXISTS (
SELECT 1 FROM `role_permission` rp
WHERE rp.`RoleId` = r.`Id` AND rp.`PermissionCode` = p.`Code`
);
INSERT INTO `role_permission` (`Id`, `RoleId`, `PermissionCode`, `CreateUserId`, `CreateTime`)
SELECT UUID(), r.`Id`, p.`Code`, @ADMIN_USER_ID, NOW()
FROM `role` r
CROSS JOIN (
SELECT 'Xhs.Agent.Query' AS `Code` UNION ALL
SELECT 'Xhs.Agent.Control' UNION ALL
SELECT 'Xhs.Analysis.Use' UNION ALL
SELECT 'Xhs.Creation.Use' UNION ALL
SELECT 'Xhs.Publish.Query' UNION ALL
SELECT 'Xhs.Publish.Cancel' UNION ALL
SELECT 'Xhs.Skills.Query' UNION ALL
SELECT 'Xhs.Skills.Save' UNION ALL
SELECT 'Xhs.Skills.Run' UNION ALL
SELECT 'Xhs.HumanSettings.Save' UNION ALL
SELECT 'Xhs.Ai.Use' UNION ALL
SELECT 'Xhs.Ai.Save'
) p
WHERE r.`Code` = 'Admin'
AND NOT EXISTS (
SELECT 1 FROM `role_permission` rp
WHERE rp.`RoleId` = r.`Id` AND rp.`PermissionCode` = p.`Code`
);
-- 若曾用 CreateUserId=0 插入过,执行 fix_rbac_bad_guids.sql 修复脏行

View File

@ -1,47 +0,0 @@
-- 小红书系统预置技能卡片(CustomerId=0)
-- 来源:LIKE AI .xhs_bridge/skills.json
--
-- 若报 1146 Table doesn't exist:请先执行 migrate_t_xhs.sql(建全部 t_xhs_* 表)
-- 或仅缺本表时,下方 CREATE TABLE 会自动创建 t_xhs_skill
CREATE TABLE IF NOT EXISTS `t_xhs_skill` (
`Id` INT NOT NULL AUTO_INCREMENT COMMENT '主键',
`CustomerId` INT NOT NULL COMMENT '客户ID;0 表示系统预置',
`ExternalId` VARCHAR(32) NOT NULL COMMENT '对外稳定 ID',
`Title` VARCHAR(256) NOT NULL COMMENT '技能名称',
`SkillType` VARCHAR(32) NOT NULL DEFAULT 'ai_create' COMMENT '技能类型',
`PresetId` VARCHAR(64) NULL COMMENT '内置预设标识',
`RecipeJson` JSON NOT NULL COMMENT '配方 JSON',
`SortOrder` INT NOT NULL DEFAULT 0 COMMENT '排序',
`IsDeleted` TINYINT NOT NULL DEFAULT 0,
`ConcurrencyStamp` CHAR(36) NOT NULL DEFAULT (UUID()),
`CreateUserId` INT NOT NULL DEFAULT 0,
`CreateTime` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`UpdateUserId` INT NULL,
`UpdateTime` DATETIME NULL,
PRIMARY KEY (`Id`),
UNIQUE KEY `uk_xhs_skill_external` (`CustomerId`, `ExternalId`),
KEY `idx_xhs_skill_customer` (`CustomerId`, `SortOrder`)
) COMMENT='小红书技能卡片表';
INSERT INTO `t_xhs_skill` (
`CustomerId`, `ExternalId`, `Title`, `SkillType`, `PresetId`, `RecipeJson`, `SortOrder`,
`IsDeleted`, `CreateUserId`, `CreateTime`
) VALUES
(0, '5a9d3c012d50', '数字型/疑问型 · 物流知识 · 图文', 'ai_create', NULL,
'{"formula":["emotion","utility","visual","social"],"title_types":["number","question"],"body":{"domain":"物流知识","content_type":"干货教程","emotion":"生活场景","social":"知识炫耀"},"image_modes":["cover_impact"],"video_modes":[],"notes":"讲解9610的简易申报和汇总申报,退税,以及申报要求"}',
1, 0, 0, NOW()),
(0, '7dd58bfe4770', '效率工具 · 干货教程(新号)', 'ai_create', 'efficiency_tutorial',
'{"formula":["emotion","utility","visual","social"],"title_types":["number","question"],"body":{"domain":"效率工具","content_type":"干货教程","emotion":"焦虑共鸣","social":"价值传递"},"image_modes":["cover_impact","step_cards"],"video_modes":[],"notes":"话题示例:笔记工具提升效率"}',
2, 0, 0, NOW()),
(0, '3f6ed9f62afd', '职场发展 · 经验分享', 'ai_create', 'career_experience',
'{"formula":["emotion","utility","social"],"title_types":["story","compare"],"body":{"domain":"职场发展","content_type":"经验分享","emotion":"理想生活","social":"身份标签"},"image_modes":["cover_impact","lifestyle"],"video_modes":[],"notes":"话题示例:职场人际关系"}',
3, 0, 0, NOW()),
(0, '61a4d4febada', '情感共鸣 · 真实场景', 'ai_create', 'emotional_relatable',
'{"formula":["emotion","social"],"title_types":["story","question"],"body":{"domain":"情感共鸣","content_type":"经验分享","emotion":"生活场景","social":"情感支持"},"image_modes":["lifestyle"],"video_modes":["vlog_clip"],"notes":"让读者觉得这也太真实了"}',
4, 0, 0, NOW()),
(0, 'ec62cc03eea9', '避坑指南 · 观点表达', 'ai_create', 'pitfall_opinion',
'{"formula":["emotion","utility","visual","social"],"title_types":["number"],"body":{"domain":"职场发展","content_type":"避坑指南","emotion":"吐槽宣泄","social":"观点表达"},"image_modes":["info_chart"],"video_modes":["talking_head"],"notes":"话题示例:避坑指南"}',
5, 0, 0, NOW())
ON DUPLICATE KEY UPDATE `Title` = VALUES(`Title`), `RecipeJson` = VALUES(`RecipeJson`);

View File

@ -1,5 +0,0 @@
-- 微信登录:客户 openId 唯一索引(允许多个 NULL)
-- 执行前请确认索引不存在
CREATE UNIQUE INDEX IF NOT EXISTS uk_customer_wechat_openid
ON t_customer (WechatOpenid);

View File

@ -0,0 +1,125 @@
using System.Text;
using Fake.Application;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Distributed;
using Oms.Application.Shared;
using Oms.Domain.CustomersAggregate.Repositories;
using Oms.Domain.SystemAggregate.Repositories;
using Oms.Domain.WarehouseAggregate.Repositories;
namespace Oms.Application.Services.Plugin;
/// <summary>
/// 浏览器采集插件草稿 / 查重(对齐哪哪发 wepost API)。
/// </summary>
[ApiExplorerSettings(GroupName = "OMS-Plugin")]
public class PluginBrowserService : ApplicationService
{
private static readonly TimeSpan DraftTtl = TimeSpan.FromSeconds(90);
private ICustomerRepository CustomerRepository => LazyServiceProvider.GetRequiredService<ICustomerRepository>();
private ICParcelRepository ParcelRepository => LazyServiceProvider.GetRequiredService<ICParcelRepository>();
private IWarehouseAddressRepository WarehouseAddressRepository =>
LazyServiceProvider.GetRequiredService<IWarehouseAddressRepository>();
private IDistributedCache Cache => LazyServiceProvider.GetRequiredService<IDistributedCache>();
/// <summary>
/// 缓存采集草稿,返回 key(确认页 getPackage 使用)。
/// </summary>
[HttpPost("/plugin/browser/add")]
[Consumes("application/x-www-form-urlencoded", "multipart/form-data")]
public async Task<object> AddDraftAsync([FromForm] string? item)
{
var customerId = await ResolveRequiredCustomerIdAsync();
var payload = item;
if (string.IsNullOrWhiteSpace(payload))
{
throw new BusinessException("草稿内容不能为空");
}
var key = $"{customerId}{DateTimeOffset.UtcNow.ToUnixTimeSeconds()}{Random.Shared.Next(100, 999)}";
await Cache.SetAsync(
CacheKey(key),
Encoding.UTF8.GetBytes(payload!),
new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = DraftTtl });
return key;
}
/// <summary>
/// 读取草稿 JSON 字符串。
/// </summary>
[HttpGet("/plugin/browser/getPackage")]
public async Task<object> GetDraftAsync([FromQuery] string key)
{
if (string.IsNullOrWhiteSpace(key))
{
throw new BusinessException("key 不能为空");
}
var bytes = await Cache.GetAsync(CacheKey(key.Trim()));
if (bytes == null || bytes.Length == 0)
{
throw new BusinessException("包裹草稿不存在或已过期");
}
return Encoding.UTF8.GetString(bytes);
}
/// <summary>
/// 查重:快递单号是否已存在于当前客户的「我的包裹」。
/// </summary>
[HttpGet("/plugin/browser/selectPackage")]
public async Task<object> SelectPackageAsync([FromQuery] string? expressNum, [FromQuery] string? orderNo)
{
var customerId = await ResolveRequiredCustomerIdAsync();
var trackingNo = (expressNum ?? string.Empty).Trim();
var trackExists = false;
if (!string.IsNullOrWhiteSpace(trackingNo))
{
var hit = await ParcelRepository.FirstOrDefaultAsync(x =>
x.CustomerId == customerId && x.TrackingNo == trackingNo);
trackExists = hit != null;
}
// OMS 包裹表无独立订单号字段;orderNo 仅作兼容保留,默认同 track 不分别标记
return new
{
trackNo = trackExists,
orderNo = false
};
}
/// <summary>
/// 插件确认页默认仓库(取第一个可用仓库)。
/// </summary>
[HttpGet("/plugin/browser/getPluginWhseInfo")]
public async Task<object?> GetPluginWhseInfoAsync()
{
await ResolveRequiredCustomerIdAsync();
var list = await WarehouseAddressRepository.GetPagedListAsync(
_ => true,
1,
20,
new Dictionary<string, bool> { [nameof(Oms.Domain.SystemAggregate.Entities.WarehouseAddress.Id)] = true });
var wh = list.FirstOrDefault();
if (wh == null)
{
return null;
}
return new
{
id = wh.Id,
name = wh.WarehouseName
};
}
private async Task<int> ResolveRequiredCustomerIdAsync() =>
await WarehouseCustomerHelper.ResolveRequiredCustomerIdAsync(
CustomerRepository,
CurrentUser,
null);
private static string CacheKey(string key) => $"oms:plugin:parcel:draft:{key}";
}

View File

@ -32,8 +32,4 @@
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<None Include="..\..\sql\seed_e2e_order_lifecycle.sql" Link="sql\seed_e2e_order_lifecycle.sql" CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
</Project>

View File

@ -18,35 +18,12 @@ internal static class E2eDatabase
}
}
public static async Task ApplySeedScriptAsync(string connectionString, CancellationToken cancellationToken = default)
public static Task ApplySeedScriptAsync(string connectionString, CancellationToken cancellationToken = default)
{
var seedPath = Path.Combine(AppContext.BaseDirectory, "sql", "seed_e2e_order_lifecycle.sql");
if (!File.Exists(seedPath))
{
throw new FileNotFoundException("E2E seed script not found.", seedPath);
}
var script = await File.ReadAllTextAsync(seedPath, cancellationToken);
var builder = new MySqlConnectionStringBuilder(connectionString)
{
AllowUserVariables = true
};
await using var conn = new MySqlConnection(builder.ConnectionString);
await conn.OpenAsync(cancellationToken);
foreach (var statement in SplitSqlStatements(script))
{
await using var cmd = new MySqlCommand(statement, conn);
await cmd.ExecuteNonQueryAsync(cancellationToken);
}
}
private static IEnumerable<string> SplitSqlStatements(string script)
{
return script
.Split(';', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
.Select(x => x.Trim())
.Where(x => x.Length > 0 && !x.StartsWith("--", StringComparison.Ordinal));
// 仓储库不再维护 E2E 种子脚本;依赖目标库既有测试数据。
_ = connectionString;
_ = cancellationToken;
return Task.CompletedTask;
}
public static async Task<string?> GetOrderStatusByServiceNoAsync(