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,344 @@
package outbound
import (
"context"
"fmt"
"io"
"strconv"
"strings"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/library/batchinput/excel"
"git.5iot.com/iotlcm-public/iotlcm-admin-svr/internal/model"
"github.com/gogf/gf/v2/os/gtime"
)
type ExcelParseResult struct {
Rows []*Row
SubmitParam *model.TSimCardOutboundSubmitParam
}
type consistencyValue struct {
rowNo int
normalized string
}
func excelHeaders() []string {
return []string{
"ICCID",
"MSISDN",
"IMSI",
"客户/机构",
"套餐",
"套餐开始时间",
"购买时长(年)",
"赠送时长(月)",
"订单金额",
"线下合同/销售/走账已完成",
"备注",
}
}
func excelRequiredHeaders() []string {
return []string{"ICCID"}
}
func ParseExcelFile(ctx context.Context, filePath string) (*ExcelParseResult, error) {
parsedRows, err := excel.ParseFile(ctx, filePath, excel.ParseOptions{
RequiredHeaders: excelRequiredHeaders(),
SingleSheet: true,
})
if err != nil {
return nil, err
}
return buildExcelParseResult(parsedRows), nil
}
func ParseExcelReader(ctx context.Context, reader io.Reader) (*ExcelParseResult, error) {
parsedRows, err := excel.ParseReader(ctx, reader, excel.ParseOptions{
RequiredHeaders: excelRequiredHeaders(),
SingleSheet: true,
})
if err != nil {
return nil, err
}
return buildExcelParseResult(parsedRows), nil
}
func buildExcelParseResult(parsedRows []excel.ParsedRow) *ExcelParseResult {
rows := make([]*Row, 0, len(parsedRows))
consistentCustomerAgentId := consistencyValue{}
consistentPackageCode := consistencyValue{}
consistentPackageBeginTime := consistencyValue{}
consistentDurationYears := consistencyValue{}
consistentDurationMonthPart := consistencyValue{}
consistentGiftDurationYears := consistencyValue{}
consistentGiftDurationMonthPart := consistencyValue{}
consistentAmount := consistencyValue{}
consistentOfflineContractCompleted := consistencyValue{}
consistentRemark := consistencyValue{}
for _, parsed := range parsedRows {
row := &Row{
RowNo: parsed.RowNo,
Iccid: excel.Field(parsed, "ICCID"),
Msisdn: excel.Field(parsed, "MSISDN"),
Imsi: excel.Field(parsed, "IMSI"),
// 出库不再配置测试期、沉默期;1 表示否。
HasTestPeriod: 1,
HasSilentPeriod: 1,
}
parseRequiredPositiveInt(row, excelField(parsed, "customerAgentId"), "客户/机构", func(value int) {
row.CustomerAgentId = int64(value)
checkConsistency(row, "客户/机构", strconv.FormatInt(row.CustomerAgentId, 10), &consistentCustomerAgentId)
})
row.PackageCode = strings.TrimSpace(excelField(parsed, "packageCode"))
if row.PackageCode == "" {
row.AddReason("套餐不能为空")
} else {
checkConsistency(row, "套餐", row.PackageCode, &consistentPackageCode)
}
parseRequiredDateTime(row, excelField(parsed, "packageBeginTime"), "套餐开始时间", func(value *gtime.Time) {
row.PackageBeginTime = value
checkConsistency(row, "套餐开始时间", formatTime(value), &consistentPackageBeginTime)
})
parseExcelDuration(row, parsed, &consistentDurationYears, &consistentDurationMonthPart)
parseExcelGiftDuration(row, parsed, &consistentGiftDurationYears, &consistentGiftDurationMonthPart)
parseRequiredAmount(row, excelField(parsed, "amount"), func(value string) {
row.Amount = value
checkConsistency(row, "订单金额", value, &consistentAmount)
})
parseRequiredBool(row, excelField(parsed, "offlineContractCompleted"), "线下合同/销售/走账已完成", func(value bool) {
row.OfflineContractCompleted = value
checkConsistency(row, "线下合同/销售/走账已完成", strconv.FormatBool(value), &consistentOfflineContractCompleted)
})
row.Remark = strings.TrimSpace(excelField(parsed, "remark"))
checkConsistency(row, "备注", row.Remark, &consistentRemark)
rows = append(rows, row)
}
result := &ExcelParseResult{Rows: rows}
if hasInvalidRows(rows) {
return result
}
result.SubmitParam = &model.TSimCardOutboundSubmitParam{
CustomerAgentId: rows[0].CustomerAgentId,
PackageCode: rows[0].PackageCode,
PackageBeginTime: rows[0].PackageBeginTime,
DurationYears: rows[0].DurationYears,
DurationMonthPart: rows[0].DurationMonthPart,
DurationMonths: rows[0].DurationMonths,
GiftDurationYears: rows[0].GiftDurationYears,
GiftDurationMonthPart: rows[0].GiftDurationMonthPart,
GiftDurationMonths: rows[0].GiftDurationMonths,
HasTestPeriod: 1,
HasSilentPeriod: 1,
Amount: rows[0].Amount,
OfflineContractCompleted: rows[0].OfflineContractCompleted,
Remark: rows[0].Remark,
BuyerNote: rows[0].Remark,
AdminNote: rows[0].Remark,
}
return result
}
func excelField(row excel.ParsedRow, name string) string {
for _, alias := range excelFieldAliases(name) {
if value := strings.TrimSpace(excel.Field(row, alias)); value != "" {
return value
}
}
return ""
}
func excelFieldAliases(name string) []string {
switch name {
case "customerAgentId":
return []string{"客户/机构", "客户/机构ID", "客户ID", "customerAgentId"}
case "packageCode":
return []string{"套餐", "套餐编码", "packageCode"}
case "packageBeginTime":
return []string{"套餐开始时间", "packageBeginTime"}
case "durationYears":
return []string{"购买时长(年)", "套餐购买时长(年)", "durationYears"}
case "durationMonthPart":
return []string{"购买时长(月)", "套餐购买时长(月)", "durationMonthPart"}
case "durationMonths":
return []string{"durationMonths"}
case "giftDurationYears":
return []string{"赠送时长(年)", "giftDurationYears"}
case "giftDurationMonthPart":
return []string{"赠送时长(月)", "giftDurationMonthPart"}
case "giftDurationMonths":
return []string{"giftDurationMonths"}
case "amount":
return []string{"订单金额", "amount"}
case "offlineContractCompleted":
return []string{"线下合同/销售/走账已完成", "是否走线下", "offlineContractCompleted"}
case "remark":
return []string{"备注", "remark", "buyerNote", "adminNote"}
default:
return []string{name}
}
}
func parseExcelDuration(row *Row, parsed excel.ParsedRow, consistentYears, consistentMonthPart *consistencyValue) {
yearsRaw := excelField(parsed, "durationYears")
monthPartRaw := excelField(parsed, "durationMonthPart")
if strings.TrimSpace(yearsRaw) != "" || strings.TrimSpace(monthPartRaw) != "" {
parseOptionalNonNegativeInt(row, yearsRaw, "购买时长(年)", 0, func(value int) {
row.DurationYears = value
checkConsistency(row, "购买时长(年)", strconv.Itoa(value), consistentYears)
})
parseOptionalMonthPart(row, monthPartRaw, "购买时长(月)", func(value int) {
row.DurationMonthPart = value
checkConsistency(row, "购买时长(月)", strconv.Itoa(value), consistentMonthPart)
})
row.DurationMonths = row.DurationYears*12 + row.DurationMonthPart
if row.DurationMonths <= 0 {
row.AddReason("购买时长必须大于0")
}
return
}
parseRequiredPositiveInt(row, excelField(parsed, "durationMonths"), "套餐购买时长(月)", func(value int) {
row.DurationMonths = value
row.DurationYears = value / 12
row.DurationMonthPart = value % 12
checkConsistency(row, "套餐购买时长(月)", strconv.Itoa(value), consistentMonthPart)
})
}
func parseExcelGiftDuration(row *Row, parsed excel.ParsedRow, consistentYears, consistentMonthPart *consistencyValue) {
yearsRaw := excelField(parsed, "giftDurationYears")
monthPartRaw := excelField(parsed, "giftDurationMonthPart")
if strings.TrimSpace(yearsRaw) != "" || strings.TrimSpace(monthPartRaw) != "" {
parseOptionalNonNegativeInt(row, yearsRaw, "赠送时长(年)", 0, func(value int) {
row.GiftDurationYears = value
checkConsistency(row, "赠送时长(年)", strconv.Itoa(value), consistentYears)
})
parseOptionalMonthPart(row, monthPartRaw, "赠送时长(月)", func(value int) {
row.GiftDurationMonthPart = value
checkConsistency(row, "赠送时长(月)", strconv.Itoa(value), consistentMonthPart)
})
row.GiftDurationMonths = row.GiftDurationYears*12 + row.GiftDurationMonthPart
return
}
parseOptionalNonNegativeInt(row, excelField(parsed, "giftDurationMonths"), "赠送时长(月)", 0, func(value int) {
row.GiftDurationMonths = value
row.GiftDurationYears = value / 12
row.GiftDurationMonthPart = value % 12
checkConsistency(row, "赠送时长(月)", strconv.Itoa(value), consistentMonthPart)
})
}
func checkConsistency(row *Row, field, normalized string, base *consistencyValue) {
if row == nil || !row.Valid() {
return
}
if base.rowNo == 0 {
base.rowNo = row.RowNo
base.normalized = normalized
return
}
if base.normalized != normalized {
row.AddReason(fmt.Sprintf("%s与第%d行不一致", field, base.rowNo))
}
}
func parseRequiredPositiveInt(row *Row, raw, field string, apply func(value int)) {
raw = strings.TrimSpace(raw)
if raw == "" {
row.AddReason(field + "不能为空")
return
}
value, err := excel.ParsePositiveInt(raw)
if err != nil {
row.AddReason(field + "格式不正确")
return
}
apply(value)
}
func parseOptionalNonNegativeInt(row *Row, raw, field string, defaultValue int, apply func(value int)) {
raw = strings.TrimSpace(raw)
if raw == "" {
apply(defaultValue)
return
}
value, err := excel.ParseNonNegativeInt(raw)
if err != nil {
row.AddReason(field + "格式不正确")
return
}
apply(value)
}
func parseOptionalMonthPart(row *Row, raw, field string, apply func(value int)) {
parseOptionalNonNegativeInt(row, raw, field, 0, func(value int) {
if value > 11 {
row.AddReason(field + "必须在0到11之间")
return
}
apply(value)
})
}
func parseOptionalAmount(row *Row, raw string, apply func(value string)) {
raw = strings.TrimSpace(raw)
if raw == "" {
apply("")
return
}
value, err := excel.ParseAmount(raw)
if err != nil {
row.AddReason("订单金额格式不正确")
return
}
apply(fmt.Sprintf("%.2f", value))
}
func parseRequiredAmount(row *Row, raw string, apply func(value string)) {
raw = strings.TrimSpace(raw)
if raw == "" {
row.AddReason("订单金额不能为空")
return
}
parseOptionalAmount(row, raw, apply)
}
func parseRequiredBool(row *Row, raw, field string, apply func(value bool)) {
raw = strings.TrimSpace(raw)
if raw == "" {
row.AddReason(field + "不能为空")
return
}
value, err := excel.ParseBool(raw)
if err != nil {
row.AddReason(field + "格式不正确")
return
}
apply(value)
}
func parseRequiredDateTime(row *Row, raw, field string, apply func(value *gtime.Time)) {
raw = strings.TrimSpace(raw)
if raw == "" {
row.AddReason(field + "不能为空")
return
}
value, err := excel.ParseDateTime(raw)
if err != nil {
row.AddReason(field + "格式不正确")
return
}
apply(value)
}