package iot import ( "context" "fmt" "strings" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/dao" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/contexts" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" ) const cardChannelAssocTable = "card_channel_assoc" type cardChannelAssocRecord struct { Id int64 `orm:"id"` ChannelKey string `orm:"channel_id"` MatchType int `orm:"match_type"` Iccid string `orm:"iccid"` IccidStart string `orm:"iccid_start"` IccidEnd string `orm:"iccid_end"` Status int `orm:"status"` } type cardChannelDisplayRecord struct { ChanKey string ChanName string ChanAlias string TempKey string } type cardChannelLookupRecord struct { Id int64 `orm:"id"` ChanKey string `orm:"chan_key"` ChanName string `orm:"chan_name"` ChanAlias string `orm:"chan_alias"` TempKey string `orm:"temp_key"` } func applyCardChannelAssocFilter(mod *gdb.Model, cardInfoTable string, chanKey string) *gdb.Model { if mod == nil { return mod } chanKey = strings.TrimSpace(chanKey) if chanKey == "" { return mod } return mod.Where(cardChannelAssocExistsSQL(cardInfoTable), chanKey) } func cardChannelAssocExistsSQL(cardInfoTable string) string { cardInfoTable = strings.TrimSpace(cardInfoTable) if cardInfoTable == "" { cardInfoTable = dao.TSimCardInfo.Table() } channelTable := dao.TSimChannels.Table() cardColumns := dao.TSimCardInfo.Columns() channelColumns := dao.TSimChannels.Columns() return fmt.Sprintf( "EXISTS (SELECT 1 FROM `%s` a LEFT JOIN `%s` c ON c.`%s` = a.`channel_id` WHERE a.`status` = 1 AND c.`%s` = `%s`.`%s` AND c.`%s` = ? AND ((a.`match_type` = 1 AND a.`iccid` COLLATE utf8mb4_general_ci = `%s`.`%s`) OR (a.`match_type` = 2 AND a.`iccid_start` COLLATE utf8mb4_general_ci <= `%s`.`%s` AND a.`iccid_end` COLLATE utf8mb4_general_ci >= `%s`.`%s`)))", cardChannelAssocTable, channelTable, channelColumns.ChanKey, channelColumns.TenantId, cardInfoTable, cardColumns.TenantId, channelColumns.ChanKey, cardInfoTable, cardColumns.Iccid, cardInfoTable, cardColumns.Iccid, cardInfoTable, cardColumns.Iccid, ) } func enrichCardChannelList(ctx context.Context, list []*model.TSimCardInfoListModel) error { if len(list) == 0 { return nil } channelCache := make(map[string]cardChannelDisplayRecord) for _, item := range list { if item == nil { continue } display, ok, err := resolveCardChannelDisplayByIccid(ctx, item.Iccid, channelCache) if err != nil { return err } if !ok { continue } item.ChanKey = display.ChanKey item.ChanName = display.ChanName item.ChanAlias = display.ChanAlias } return nil } func enrichCardChannelView(ctx context.Context, item *model.TSimCardInfoViewModel) error { if item == nil { return nil } display, ok, err := resolveCardChannelDisplayByIccid(ctx, item.Iccid, nil) if err != nil { return err } if !ok { return nil } item.ChanKey = display.ChanKey item.ChanName = display.ChanName item.ChanAlias = display.ChanAlias return nil } func enrichSimKeyChannelFromAssoc(ctx context.Context, simKey *model.SimKey) error { if simKey == nil { return nil } display, ok, err := resolveCardChannelDisplayByIccid(ctx, simKey.ICCID, nil) if err != nil { return err } if ok && strings.TrimSpace(display.ChanKey) != "" { simKey.ChanKey = display.ChanKey } return nil } func resolveCardChannelDisplayByIccid(ctx context.Context, iccid string, channelCache map[string]cardChannelDisplayRecord) (cardChannelDisplayRecord, bool, error) { assoc, err := resolveCardChannelAssocByIccid(ctx, iccid) if err != nil || assoc == nil { return cardChannelDisplayRecord{}, false, err } return resolveCardChannelDisplayByAssoc(ctx, assoc, channelCache) } func resolveCardChannelDisplayByAssoc(ctx context.Context, assoc *cardChannelAssocRecord, channelCache map[string]cardChannelDisplayRecord) (cardChannelDisplayRecord, bool, error) { if assoc == nil { return cardChannelDisplayRecord{}, false, nil } return resolveCardChannelDisplayByChannelKey(ctx, assoc.ChannelKey, channelCache) } func resolveCardChannelAssocByIccid(ctx context.Context, iccid string) (*cardChannelAssocRecord, error) { iccid = strings.TrimSpace(iccid) if iccid == "" { return nil, nil } var exact *cardChannelAssocRecord if err := g.DB().Ctx(ctx).Model(cardChannelAssocTable). Fields("id", "channel_id", "match_type", "iccid", "iccid_start", "iccid_end", "status"). Where("status", 1). Where("match_type", 1). Where("iccid COLLATE utf8mb4_general_ci = ?", iccid). OrderDesc("id"). Limit(1). Scan(&exact); err != nil { return nil, gerror.Wrap(err, "查询卡通道单卡关联失败") } if exact != nil && strings.TrimSpace(exact.ChannelKey) != "" { return exact, nil } var ranged *cardChannelAssocRecord if err := g.DB().Ctx(ctx).Model(cardChannelAssocTable). Fields("id", "channel_id", "match_type", "iccid", "iccid_start", "iccid_end", "status"). Where("status", 1). Where("match_type", 2). Where("iccid_start COLLATE utf8mb4_general_ci <= ? AND iccid_end COLLATE utf8mb4_general_ci >= ?", iccid, iccid). OrderDesc("id"). Limit(1). Scan(&ranged); err != nil { return nil, gerror.Wrap(err, "查询卡通道号段关联失败") } if ranged != nil && strings.TrimSpace(ranged.ChannelKey) != "" { return ranged, nil } return nil, nil } func resolveCardChannelDisplayByChannelKey(ctx context.Context, chanKey string, channelCache map[string]cardChannelDisplayRecord) (cardChannelDisplayRecord, bool, error) { chanKey = strings.TrimSpace(chanKey) if chanKey == "" { return cardChannelDisplayRecord{}, false, nil } if channelCache != nil { if cached, ok := channelCache[chanKey]; ok { return cached, true, nil } } channel, err := loadCardChannelByKey(ctx, chanKey) if err != nil { return cardChannelDisplayRecord{}, false, err } if channel == nil { return cardChannelDisplayRecord{}, false, nil } display := cardChannelDisplayRecord{ ChanKey: strings.TrimSpace(channel.ChanKey), ChanName: strings.TrimSpace(channel.ChanName), ChanAlias: strings.TrimSpace(channel.ChanAlias), TempKey: strings.TrimSpace(channel.TempKey), } if channelCache != nil { channelCache[chanKey] = display } return display, true, nil } func loadCardChannelByKey(ctx context.Context, chanKey string) (*cardChannelLookupRecord, error) { chanKey = strings.TrimSpace(chanKey) if chanKey == "" { return nil, nil } var channel *cardChannelLookupRecord columns := dao.TSimChannels.Columns() if err := cardChannelLookupModel(ctx). Where(columns.ChanKey, chanKey). Limit(1). Scan(&channel); err != nil { return nil, gerror.Wrap(err, "查询通道信息失败") } if channel != nil && strings.TrimSpace(channel.ChanKey) != "" { return channel, nil } channel = nil if err := dao.TSimChannels.Ctx(ctx). Fields(columns.Id, columns.ChanKey, columns.ChanName, columns.ChanAlias, columns.TempKey). Where(columns.ChanKey, chanKey). Limit(1). Scan(&channel); err != nil { return nil, gerror.Wrap(err, "查询通道信息失败") } return channel, nil } func cardChannelLookupModel(ctx context.Context) *gdb.Model { columns := dao.TSimChannels.Columns() return dao.TSimChannels.Ctx(ctx). Fields(columns.Id, columns.ChanKey, columns.ChanName, columns.ChanAlias, columns.TempKey). Where(columns.TenantId, contexts.GetTenantId(ctx)) } func logCardChannelDisplayResolverError(ctx context.Context, err error) { if err != nil { g.Log().Warningf(ctx, "load card channel display failed: %v", err) } }