feat: 资产标识符标准化、资产历史订单查询及导入虚拟号强制验证
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m21s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 7m21s
主要变更: - 新增 AssetIdentifier 模型及 Store,统一管理资产标识符(ICCID/IMEI/SN 等) - 新增迁移:asset_identifier 表、order 表新增 asset_identifier 字段、iot_card.virtual_no NOT NULL 约束 - 资产 Handler/Service/Route 全面重构,支持标识符路由查询与解析 - 新增资产历史订单查询接口,支持跨设备/卡/钱包维度的订单聚合 - 设备与物联卡导入任务强制校验虚拟号,缺失时直接拒绝 - Excel 工具函数优化,前端导入指引文档同步更新 - 归档三个 OpenSpec 提案:asset-identifier-standardization、asset-historical-orders、import-mandatory-virtual-no - 更新 OpenAPI 文档及相关 DTO Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
2
migrations/000105_create_asset_identifier.down.sql
Normal file
2
migrations/000105_create_asset_identifier.down.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
DROP INDEX IF EXISTS idx_asset_identifier_asset;
|
||||
DROP TABLE IF EXISTS tb_asset_identifier;
|
||||
14
migrations/000105_create_asset_identifier.up.sql
Normal file
14
migrations/000105_create_asset_identifier.up.sql
Normal file
@@ -0,0 +1,14 @@
|
||||
-- 创建全局资产标识符注册表,保证 ICCID/VirtualNo 跨 tb_iot_card 和 tb_device 全局唯一
|
||||
CREATE TABLE IF NOT EXISTS tb_asset_identifier (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
identifier VARCHAR(100) NOT NULL,
|
||||
asset_type VARCHAR(20) NOT NULL,
|
||||
asset_id BIGINT NOT NULL,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
CONSTRAINT uq_asset_identifier UNIQUE (identifier)
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_asset_identifier_asset ON tb_asset_identifier(asset_type, asset_id);
|
||||
COMMENT ON TABLE tb_asset_identifier IS '全局资产标识符注册表';
|
||||
COMMENT ON COLUMN tb_asset_identifier.identifier IS '标识符值(ICCID 或 VirtualNo,全局唯一)';
|
||||
COMMENT ON COLUMN tb_asset_identifier.asset_type IS '资产类型:iot_card 或 device';
|
||||
COMMENT ON COLUMN tb_asset_identifier.asset_id IS '对应资产的主键 ID';
|
||||
1
migrations/000106_add_asset_identifier_to_order.down.sql
Normal file
1
migrations/000106_add_asset_identifier_to_order.down.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE tb_order DROP COLUMN IF EXISTS asset_identifier;
|
||||
2
migrations/000106_add_asset_identifier_to_order.up.sql
Normal file
2
migrations/000106_add_asset_identifier_to_order.up.sql
Normal file
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE tb_order ADD COLUMN IF NOT EXISTS asset_identifier VARCHAR(100);
|
||||
COMMENT ON COLUMN tb_order.asset_identifier IS '下单时资产的标识符快照(ICCID 或 VirtualNo)';
|
||||
11
migrations/000107_iot_card_virtual_no_not_null.down.sql
Normal file
11
migrations/000107_iot_card_virtual_no_not_null.down.sql
Normal file
@@ -0,0 +1,11 @@
|
||||
-- 回滚:将 tb_iot_card.virtual_no 恢复为 nullable,并还原条件唯一索引
|
||||
|
||||
-- 删除新的无条件唯一索引
|
||||
DROP INDEX IF EXISTS idx_iot_card_virtual_no;
|
||||
|
||||
-- 将 virtual_no 列改回允许 NULL
|
||||
ALTER TABLE tb_iot_card ALTER COLUMN virtual_no DROP NOT NULL;
|
||||
|
||||
-- 恢复旧的条件唯一索引(允许多条 NULL 值共存)
|
||||
CREATE UNIQUE INDEX idx_iot_card_virtual_no ON tb_iot_card(virtual_no)
|
||||
WHERE deleted_at IS NULL AND virtual_no IS NOT NULL AND virtual_no <> '';
|
||||
15
migrations/000107_iot_card_virtual_no_not_null.up.sql
Normal file
15
migrations/000107_iot_card_virtual_no_not_null.up.sql
Normal file
@@ -0,0 +1,15 @@
|
||||
-- 将 tb_iot_card.virtual_no 改为 NOT NULL,并重建唯一索引
|
||||
-- 背景:虚拟号是资产核心业务标识符,不允许为空
|
||||
-- 步骤:1. 清理空值记录(测试环境),2. 加约束,3. 重建索引
|
||||
|
||||
-- 清理空值记录(适用于测试环境)
|
||||
DELETE FROM tb_iot_card WHERE virtual_no IS NULL OR virtual_no = '';
|
||||
|
||||
-- 将 virtual_no 列改为 NOT NULL
|
||||
ALTER TABLE tb_iot_card ALTER COLUMN virtual_no SET NOT NULL;
|
||||
|
||||
-- 删除旧的条件唯一索引(含 IS NOT NULL AND <> '' 条件)
|
||||
DROP INDEX IF EXISTS idx_iot_card_virtual_no;
|
||||
|
||||
-- 重建无条件唯一索引(仅排除软删除记录)
|
||||
CREATE UNIQUE INDEX idx_iot_card_virtual_no ON tb_iot_card(virtual_no) WHERE deleted_at IS NULL;
|
||||
Reference in New Issue
Block a user