chore: 初始开源发布

iotlcm-openapi:对外 OpenAPI 网关(V3 接口 + 旧版兼容接口)。

- Go module:iotlcm-openapi → git.5iot.com/iotlcm-public/iotlcm-openapi(178 文件)
- 凭据与地址脱敏:JWT signingKey、MySQL DSN、Redis 口令、
  RabbitMQ DSN 全部改为 ${*} 占位;私网 IP → 文档地址段
- 7 处真实手机号 → 合法 11 位编造号
- 启动 banner 统一 IOTLCM 方块字 + 社区惯例署名
- 移除内部资产:CI 触发器
- Dockerfile 改用公共基础镜像,移除 GOPRIVATE 内网设置
- README 重写(原为 GoFrame 模板占位文案),补 Apache-2.0 LICENSE,
  LF 行尾 + .gitattributes
This commit is contained in:
MiFaZhan
2026-10-23 14:15:47 +08:00
commit 88dfe5c640
482 changed files with 34475 additions and 0 deletions
+189
View File
@@ -0,0 +1,189 @@
package common
import (
"context"
"strconv"
"strings"
"github.com/gogf/gf/v2/encoding/gjson"
"github.com/gogf/gf/v2/errors/gerror"
"git.5iot.com/iotlcm-public/iotlcm-openapi/internal/consts"
"git.5iot.com/iotlcm-public/iotlcm-openapi/internal/dao"
"git.5iot.com/iotlcm-public/iotlcm-openapi/internal/library/contexts"
"git.5iot.com/iotlcm-public/iotlcm-openapi/internal/model"
"git.5iot.com/iotlcm-public/iotlcm-openapi/internal/model/entity"
)
func (s *sCommon) loadSingleRenewResult(ctx context.Context, batchNo, packageID string, validity int) (*model.CommonSingleRenewRes, error) {
batch, err := s.loadBatchMain(ctx, batchNo, consts.BatchTypeRenew)
if err != nil {
return nil, err
}
detail, err := s.loadSingleBatchDetail(ctx, batchNo, consts.BatchTypeRenew)
if err != nil {
return nil, err
}
result := &model.CommonSingleRenewRes{
OrderId: "0",
OrderSn: strings.TrimSpace(batch.OrderSn),
Status: "success",
}
orderSn := result.OrderSn
if orderSn != "" {
var order entity.TOrder
orderColumns := dao.TOrder.Columns()
if err := dao.TOrder.Ctx(ctx).
Where(orderColumns.TenantId, batch.TenantId).
Where(orderColumns.OrderSn, orderSn).
Scan(&order); err == nil && order.Id > 0 {
result.OrderId = strconv.FormatInt(order.Id, 10)
result.Amount = order.TotalAmount
}
}
if detail.Snapshot != nil {
result.Iccid = firstSnapshotValue(detail.Snapshot, "iccid", "ICCID", "targetCode")
result.PlanName = firstSnapshotValue(detail.Snapshot, "packageName")
result.EffectiveType = firstSnapshotValue(detail.Snapshot, "effectiveType", "effectiveMode")
result.EffectiveDate = firstSnapshotValue(detail.Snapshot, "renewEffectiveTime")
result.ExpireDate = firstSnapshotValue(detail.Snapshot, "renewExpectedExpireTime", "cardFlowPkgEndAt")
if snapshotAmount := firstSnapshotFloat(detail.Snapshot, "amount", "totalAmount"); snapshotAmount > 0 {
result.Amount = snapshotAmount
}
}
if result.EffectiveType == "" {
result.EffectiveType = "immediate"
}
if detail.DetailStatus != consts.BatchDetailStatusSuccess {
result.Status = "failed"
result.ErrorCode = strings.TrimSpace(detail.ErrorCode)
result.ErrorMessage = strings.TrimSpace(detail.ErrorReason)
if result.ErrorCode == "" {
result.ErrorCode = "RENEW_FAILED"
}
if result.ErrorMessage == "" {
result.ErrorMessage = "续费失败,执行明细未记录具体原因"
}
}
return result, nil
}
func (s *sCommon) loadSingleTrafficCutoffResult(ctx context.Context, batchNo string) (*model.CommonSingleTrafficCutoffRes, error) {
detail, err := s.loadSingleBatchDetail(ctx, batchNo, consts.BatchTypeTrafficCutoffConfig)
if err != nil {
return nil, err
}
result := &model.CommonSingleTrafficCutoffRes{
Success: detail.DetailStatus == consts.BatchDetailStatusSuccess,
Iccid: strings.TrimSpace(detail.ItemId),
Message: "traffic cutoff configuration succeeded",
ErrorCode: strings.TrimSpace(detail.ErrorCode),
}
if detail.Snapshot != nil {
result.Iccid = firstSnapshotValue(detail.Snapshot, "iccid", "ICCID")
result.Msisdn = firstSnapshotValue(detail.Snapshot, "msisdn", "MSISDN")
result.Imsi = firstSnapshotValue(detail.Snapshot, "imsi", "IMSI")
result.TrafficCutoffStatus = firstSnapshotInt(detail.Snapshot, "trafficCutoffStatusAfter", "trafficCutoffStatus")
result.TrafficCutoffThreshold = firstSnapshotFloat(detail.Snapshot, "trafficCutoffThresholdAfter", "trafficCutoffThreshold")
result.TrafficCutoffThresholdUnit = firstSnapshotValue(detail.Snapshot, "thresholdUnit", "trafficCutoffThresholdUnit")
}
if result.TrafficCutoffStatus == 0 {
result.TrafficCutoffThreshold = 0
}
if result.TrafficCutoffThresholdUnit == "" {
result.TrafficCutoffThresholdUnit = "MB"
}
if !result.Success {
result.Message = strings.TrimSpace(detail.ErrorReason)
if result.Message == "" {
result.Message = "traffic cutoff configuration failed"
}
}
return result, nil
}
func (s *sCommon) loadSingleBatchDetail(ctx context.Context, batchNo string, batchType int) (*entity.BatchDetail, error) {
tenantID := strings.TrimSpace(contexts.GetTenantId(ctx))
deptID := contexts.GetAgentDeptId(ctx)
if tenantID == "" || deptID <= 0 {
return nil, gerror.New("request context is incomplete")
}
columns := dao.BatchDetail.Columns()
var detail entity.BatchDetail
err := dao.BatchDetail.Ctx(ctx).
Where(columns.TenantId, tenantID).
Where(columns.CreatedDept, deptID).
Where(columns.BatchNo, batchNo).
Where(columns.BatchType, batchType).
Scan(&detail)
if err != nil {
return nil, gerror.Wrap(err, "failed to query single-card execution result")
}
if detail.Id == 0 {
return nil, gerror.New("single-card execution result does not exist")
}
return &detail, nil
}
func (s *sCommon) loadBatchMain(ctx context.Context, batchNo string, batchType int) (*entity.BatchMain, error) {
tenantID := strings.TrimSpace(contexts.GetTenantId(ctx))
deptID := contexts.GetAgentDeptId(ctx)
if tenantID == "" || deptID <= 0 {
return nil, gerror.New("request context is incomplete")
}
columns := dao.BatchMain.Columns()
var batch entity.BatchMain
err := dao.BatchMain.Ctx(ctx).
Where(columns.TenantId, tenantID).
Where(columns.CreatedDept, deptID).
Where(columns.BatchNo, batchNo).
Where(columns.BatchType, batchType).
Scan(&batch)
if err != nil {
return nil, gerror.Wrap(err, "failed to query batch")
}
if batch.Id == 0 {
return nil, gerror.New("batch does not exist")
}
return &batch, nil
}
func firstSnapshotValue(snapshot *gjson.Json, keys ...string) string {
for _, key := range keys {
if value := strings.TrimSpace(snapshot.Get(key).String()); value != "" {
return value
}
}
return ""
}
func firstSnapshotInt(snapshot *gjson.Json, keys ...string) int {
for _, key := range keys {
if value := snapshot.Get(key); value != nil && value.String() != "" {
return value.Int()
}
}
return 0
}
func firstSnapshotFloat(snapshot *gjson.Json, keys ...string) float64 {
for _, key := range keys {
if value := snapshot.Get(key); value != nil && value.String() != "" {
return value.Float64()
}
}
return 0
}
func trafficCutoffStatusName(status int) string {
switch status {
case 1:
return "已开启"
case 2:
return "已关闭"
default:
return "删除"
}
}