package app import ( "context" "strings" "git.5iot.com/iotlcm-public/iotlcm-app/internal/consts" "git.5iot.com/iotlcm-public/iotlcm-app/internal/dao" "git.5iot.com/iotlcm-public/iotlcm-app/internal/model" "git.5iot.com/iotlcm-public/iotlcm-app/internal/model/do" "git.5iot.com/iotlcm-public/iotlcm-app/internal/model/entity" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/os/gtime" ) // 只处理终端用户绑卡。企业用户的持卡范围由管理平台权限逻辑决定,不写终端卡关联表。 type appSimTerminalBindRow struct { Id int64 `orm:"id"` TerminalId int64 `orm:"terminal_id"` DeptId int64 `orm:"dept_id"` CurrentPackageCode string `orm:"current_package_code"` } func (s *sAppCard) Bind(ctx context.Context, param *model.AppCardBindParam) (res *model.AppCardModel, err error) { user, err := appCurrentUser(ctx) if err != nil { return nil, err } if !s.isTerminalUser(ctx, user) { return nil, gerror.New("企业用户无需绑定卡,请在我的卡片中查询当前可见卡") } card, err := s.findCardByValue(ctx, user.TenantId, param.CardValue) if err != nil { return nil, err } if card == nil { return nil, gerror.New("卡信息不存在,请确认查询号码是否正确") } now := gtime.Now() alreadyBound := false err = dao.TSimTerminal.Transaction(ctx, func(ctx context.Context, tx gdb.TX) error { terminal, err := s.ensureTerminal(ctx, tx, user, now) if err != nil { return err } var bind *appSimTerminalBindRow err = dao.TSimTerminal.Ctx(ctx).TX(tx). Where(dao.TSimTerminal.Columns().TenantId, user.TenantId). Where(dao.TSimTerminal.Columns().Iccid, card.Iccid). Where(dao.TSimTerminal.Columns().TerminalId, user.UserId). Scan(&bind) if err != nil { return err } if bind != nil { alreadyBound = true if bind.DeptId != card.DeptId || strings.TrimSpace(bind.CurrentPackageCode) != strings.TrimSpace(card.CurrentPackageCode) { _, err = dao.TSimTerminal.Ctx(ctx).TX(tx). Where(dao.TSimTerminal.Columns().Id, bind.Id). Data(do.TSimTerminal{ DeptId: card.DeptId, CurrentPackageCode: strings.TrimSpace(card.CurrentPackageCode), UpdatedBy: user.UserId, UpdatedAt: now, }). Update() } return err } _, err = dao.TSimTerminal.Ctx(ctx).TX(tx).Data(do.TSimTerminal{ Iccid: card.Iccid, Msisdn: card.Msisdn, Imsi: card.Imsi, TerminalId: user.UserId, TerminalName: terminal.TerminalName, DeptId: card.DeptId, CurrentPackageCode: strings.TrimSpace(card.CurrentPackageCode), Remark: param.Remark, TenantId: user.TenantId, CreatedDept: appUserDeptOrDefault(user), CreatedBy: user.UserId, CreatedAt: now, UpdatedBy: user.UserId, UpdatedAt: now, }).Insert() return err }) if err != nil { if isOldSimTerminalUniqueKeyError(err) { return nil, gerror.New("终端卡关联表唯一索引未更新,当前数据库仍限制一个终端用户只能绑定一张卡") } if isSimTerminalCardUniqueKeyError(err) { return nil, gerror.New("该卡已绑定当前用户,请刷新后重试") } return nil, err } if alreadyBound { return nil, gerror.New("该卡已绑定当前用户") } cardRow, err := s.findVisibleCard(ctx, user, card.Iccid) if err != nil { return nil, err } if cardRow == nil { return nil, gerror.New("绑卡成功,但刷新卡信息失败") } return s.cardRowToModel(ctx, cardRow, user, appCardOwnerTerminal, true), nil } func (s *sAppCard) ensureTerminal(ctx context.Context, tx gdb.TX, user *entity.SysUser, now *gtime.Time) (*entity.TTerminal, error) { var terminal *entity.TTerminal err := dao.TTerminal.Ctx(ctx).TX(tx). Where(dao.TTerminal.Columns().TerminalId, user.UserId). Scan(&terminal) if err != nil { return nil, err } if terminal != nil { if strings.TrimSpace(terminal.TerminalName) == "" { terminal.TerminalName = user.NickName } return terminal, nil } name := user.NickName if name == "" { name = user.UserName } _, err = dao.TTerminal.Ctx(ctx).TX(tx).Data(do.TTerminal{ TerminalId: user.UserId, TerminalName: name, Phone: user.Phonenumber, Status: consts.SysUserStatusNormal, FullName: name, LegalPersonName: name, LegalPersonIdCard: "000000000000000000", Balance: 0, TenantId: user.TenantId, CreatedDept: appUserDeptOrDefault(user), CreatedBy: user.UserId, CreatedAt: now, UpdatedBy: user.UserId, UpdatedAt: now, }).Insert() if err != nil { return nil, err } return &entity.TTerminal{ TerminalId: user.UserId, TerminalName: name, Phone: user.Phonenumber, TenantId: user.TenantId, CreatedDept: appUserDeptOrDefault(user), }, nil } func (s *sAppCard) isCardBoundToUser(ctx context.Context, iccid string, user *entity.SysUser) bool { count, err := dao.TSimTerminal.Ctx(ctx). Where(dao.TSimTerminal.Columns().TenantId, user.TenantId). Where(dao.TSimTerminal.Columns().TerminalId, user.UserId). Where(dao.TSimTerminal.Columns().Iccid, iccid). Count() return err == nil && count > 0 } func isOldSimTerminalUniqueKeyError(err error) bool { if err == nil { return false } errText := err.Error() return strings.Contains(errText, "Duplicate entry") && strings.Contains(errText, "uk_package_terminal") } func isSimTerminalCardUniqueKeyError(err error) bool { if err == nil { return false } errText := err.Error() return strings.Contains(errText, "Duplicate entry") && strings.Contains(errText, "uk_sim_terminal_card") }