package allocate import ( "context" "sort" "strings" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/errors/gerror" "git.5iot.com/iotlcm-public/iotlcm-worker-svr/internal/consts" "git.5iot.com/iotlcm-public/iotlcm-worker-svr/internal/dao" "git.5iot.com/iotlcm-public/iotlcm-worker-svr/internal/model/entity" ) func (r *Repository) loadParentTaskTx(ctx context.Context, tx gdb.TX, parent *entity.BatchMain) (*Task, error) { var batchDetails []*entity.BatchDetail if err := tx.Ctx(ctx).Model(dao.BatchDetail.Table()). Where("batch_no IN (SELECT batch_no FROM batch_main WHERE source_batch_no = ? AND batch_type = ? AND tenant_id = ?)", parent.BatchNo, consts.BatchTypeAllocate, parent.TenantId). Where(dao.BatchDetail.Columns().BatchType, consts.BatchTypeAllocate). OrderAsc(dao.BatchDetail.Columns().RowNo). OrderAsc(dao.BatchDetail.Columns().BatchNo). OrderAsc(dao.BatchDetail.Columns().Id). Scan(&batchDetails); err != nil { return nil, gerror.Wrap(err, "load allocate parent details failed") } if len(batchDetails) == 0 { return nil, gerror.New("allocate parent has no child details") } task := &Task{ Batch: Batch{ ID: parent.Id, BatchNo: parent.BatchNo, BatchType: consts.BatchTypeAllocate, TenantID: parent.TenantId, TargetDeptID: targetDeptIDFromBatch(parent), CreatedDept: parent.CreatedDept, CreatedBy: parent.CreatedBy, StartTime: parent.StartTime, BatchInfo: parent.BatchInfo, }, Details: make([]*Detail, 0, len(batchDetails)), TargetsByID: make(map[int64]*Target), TargetsByKey: make(map[string]*Target), TargetsByName: make(map[string][]*Target), } cardIDs := make([]int64, 0, len(batchDetails)) targetIDs := make([]int64, 0, len(batchDetails)) cardIDByDetailID := make(map[int64]int64, len(batchDetails)) for _, batchDetail := range batchDetails { if batchDetail == nil { continue } detail := &Detail{OriginalSnapshot: batchDetail.Snapshot, ID: batchDetail.Id, BatchNo: batchDetail.BatchNo, RowNo: batchDetail.RowNo, DetailStatus: batchDetail.DetailStatus, ICCID: strings.TrimSpace(batchDetail.ItemId), Reason: strings.TrimSpace(batchDetail.ErrorReason)} if detail.DetailStatus != consts.BatchDetailStatusSuccess && detail.DetailStatus != consts.BatchDetailStatusRunning && detail.Reason == "" { detail.Reason = "子批次明细尚未全部验证成功" } if snapshot := batchDetail.Snapshot; snapshot != nil { detail.Remark = firstSnapshot(snapshot, "remark") detail.MSISDN = firstSnapshot(snapshot, "MSISDN", "msisdn") detail.IMSI = firstSnapshot(snapshot, "IMSI", "imsi") detail.TargetDeptID = snapshot.Get("targetDeptId").Int64() detail.TargetDeptKey = firstSnapshot(snapshot, "targetDeptKey", "target_dept_key") detail.TargetDeptName = firstSnapshot(snapshot, "targetDeptName", "target_dept_name") if cardID := snapshot.Get("cardId").Int64(); cardID > 0 { cardIDs = append(cardIDs, cardID) cardIDByDetailID[batchDetail.Id] = cardID } else if detail.Reason == "" { detail.Reason = "卡片快照缺少有效卡片ID" } } if detail.TargetDeptID > 0 { targetIDs = append(targetIDs, detail.TargetDeptID) } task.Details = append(task.Details, detail) } cardsByID := make(map[int64]*entity.TSimCardInfo, len(cardIDs)) cardIDs = uniqueInt64s(cardIDs) sort.Slice(cardIDs, func(i, j int) bool { return cardIDs[i] < cardIDs[j] }) for start := 0; start < len(cardIDs); start += allocateCardQueryBatchSize { end := min(start+allocateCardQueryBatchSize, len(cardIDs)) var cards []*entity.TSimCardInfo if err := tx.Ctx(ctx).Model(dao.TSimCardInfo.Table()).Safe(). Where(dao.TSimCardInfo.Columns().TenantId, parent.TenantId). WhereIn(dao.TSimCardInfo.Columns().Id, cardIDs[start:end]). LockUpdate().Scan(&cards); err != nil { return nil, gerror.Wrap(err, "lock allocate parent cards failed") } for _, card := range cards { if card != nil { cardsByID[card.Id] = card } } } targetsByID := make(map[int64]*Target, len(targetIDs)) targetIDs = uniqueInt64s(targetIDs) sort.Slice(targetIDs, func(i, j int) bool { return targetIDs[i] < targetIDs[j] }) for start := 0; start < len(targetIDs); start += allocateCardQueryBatchSize { end := min(start+allocateCardQueryBatchSize, len(targetIDs)) var depts []*entity.SysDept if err := tx.Ctx(ctx).Model(dao.SysDept.Table()). Where(dao.SysDept.Columns().TenantId, parent.TenantId). Where(dao.SysDept.Columns().ParentId, parent.CreatedDept). Where(dao.SysDept.Columns().Status, "0"). WhereNull(dao.SysDept.Columns().DeletedAt). WhereIn(dao.SysDept.Columns().DeptId, targetIDs[start:end]). LockUpdate().Scan(&depts); err != nil { return nil, gerror.Wrap(err, "lock allocate parent targets failed") } for _, dept := range depts { if dept == nil { continue } target := &Target{DeptID: dept.DeptId, ParentID: dept.ParentId, DeptKey: strings.TrimSpace(dept.DeptKey), DeptName: strings.TrimSpace(dept.DeptName)} targetsByID[target.DeptID] = target task.TargetsByID[target.DeptID] = target if target.DeptKey != "" { task.TargetsByKey[target.DeptKey] = target } if target.DeptName != "" { task.TargetsByName[target.DeptName] = append(task.TargetsByName[target.DeptName], target) } } } for _, detail := range task.Details { if detail == nil { continue } if detail.Target == nil { detail.Target = targetsByID[detail.TargetDeptID] } cardID := cardIDByDetailID[detail.ID] if card := cardsByID[cardID]; card != nil { detail.Card = &Card{ID: card.Id, ICCID: strings.TrimSpace(card.Iccid), MSISDN: strings.TrimSpace(card.Msisdn), IMSI: strings.TrimSpace(card.Imsi), DeptID: card.DeptId, AllocationBatchNo: strings.TrimSpace(card.AllocationBatchNo), PackageStatus: card.PackageStatus, BossCardStatus: card.BossCardStatus, FlowPkgEndAt: card.FlowPkgEndAt} } } return task, nil } func uniqueInt64s(values []int64) []int64 { seen := make(map[int64]struct{}, len(values)) unique := make([]int64, 0, len(values)) for _, value := range values { if _, exists := seen[value]; exists { continue } seen[value] = struct{}{} unique = append(unique, value) } return unique }