chore: 并入 iotlcm-admin-svr 历史到 admin-svr/(原提交 49818c6)

This commit is contained in:
MiFaZhan
2026-11-02 13:27:59 +08:00
1250 changed files with 154111 additions and 0 deletions
@@ -0,0 +1,464 @@
// Package gen
// @Link https://github.com/xiujiecn/xiu-admin
// @Copyright Copyright (c) 2026 LiXiujie
// @Author Lxj <xxx@example.com>
// @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"
"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/service"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/utility/convert"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/utility/excel"
"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 sIotTSimFlowPool struct{}
func NewIotTSimFlowPool() *sIotTSimFlowPool {
return &sIotTSimFlowPool{}
}
func init() {
service.RegisterIotTSimFlowPool(NewIotTSimFlowPool())
}
// Model 流量池表ORM模型
func (s *sIotTSimFlowPool) 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.TSimFlowPool.Ctx(ctx), option...)
}
// List 获取流量池表列表
func (s *sIotTSimFlowPool) List(ctx context.Context, in *model.TSimFlowPoolListParam) (list []*model.TSimFlowPoolListModel, totalCount int, err error) {
mod := s.Model(ctx)
poolPackage := dao.TSimFlowPackageInfo.Table()
flowPool := dao.TSimFlowPool.Table()
sysDept := dao.SysDept.Table()
mod = mod.FieldsPrefix(flowPool, model.TSimFlowPoolListModel{})
// package_codes stores the actual pool package codes. pool_package_code is
// a pool dimension/configuration value and must not be used to collect names.
mod = mod.Fields("GROUP_CONCAT(DISTINCT " + poolPackage + "." + dao.TSimFlowPackageInfo.Columns().PackageName + " ORDER BY " + poolPackage + "." + dao.TSimFlowPackageInfo.Columns().PackageName + " SEPARATOR ',') as poolPackageName")
mod = mod.Fields(sysDept + "." + dao.SysDept.Columns().DeptName + " as deptName")
// 查询主键ID
if in.Id > 0 {
mod = mod.Where(dao.TSimFlowPool.Columns().Id, in.Id)
}
// 查询客户编号
if in.DeptId > 0 {
mod = mod.Where(dao.TSimFlowPool.Columns().DeptId, in.DeptId)
}
// 查询流量池编号
if in.FlowPoolCode != "" {
mod = mod.Where(dao.TSimFlowPool.Columns().FlowPoolCode, in.FlowPoolCode)
}
// 查询状态:0 正常、1 停用、2 锁定
if in.PoolStatus != nil {
mod = mod.Where(dao.TSimFlowPool.Columns().PoolStatus, *in.PoolStatus)
}
// 查询创建时间
if len(in.CreatedAt) == 2 {
in.CreatedAt[1] = in.CreatedAt[1].EndOfDay()
}
if len(in.CreatedAt) == 2 {
mod = mod.WhereBetween(dao.TSimFlowPool.Columns().CreatedAt, in.CreatedAt[0], in.CreatedAt[1])
}
// 分页
mod = mod.Page(in.Page, in.PageSize)
// 排序
mod = mod.OrderDesc(dao.TSimFlowPool.Columns().Id)
mod = mod.LeftJoin(poolPackage, fmt.Sprintf(
"%s.%s = 102 AND JSON_CONTAINS(%s.%s, JSON_QUOTE(%s.%s))",
poolPackage,
dao.TSimFlowPackageInfo.Columns().PackageType,
flowPool,
dao.TSimFlowPool.Columns().PackageCodes,
poolPackage,
dao.TSimFlowPackageInfo.Columns().PackageCode,
))
mod = mod.LeftJoin(sysDept, sysDept+"."+dao.SysDept.Columns().DeptId+"="+flowPool+"."+dao.TSimFlowPool.Columns().DeptId)
// 按流量池主键分组(因为使用了聚合函数 GROUP_CONCAT)
mod = mod.Group(flowPool + ".id")
// 操作人摘要信息
mod = mod.Hook(hook.MemberSummary)
// 查询数据
if err = mod.ScanAndCount(&list, &totalCount, false); err != nil {
err = gerror.Wrap(err, "获取流量池表列表失败,请稍后重试!")
return
}
return
}
// Export 导出流量池表
func (s *sIotTSimFlowPool) Export(ctx context.Context, in *model.TSimFlowPoolListParam) (err error) {
list, totalCount, err := s.List(ctx, in)
if err != nil {
return
}
// 字段的排序是依据tags的字段顺序,如果你不想使用默认的排序方式,可以直接定义 tags = []string{"字段名称", "字段名称2", ...}
tags, err := convert.GetEntityDescTags(model.TSimFlowPoolExportModel{})
if err != nil {
return
}
var (
fileName = "导出流量池表-" + gctx.CtxId(ctx)
sheetName = fmt.Sprintf("索引条件共%v行,共%v页,当前导出是第%v页,本页共%v行", totalCount, (totalCount+in.PageSize-1)/in.PageSize, in.Page, len(list))
exports []model.TSimFlowPoolExportModel
)
if err = gconv.Scan(list, &exports); err != nil {
return
}
err = excel.ExportByStructs(ctx, tags, exports, fileName, sheetName)
return
}
// Edit 修改/新增流量池表
func (s *sIotTSimFlowPool) Edit(ctx context.Context, in *model.TSimFlowPoolEditParam) (err error) {
// 验证'FlowPoolCode'唯一
if err = xgorm.IsUnique(ctx, &dao.TSimFlowPool, g.Map{dao.TSimFlowPool.Columns().FlowPoolCode: in.FlowPoolCode}, "流量池编号已存在", in.Id); err != nil {
return
}
return g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) (err error) {
// 修改
if in.Id > 0 {
updateBy := contexts.GetUserId(ctx)
in.UpdatedBy = &updateBy
in.UpdatedAt = gtime.Now()
if _, err = s.Model(ctx).
Fields(model.TSimFlowPoolUpdateFields{}).
WherePri(in.Id).Data(in).Update(); err != nil {
err = gerror.Wrap(err, "修改流量池表失败,请稍后重试!")
}
return
}
// 新增
tenantId := contexts.GetTenantId(ctx)
in.TenantId = &tenantId
deptId := contexts.GetDeptId(ctx)
in.CreatedDept = &deptId
userid := contexts.GetUserId(ctx)
in.CreatedBy = &userid
in.CreatedAt = gtime.Now()
if _, err = s.Model(ctx, &handler.Option{FilterAuth: false}).
Fields(model.TSimFlowPoolInsertFields{}).
Data(in).Insert(); err != nil {
err = gerror.Wrap(err, "新增流量池表失败,请稍后重试!")
}
return
})
}
// Delete 删除流量池表
func (s *sIotTSimFlowPool) Delete(ctx context.Context, in *model.TSimFlowPoolDeleteParam) (err error) {
if _, err = s.Model(ctx).WherePri(in.Id).Unscoped().Delete(); err != nil {
err = gerror.Wrap(err, "删除流量池表失败,请稍后重试!")
return
}
return
}
// View 获取流量池表指定信息
func (s *sIotTSimFlowPool) View(ctx context.Context, in *model.TSimFlowPoolViewParam) (res *model.TSimFlowPoolViewModel, err error) {
mod := s.Model(ctx)
poolPackage := dao.TSimFlowPackageInfo.Table()
flowPool := dao.TSimFlowPool.Table()
sysDept := dao.SysDept.Table()
mod = mod.WherePri(in.Id)
mod = mod.LeftJoin(poolPackage, fmt.Sprintf(
"%s.%s = 102 AND JSON_CONTAINS(%s.%s, JSON_QUOTE(%s.%s))",
poolPackage,
dao.TSimFlowPackageInfo.Columns().PackageType,
flowPool,
dao.TSimFlowPool.Columns().PackageCodes,
poolPackage,
dao.TSimFlowPackageInfo.Columns().PackageCode,
))
mod = mod.LeftJoin(sysDept, sysDept+"."+dao.SysDept.Columns().DeptId+"="+flowPool+"."+dao.TSimFlowPool.Columns().DeptId)
mod = mod.FieldsPrefix(flowPool, model.TSimFlowPoolListModel{})
mod = mod.Fields("GROUP_CONCAT(DISTINCT " + poolPackage + "." + dao.TSimFlowPackageInfo.Columns().PackageName + " ORDER BY " + poolPackage + "." + dao.TSimFlowPackageInfo.Columns().PackageName + " SEPARATOR ',') as poolPackageName")
mod = mod.Fields(sysDept + "." + dao.SysDept.Columns().DeptName + " as deptName")
mod = mod.Group(flowPool + ".id")
if err = mod.Hook(hook.MemberSummary).Scan(&res); err != nil {
err = gerror.Wrap(err, "获取流量池表信息,请稍后重试!")
return
}
return
}
// SyncPoolCard 流量池同步卡信息(调用计算方法)
func (s *sIotTSimFlowPool) SyncPoolCard(ctx context.Context, deptId int64) (err error) {
// 调用卡信息表获取套餐选项
packageOptions, err := service.IotTSimCardInfo().GetCardPackageOptions(ctx, deptId)
if err != nil {
return gerror.Wrap(err, "获取卡套餐选项失败,请稍后重试!")
}
g.Log().Info(ctx, "packageOptions 卡套餐列表长度(当前所有生效中的套餐):%v", len(packageOptions))
g.Log().Info(ctx, "packageOptions 卡套餐列表:%v", packageOptions)
// 提取套餐编码列表
var cardPackageCodes []string
for _, pkg := range packageOptions {
cardPackageCodes = append(cardPackageCodes, pkg.CurrentPackageCode)
}
g.Log().Info(ctx, "cardPackageCodes 卡套餐编码列表长度:%v", len(cardPackageCodes))
g.Log().Info(ctx, "cardPackageCodes 卡套餐编码列表(卡信息表该用户当前所有生效中的套餐):%v", cardPackageCodes)
if len(cardPackageCodes) == 0 {
g.Log().Info(ctx, "SyncPoolCard 卡套餐列表为空,跳过同步")
return nil
}
// 调用流量套餐服务获取对应的池套餐编码列表
poolPackageMap102, poolPackageMap104, err := service.IotTSimFlowPackageInfo().GetPoolPackagesByCardPackages(ctx, cardPackageCodes)
if err != nil {
return gerror.Wrap(err, "获取池套餐列表失败,请稍后重试!")
}
g.Log().Info(ctx, "poolPackageMap102 102池套餐编码列表:%v", poolPackageMap102) //{"dx-1g-1y":400,"dx-1g-1y-130":400,"dx-300m-3y":300}池套餐
g.Log().Info(ctx, "poolPackageMap104 104池套餐编码列表:%v", poolPackageMap104) //{"dx-30g-1y":400}加油包
// 合并所有池套餐编码
var poolPackageCodes []int64
seenPoolPackageCodes := make(map[int64]bool)
for _, code := range poolPackageMap102 {
if !seenPoolPackageCodes[code] {
seenPoolPackageCodes[code] = true
poolPackageCodes = append(poolPackageCodes, code)
}
}
for _, code := range poolPackageMap104 {
if !seenPoolPackageCodes[code] {
seenPoolPackageCodes[code] = true
poolPackageCodes = append(poolPackageCodes, code)
}
}
g.Log().Info(ctx, "poolPackageCodes 池套餐列表:%v", poolPackageCodes) // [400,300]
if len(poolPackageCodes) == 0 {
g.Log().Info(ctx, "SyncPoolCard 池套餐列表为空,跳过同步")
return nil
}
// 根据 deptId 查询已有的流量池
var existingPools []*model.TSimFlowPoolListModel
existingPoolMod := dao.TSimFlowPool.Ctx(ctx).
Where(dao.TSimFlowPool.Columns().DeptId, deptId).
WhereIn(dao.TSimFlowPool.Columns().PoolPackageCode, poolPackageCodes).
OrderDesc(dao.TSimFlowPool.Columns().Id)
if tenantId := contexts.GetTenantId(ctx); tenantId != "" {
existingPoolMod = existingPoolMod.Where(dao.TSimFlowPool.Columns().TenantId, tenantId)
}
err = existingPoolMod.Scan(&existingPools)
if err != nil {
return gerror.Wrap(err, "获取已有流量池列表失败,请稍后重试!")
}
// 构建已有流量池的 map,key 为 poolPackageCode
existingPoolMap := make(map[int64]*model.TSimFlowPoolListModel)
duplicatePoolIdsMap := make(map[int64][]int64)
for _, pool := range existingPools {
if _, ok := existingPoolMap[pool.PoolPackageCode]; ok {
duplicatePoolIdsMap[pool.PoolPackageCode] = append(duplicatePoolIdsMap[pool.PoolPackageCode], pool.Id)
continue
}
existingPoolMap[pool.PoolPackageCode] = pool
}
// 生成流量池编号前缀:POOL + 毫秒时间戳
flowPoolCodePrefix := fmt.Sprintf("POOL%d", gtime.TimestampMilli())
// 开启事务
err = s.Model(ctx).Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
for i, poolPackageCode := range poolPackageCodes { // [400,300]
now := gtime.Now()
var keepPoolId int64
// 分别收集102套餐编码和104加油包套餐编码
var codesForPackage102 []string
var codesForPackage104 []string
for cardCode, pcCode := range poolPackageMap102 { //{"dx-1g-1y":400,"dx-1g-1y-130":400,"dx-300m-3y":300}池套餐
if pcCode == poolPackageCode {
codesForPackage102 = append(codesForPackage102, cardCode)
}
}
for cardCode, pcCode := range poolPackageMap104 { //{"dx-30g-1y":400}加油包
if pcCode == poolPackageCode {
codesForPackage104 = append(codesForPackage104, cardCode)
}
}
g.Log().Info(ctx, "池套餐编码:", poolPackageCode, " 102套餐列表:", codesForPackage102, " 104加油包列表:", codesForPackage104)
// 调用计算流量池统计数据方法
poolStats, err := service.IotTSimCardInfo().CalculatePoolStatistics(ctx, &model.CalculatePoolStatisticsReq{
DeptId: deptId,
PoolPackageCode: poolPackageCode,
CardCodes102: codesForPackage102,
CardCodes104: codesForPackage104,
})
if err != nil {
return gerror.Wrap(err, "计算流量池统计数据失败,请稍后重试!")
}
// 生成流量池编号
flowPoolCode := fmt.Sprintf("%s%02d", flowPoolCodePrefix, i+1)
// 判断是否存在
// 只存储102套餐编码,不存储104加油包编码
if existingPool, ok := existingPoolMap[poolPackageCode]; ok {
keepPoolId = existingPool.Id
// 存在则更新
g.Log().Info(ctx, "准备更新流量池, poolId:", existingPool.Id, "poolPackageCode:", poolPackageCode)
g.Log().Info(ctx, "更新数据: PoolPackageFlowMb:", poolStats.PoolPackageFlowMb, "AddOnFlowMb:", poolStats.AddOnFlowMb, "TotalFlowMb:", poolStats.TotalFlowMb)
result, err := tx.Model(dao.TSimFlowPool.Table()).WherePri(existingPool.Id).Data(map[string]interface{}{
dao.TSimFlowPool.Columns().FlowPoolCode: flowPoolCode,
dao.TSimFlowPool.Columns().DeptId: deptId,
dao.TSimFlowPool.Columns().PackageCodes: gjson.New(codesForPackage102),
dao.TSimFlowPool.Columns().CardCount: poolStats.TotalCardCount,
dao.TSimFlowPool.Columns().CardFlowMb: poolStats.CardFlowMb,
dao.TSimFlowPool.Columns().PoolPackageFlowMb: poolStats.PoolPackageFlowMb,
dao.TSimFlowPool.Columns().AddOnFlowMb: poolStats.AddOnFlowMb,
dao.TSimFlowPool.Columns().TotalFlowMb: poolStats.TotalFlowMb,
dao.TSimFlowPool.Columns().UsedFlowMb: poolStats.TotalUsedFlowMb,
dao.TSimFlowPool.Columns().RemainFlowMb: poolStats.RemainFlowMb,
dao.TSimFlowPool.Columns().PoolStatus: poolStats.PoolStatus,
}).Update()
if err != nil {
return gerror.Wrap(err, "更新流量池失败,请稍后重试!")
}
affected, _ := result.RowsAffected()
g.Log().Info(ctx, "更新流量池成功, poolId:", existingPool.Id, "affected:", affected, "poolPackageCode:", poolPackageCode, "remainFlowMb:", poolStats.RemainFlowMb)
} else {
// 不存在则插入
result, err := tx.Model(dao.TSimFlowPool.Table()).Data(map[string]interface{}{
dao.TSimFlowPool.Columns().FlowPoolCode: flowPoolCode,
dao.TSimFlowPool.Columns().DeptId: deptId,
dao.TSimFlowPool.Columns().TenantId: contexts.GetTenantId(ctx),
dao.TSimFlowPool.Columns().CreatedDept: contexts.GetDeptId(ctx),
dao.TSimFlowPool.Columns().CreatedBy: contexts.GetUserId(ctx),
dao.TSimFlowPool.Columns().CreatedAt: now,
dao.TSimFlowPool.Columns().UpdatedAt: now,
dao.TSimFlowPool.Columns().PackageCodes: gjson.New(codesForPackage102),
dao.TSimFlowPool.Columns().PoolPackageCode: poolPackageCode,
dao.TSimFlowPool.Columns().CardCount: poolStats.TotalCardCount,
dao.TSimFlowPool.Columns().CardFlowMb: poolStats.CardFlowMb,
dao.TSimFlowPool.Columns().PoolPackageFlowMb: poolStats.PoolPackageFlowMb,
dao.TSimFlowPool.Columns().AddOnFlowMb: poolStats.AddOnFlowMb,
dao.TSimFlowPool.Columns().TotalFlowMb: poolStats.TotalFlowMb,
dao.TSimFlowPool.Columns().UsedFlowMb: poolStats.TotalUsedFlowMb,
dao.TSimFlowPool.Columns().RemainFlowMb: poolStats.RemainFlowMb,
dao.TSimFlowPool.Columns().PoolStatus: poolStats.PoolStatus,
}).Insert()
if err != nil {
return gerror.Wrap(err, "插入流量池失败,请稍后重试!")
}
keepPoolId, _ = result.LastInsertId()
g.Log().Info(ctx, "插入流量池成功, poolPackageCode:", poolPackageCode, "remainFlowMb:", poolStats.RemainFlowMb)
}
if keepPoolId > 0 && len(duplicatePoolIdsMap[poolPackageCode]) > 0 {
_, err = tx.Model(dao.TSimFlowPool.Table()).
WhereIn(dao.TSimFlowPool.Columns().Id, duplicatePoolIdsMap[poolPackageCode]).
Delete()
if err != nil {
return gerror.Wrap(err, "清理重复流量池失败,请稍后重试!")
}
}
if len(codesForPackage102) > 0 {
_, err = tx.Model(dao.TSimCardInfo.Table()).
Where(dao.TSimCardInfo.Columns().DeptId, deptId).
WhereIn(dao.TSimCardInfo.Columns().CurrentPackageCode, codesForPackage102).
Data(g.Map{
dao.TSimCardInfo.Columns().IsFlowPool: 1,
dao.TSimCardInfo.Columns().FlowPoolCode: flowPoolCode,
dao.TSimCardInfo.Columns().UpdatedBy: contexts.GetUserId(ctx),
dao.TSimCardInfo.Columns().UpdatedAt: now,
}).Update()
if err != nil {
return gerror.Wrap(err, "同步流量池卡归属失败,请稍后重试!")
}
}
}
return nil
})
if err != nil {
return err
}
g.Log().Info(ctx, "SyncPoolCard 同步完成, 共处理:", len(poolPackageCodes), "个流量池")
return nil
}
// GetCardsByPackageCodes 根据套餐编码列表获取卡列表
func (s *sIotTSimFlowPool) GetCardsByPackageCodes(ctx context.Context, req *model.GetCardsByPackageCodesParam) (list []*model.TSimCardInfoListModel, totalCount int, err error) {
deptId := contexts.GetDeptId(ctx)
g.Log().Info(ctx, "GetCardsByPackageCodes - deptId:", deptId, "FlowPoolCode:", req.FlowPoolCode)
// 从流量池表查询套餐编码列表和部门ID
type FlowPoolInfo struct {
DeptId int64 `json:"deptId" dc:"部门ID"`
PackageCodes *gjson.Json `json:"packageCodes" dc:"套餐编号列表"`
}
var flowPool FlowPoolInfo
// 先用 FlowPoolCode 查询
err = dao.TSimFlowPool.Ctx(ctx).
Where(dao.TSimFlowPool.Columns().FlowPoolCode, req.FlowPoolCode).
Fields(dao.TSimFlowPool.Columns().DeptId, dao.TSimFlowPool.Columns().PackageCodes).
Scan(&flowPool)
if err != nil || flowPool.PackageCodes == nil {
g.Log().Warning(ctx, "未找到流量池记录, FlowPoolCode:", req.FlowPoolCode, "err:", err)
return
}
g.Log().Info(ctx, "GetCardsByPackageCodes - flowPool.DeptId:", flowPool.DeptId)
// 解析 JSON 为字符串数组
if flowPool.PackageCodes != nil {
var packageCodes []string
_ = flowPool.PackageCodes.Scan(&packageCodes)
req.PackageCodes = packageCodes
g.Log().Info(ctx, "GetCardsByPackageCodes - packageCodes:", req.PackageCodes)
}
// 将流量池的 deptId 放到请求参数中
req.DeptId = flowPool.DeptId
return service.IotTSimCardInfo().GetCardsByPackageCodes(ctx, req)
}