Files
junhong_cmp_fiber/docs/7月迭代/需求08-设备批量分配Excel.md
2026-07-13 12:01:18 +09:00

5.0 KiB
Raw Blame History

需求08设备批量分配代理和套餐系列Excel导入


背景

设备号不连续,无法通过号段批量分配。需要通过上传 Excel 表(表头:设备号)来批量指定分配目标。

Device 表已有 shop_id *uintseries_id *uint 字段,分配即更新这两个字段。


数据库变更

新建批量分配任务表(不复用 DeviceImportTask,业务语义不同):

CREATE TABLE tb_device_batch_allocation_task (
    id            BIGSERIAL PRIMARY KEY,
    created_at    TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at    TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    deleted_at    TIMESTAMPTZ,
    creator       BIGINT NOT NULL DEFAULT 0,
    updater       BIGINT NOT NULL DEFAULT 0,
    task_no       VARCHAR(30) NOT NULL,
    shop_id       BIGINT NOT NULL,
    series_id     BIGINT,
    operator_id   BIGINT NOT NULL,
    total_count   INT NOT NULL DEFAULT 0,
    success_count INT NOT NULL DEFAULT 0,
    fail_count    INT NOT NULL DEFAULT 0,
    status        INT NOT NULL DEFAULT 1,
    failed_items  JSONB,
    started_at    TIMESTAMPTZ,
    completed_at  TIMESTAMPTZ
);

CREATE UNIQUE INDEX idx_device_batch_allocation_task_no ON tb_device_batch_allocation_task(task_no) WHERE deleted_at IS NULL;

状态常量1=处理中2=已完成3=失败。

失败明细存 JSONBfailed_items),失败条数有限,无需单独明细表。


Modelinternal/model/device_batch_allocation_task.go

// DeviceBatchAllocationTask 设备批量分配任务模型
type DeviceBatchAllocationTask struct {
    gorm.Model
    BaseModel    `gorm:"embedded"`
    TaskNo       string            `gorm:"column:task_no;type:varchar(30);uniqueIndex:idx_device_batch_allocation_task_no,where:deleted_at IS NULL;not null" json:"task_no"`
    ShopID       uint              `gorm:"column:shop_id;not null;comment:分配目标代理店铺ID" json:"shop_id"`
    SeriesID     *uint             `gorm:"column:series_id;comment:套餐系列ID可选" json:"series_id,omitempty"`
    OperatorID   uint              `gorm:"column:operator_id;not null;comment:操作人ID" json:"operator_id"`
    TotalCount   int               `gorm:"column:total_count;default:0;comment:总记录数" json:"total_count"`
    SuccessCount int               `gorm:"column:success_count;default:0;comment:成功数" json:"success_count"`
    FailCount    int               `gorm:"column:fail_count;default:0;comment:失败数" json:"fail_count"`
    Status       int               `gorm:"column:status;type:int;default:1;not null;comment:状态 1=处理中 2=已完成 3=失败" json:"status"`
    FailedItems  ImportResultItems `gorm:"column:failed_items;type:jsonb;comment:失败记录详情" json:"failed_items"`
    StartedAt    *time.Time        `gorm:"column:started_at" json:"started_at"`
    CompletedAt  *time.Time        `gorm:"column:completed_at" json:"completed_at"`
}

func (DeviceBatchAllocationTask) TableName() string {
    return "tb_device_batch_allocation_task"
}

ImportResultItems 复用 internal/model/device_import_task.go 中已定义的类型。


API 设计

1. 下载 Excel 模板

GET /admin/devices/batch-allocation/template

响应Excel 文件,表头为"设备号"(一列)。

2. 上传并提交

POST /admin/devices/batch-allocation
Content-Type: multipart/form-data

字段:
  shop_id:  123   (必填,分配给哪个代理)
  series_id: 45   (可选,同时分配套餐系列)
  file: <Excel文件>

处理逻辑Asynq 异步)

  1. 解析 Excel读取"设备号"列
  2. 逐行查找 tb_device 中匹配的设备(按 virtual_noimei
  3. 对找到的设备:更新 shop_id + series_id
  4. 未找到的:记录失败原因"设备号不存在"
  5. 已分配给其他代理的:记录"该设备已分配,请先回收"

3. 查询任务状态

GET /admin/devices/batch-allocation/{task_id}

响应:

{
  "task_no": "DBA20240101001",
  "status": 2,
  "status_name": "已完成",
  "total_count": 100,
  "success_count": 95,
  "fail_count": 5,
  "failed_items": [
    { "line": 3, "virtual_no": "12345", "reason": "设备号不存在" },
    { "line": 7, "virtual_no": "67890", "reason": "该设备已分配,请先回收" }
  ],
  "started_at": "2024-01-01T10:00:00Z",
  "completed_at": "2024-01-01T10:00:05Z"
}

前端对接

入口

设备管理页 > 批量操作 > "批量分配代理"

操作流程

  1. 点击"批量分配代理"
  2. 弹框内:
    • 代理选择器(搜索+选择目标代理,必填)
    • 套餐系列选择器(可选)
    • Excel 上传区域(含模板下载链接)
  3. 上传后点击"提交" → POST /admin/devices/batch-allocation
  4. 提示"任务提交成功,正在处理..."
  5. 轮询 GET /admin/devices/batch-allocation/{task_id} 直到 status != 1
  6. 展示结果成功X条失败X条失败明细在页面展示

Excel 规范

  • 表头:设备号
  • 每行一个设备号支持虚拟号或IMEI