// Package gen // @Link https://github.com/xiujiecn/xiu-admin // @Copyright Copyright (c) 2026 LiXiujie // @Author Lxj // @License https://github.com/xiujiecn/xiu-admin/blob/master/LICENSE // @AutoGenerate Version package iot import ( "context" "fmt" "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/library/xgorm/handler" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/xgorm/hook" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model/entity" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/service" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/utility/convert" "git.5iot.com/iotlcm-public/iotlcm-admin-svr/utility/excel" "strings" "github.com/gogf/gf/v2/database/gdb" "github.com/gogf/gf/v2/encoding/gjson" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/os/gctx" "github.com/gogf/gf/v2/os/gtime" "github.com/gogf/gf/v2/util/gconv" ) type sIotTFlowPackageConfig struct{} func NewIotTFlowPackageConfig() *sIotTFlowPackageConfig { return &sIotTFlowPackageConfig{} } func init() { service.RegisterIotTFlowPackageConfig(NewIotTFlowPackageConfig()) } // Model SIM流量池套餐配置表ORM模型 func (s *sIotTFlowPackageConfig) Model(ctx context.Context, option ...*handler.Option) *gdb.Model { if len(option) == 0 { option = append(option, &handler.Option{ FilterTenant: true, FilterAuth: true, }) } return handler.Model(dao.TFlowPackageConfig.Ctx(ctx), option...) } // List 获取SIM流量池套餐配置表列表 func (s *sIotTFlowPackageConfig) List(ctx context.Context, in *model.TFlowPackageConfigListParam) (list []*model.TFlowPackageConfigListModel, totalCount int, err error) { mod := s.Model(ctx) // 字段过滤(排除套餐名称列表字段,由程序处理) mod = mod.Fields(model.TFlowPackageConfigListModel{ Id: 0, PoolPackageCode: "", PackageCodes: nil, TopupPackageCodes: nil, Remark: "", TenantId: "", CreatedDept: 0, CreatedBy: 0, CreatedBySumma: nil, CreatedAt: nil, UpdatedBy: 0, UpdatedBySumma: nil, UpdatedAt: nil, }) // 查询主键ID if in.PoolPackageCode != "" { mod = mod.WhereLike(dao.TFlowPackageConfig.Columns().PoolPackageCode, "%"+in.PoolPackageCode+"%") } // 排序 mod = mod.OrderDesc(dao.TFlowPackageConfig.Columns().Id) // 分页 mod = mod.Page(in.Page, in.PageSize) // 操作人摘要信息 mod = mod.Hook(hook.MemberSummary) // 查询数据 if err = mod.ScanAndCount(&list, &totalCount, false); err != nil { err = gerror.Wrap(err, "获取SIM流量池套餐配置表列表失败,请稍后重试!") return } // 补充套餐名称列表 if len(list) > 0 { tenantId := contexts.GetTenantId(ctx) // 收集所有套餐编码 var allPackageCodes []string var allTopupPackageCodes []string for _, item := range list { if item.PackageCodes != nil { var codes []string if err = item.PackageCodes.Scan(&codes); err == nil { allPackageCodes = append(allPackageCodes, codes...) } } if item.TopupPackageCodes != nil { var topupCodes []string if err = item.TopupPackageCodes.Scan(&topupCodes); err == nil { allTopupPackageCodes = append(allTopupPackageCodes, topupCodes...) } } } // 查询套餐编码对应的名称映射 packageNameMap := make(map[string]string) if len(allPackageCodes) > 0 || len(allTopupPackageCodes) > 0 { modPkg := dao.TSimFlowPackageInfo.Ctx(ctx). Where(dao.TSimFlowPackageInfo.Columns().TenantId, tenantId). WhereIn(dao.TSimFlowPackageInfo.Columns().PackageCode, append(allPackageCodes, allTopupPackageCodes...)). Fields(dao.TSimFlowPackageInfo.Columns().PackageCode, dao.TSimFlowPackageInfo.Columns().PackageName) var pkgList []struct { PackageCode string `json:"packageCode"` PackageName string `json:"packageName"` } if err = modPkg.Scan(&pkgList); err != nil { err = gerror.Wrap(err, "查询套餐名称失败") return } for _, pkg := range pkgList { packageNameMap[pkg.PackageCode] = pkg.PackageName } } // 组装套餐名称列表 for _, item := range list { // 套餐名称列表 if item.PackageCodes != nil { var codes []string if err = item.PackageCodes.Scan(&codes); err == nil { names := make([]string, 0, len(codes)) for _, code := range codes { if name, ok := packageNameMap[code]; ok { names = append(names, name) } else { names = append(names, "") } } item.PackageNames = gjson.New(names) } } // 加油包套餐名称列表 if item.TopupPackageCodes != nil { var topupCodes []string if err = item.TopupPackageCodes.Scan(&topupCodes); err == nil { names := make([]string, 0, len(topupCodes)) for _, code := range topupCodes { if name, ok := packageNameMap[code]; ok { names = append(names, name) } else { names = append(names, "") } } item.TopupPackageNames = gjson.New(names) } } } } return } // Export 导出SIM流量池套餐配置表 func (s *sIotTFlowPackageConfig) Export(ctx context.Context, in *model.TFlowPackageConfigListParam) (err error) { list, totalCount, err := s.List(ctx, in) if err != nil { return } // 字段的排序是依据tags的字段顺序,如果你不想使用默认的排序方式,可以直接定义 tags = []string{"字段名称", "字段名称2", ...} tags, err := convert.GetEntityDescTags(model.TFlowPackageConfigExportModel{}) if err != nil { return } var ( fileName = "导出SIM流量池套餐配置表-" + gctx.CtxId(ctx) sheetName = fmt.Sprintf("索引条件共%v行,共%v页,当前导出是第%v页,本页共%v行", totalCount, (totalCount+in.PageSize-1)/in.PageSize, in.Page, len(list)) exports []model.TFlowPackageConfigExportModel ) if err = gconv.Scan(list, &exports); err != nil { return } err = excel.ExportByStructs(ctx, tags, exports, fileName, sheetName) return } // Edit 修改/新增SIM流量池套餐配置表 func (s *sIotTFlowPackageConfig) Edit(ctx context.Context, in *model.TFlowPackageConfigEditParam) (err error) { return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) { // 修改 if in.Id > 0 { // 先查询当前配置信息 var oldConfig entity.TFlowPackageConfig if err = s.Model(ctx, &handler.Option{FilterTenant: true, FilterAuth: false}). WherePri(in.Id).Scan(&oldConfig); err != nil { return gerror.Wrap(err, "查询池配置信息失败") } if oldConfig.Id == 0 { return gerror.New("池配置不存在") } tenantId := oldConfig.TenantId now := gtime.Now() updatedBy := contexts.GetUserId(ctx) // 解析新的套餐编码列表 var newPackageCodes []string if in.PackageCodes != nil { if err = in.PackageCodes.Scan(&newPackageCodes); err != nil { return gerror.Wrap(err, "套餐编码列表格式错误") } } // 1. 先将套餐表按照该池编码全部置空(旧套餐) if oldConfig.PackageCodes != nil && oldConfig.PoolPackageCode != "" { var oldPackageCodes []string if err = oldConfig.PackageCodes.Scan(&oldPackageCodes); err == nil && len(oldPackageCodes) > 0 { if _, err = tx.Ctx(ctx).Model(dao.TSimFlowPackageInfo.Table()). Where(dao.TSimFlowPackageInfo.Columns().TenantId, tenantId). WhereIn(dao.TSimFlowPackageInfo.Columns().PackageCode, oldPackageCodes). Data(g.Map{ dao.TSimFlowPackageInfo.Columns().PoolPackageCode: nil, dao.TSimFlowPackageInfo.Columns().UpdatedBy: updatedBy, dao.TSimFlowPackageInfo.Columns().UpdatedAt: now, }).Update(); err != nil { return gerror.Wrap(err, "清除旧套餐池编码失败") } } } // 2. 校验新套餐编码 if len(newPackageCodes) > 0 { packageCodes := make([]string, 0, len(newPackageCodes)) seenPackageCodes := make(map[string]struct{}, len(newPackageCodes)) for _, code := range newPackageCodes { code = strings.TrimSpace(code) if code == "" { return gerror.New("套餐编码不能为空") } if _, exists := seenPackageCodes[code]; exists { continue } seenPackageCodes[code] = struct{}{} packageCodes = append(packageCodes, code) } var matchedPackageCodes []string if err = tx.Ctx(ctx).Model(dao.TSimFlowPackageInfo.Table()). Where(dao.TSimFlowPackageInfo.Columns().TenantId, tenantId). WhereIn(dao.TSimFlowPackageInfo.Columns().PackageCode, packageCodes). Fields(dao.TSimFlowPackageInfo.Columns().PackageCode). Scan(&matchedPackageCodes); err != nil { return gerror.Wrap(err, "校验套餐编码失败") } if len(matchedPackageCodes) != len(packageCodes) { return gerror.New("套餐编码不存在或不属于当前租户") } // 3. 按照新的组合填入套餐编码 if _, err = tx.Ctx(ctx).Model(dao.TSimFlowPackageInfo.Table()). Where(dao.TSimFlowPackageInfo.Columns().TenantId, tenantId). WhereIn(dao.TSimFlowPackageInfo.Columns().PackageCode, packageCodes). Data(g.Map{ dao.TSimFlowPackageInfo.Columns().PoolPackageCode: oldConfig.PoolPackageCode, dao.TSimFlowPackageInfo.Columns().UpdatedBy: updatedBy, dao.TSimFlowPackageInfo.Columns().UpdatedAt: now, }).Update(); err != nil { return gerror.Wrap(err, "更新套餐池编码失败") } } // 4. 更新池配置表 in.UpdatedBy = &updatedBy in.UpdatedAt = now in.TenantId = &tenantId if _, err = tx.Ctx(ctx).Model(dao.TFlowPackageConfig.Table()). Fields(model.TFlowPackageConfigUpdateFields{}). WherePri(in.Id).Data(in).Update(); err != nil { err = gerror.Wrap(err, "修改SIM流量池套餐配置表失败,请稍后重试!") } return } // 新增 tenantId := contexts.GetTenantId(ctx) in.TenantId = &tenantId createdDept := contexts.GetDeptId(ctx) in.CreatedDept = &createdDept createdBy := contexts.GetUserId(ctx) in.CreatedBy = &createdBy now := gtime.Now() in.CreatedAt = now var rawPackageCodes []string if in.PackageCodes == nil { return gerror.New("套餐编码列表不能为空") } if err = in.PackageCodes.Scan(&rawPackageCodes); err != nil { return gerror.Wrap(err, "套餐编码列表格式错误") } packageCodes := make([]string, 0, len(rawPackageCodes)) seenPackageCodes := make(map[string]struct{}, len(rawPackageCodes)) for _, code := range rawPackageCodes { code = strings.TrimSpace(code) if code == "" { return gerror.New("套餐编码不能为空") } if _, exists := seenPackageCodes[code]; exists { continue } seenPackageCodes[code] = struct{}{} packageCodes = append(packageCodes, code) } if len(packageCodes) == 0 { return gerror.New("套餐编码列表不能为空") } var matchedPackageCodes []string if err = tx.Ctx(ctx).Model(dao.TSimFlowPackageInfo.Table()). Where(dao.TSimFlowPackageInfo.Columns().TenantId, tenantId). WhereIn(dao.TSimFlowPackageInfo.Columns().PackageCode, packageCodes). Fields(dao.TSimFlowPackageInfo.Columns().PackageCode). Scan(&matchedPackageCodes); err != nil { return gerror.Wrap(err, "校验套餐编码失败") } if len(matchedPackageCodes) != len(packageCodes) { return gerror.New("套餐编码不存在或不属于当前租户") } // 流量池套餐编码使用 pool_ 前缀加秒级时间戳。 poolCode := fmt.Sprintf("pool_%d", now.Unix()) in.PoolPackageCode = &poolCode if _, err = tx.Ctx(ctx).Model(dao.TFlowPackageConfig.Table()). Fields(model.TFlowPackageConfigInsertFields{}). Data(in).Insert(); err != nil { err = gerror.Wrap(err, "新增SIM流量池套餐配置表失败,请稍后重试!") } if err != nil { return } if _, err = tx.Ctx(ctx).Model(dao.TSimFlowPackageInfo.Table()). Where(dao.TSimFlowPackageInfo.Columns().TenantId, tenantId). WhereIn(dao.TSimFlowPackageInfo.Columns().PackageCode, packageCodes). Data(g.Map{ dao.TSimFlowPackageInfo.Columns().PoolPackageCode: poolCode, dao.TSimFlowPackageInfo.Columns().UpdatedBy: createdBy, dao.TSimFlowPackageInfo.Columns().UpdatedAt: now, }).Update(); err != nil { return gerror.Wrap(err, "更新套餐池编码失败") } return }) } // Delete 删除SIM流量池套餐配置表 func (s *sIotTFlowPackageConfig) Delete(ctx context.Context, in *model.TFlowPackageConfigDeleteParam) (err error) { // 先查询当前配置,获取套餐编码列表 var config entity.TFlowPackageConfig if err = s.Model(ctx, &handler.Option{FilterTenant: true, FilterAuth: false}).WherePri(in.Id).Scan(&config); err != nil { err = gerror.Wrap(err, "查询池配置信息失败") return } if config.Id == 0 { return gerror.New("池配置不存在") } return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) { // 删除池配置记录 if _, err = tx.Ctx(ctx).Model(dao.TFlowPackageConfig.Table()). WherePri(in.Id).Unscoped().Delete(); err != nil { err = gerror.Wrap(err, "删除SIM流量池套餐配置表失败,请稍后重试!") return } // 清除该池下所有套餐和加油包的池编码。 // 删除池配置时,直接按池编码兜底清理,避免配置表里的 package_codes/topup_package_codes // 和真实绑定关系不一致时留下脏数据。 if config.PoolPackageCode != "" { if _, err = tx.Ctx(ctx).Model(dao.TSimFlowPackageInfo.Table()). Where(dao.TSimFlowPackageInfo.Columns().TenantId, config.TenantId). Where(dao.TSimFlowPackageInfo.Columns().PoolPackageCode, config.PoolPackageCode). Data(g.Map{ dao.TSimFlowPackageInfo.Columns().PoolPackageCode: nil, dao.TSimFlowPackageInfo.Columns().UpdatedBy: contexts.GetUserId(ctx), dao.TSimFlowPackageInfo.Columns().UpdatedAt: gtime.Now(), }).Update(); err != nil { err = gerror.Wrap(err, "清除套餐池编码失败") return } } return }) } // View 获取SIM流量池套餐配置表指定信息 func (s *sIotTFlowPackageConfig) View(ctx context.Context, in *model.TFlowPackageConfigViewParam) (res *model.TFlowPackageConfigViewModel, err error) { if err = s.Model(ctx).WherePri(in.Id).Hook(hook.MemberSummary).Scan(&res); err != nil { err = gerror.Wrap(err, "获取SIM流量池套餐配置表信息,请稍后重试!") return } if res == nil || res.Id == 0 { return nil, gerror.New("池配置不存在") } // 补充套餐名称列表 tenantId := res.TenantId var allPackageCodes []string var allTopupPackageCodes []string if res.PackageCodes != nil { var codes []string if err = res.PackageCodes.Scan(&codes); err == nil { allPackageCodes = codes } } if res.TopupPackageCodes != nil { var topupCodes []string if err = res.TopupPackageCodes.Scan(&topupCodes); err == nil { allTopupPackageCodes = topupCodes } } // 修改时回显当前池子大小,供前端加载当前池可选套餐。 if len(allPackageCodes) > 0 { var flow struct { FlowGb string FlowMb string } if err = dao.TSimFlowPackageInfo.Ctx(ctx). Where(dao.TSimFlowPackageInfo.Columns().TenantId, tenantId). Where(dao.TSimFlowPackageInfo.Columns().PackageType, 102). WhereIn(dao.TSimFlowPackageInfo.Columns().PackageCode, allPackageCodes). Fields(dao.TSimFlowPackageInfo.Columns().FlowGb, dao.TSimFlowPackageInfo.Columns().FlowMb). Limit(1). Scan(&flow); err != nil { return nil, gerror.Wrap(err, "查询流量池大小失败") } if flow.FlowGb != "" || flow.FlowMb != "" { res.PoolFlow = flow.FlowGb + "," + flow.FlowMb } } // 查询套餐名称映射 if len(allPackageCodes) > 0 || len(allTopupPackageCodes) > 0 { packageNameMap := make(map[string]string) modPkg := dao.TSimFlowPackageInfo.Ctx(ctx). Where(dao.TSimFlowPackageInfo.Columns().TenantId, tenantId). WhereIn(dao.TSimFlowPackageInfo.Columns().PackageCode, append(allPackageCodes, allTopupPackageCodes...)). Fields(dao.TSimFlowPackageInfo.Columns().PackageCode, dao.TSimFlowPackageInfo.Columns().PackageName) var pkgList []struct { PackageCode string `json:"packageCode"` PackageName string `json:"packageName"` } if err = modPkg.Scan(&pkgList); err != nil { return nil, gerror.Wrap(err, "查询套餐名称失败") } for _, pkg := range pkgList { packageNameMap[pkg.PackageCode] = pkg.PackageName } // 组装套餐名称列表 if len(allPackageCodes) > 0 { names := make([]string, 0, len(allPackageCodes)) for _, code := range allPackageCodes { if name, ok := packageNameMap[code]; ok { names = append(names, name) } else { names = append(names, "") } } res.PackageNames = gjson.New(names) } if len(allTopupPackageCodes) > 0 { names := make([]string, 0, len(allTopupPackageCodes)) for _, code := range allTopupPackageCodes { if name, ok := packageNameMap[code]; ok { names = append(names, name) } else { names = append(names, "") } } res.TopupPackageNames = gjson.New(names) } } return }