package app import ( "context" "fmt" "strings" "git.5iot.com/iotlcm-public/iotlcm-app/internal/consts" "git.5iot.com/iotlcm-public/iotlcm-app/internal/model" "git.5iot.com/iotlcm-public/iotlcm-app/internal/model/entity" "github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/util/gconv" ) func (s *sAppCard) cardRowToModel(ctx context.Context, row *appCardQueryRow, user *entity.SysUser, ownerType string, canBusiness bool) *model.AppCardModel { if row == nil { return nil } canBusiness = canBusiness && s.canOperateCard(ctx, user, row) remain := row.PackageTotalFlowMb - row.UsedFlowMb if remain < 0 { remain = 0 } usedPercent := float64(0) if row.PackageTotalFlowMb > 0 { usedPercent = row.UsedFlowMb / row.PackageTotalFlowMb * 100 } isBound := false if user != nil && s.isTerminalUser(ctx, user) && ownerType == appCardOwnerTerminal { isBound = true } else if user != nil { isBound = s.isCardBoundToUser(ctx, row.Iccid, user) } currentPackageCode := appCardCurrentPackageCode(row) packageName := appCardPackageName(row) packageType := appCardPackageType(row) categoryCode := appCardCategoryCode(row) categoryName := appCardCategoryName(row) abnormalReasons := appCardAbnormalReasons(row.BossCardStatus, row.PackageStatus) deptName := "" deptKey := "" deptId := int64(0) tenantId := "" chanName := "" chanAlias := "" if ownerType == appCardOwnerAgent { actualDeptId := appCardOwnerDeptId(row) if user != nil && !s.isTerminalUser(ctx, user) && user.DeptId > 0 && actualDeptId > 0 { if displayDept, err := appEnterpriseDisplayDept(ctx, row.TenantId, user.DeptId, actualDeptId); err == nil && displayDept != nil && displayDept.DeptId > 0 { deptId = displayDept.DeptId deptName = strings.TrimSpace(displayDept.DeptName) deptKey = strings.TrimSpace(displayDept.DeptKey) } } else { deptId = actualDeptId deptName = appCardOwnerDeptName(row) deptKey = appCardOwnerDeptKey(row) } tenantId = row.TenantId chanName = row.ChanName chanAlias = row.ChanAlias } return &model.AppCardModel{ Id: row.Id, Iccid: row.Iccid, Msisdn: row.Msisdn, Imsi: row.Imsi, Imei: row.Imei, RegionCode: row.RegionCode, DeptId: deptId, DeptName: deptName, DeptKey: deptKey, CurrentPackageCode: currentPackageCode, PackageName: packageName, PackageType: packageType, CategoryCode: categoryCode, CategoryName: categoryName, PackageStatus: row.PackageStatus, AccessType: row.AccessType, BossCardStatus: row.BossCardStatus, AbnormalReason: strings.Join(abnormalReasons, "、"), AbnormalReasons: abnormalReasons, CardType: row.CardType, NetModel: row.NetModel, PackageTotalFlowMb: row.PackageTotalFlowMb, UsedFlowMb: row.UsedFlowMb, RemainFlowMb: remain, UsedFlowPercent: usedPercent, FlowPkgBeginAt: row.FlowPkgBeginAt, FlowPkgEndAt: row.FlowPkgEndAt, DataServiceStatus: row.DataServiceStatus, PackageTotalSms: row.PackageTotalSms, UsedSms: row.UsedSms, SmsServiceStatus: row.SmsServiceStatus, PackageTotalVoice: row.PackageTotalVoice, UsedVoice: row.UsedVoice, VoiceServiceStatus: row.VoiceServiceStatus, RoamServiceStatus: row.RoamServiceStatus, StatusSyncTime: row.StatusSyncTime, FlowSyncTime: row.FlowSyncTime, ChanKey: "", ChanName: chanName, ChanAlias: chanAlias, Remark: row.Remark, TenantId: tenantId, TerminalName: row.TerminalName, IsBound: isBound, CanBusiness: canBusiness, CanAllocate: s.canAllocateCard(ctx, user, row, ownerType, canBusiness), OwnerType: ownerType, DataSource: "local", } } func (s *sAppCard) canAllocateCard(ctx context.Context, user *entity.SysUser, row *appCardQueryRow, ownerType string, canBusiness bool) bool { return user != nil && row != nil && ownerType == appCardOwnerAgent && !s.isTerminalUser(ctx, user) && canBusiness && user.DeptId > 0 && row.DeptId == user.DeptId } func (s *sAppCard) publicCardRowToModel(ctx context.Context, row *appCardQueryRow, cardValue string) *model.AppCardModel { card := s.cardRowToModel(ctx, row, nil, appCardOwnerPublic, false) if card == nil { return nil } card.Id = 0 card.DeptId = 0 card.DeptName = "" card.DeptKey = "" card.ChanKey = "" card.ChanName = "" card.ChanAlias = "" card.Remark = "" card.TenantId = "" card.TerminalName = "" card.IsBound = false card.CanBusiness = false card.CanAllocate = false card.OwnerType = appCardOwnerPublic return card } func (s *sAppCard) upstreamPublicCardToModel(info *appSimBasicInfoOutput, cardValue string) *model.AppCardModel { if info == nil { return nil } cardStatus := info.CardStatus if cardStatus == 0 { cardStatus = consts.V3ApiSimBossCardStatusActivated } packageCode, packageName := appOneLinkMockPackageFromRemark(info.Remark) abnormalReasons := appCardAbnormalReasons(cardStatus, 0) return &model.AppCardModel{ Iccid: appFirstNotEmpty(info.Iccid, strings.TrimSpace(cardValue)), Msisdn: info.Msisdn, Imsi: info.Imsi, Imei: info.Imei, CurrentPackageCode: packageCode, PackageName: packageName, BossCardStatus: cardStatus, AbnormalReason: strings.Join(abnormalReasons, "、"), AbnormalReasons: abnormalReasons, StatusSyncTime: appParseOneLinkTime(info.LastChangeDate), FlowPkgBeginAt: appParseOneLinkTime(info.ActiveDate), OwnerType: appCardOwnerPublic, DataSource: info.Provider, UpstreamProvider: info.Provider, IsBound: false, CanBusiness: false, CanAllocate: false, } } func (s *sAppCard) packageRowToModel(row *appPackageQueryRow, ownerType string, canBusiness bool) *model.AppPackageModel { if row == nil { return nil } status, statusType := appPackageStatus(row.EffectiveStatus, row.ExpectedExpireTime) return &model.AppPackageModel{ Id: row.Id, SubscriptionNo: row.SubscriptionNo, PackageCode: row.PackageCode, PackageName: row.PackageName, PackageType: row.PackageType, PackageTypeName: appPackageTypeName(row.PackageType), CategoryCode: row.CategoryCode, CategoryName: row.CategoryName, Iccid: row.Iccid, Msisdn: row.Msisdn, CardId: row.CardId, CardValue: appFirstNotEmpty(row.Msisdn, row.Iccid), CardRemark: row.CardRemark, TerminalName: row.TerminalName, BusinessType: row.BusinessType, BusinessTypeName: appBusinessTypeName(row.BusinessType), EffectiveStatus: row.EffectiveStatus, Status: status, StatusType: statusType, FilterValue: row.PackageCode, EffectiveTime: row.EffectiveTime, ExpireTime: row.ExpectedExpireTime, ValidText: appPackageValidText(row.EffectiveTime, row.ExpectedExpireTime), EffectText: appPackageEffectText(row.EffectiveStatus), FlowMb: row.FlowMb, FlowText: appFlowText(row.FlowMb), OwnerType: ownerType, CanBusiness: canBusiness, } } func (s *sAppCard) publicPackageRowToModel(card *appCardQueryRow, pkg *appPublicPackageQueryRow) *model.AppPackageModel { if card == nil || pkg == nil { return nil } effectiveStatus := appEffectiveStatusFromCardPackageStatus(card.PackageStatus) status, statusType := appPackageStatus(effectiveStatus, card.FlowPkgEndAt) flowMb := pkg.FlowMb if flowMb <= 0 { flowMb = card.PackageTotalFlowMb } return &model.AppPackageModel{ Id: pkg.Id, PackageCode: pkg.PackageCode, PackageName: pkg.PackageName, PackageType: pkg.PackageType, PackageTypeName: appPackageTypeName(pkg.PackageType), CategoryCode: pkg.CategoryCode, CategoryName: pkg.CategoryName, Iccid: card.Iccid, Msisdn: card.Msisdn, CardId: card.Id, CardValue: appFirstNotEmpty(card.Msisdn, card.Iccid), CardRemark: card.Remark, TerminalName: card.TerminalName, BusinessTypeName: "当前套餐", EffectiveStatus: effectiveStatus, Status: status, StatusType: statusType, FilterValue: pkg.PackageCode, EffectiveTime: card.FlowPkgBeginAt, ExpireTime: card.FlowPkgEndAt, ValidText: appPackageValidText(card.FlowPkgBeginAt, card.FlowPkgEndAt), EffectText: appPackageEffectText(effectiveStatus), FlowMb: flowMb, FlowText: appFlowText(flowMb), OwnerType: appCardOwnerPublic, CanBusiness: false, } } func appSanitizePublicPackageModel(pkg *model.AppPackageModel, cardValue string) *model.AppPackageModel { if pkg == nil { return nil } pkg.Id = 0 pkg.SubscriptionNo = "" pkg.CardId = 0 pkg.CardValue = appFirstNotEmpty(pkg.Msisdn, pkg.Iccid, strings.TrimSpace(cardValue)) pkg.CardRemark = "" pkg.TerminalName = "" pkg.BusinessType = 0 pkg.BusinessTypeName = "当前套餐" pkg.OwnerType = appCardOwnerPublic pkg.CanBusiness = false return pkg } func appPackageStatus(status int, expireAt *gtime.Time) (string, string) { if expireAt != nil && !expireAt.IsZero() && expireAt.Before(gtime.Now()) { return "已过期", "danger" } if status == 1 && expireAt != nil && !expireAt.IsZero() && expireAt.Before(gtime.Now().AddDate(0, 0, 30)) { return "即将到期", "warning" } switch status { case 0: return "待生效", "primary" case 1: return "生效中", "success" case 2: return "已过期", "danger" case 3: return "已终止", "danger" case 4: return "已作废", "danger" default: return "未知", "primary" } } func appCardAbnormalReasons(bossCardStatus int, packageStatus int) []string { reasons := make([]string, 0, 2) if packageStatus == consts.PackageStatusExpired { reasons = append(reasons, "套餐已过期") } switch bossCardStatus { case 0: reasons = append(reasons, "卡状态未知") case consts.V3ApiSimBossCardStatusStopped: reasons = append(reasons, "卡状态停机") case 8: reasons = append(reasons, "卡状态预销户") case 9: reasons = append(reasons, "卡状态已销户") case consts.V3ApiSimBossCardStatusPendingActivate, consts.V3ApiSimBossCardStatusActivated, 6, 7: default: reasons = append(reasons, fmt.Sprintf("未知卡状态:%d", bossCardStatus)) } return reasons } func appEffectiveStatusFromCardPackageStatus(status int) int { switch status { case 1: return 0 case 2: return 1 case 3: return 2 default: return 4 } } func appPackageTypeName(packageType int) string { switch packageType { case 101: return "单卡套餐" case 102: return "池套餐" case 103: return "单卡加油包" case 104: return "池卡加油包" default: return gconv.String(packageType) } } func appBusinessTypeName(businessType int) string { switch businessType { case 0: return "订购" case 1: return "变更" case 2: return "续费" default: return gconv.String(businessType) } } func appPackageValidText(beginAt, expireAt *gtime.Time) string { if beginAt == nil || beginAt.IsZero() || expireAt == nil || expireAt.IsZero() { return "" } return beginAt.Format("Y-m-d") + " 至 " + expireAt.Format("Y-m-d") } func appPackageEffectText(status int) string { switch status { case 0: return "套餐待生效" case 1: return "套餐生效中" case 2: return "套餐已过期" case 3: return "套餐已终止" case 4: return "套餐已作废" default: return "" } } func appFlowText(flowMb float64) string { if flowMb <= 0 { return "" } if flowMb >= 1024 { return fmt.Sprintf("%.2fGB", flowMb/1024) } return fmt.Sprintf("%.0fMB", flowMb) } func appFirstNotEmpty(values ...string) string { for _, value := range values { if strings.TrimSpace(value) != "" { return value } } return "" } func appCardOwnerDeptId(row *appCardQueryRow) int64 { if row == nil { return 0 } if row.TerminalDeptId > 0 { return row.TerminalDeptId } return row.DeptId } func appCardOwnerDeptName(row *appCardQueryRow) string { if row == nil { return "" } return strings.TrimSpace(row.OwnerDeptName) } func appCardOwnerDeptKey(row *appCardQueryRow) string { if row == nil { return "" } return strings.TrimSpace(row.OwnerDeptKey) } func appCardCurrentPackageCode(row *appCardQueryRow) string { if row == nil { return "" } if strings.TrimSpace(row.TerminalCurrentPackageCode) != "" { return strings.TrimSpace(row.TerminalCurrentPackageCode) } return strings.TrimSpace(row.CurrentPackageCode) } func appCardPackageName(row *appCardQueryRow) string { if row == nil { return "" } terminalPackageCode := strings.TrimSpace(row.TerminalCurrentPackageCode) if terminalPackageCode != "" { if strings.TrimSpace(row.TerminalPackageName) != "" { return row.TerminalPackageName } if terminalPackageCode != strings.TrimSpace(row.CurrentPackageCode) { return "" } } return row.PackageName } func appCardPackageType(row *appCardQueryRow) int { if row == nil { return 0 } terminalPackageCode := strings.TrimSpace(row.TerminalCurrentPackageCode) if terminalPackageCode != "" { if row.TerminalPackageType > 0 { return row.TerminalPackageType } if terminalPackageCode != strings.TrimSpace(row.CurrentPackageCode) { return 0 } } return row.PackageType } func appCardCategoryCode(row *appCardQueryRow) string { if row == nil { return "" } terminalPackageCode := strings.TrimSpace(row.TerminalCurrentPackageCode) if terminalPackageCode != "" { if strings.TrimSpace(row.TerminalCategoryCode) != "" { return row.TerminalCategoryCode } if terminalPackageCode != strings.TrimSpace(row.CurrentPackageCode) { return "" } } return row.CategoryCode } func appCardCategoryName(row *appCardQueryRow) string { if row == nil { return "" } terminalPackageCode := strings.TrimSpace(row.TerminalCurrentPackageCode) if terminalPackageCode != "" { if strings.TrimSpace(row.TerminalCategoryName) != "" { return row.TerminalCategoryName } if terminalPackageCode != strings.TrimSpace(row.CurrentPackageCode) { return "" } } return row.CategoryName } func appOneLinkMockPackageFromRemark(remark string) (packageCode string, packageName string) { for _, part := range strings.Split(remark, ";") { item := strings.TrimSpace(part) if item == "" { continue } key, value, ok := strings.Cut(item, "=") if !ok { continue } switch strings.TrimSpace(key) { case "package": packageCode = strings.TrimSpace(value) case "name": packageName = strings.TrimSpace(value) } } if packageName == "" { packageName = packageCode } return packageCode, packageName } func appParseOneLinkTime(value string) *gtime.Time { value = strings.TrimSpace(value) if value == "" { return nil } parsed := gtime.NewFromStr(value) if parsed == nil || parsed.IsZero() { return nil } return parsed }