daShangDao_psiServer/service/location_import.go
2026-06-15 13:47:39 +08:00

141 lines
3.5 KiB
Go
Raw Permalink 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 service
import (
"fmt"
"strings"
"time"
"github.com/xuri/excelize/v2"
"gorm.io/gorm"
"psi/database"
"psi/models"
"psi/models/request"
)
// LocationImportService 库位导入服务
type LocationImportService struct{}
// LOCATION_IMPORT_COLUMNS 库位导入表格列仅1列
var LOCATION_IMPORT_COLUMNS = []string{"库位编码"}
// LocationImportResult 导入结果
type LocationImportResult struct {
SuccessCount int
FailCount int
FailList []string
Message string
}
// AddFail 添加失败记录
func (r *LocationImportResult) AddFail(reason string) {
r.FailCount++
r.FailList = append(r.FailList, reason)
}
// ParseLocationImportExcel 解析Excel文件为库位行数据
func (s *LocationImportService) ParseLocationImportExcel(fileBytes []byte) ([]request.LocationImportRow, error) {
f, err := excelize.OpenReader(strings.NewReader(string(fileBytes)))
if err != nil {
return nil, fmt.Errorf("无法打开Excel文件: %v", err)
}
defer f.Close()
rows, err := f.GetRows(f.GetSheetName(0))
if err != nil {
return nil, fmt.Errorf("读取Sheet失败: %v", err)
}
if len(rows) < 2 {
return nil, fmt.Errorf("Excel至少需要表头+1行数据")
}
// 校验表头
header := rows[0]
if len(header) < len(LOCATION_IMPORT_COLUMNS) {
return nil, fmt.Errorf("表头列数不足,期望%d列(库位编码),实际%d列", len(LOCATION_IMPORT_COLUMNS), len(header))
}
var result []request.LocationImportRow
for i := 1; i < len(rows); i++ {
row := rows[i]
code := strings.TrimSpace(getCell(row, 0))
if code == "" {
continue
}
result = append(result, request.LocationImportRow{Code: code})
}
return result, nil
}
// getCell 安全获取单元格值
func getCell(row []string, idx int) string {
if idx < len(row) {
return row[idx]
}
return ""
}
// ImportLocationsFromExcel 从Excel导入库位事务内批量创建
func (s *LocationImportService) ImportLocationsFromExcel(userID, warehouseID int64, rows []request.LocationImportRow) (*LocationImportResult, error) {
databaseConn, err := database.GetTenantDB(userID)
if err != nil {
return nil, fmt.Errorf("获取数据库连接失败: %v", err)
}
result := &LocationImportResult{}
err = databaseConn.Transaction(func(tx *gorm.DB) error {
now := time.Now().Unix()
for _, row := range rows {
code := strings.TrimSpace(row.Code)
if code == "" {
result.AddFail("库位编码为空")
continue
}
// 检查同仓库下是否已存在
var existing models.Location
if err := tx.Where("warehouse_id = ? AND code = ? AND is_del = ?", warehouseID, code, 0).First(&existing).Error; err == nil {
result.AddFail(fmt.Sprintf("%s: 库位已存在", code))
continue
}
loc := models.Location{
WarehouseID: warehouseID,
Code: code,
Type: 1, // 存储库位
Capacity: 255,
Sort: 0,
Status: 1, // 启用
CreatedAt: now,
UpdatedAt: now,
IsDel: 0,
}
if err := tx.Create(&loc).Error; err != nil {
result.AddFail(fmt.Sprintf("%s: 创建失败: %v", code, err))
continue
}
result.SuccessCount++
}
return nil
})
if err != nil {
return nil, fmt.Errorf("导入库位事务失败: %v", err)
}
if result.FailCount > 0 {
result.Message = fmt.Sprintf("成功 %d 条,失败 %d 条。失败明细: %s",
result.SuccessCount, result.FailCount, strings.Join(result.FailList, "; "))
} else {
result.Message = fmt.Sprintf("全部成功,共 %d 条", result.SuccessCount)
}
return result, nil
}