chore: 初始开源发布
iotlcm-admin-svr:管理后台服务。 - Go module:iotlcm → git.5iot.com/iotlcm-public/iotlcm-admin-svr(729 文件) - 凭据与地址脱敏:JWT signingKey(含代码里的 MustGet 默认值)、 MySQL DSN、Redis 口令、告警邮件发件人邮箱全部改为占位; 私网 IP → 文档地址段;库名 xiujie_admin → iotlcm - 真实手机号/邮箱 → 合法 11 位编造号 / example.com - 移除内部资产:CI 触发器、过时 DDL(sql/db_iotlcm.sql)、 私有依赖 go get 行、明文 registry 登录口令 - 启动 banner 统一 IOTLCM 方块字 + 社区惯例署名 - Dockerfile 改用公共基础镜像 - 拼错的 RADEME.md → README.md,README 重写 - 需要真实数据库的用例改为可用 IOTLCM_TEST_WITH_DB=1 显式启用 - 补 Apache-2.0 LICENSE,LF 行尾 + .gitattributes 数据库 schema 不随本仓发布(生产 DDL 已过时),README 已说明。
This commit is contained in:
@@ -0,0 +1,258 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user