// 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
}