chore: 初始开源发布

iotlcm-admin-svr:管理后台服务。

- Go module:iotlcm → git.5iot.com/iotlcm-public/iotlcm-admin-svr(729 文件)
- 凭据与地址脱敏:JWT signingKey(含代码里的 MustGet 默认值)、
  MySQL DSN、Redis 口令、告警邮件发件人邮箱全部改为占位;
  私网 IP → 文档地址段;库名 xiujie_admin → iotlcm
- 真实手机号/邮箱 → 合法 11 位编造号 / example.com
- 移除内部资产:CI 触发器、过时 DDL(sql/db_iotlcm.sql)、
  私有依赖 go get 行、明文 registry 登录口令
- 启动 banner 统一 IOTLCM 方块字 + 社区惯例署名
- Dockerfile 改用公共基础镜像
- 拼错的 RADEME.md → README.md,README 重写
- 需要真实数据库的用例改为可用 IOTLCM_TEST_WITH_DB=1 显式启用
- 补 Apache-2.0 LICENSE,LF 行尾 + .gitattributes

数据库 schema 不随本仓发布(生产 DDL 已过时),README 已说明。
This commit is contained in:
MiFaZhan
2026-10-23 14:46:05 +08:00
commit 59eb34976a
1132 changed files with 138197 additions and 0 deletions
@@ -0,0 +1,194 @@
package renew
import (
"context"
"errors"
"strconv"
"strings"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/batchinput/excel"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model"
)
type ExcelSubmitOptions struct {
DurationYears int
PaymentMode string
}
func ExcelTemplateHeaders() []string {
return []string{
"ICCID",
"MSISDN",
"IMSI",
"续费年限",
"是否走线下",
}
}
func (o *ExcelSubmitOptions) ToBatchSubmitParam() *model.TSimCardRenewBatchSubmitParam {
if o == nil {
return &model.TSimCardRenewBatchSubmitParam{}
}
return &model.TSimCardRenewBatchSubmitParam{
DurationYears: o.DurationYears,
DurationMonths: o.DurationYears * 12,
PaymentMode: strings.TrimSpace(o.PaymentMode),
OfflineContractCompleted: true,
}
}
func (o *ExcelSubmitOptions) ToBatchConfirmParam(batchNo string) *model.TSimCardRenewBatchConfirmParam {
if o == nil {
return &model.TSimCardRenewBatchConfirmParam{BatchNo: strings.TrimSpace(batchNo), OfflineContractCompleted: true}
}
return &model.TSimCardRenewBatchConfirmParam{
BatchNo: strings.TrimSpace(batchNo),
DurationYears: o.DurationYears,
DurationMonths: o.DurationYears * 12,
PaymentMode: strings.TrimSpace(o.PaymentMode),
OfflineContractCompleted: true,
}
}
func ParseExcelFileRows(ctx context.Context, filePath string) ([]*Row, *ExcelSubmitOptions, error) {
parsedRows, err := excel.ParseFile(ctx, filePath, excel.ParseOptions{
RequiredHeaders: []string{"ICCID"},
SingleSheet: true,
})
if err != nil {
return nil, nil, err
}
rows := make([]*Row, 0, len(parsedRows))
var options *ExcelSubmitOptions
inconsistent := false
for _, parsed := range parsedRows {
row := &Row{
RowNo: parsed.RowNo,
Iccid: excel.Field(parsed, "ICCID"),
Msisdn: excel.Field(parsed, "MSISDN"),
Imsi: excel.Field(parsed, "IMSI"),
InputCode: firstNonEmpty(
excel.Field(parsed, "ICCID"),
excel.Field(parsed, "MSISDN"),
excel.Field(parsed, "IMSI"),
),
}
rowOptions, reasons := parseExcelSubmitOptions(parsed)
if len(reasons) > 0 {
row.AddReason(strings.Join(reasons, "; "))
rows = append(rows, row)
continue
}
if options == nil {
options = rowOptions
} else if !sameExcelSubmitOptions(options, rowOptions) {
row.AddReason("同一批续费年限和是否走线下必须一致")
inconsistent = true
}
rows = append(rows, row)
}
if inconsistent {
markRowsWithoutReason(rows, "同一批续费年限和是否走线下必须一致")
}
return rows, options, nil
}
func parseExcelSubmitOptions(row excel.ParsedRow) (*ExcelSubmitOptions, []string) {
var reasons []string
durationYears, err := parseExcelDurationYears(row)
if err != nil {
reasons = append(reasons, err.Error())
}
paymentMode, err := parseExcelPaymentMode(row)
if err != nil {
reasons = append(reasons, err.Error())
}
if len(reasons) > 0 {
return nil, reasons
}
return &ExcelSubmitOptions{
DurationYears: durationYears,
PaymentMode: paymentMode,
}, nil
}
func parseExcelDurationYears(row excel.ParsedRow) (int, error) {
if value := strings.TrimSpace(excelField(row, "续费年限(年)")); value != "" {
years, err := parsePositiveInt(value)
if err != nil {
return 0, errors.New("续费年限必须为正整数")
}
return years, nil
}
if value := strings.TrimSpace(excelField(row, "续费年限")); value != "" {
years, err := parsePositiveInt(value)
if err != nil {
return 0, errors.New("续费年限必须为正整数")
}
return years, nil
}
if value := strings.TrimSpace(excelField(row, "续费时长")); value != "" {
years, err := parsePositiveInt(value)
if err != nil {
return 0, errors.New("续费年限必须为正整数")
}
return years, nil
}
if value := strings.TrimSpace(excelField(row, "durationMonths")); value != "" {
years, err := parsePositiveInt(value)
if err != nil {
return 0, errors.New("续费年限必须为正整数")
}
return years, nil
}
return 0, errors.New("续费年限不能为空")
}
func parseExcelPaymentMode(row excel.ParsedRow) (string, error) {
value := strings.TrimSpace(excelField(row, "是否走线下"))
if value == "" {
value = strings.TrimSpace(excelField(row, "付款方式"))
}
if value == "" {
value = strings.TrimSpace(excelField(row, "paymentMode"))
}
if value == "" {
return "", nil
}
switch strings.ToLower(strings.TrimSpace(value)) {
case "1", "y", "yes", "true", "offline", "线下", "走线下", "是":
return "offline", nil
case "0", "n", "no", "false", "balance", "余额", "余额支付", "否":
return "balance", nil
default:
return "", errors.New("是否走线下格式不正确")
}
}
func excelField(row excel.ParsedRow, name string) string {
return excel.Field(row, name)
}
func parsePositiveInt(value string) (int, error) {
value = strings.TrimSpace(value)
if value == "" {
return 0, strconv.ErrSyntax
}
parsed, err := strconv.Atoi(value)
if err != nil || parsed <= 0 {
return 0, strconv.ErrSyntax
}
return parsed, nil
}
func sameExcelSubmitOptions(left, right *ExcelSubmitOptions) bool {
if left == nil || right == nil {
return false
}
return left.DurationYears == right.DurationYears && strings.TrimSpace(left.PaymentMode) == strings.TrimSpace(right.PaymentMode)
}