Files
iotlcm/server/internal/library/batchinput/excel/value.go
T
MiFaZhan 59eb34976a 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 已说明。
2026-10-23 14:48:30 +08:00

221 lines
4.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package excel
import (
"fmt"
"math"
"strconv"
"strings"
"time"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/os/gtime"
)
func NormalizeHeader(header string) string {
header = strings.ReplaceAll(header, "\uFEFF", "")
header = strings.TrimSpace(header)
header = strings.TrimRight(header, "**")
return strings.ToUpper(strings.TrimSpace(header))
}
func ParseString(value string) string {
return strings.TrimSpace(value)
}
func ParseInt(value string) (int, error) {
value = strings.TrimSpace(value)
if value == "" {
return 0, strconv.ErrSyntax
}
return strconv.Atoi(value)
}
func ParsePositiveInt(value string) (int, error) {
parsed, err := ParseInt(value)
if err != nil || parsed <= 0 {
return 0, strconv.ErrSyntax
}
return parsed, nil
}
func ParseNonNegativeInt(value string) (int, error) {
parsed, err := ParseInt(value)
if err != nil || parsed < 0 {
return 0, strconv.ErrSyntax
}
return parsed, nil
}
func ParseBool(value string) (bool, error) {
switch strings.ToLower(strings.TrimSpace(value)) {
case "1", "true", "yes", "y", "\u662f", "\u5df2\u5b8c\u6210", "\u5b8c\u6210":
return true, nil
case "0", "false", "no", "n", "\u5426", "\u672a\u5b8c\u6210":
return false, nil
default:
return false, strconv.ErrSyntax
}
}
func ParseDate(value string) (*gtime.Time, error) {
parsed, err := parseTimeValue(value)
if err != nil {
return nil, err
}
return gtime.NewFromTime(time.Date(
parsed.Year(),
time.Month(parsed.Month()),
parsed.Day(),
0,
0,
0,
0,
parsed.Location(),
)), nil
}
func ParseDateTime(value string) (*gtime.Time, error) {
return parseTimeValue(value)
}
func ParseAmount(value string) (float64, error) {
value = strings.TrimSpace(value)
if value == "" {
return 0, strconv.ErrSyntax
}
value = strings.ReplaceAll(value, ",", "")
parsed, err := strconv.ParseFloat(value, 64)
if err != nil || parsed < 0 {
return 0, strconv.ErrSyntax
}
return math.Round(parsed*100) / 100, nil
}
func normalizedValue(value string, typ ColumnType) (string, error) {
switch typ {
case "", ColumnTypeString:
return ParseString(value), nil
case ColumnTypeInt:
parsed, err := ParseInt(value)
if err != nil {
return "", err
}
return strconv.Itoa(parsed), nil
case ColumnTypePositiveInt:
parsed, err := ParsePositiveInt(value)
if err != nil {
return "", err
}
return strconv.Itoa(parsed), nil
case ColumnTypeNonNegativeInt:
parsed, err := ParseNonNegativeInt(value)
if err != nil {
return "", err
}
return strconv.Itoa(parsed), nil
case ColumnTypeBool:
parsed, err := ParseBool(value)
if err != nil {
return "", err
}
return strconv.FormatBool(parsed), nil
case ColumnTypeDate:
parsed, err := ParseDate(value)
if err != nil {
return "", err
}
return parsed.Format("Y-m-d"), nil
case ColumnTypeDateTime:
parsed, err := ParseDateTime(value)
if err != nil {
return "", err
}
return parsed.Format("Y-m-d H:i:s"), nil
case ColumnTypeAmount:
parsed, err := ParseAmount(value)
if err != nil {
return "", err
}
return fmt.Sprintf("%.2f", parsed), nil
default:
return "", gerror.Newf("unsupported column type: %s", typ)
}
}
func parseTimeValue(value string) (*gtime.Time, error) {
value = strings.TrimSpace(value)
if value == "" {
return nil, strconv.ErrSyntax
}
if parsed, ok := parseCompactTime(value); ok {
return parsed, nil
}
if parsed, ok := parseLayoutTime(value); ok {
return parsed, nil
}
parsed, err := gtime.StrToTime(value)
if err != nil || parsed == nil || parsed.IsZero() || parsed.Year() <= 0 {
if err != nil {
return nil, err
}
return nil, strconv.ErrSyntax
}
return parsed, nil
}
func parseCompactTime(value string) (*gtime.Time, bool) {
if !isDigits(value) {
return nil, false
}
layout := ""
switch len(value) {
case 8:
layout = "20060102"
case 12:
layout = "200601021504"
case 14:
layout = "20060102150405"
default:
return nil, false
}
parsed, err := time.ParseInLocation(layout, value, time.Local)
if err != nil {
return nil, false
}
return gtime.NewFromTime(parsed), true
}
func parseLayoutTime(value string) (*gtime.Time, bool) {
layouts := []string{
time.RFC3339,
time.RFC3339Nano,
"2006-1-2 15:04:05",
"2006-1-2 15:04",
"2006/1/2 15:04:05",
"2006/1/2 15:04",
"2006.1.2 15:04:05",
"2006.1.2 15:04",
"2006-1-2T15:04:05",
"2006-1-2T15:04",
"2006-1-2",
"2006/1/2",
"2006.1.2",
}
for _, layout := range layouts {
parsed, err := time.ParseInLocation(layout, value, time.Local)
if err == nil {
return gtime.NewFromTime(parsed), true
}
}
return nil, false
}
func isDigits(value string) bool {
for _, r := range value {
if r < '0' || r > '9' {
return false
}
}
return value != ""
}