feat: 实现物联网卡独立管理和批量导入功能
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 4m42s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 4m42s
新增物联网卡独立管理模块,支持单卡查询、批量导入和状态管理。主要变更包括: 功能特性: - 新增物联网卡 CRUD 接口(查询、分页列表、删除) - 支持 CSV/Excel 批量导入物联网卡 - 实现异步导入任务处理和进度跟踪 - 新增 ICCID 号码格式校验器(支持 Luhn 算法) - 新增 CSV 文件解析工具(支持编码检测和错误处理) 数据库变更: - 移除 iot_card 和 device 表的 owner_id/owner_type 字段 - 新增 iot_card_import_task 导入任务表 - 为导入任务添加运营商类型字段 测试覆盖: - 新增 IoT 卡 Store 层单元测试 - 新增 IoT 卡导入任务单元测试 - 新增 IoT 卡集成测试(包含导入流程测试) - 新增 CSV 工具和 ICCID 校验器测试 文档更新: - 更新 OpenAPI 文档(新增 7 个 IoT 卡接口) - 归档 OpenSpec 变更提案 - 更新 API 文档规范和生成器指南 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
-- 回滚:恢复 tb_iot_card 和 tb_device 表中的 owner_type 和 owner_id 字段
|
||||
|
||||
-- 恢复 tb_iot_card.iccid 字段长度
|
||||
ALTER TABLE tb_iot_card ALTER COLUMN iccid TYPE varchar(50);
|
||||
COMMENT ON COLUMN tb_iot_card.iccid IS 'ICCID(唯一标识)';
|
||||
|
||||
-- 恢复 tb_iot_card 的 owner_type 和 owner_id 列
|
||||
ALTER TABLE tb_iot_card ADD COLUMN IF NOT EXISTS owner_type varchar(20) NOT NULL DEFAULT 'platform';
|
||||
ALTER TABLE tb_iot_card ADD COLUMN IF NOT EXISTS owner_id bigint NOT NULL DEFAULT 0;
|
||||
COMMENT ON COLUMN tb_iot_card.owner_type IS '所有者类型 platform-平台 shop-店铺';
|
||||
COMMENT ON COLUMN tb_iot_card.owner_id IS '所有者ID';
|
||||
CREATE INDEX IF NOT EXISTS idx_iot_card_owner_id ON tb_iot_card(owner_id);
|
||||
|
||||
-- 恢复 tb_device 的 owner_type 和 owner_id 列
|
||||
ALTER TABLE tb_device ADD COLUMN IF NOT EXISTS owner_type varchar(20) NOT NULL DEFAULT 'platform';
|
||||
ALTER TABLE tb_device ADD COLUMN IF NOT EXISTS owner_id bigint NOT NULL DEFAULT 0;
|
||||
COMMENT ON COLUMN tb_device.owner_type IS '所有者类型 platform-平台 shop-店铺';
|
||||
COMMENT ON COLUMN tb_device.owner_id IS '所有者ID';
|
||||
CREATE INDEX IF NOT EXISTS idx_device_owner_id ON tb_device(owner_id);
|
||||
|
||||
-- 恢复 shop_id 字段的注释
|
||||
COMMENT ON COLUMN tb_iot_card.shop_id IS '店铺ID(冗余字段,方便查询)';
|
||||
COMMENT ON COLUMN tb_device.shop_id IS '店铺ID(冗余字段,方便查询)';
|
||||
@@ -0,0 +1,20 @@
|
||||
-- 移除 tb_iot_card 和 tb_device 表中的 owner_type 和 owner_id 字段
|
||||
-- 原因:所有权模型重构,改用 shop_id 字段表示所有权(NULL=平台所有,有值=店铺所有)
|
||||
|
||||
-- 删除 tb_iot_card 的 owner_type 和 owner_id 列
|
||||
ALTER TABLE tb_iot_card DROP COLUMN IF EXISTS owner_type;
|
||||
ALTER TABLE tb_iot_card DROP COLUMN IF EXISTS owner_id;
|
||||
|
||||
-- 删除 tb_device 的 owner_type 和 owner_id 列
|
||||
ALTER TABLE tb_device DROP COLUMN IF EXISTS owner_type;
|
||||
ALTER TABLE tb_device DROP COLUMN IF EXISTS owner_id;
|
||||
|
||||
-- 更新 tb_iot_card 的 shop_id 字段注释
|
||||
COMMENT ON COLUMN tb_iot_card.shop_id IS '店铺ID(NULL=平台所有,有值=店铺所有)';
|
||||
|
||||
-- 更新 tb_device 的 shop_id 字段注释
|
||||
COMMENT ON COLUMN tb_device.shop_id IS '店铺ID(NULL=平台库存,有值=店铺所有)';
|
||||
|
||||
-- 修改 tb_iot_card.iccid 字段长度从 varchar(50) 改为 varchar(20)
|
||||
ALTER TABLE tb_iot_card ALTER COLUMN iccid TYPE varchar(20);
|
||||
COMMENT ON COLUMN tb_iot_card.iccid IS 'ICCID(唯一标识,电信19位/其他20位,支持字母数字混合)';
|
||||
@@ -0,0 +1 @@
|
||||
DROP TABLE IF EXISTS tb_iot_card_import_task;
|
||||
48
migrations/000012_create_iot_card_import_task_table.up.sql
Normal file
48
migrations/000012_create_iot_card_import_task_table.up.sql
Normal file
@@ -0,0 +1,48 @@
|
||||
CREATE TABLE IF NOT EXISTS tb_iot_card_import_task (
|
||||
id BIGSERIAL PRIMARY KEY,
|
||||
task_no VARCHAR(50) NOT NULL,
|
||||
status INT NOT NULL DEFAULT 1,
|
||||
carrier_id BIGINT NOT NULL,
|
||||
batch_no VARCHAR(100),
|
||||
file_name VARCHAR(255),
|
||||
total_count INT NOT NULL DEFAULT 0,
|
||||
success_count INT NOT NULL DEFAULT 0,
|
||||
skip_count INT NOT NULL DEFAULT 0,
|
||||
fail_count INT NOT NULL DEFAULT 0,
|
||||
skipped_items JSONB DEFAULT '[]',
|
||||
failed_items JSONB DEFAULT '[]',
|
||||
started_at TIMESTAMP,
|
||||
completed_at TIMESTAMP,
|
||||
error_message TEXT,
|
||||
shop_id BIGINT,
|
||||
created_at TIMESTAMP DEFAULT NOW(),
|
||||
updated_at TIMESTAMP DEFAULT NOW(),
|
||||
deleted_at TIMESTAMP,
|
||||
creator BIGINT NOT NULL DEFAULT 0,
|
||||
updater BIGINT NOT NULL DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX idx_import_task_no ON tb_iot_card_import_task(task_no) WHERE deleted_at IS NULL;
|
||||
CREATE INDEX idx_import_task_carrier_id ON tb_iot_card_import_task(carrier_id);
|
||||
CREATE INDEX idx_import_task_shop_id ON tb_iot_card_import_task(shop_id);
|
||||
CREATE INDEX idx_import_task_status ON tb_iot_card_import_task(status);
|
||||
CREATE INDEX idx_import_task_created_at ON tb_iot_card_import_task(created_at);
|
||||
|
||||
COMMENT ON TABLE tb_iot_card_import_task IS 'IoT 卡导入任务表';
|
||||
COMMENT ON COLUMN tb_iot_card_import_task.task_no IS '任务编号(IMP-YYYYMMDD-XXXXXX)';
|
||||
COMMENT ON COLUMN tb_iot_card_import_task.status IS '任务状态 1-待处理 2-处理中 3-已完成 4-失败';
|
||||
COMMENT ON COLUMN tb_iot_card_import_task.carrier_id IS '运营商ID';
|
||||
COMMENT ON COLUMN tb_iot_card_import_task.batch_no IS '批次号';
|
||||
COMMENT ON COLUMN tb_iot_card_import_task.file_name IS '原始文件名';
|
||||
COMMENT ON COLUMN tb_iot_card_import_task.total_count IS '总数';
|
||||
COMMENT ON COLUMN tb_iot_card_import_task.success_count IS '成功数';
|
||||
COMMENT ON COLUMN tb_iot_card_import_task.skip_count IS '跳过数';
|
||||
COMMENT ON COLUMN tb_iot_card_import_task.fail_count IS '失败数';
|
||||
COMMENT ON COLUMN tb_iot_card_import_task.skipped_items IS '跳过记录详情';
|
||||
COMMENT ON COLUMN tb_iot_card_import_task.failed_items IS '失败记录详情';
|
||||
COMMENT ON COLUMN tb_iot_card_import_task.started_at IS '开始处理时间';
|
||||
COMMENT ON COLUMN tb_iot_card_import_task.completed_at IS '完成时间';
|
||||
COMMENT ON COLUMN tb_iot_card_import_task.error_message IS '任务级错误信息';
|
||||
COMMENT ON COLUMN tb_iot_card_import_task.shop_id IS '店铺ID(发起导入的店铺)';
|
||||
COMMENT ON COLUMN tb_iot_card_import_task.creator IS '创建人ID';
|
||||
COMMENT ON COLUMN tb_iot_card_import_task.updater IS '更新人ID';
|
||||
@@ -0,0 +1,2 @@
|
||||
ALTER TABLE tb_iot_card_import_task DROP COLUMN IF EXISTS carrier_type;
|
||||
ALTER TABLE tb_iot_card_import_task DROP COLUMN IF EXISTS iccid_list;
|
||||
5
migrations/000013_add_carrier_type_to_import_task.up.sql
Normal file
5
migrations/000013_add_carrier_type_to_import_task.up.sql
Normal file
@@ -0,0 +1,5 @@
|
||||
ALTER TABLE tb_iot_card_import_task ADD COLUMN IF NOT EXISTS carrier_type VARCHAR(20) NOT NULL DEFAULT 'CMCC';
|
||||
ALTER TABLE tb_iot_card_import_task ADD COLUMN IF NOT EXISTS iccid_list JSONB DEFAULT '[]';
|
||||
|
||||
COMMENT ON COLUMN tb_iot_card_import_task.carrier_type IS '运营商类型(CMCC/CUCC/CTCC/CBN)';
|
||||
COMMENT ON COLUMN tb_iot_card_import_task.iccid_list IS '待导入ICCID列表';
|
||||
Reference in New Issue
Block a user