Files
bj_power/bj_power_wms/internal/handler/excel.go
T
SunYF a2afd2f6dc feat: 五项目业务实现并对接完成
- MES(B): 工单/BOM/备料/工序字典/PLC下发/拧紧/扫码报工/半成品/AGV/追溯逻辑,WMS与海康RCS客户端,看板Redis缓存API(概览/设备/进度/报警/趋势)+SSE
- WMS(C): JWT滑动续签、Excel导入、盘点、内部API、种子数据、独立Postgres配置
- WMS客户端(E): Go网关8891反向代理+内嵌Vue3十页
- 工位终端(D): SQLite本地缓存+模拟拧紧源+内嵌Vue3页面
- Dashboard(A): 看板数据改接MES内部缓存API,SSE实时刷新+vite代理
- 清理各项目球形磨遗留代码,新增部署手册.md
2026-08-27 19:50:57 +08:00

131 lines
3.5 KiB
Go

package handler
import (
"fmt"
"net/http"
"strings"
"bj_power_wms/ent/inventorybatch"
"bj_power_wms/ent/material"
"bj_power_wms/internal/svc"
"github.com/xuri/excelize/v2"
)
// excelInboundHandler Excel 批量导入入库(结构件)
// 列头(第一行忽略):物料编码 | 批次号(可空,自动生成) | 数量 | 生产日期 | 供应商 | 区域
func excelInboundHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
if err := r.ParseMultipartForm(20 << 20); err != nil {
fail(w, http.StatusBadRequest, "文件上传失败: "+err.Error())
return
}
f, _, err := r.FormFile("file")
if err != nil {
fail(w, http.StatusBadRequest, "缺少 file 字段")
return
}
defer f.Close()
xl, err := excelize.OpenReader(f)
if err != nil {
fail(w, http.StatusBadRequest, "无法解析 Excel: "+err.Error())
return
}
defer xl.Close()
sheet := xl.GetSheetList()[0]
rows, err := xl.GetRows(sheet)
if err != nil {
fail(w, http.StatusBadRequest, "读取工作表失败: "+err.Error())
return
}
type resultRow struct {
Row int `json:"row"`
Code string `json:"materialCode"`
BatchNo string `json:"batchNo"`
Qty int `json:"quantity"`
Error string `json:"error,omitempty"`
}
results := []resultRow{}
success := 0
for i, row := range rows {
if i == 0 {
continue // 表头
}
cell := func(idx int) string {
if idx < len(row) {
return strings.TrimSpace(row[idx])
}
return ""
}
code := cell(0)
batchNo := cell(1)
qtyStr := cell(2)
qty := atoi(qtyStr, 0)
prodDate := cell(3)
supplier := cell(4)
zone := cell(5)
res := resultRow{Row: i + 1, Code: code, BatchNo: batchNo, Qty: qty}
switch {
case code == "":
res.Error = "物料编码为空"
case qty <= 0:
res.Error = "数量必须大于 0"
default:
m, err := ctx.EntClient.Material.Query().
Where(material.CodeEQ(code)).Only(ctx0())
if err != nil {
res.Error = "物料不存在"
} else if m.ManageMode == 2 {
res.Error = "精密件请使用 SN 扫码入库,不支持 Excel 导入"
} else {
if batchNo == "" {
batchNo = genBatchNo(code)
}
// 同批次追加或新建
existing, err := ctx.EntClient.InventoryBatch.Query().
Where(inventorybatch.BatchNoEQ(batchNo)).Only(ctx0())
if err == nil {
ctx.EntClient.InventoryBatch.UpdateOneID(existing.ID).
SetQuantity(existing.Quantity + qty).
SetNillableSupplier(strPtr(supplier)).
ExecX(ctx0())
} else {
ctx.EntClient.InventoryBatch.Create().
SetBatchNo(batchNo).
SetMaterialCode(code).
SetNillableMaterialName(strPtr(m.Name)).
SetQuantity(qty).
SetLockedQty(0).
SetNillableProductionDate(strPtr(prodDate)).
SetNillableSupplier(strPtr(supplier)).
SetQualityStatus("未检").
SetNillableZoneCode(strPtr(zone)).
SaveX(ctx0())
}
inboundNo := "IB" + nowStr() + fmt.Sprintf("%03d", i)
ctx.EntClient.InboundOrder.Create().
SetInboundNo(inboundNo).
SetNillableInboundType(strPtr("purchase")).
SetMaterialCode(code).
SetNillableMaterialName(strPtr(m.Name)).
SetManageMode(1).
SetNillableZoneCode(strPtr(zone)).
SetQuantity(qty).
SetOperator("excel-import").
SaveX(ctx0())
res.BatchNo = batchNo
success++
}
}
results = append(results, res)
}
ok(w, map[string]any{"total": len(results), "success": success, "rows": results})
}
}