Files
zsp-project/backend/internal/handler/contract_handler.go
2026-06-03 20:59:39 +08:00

483 lines
14 KiB
Go
Executable File

package handler
import (
"fmt"
"net/http"
"os"
"path/filepath"
"strconv"
"strings"
"time"
"github.com/gin-gonic/gin"
"github.com/rovina/zsp-backend/internal/model"
"github.com/rovina/zsp-backend/internal/service"
)
func (h *ContractHandler) List(c *gin.Context) {
contractType := c.Query("contractType")
list, err := h.service.List(contractType)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"success": true, "data": list})
}
func (h *ContractHandler) Get(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "invalid id"})
return
}
contract, err := h.service.GetByID(uint(id))
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"success": false, "message": "contract not found"})
return
}
c.JSON(http.StatusOK, gin.H{"success": true, "data": contract})
}
func (h *ContractHandler) Update(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "invalid id"})
return
}
existing, err := h.service.GetByID(uint(id))
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"success": false, "message": "contract not found"})
return
}
var body struct {
Name string `json:"name"`
ContractType string `json:"contractType"`
ContractCode string `json:"contractCode"`
BuyParty string `json:"buyParty"`
SellParty string `json:"sellParty"`
Commodity string `json:"commodity"`
Count float64 `json:"count"`
UnitPrice float64 `json:"unitPrice"`
BLNumber string `json:"blNumber"`
DeliveryTime string `json:"deliveryTime"`
PickUpTime string `json:"pickUpTime"`
Packaging string `json:"packaging"`
Remarks string `json:"remarks"`
}
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": err.Error()})
return
}
existing.Name = body.Name
existing.ContractType = body.ContractType
existing.ContractCode = body.ContractCode
existing.BuyParty = body.BuyParty
existing.SellParty = body.SellParty
existing.Commodity = body.Commodity
existing.Count = body.Count
existing.UnitPrice = body.UnitPrice
existing.BLNumber = body.BLNumber
existing.DeliveryTime = body.DeliveryTime
existing.PickUpTime = body.PickUpTime
existing.Packaging = body.Packaging
existing.Remarks = body.Remarks
existing.UpdateTime = time.Now()
if err := h.service.Update(existing); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"success": true, "message": "updated"})
}
func (h *ContractHandler) UpdateWithFiles(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "invalid id"})
return
}
form, err := c.MultipartForm()
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": err.Error()})
return
}
formMap := make(map[string]string)
for k, v := range form.Value {
if len(v) > 0 {
formMap[k] = v[0]
}
}
keepFileIds := parseUintSlice(formMap["keepFileIds"])
newFileHeaders := form.File["files"]
if len(keepFileIds) == 0 && len(newFileHeaders) == 0 {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "至少需要保留一个合同扫描件"})
return
}
var newFileModels []model.ContractFile
path := "./data/contract/uploads"
os.MkdirAll(path, os.ModePerm)
for _, fh := range newFileHeaders {
filename := fmt.Sprintf("%d_%s", time.Now().UnixNano(), fh.Filename)
savePath := filepath.Join(path, filename)
if err := c.SaveUploadedFile(fh, savePath); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
return
}
newFileModels = append(newFileModels, model.ContractFile{
Name: fh.Filename,
URL: "uploads/" + filename,
})
}
if len(keepFileIds)+len(newFileModels) == 0 {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "至少需要保留一个合同扫描件"})
return
}
if err := h.service.UpdateWithFiles(uint(id), keepFileIds, newFileModels, formMap); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"success": true, "message": "updated"})
}
func parseUintSlice(s string) []uint {
if s == "" {
return nil
}
parts := strings.Split(s, ",")
var result []uint
for _, p := range parts {
p = strings.TrimSpace(p)
if p == "" {
continue
}
if v, err := strconv.ParseUint(p, 10, 32); err == nil {
result = append(result, uint(v))
}
}
return result
}
func (h *ContractHandler) Delete(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "invalid id"})
return
}
if err := h.service.Delete(uint(id)); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"success": true, "message": "deleted"})
}
type ContractHandler struct {
service service.ContractService
folderService service.ContractFolderService
batchService service.ContractBatchService
}
func NewContractHandler(
service service.ContractService,
folderService service.ContractFolderService,
batchService service.ContractBatchService,
) *ContractHandler {
return &ContractHandler{
service: service,
folderService: folderService,
batchService: batchService,
}
}
func (h *ContractHandler) Upload(c *gin.Context) {
var contract model.Contract
contract.Name = c.PostForm("name")
contract.ContractType = c.PostForm("contractType")
contract.ContractCode = c.PostForm("contractCode")
contract.BuyParty = c.PostForm("buyParty")
contract.SellParty = c.PostForm("sellParty")
contract.Commodity = c.PostForm("commodity")
contract.BLNumber = c.PostForm("BLNumber")
contract.DeliveryTime = c.PostForm("deliveryTime")
contract.PickUpTime = c.PostForm("pickUpTime")
contract.Packaging = c.PostForm("packaging")
contract.Remarks = c.PostForm("remarks")
if countStr := c.PostForm("count"); countStr != "" {
if v, err := strconv.ParseFloat(countStr, 64); err == nil {
contract.Count = v
}
}
if priceStr := c.PostForm("unitPrice"); priceStr != "" {
if v, err := strconv.ParseFloat(priceStr, 64); err == nil {
contract.UnitPrice = v
}
}
contract.CreateTime = time.Now()
contract.UpdateTime = time.Now()
form, err := c.MultipartForm()
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": err.Error()})
return
}
files := form.File["files"]
if len(files) == 0 {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "no files"})
return
}
path := "./data/contract/uploads"
os.MkdirAll(path, os.ModePerm)
var fileModels []model.ContractFile
for _, file := range files {
filename := fmt.Sprintf("%d_%s", time.Now().UnixNano(), file.Filename)
savePath := filepath.Join(path, filename)
if err := c.SaveUploadedFile(file, savePath); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
return
}
fileModels = append(fileModels, model.ContractFile{
Name: file.Filename,
URL: "uploads/" + filename,
})
}
if err := h.service.CreateContract(&contract, fileModels); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"message": "upload success",
})
}
func (h *ContractHandler) BatchUpload(c *gin.Context) {
path := c.PostForm("path")
if path == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "path required"})
return
}
form, err := c.MultipartForm()
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid form"})
return
}
files := form.File["files"]
if len(files) == 0 {
c.JSON(http.StatusBadRequest, gin.H{"error": "no files"})
return
}
saved, err := h.service.BatchSaveFiles(path, files)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{
"success": true,
"count": saved,
})
}
// ========== 批量归档文件夹 ==========
func (h *ContractHandler) ListFolders(c *gin.Context) {
list, err := h.folderService.List()
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"success": true, "data": list})
}
func (h *ContractHandler) CreateFolder(c *gin.Context) {
var body struct {
Name string `json:"name" binding:"required"`
Description string `json:"description"`
}
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": err.Error()})
return
}
f, err := h.folderService.Create(body.Name, body.Description)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"success": true, "data": f})
}
func (h *ContractHandler) GetFolder(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "invalid id"})
return
}
f, err := h.folderService.GetByID(uint(id))
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"success": false, "message": "not found"})
return
}
c.JSON(http.StatusOK, gin.H{"success": true, "data": f})
}
func (h *ContractHandler) UpdateFolder(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "invalid id"})
return
}
var body struct {
Name string `json:"name" binding:"required"`
Description string `json:"description"`
}
if err := c.ShouldBindJSON(&body); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": err.Error()})
return
}
if err := h.folderService.Update(uint(id), body.Name, body.Description); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"success": true, "message": "updated"})
}
func (h *ContractHandler) DeleteFolder(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "invalid id"})
return
}
if err := h.folderService.Delete(uint(id)); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"success": true, "message": "deleted"})
}
// ========== 批量上传记录 ==========
func (h *ContractHandler) ListBatches(c *gin.Context) {
var folderID *uint
if idStr := c.Query("folderId"); idStr != "" {
if id, err := strconv.ParseUint(idStr, 10, 32); err == nil {
uid := uint(id)
folderID = &uid
}
}
list, err := h.batchService.List(folderID)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"success": true, "data": list})
}
func (h *ContractHandler) CreateBatch(c *gin.Context) {
folderIDStr := c.PostForm("folderId")
batchName := c.PostForm("batchName")
remark := c.PostForm("remark")
if folderIDStr == "" || batchName == "" {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "folderId and batchName required"})
return
}
folderID, err := strconv.ParseUint(folderIDStr, 10, 32)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "invalid folderId"})
return
}
form, err := c.MultipartForm()
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": err.Error()})
return
}
files := form.File["files"]
if len(files) == 0 {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "no files"})
return
}
path := "./data/contract/batch_archive"
os.MkdirAll(path, os.ModePerm)
var fileModels []model.ContractBatchFile
for _, file := range files {
filename := fmt.Sprintf("%d_%s", time.Now().UnixNano(), file.Filename)
savePath := filepath.Join(path, filename)
if err := c.SaveUploadedFile(file, savePath); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
return
}
fileModels = append(fileModels, model.ContractBatchFile{
Name: file.Filename,
URL: "batch_archive/" + filename,
FileSize: file.Size,
})
}
b, err := h.batchService.Create(uint(folderID), batchName, remark, fileModels)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"success": true, "data": b, "message": "created"})
}
func (h *ContractHandler) GetBatch(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "invalid id"})
return
}
b, err := h.batchService.GetByID(uint(id))
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"success": false, "message": "not found"})
return
}
c.JSON(http.StatusOK, gin.H{"success": true, "data": b})
}
func (h *ContractHandler) DeleteBatch(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 32)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"success": false, "message": "invalid id"})
return
}
if err := h.batchService.Delete(uint(id)); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"success": false, "message": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{"success": true, "message": "deleted"})
}