chore: 初始开源发布
iotlcm-app:小程序端 + 用户端服务。 - app/:uni-app 小程序前端(基于 unibest,MIT) - 微信 AppID → YOUR_WX_APPID,uni-app AppID → __UNI__YOURAPPID - 内网后端地址 → admin.iotlcm.example.com - 应用标题与 unibest 模板 README 重写(保留上游致谢与 MIT 声明) - server/:GoFrame 用户端服务(基于 XiuAdmin,Apache-2.0) - module xiuadmin → git.5iot.com/iotlcm-public/iotlcm-app(360 文件) - 支付回调地址 → app.iotlcm.example.com,商户名与应用名泛化 - 真实手机号 → 合法 11 位编造号(保留号段前 3 位 + 后 4 位) - 依赖号码尾部的断言同步更新 - 补 server/LICENSE(Apache-2.0) - 移除内部资产:CI 触发器 - 补根 README,LF 行尾 + .gitattributes 已知:TestSysDept_RefreshDeptAncestors 在源仓同一提交上同样失败,属既有缺陷。
This commit is contained in:
@@ -0,0 +1,299 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/dao"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/library/contexts"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model"
|
||||
"git.5iot.com/iotlcm-public/iotlcm-app/internal/model/entity"
|
||||
|
||||
"github.com/gogf/gf/v2/database/gdb"
|
||||
"github.com/gogf/gf/v2/errors/gerror"
|
||||
"github.com/gogf/gf/v2/os/gtime"
|
||||
)
|
||||
|
||||
// 查询当前登录用户可见的套餐订购记录。
|
||||
func (s *sAppCard) PackageList(ctx context.Context, param *model.AppPackageListParam) (items []*model.AppPackageModel, total int, err error) {
|
||||
user, err := appCurrentUser(ctx)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
mod := s.visiblePackageModel(ctx, user)
|
||||
mod = s.applyPackageFilters(mod, param)
|
||||
if param.Page <= 0 {
|
||||
param.Page = 1
|
||||
}
|
||||
if param.PageSize <= 0 {
|
||||
param.PageSize = 10
|
||||
}
|
||||
|
||||
var rows []*appPackageQueryRow
|
||||
err = mod.OrderDesc(dao.TSimCardBindPkg.Table()+"."+dao.TSimCardBindPkg.Columns().Id).
|
||||
Page(param.Page, param.PageSize).
|
||||
ScanAndCount(&rows, &total, false)
|
||||
if err != nil {
|
||||
return nil, 0, gerror.Wrap(err, "查询套餐列表失败,请稍后重试")
|
||||
}
|
||||
|
||||
ownerType := s.ownerType(ctx, user)
|
||||
items = make([]*model.AppPackageModel, 0, len(rows))
|
||||
for _, row := range rows {
|
||||
items = append(items, s.packageRowToModel(row, ownerType, s.canOperatePackageRow(ctx, user, row)))
|
||||
}
|
||||
return items, total, nil
|
||||
}
|
||||
|
||||
// 查询卡片当前套餐详情。
|
||||
// 核心规则是“卡主表 current_package_code -> 套餐表 package_code”,订购记录只做详情兜底,
|
||||
// 避免卡主表与订购表不同步时前端报“套餐信息不存在”。
|
||||
func (s *sAppCard) PublicPackageDetail(ctx context.Context, param *model.AppPackagePublicDetailParam) (res *model.AppPackageModel, err error) {
|
||||
if param == nil {
|
||||
param = &model.AppPackagePublicDetailParam{}
|
||||
}
|
||||
card, err := s.findPublicCard(ctx, param.TenantId, param.CardValue)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if card == nil {
|
||||
return nil, gerror.New("卡信息不存在,请确认查询号码是否正确")
|
||||
}
|
||||
|
||||
ownerType := appCardOwnerPublic
|
||||
canBusiness := false
|
||||
displayCard := card
|
||||
if userId := contexts.GetUserId(ctx); userId > 0 {
|
||||
user, userErr := appCurrentUser(ctx)
|
||||
if userErr == nil && user != nil {
|
||||
visibleCard, visibleErr := s.findVisibleCard(ctx, user, param.CardValue)
|
||||
if visibleErr == nil && visibleCard != nil &&
|
||||
strings.TrimSpace(visibleCard.Iccid) == strings.TrimSpace(card.Iccid) &&
|
||||
strings.TrimSpace(visibleCard.TenantId) == strings.TrimSpace(card.TenantId) {
|
||||
displayCard = visibleCard
|
||||
ownerType = s.ownerType(ctx, user)
|
||||
canBusiness = s.canOperateCard(ctx, user, visibleCard)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var subscriptionBind *entity.TSimCardBindPkg
|
||||
if strings.TrimSpace(param.SubscriptionNo) != "" {
|
||||
subscriptionBind, err = s.loadRenewSubscription(ctx, card, param.SubscriptionNo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
latestBind, err := s.loadLatestRenewBind(ctx, card)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
candidates := appPublicPackageCandidates(displayCard, subscriptionBind, latestBind, param.PackageCode)
|
||||
if len(candidates) == 0 {
|
||||
return nil, gerror.New("当前卡片没有套餐信息")
|
||||
}
|
||||
|
||||
for _, packageCode := range candidates {
|
||||
pkg, err := s.loadPublicPackageInfo(ctx, card.TenantId, packageCode)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if pkg == nil {
|
||||
continue
|
||||
}
|
||||
result := s.publicPackageRowToModel(displayCard, pkg)
|
||||
result.OwnerType = ownerType
|
||||
result.CanBusiness = canBusiness
|
||||
if subscriptionBind != nil && strings.TrimSpace(subscriptionBind.PackageCode) == strings.TrimSpace(pkg.PackageCode) {
|
||||
appFillPublicPackageFromBind(result, subscriptionBind)
|
||||
} else if latestBind != nil && strings.TrimSpace(latestBind.PackageCode) == strings.TrimSpace(pkg.PackageCode) {
|
||||
appFillPublicPackageFromBind(result, latestBind)
|
||||
}
|
||||
if ownerType == appCardOwnerPublic {
|
||||
result = appSanitizePublicPackageModel(result, param.CardValue)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
return nil, gerror.Newf("当前卡片套餐编码 %s 未配置套餐信息", strings.Join(candidates, "、"))
|
||||
}
|
||||
|
||||
func appPublicPackageCandidates(card *appCardQueryRow, subscriptionBind *entity.TSimCardBindPkg, latestBind *entity.TSimCardBindPkg, requestedPackageCode string) []string {
|
||||
var candidates []string
|
||||
addCandidate := func(value string) {
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
return
|
||||
}
|
||||
for _, item := range candidates {
|
||||
if item == value {
|
||||
return
|
||||
}
|
||||
}
|
||||
candidates = append(candidates, value)
|
||||
}
|
||||
if subscriptionBind != nil {
|
||||
addCandidate(subscriptionBind.PackageCode)
|
||||
}
|
||||
currentPackageCode := ""
|
||||
if card != nil {
|
||||
currentPackageCode = appCardCurrentPackageCode(card)
|
||||
addCandidate(currentPackageCode)
|
||||
}
|
||||
if latestBind != nil && currentPackageCode == "" {
|
||||
addCandidate(latestBind.PackageCode)
|
||||
}
|
||||
if appPublicPackageCodeAllowed(requestedPackageCode, card, subscriptionBind, latestBind) {
|
||||
addCandidate(requestedPackageCode)
|
||||
}
|
||||
return candidates
|
||||
}
|
||||
|
||||
func appPublicPackageCodeAllowed(packageCode string, card *appCardQueryRow, subscriptionBind *entity.TSimCardBindPkg, latestBind *entity.TSimCardBindPkg) bool {
|
||||
packageCode = strings.TrimSpace(packageCode)
|
||||
if packageCode == "" {
|
||||
return false
|
||||
}
|
||||
if card != nil {
|
||||
currentPackageCode := appCardCurrentPackageCode(card)
|
||||
if currentPackageCode != "" {
|
||||
return currentPackageCode == packageCode
|
||||
}
|
||||
}
|
||||
if subscriptionBind != nil && strings.TrimSpace(subscriptionBind.PackageCode) == packageCode {
|
||||
return true
|
||||
}
|
||||
return latestBind != nil && strings.TrimSpace(latestBind.PackageCode) == packageCode
|
||||
}
|
||||
|
||||
func (s *sAppCard) loadPublicPackageInfo(ctx context.Context, tenantId string, packageCode string) (*appPublicPackageQueryRow, error) {
|
||||
packageTable := dao.TSimFlowPackageInfo.Table()
|
||||
categoryTable := dao.TSimPackageCategory.Table()
|
||||
packageColumns := dao.TSimFlowPackageInfo.Columns()
|
||||
categoryColumns := dao.TSimPackageCategory.Columns()
|
||||
|
||||
var pkg *appPublicPackageQueryRow
|
||||
err := dao.TSimFlowPackageInfo.Ctx(ctx).
|
||||
FieldsPrefix(packageTable, entity.TSimFlowPackageInfo{}).
|
||||
Fields(categoryTable+"."+categoryColumns.CategoryName+" as categoryName").
|
||||
LeftJoin(categoryTable, categoryTable+"."+categoryColumns.CategoryCode+"="+packageTable+"."+packageColumns.CategoryCode+" AND "+categoryTable+"."+categoryColumns.TenantId+"="+packageTable+"."+packageColumns.TenantId).
|
||||
Where(packageTable+"."+packageColumns.TenantId, strings.TrimSpace(tenantId)).
|
||||
Where(packageTable+"."+packageColumns.PackageCode, strings.TrimSpace(packageCode)).
|
||||
Limit(1).
|
||||
Scan(&pkg)
|
||||
if err != nil {
|
||||
return nil, gerror.Wrap(err, "查询套餐详情失败")
|
||||
}
|
||||
if pkg == nil || pkg.Id == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return pkg, nil
|
||||
}
|
||||
|
||||
func appFillPublicPackageFromBind(pkg *model.AppPackageModel, bind *entity.TSimCardBindPkg) {
|
||||
if pkg == nil || bind == nil {
|
||||
return
|
||||
}
|
||||
pkg.Id = bind.Id
|
||||
pkg.SubscriptionNo = bind.SubscriptionNo
|
||||
pkg.BusinessType = bind.BusinessType
|
||||
pkg.BusinessTypeName = appBusinessTypeName(bind.BusinessType)
|
||||
pkg.EffectiveStatus = bind.EffectiveStatus
|
||||
pkg.EffectiveTime = bind.EffectiveTime
|
||||
pkg.ExpireTime = bind.ExpectedExpireTime
|
||||
pkg.ValidText = appPackageValidText(bind.EffectiveTime, bind.ExpectedExpireTime)
|
||||
pkg.EffectText = appPackageEffectText(bind.EffectiveStatus)
|
||||
}
|
||||
|
||||
func (s *sAppCard) visiblePackageModel(ctx context.Context, user *entity.SysUser) *gdb.Model {
|
||||
cardTable := dao.TSimCardInfo.Table()
|
||||
bindPkgTable := dao.TSimCardBindPkg.Table()
|
||||
packageTable := dao.TSimFlowPackageInfo.Table()
|
||||
categoryTable := dao.TSimPackageCategory.Table()
|
||||
terminalBindTable := dao.TSimTerminal.Table()
|
||||
|
||||
mod := dao.TSimCardBindPkg.Ctx(ctx).
|
||||
FieldsPrefix(bindPkgTable, entity.TSimCardBindPkg{}).
|
||||
Fields(cardTable+"."+dao.TSimCardInfo.Columns().Id+" as cardId").
|
||||
Fields(cardTable+"."+dao.TSimCardInfo.Columns().DeptId+" as cardDeptId").
|
||||
Fields(cardTable+"."+dao.TSimCardInfo.Columns().Remark+" as cardRemark").
|
||||
Fields(packageTable+"."+dao.TSimFlowPackageInfo.Columns().PackageName+" as packageName").
|
||||
Fields(packageTable+"."+dao.TSimFlowPackageInfo.Columns().CategoryCode+" as categoryCode").
|
||||
Fields(packageTable+"."+dao.TSimFlowPackageInfo.Columns().FlowMb+" as flowMb").
|
||||
Fields(categoryTable+"."+dao.TSimPackageCategory.Columns().CategoryName+" as categoryName").
|
||||
LeftJoin(cardTable, cardTable+"."+dao.TSimCardInfo.Columns().Iccid+"="+bindPkgTable+"."+dao.TSimCardBindPkg.Columns().Iccid+" AND "+cardTable+"."+dao.TSimCardInfo.Columns().TenantId+"="+bindPkgTable+"."+dao.TSimCardBindPkg.Columns().TenantId).
|
||||
LeftJoin(packageTable, packageTable+"."+dao.TSimFlowPackageInfo.Columns().PackageCode+"="+bindPkgTable+"."+dao.TSimCardBindPkg.Columns().PackageCode+" AND "+packageTable+"."+dao.TSimFlowPackageInfo.Columns().TenantId+"="+bindPkgTable+"."+dao.TSimCardBindPkg.Columns().TenantId).
|
||||
LeftJoin(categoryTable, categoryTable+"."+dao.TSimPackageCategory.Columns().CategoryCode+"="+packageTable+"."+dao.TSimFlowPackageInfo.Columns().CategoryCode+" AND "+categoryTable+"."+dao.TSimPackageCategory.Columns().TenantId+"="+packageTable+"."+dao.TSimFlowPackageInfo.Columns().TenantId)
|
||||
|
||||
if s.isTerminalUser(ctx, user) {
|
||||
return mod.
|
||||
Fields(terminalBindTable+"."+dao.TSimTerminal.Columns().TerminalName+" as terminalName").
|
||||
InnerJoin(terminalBindTable, terminalBindTable+"."+dao.TSimTerminal.Columns().Iccid+"="+cardTable+"."+dao.TSimCardInfo.Columns().Iccid+" AND "+terminalBindTable+"."+dao.TSimTerminal.Columns().TenantId+"="+cardTable+"."+dao.TSimCardInfo.Columns().TenantId).
|
||||
Where(terminalBindTable+"."+dao.TSimTerminal.Columns().TenantId, user.TenantId).
|
||||
Where(terminalBindTable+"."+dao.TSimTerminal.Columns().TerminalId, user.UserId).
|
||||
Where(bindPkgTable+"."+dao.TSimCardBindPkg.Columns().TenantId, user.TenantId)
|
||||
}
|
||||
mod = mod.Where(bindPkgTable+"."+dao.TSimCardBindPkg.Columns().TenantId, user.TenantId)
|
||||
return appApplyEnterpriseDataScope(
|
||||
ctx,
|
||||
user,
|
||||
mod,
|
||||
cardTable+"."+dao.TSimCardInfo.Columns().DeptId,
|
||||
cardTable+"."+dao.TSimCardInfo.Columns().CreatedBy,
|
||||
func(legacyMod *gdb.Model) *gdb.Model {
|
||||
return appLegacyEnterpriseDeptAndSubScope(ctx, user, legacyMod, cardTable+"."+dao.TSimCardInfo.Columns().DeptId)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func (s *sAppCard) applyPackageFilters(mod *gdb.Model, param *model.AppPackageListParam) *gdb.Model {
|
||||
if strings.TrimSpace(param.Keyword) != "" {
|
||||
keyword := "%" + strings.TrimSpace(param.Keyword) + "%"
|
||||
mod = mod.Where(
|
||||
"("+dao.TSimCardBindPkg.Table()+"."+dao.TSimCardBindPkg.Columns().Iccid+" LIKE ? OR "+
|
||||
dao.TSimCardBindPkg.Table()+"."+dao.TSimCardBindPkg.Columns().Msisdn+" LIKE ? OR "+
|
||||
dao.TSimCardInfo.Table()+"."+dao.TSimCardInfo.Columns().Imsi+" LIKE ? OR "+
|
||||
dao.TSimCardInfo.Table()+"."+dao.TSimCardInfo.Columns().Imei+" LIKE ? OR "+
|
||||
dao.TSimCardBindPkg.Table()+"."+dao.TSimCardBindPkg.Columns().PackageCode+" LIKE ? OR "+
|
||||
dao.TSimFlowPackageInfo.Table()+"."+dao.TSimFlowPackageInfo.Columns().PackageName+" LIKE ? OR "+
|
||||
dao.TSimPackageCategory.Table()+"."+dao.TSimPackageCategory.Columns().CategoryName+" LIKE ? OR "+
|
||||
dao.TSimCardBindPkg.Table()+"."+dao.TSimCardBindPkg.Columns().Remark+" LIKE ?)",
|
||||
keyword, keyword, keyword, keyword, keyword, keyword, keyword, keyword,
|
||||
)
|
||||
}
|
||||
if strings.TrimSpace(param.CardValue) != "" {
|
||||
value := strings.TrimSpace(param.CardValue)
|
||||
mod = mod.Where(
|
||||
"("+dao.TSimCardBindPkg.Table()+"."+dao.TSimCardBindPkg.Columns().Iccid+" = ? OR "+
|
||||
dao.TSimCardBindPkg.Table()+"."+dao.TSimCardBindPkg.Columns().Msisdn+" = ? OR "+
|
||||
dao.TSimCardInfo.Table()+"."+dao.TSimCardInfo.Columns().Imsi+" = ? OR "+
|
||||
dao.TSimCardInfo.Table()+"."+dao.TSimCardInfo.Columns().Imei+" = ?)",
|
||||
value, value, value, value,
|
||||
)
|
||||
}
|
||||
if strings.TrimSpace(param.SubscriptionNo) != "" {
|
||||
mod = mod.Where(dao.TSimCardBindPkg.Table()+"."+dao.TSimCardBindPkg.Columns().SubscriptionNo, strings.TrimSpace(param.SubscriptionNo))
|
||||
}
|
||||
if strings.TrimSpace(param.PackageCode) != "" {
|
||||
mod = mod.Where(dao.TSimCardBindPkg.Table()+"."+dao.TSimCardBindPkg.Columns().PackageCode, strings.TrimSpace(param.PackageCode))
|
||||
}
|
||||
if strings.TrimSpace(param.CategoryCode) != "" {
|
||||
mod = mod.Where(dao.TSimFlowPackageInfo.Table()+"."+dao.TSimFlowPackageInfo.Columns().CategoryCode, strings.TrimSpace(param.CategoryCode))
|
||||
}
|
||||
switch strings.TrimSpace(param.Status) {
|
||||
case "active":
|
||||
mod = mod.Where(dao.TSimCardBindPkg.Table()+"."+dao.TSimCardBindPkg.Columns().EffectiveStatus, 1)
|
||||
case "expiring":
|
||||
mod = mod.Where(dao.TSimCardBindPkg.Table()+"."+dao.TSimCardBindPkg.Columns().ExpectedExpireTime+" IS NOT NULL").
|
||||
Where(dao.TSimCardBindPkg.Table()+"."+dao.TSimCardBindPkg.Columns().ExpectedExpireTime+" >= ?", gtime.Now()).
|
||||
Where(dao.TSimCardBindPkg.Table()+"."+dao.TSimCardBindPkg.Columns().ExpectedExpireTime+" <= ?", gtime.Now().AddDate(0, 0, 30))
|
||||
case "expired":
|
||||
mod = mod.Where(dao.TSimCardBindPkg.Table()+"."+dao.TSimCardBindPkg.Columns().EffectiveStatus, 2)
|
||||
case "pending":
|
||||
mod = mod.Where(dao.TSimCardBindPkg.Table()+"."+dao.TSimCardBindPkg.Columns().EffectiveStatus, 0)
|
||||
case "addon":
|
||||
mod = mod.WhereIn(dao.TSimCardBindPkg.Table()+"."+dao.TSimCardBindPkg.Columns().PackageType, []int{103, 104})
|
||||
}
|
||||
return mod
|
||||
}
|
||||
Reference in New Issue
Block a user