package service import ( "fmt" "io" "mime/multipart" "os" "path/filepath" "strconv" "time" "github.com/rovina/zsp-backend/internal/model" "github.com/rovina/zsp-backend/internal/repository" ) type ContractService interface { CreateContract(contract *model.Contract, files []model.ContractFile) error SaveFiles(files []model.ContractFile) error BatchSaveFiles( basePath string, files []*multipart.FileHeader, ) (int, error) List(contractType string) ([]model.Contract, error) GetByID(id uint) (*model.Contract, error) Update(contract *model.Contract) error UpdateWithFiles(id uint, keepFileIDs []uint, newFileModels []model.ContractFile, form map[string]string) error Delete(id uint) error } type contractService struct { repo repository.ContractRepository } func NewContractService(repo repository.ContractRepository) (ContractService, error) { return &contractService{repo: repo}, nil } func (s *contractService) CreateContract(contract *model.Contract, files []model.ContractFile) error { return s.repo.CreateWithFiles(contract, files) } func (s *contractService) SaveFiles(files []model.ContractFile) error { return s.repo.CreateFiles(files) } func (s *contractService) BatchSaveFiles( basePath string, files []*multipart.FileHeader, ) (int, error) { // 相对路径根目录 root := filepath.Join("./data/contract/batch", basePath) if err := os.MkdirAll(root, os.ModePerm); err != nil { return 0, err } count := 0 for _, file := range files { filename := fmt.Sprintf("%d_%s", time.Now().UnixNano(), file.Filename) savePath := filepath.Join(root, filename) if err := saveUploadedFile(file, savePath); err != nil { return count, err } count++ } return count, nil } func (s *contractService) List(contractType string) ([]model.Contract, error) { return s.repo.List(contractType) } func (s *contractService) GetByID(id uint) (*model.Contract, error) { return s.repo.GetByID(id) } func (s *contractService) Update(contract *model.Contract) error { return s.repo.Update(contract) } func (s *contractService) UpdateWithFiles(id uint, keepFileIDs []uint, newFileModels []model.ContractFile, form map[string]string) error { contract, err := s.repo.GetByID(id) if err != nil { return err } // 更新合同元信息 get := func(k string) string { return form[k] } if v := get("name"); v != "" { contract.Name = v } if v := get("contractType"); v != "" { contract.ContractType = v } if v := get("contractCode"); v != "" { contract.ContractCode = v } if v := get("buyParty"); v != "" { contract.BuyParty = v } if v := get("sellParty"); v != "" { contract.SellParty = v } if v := get("commodity"); v != "" { contract.Commodity = v } if v := get("count"); v != "" { if n, e := strconv.ParseFloat(v, 64); e == nil { contract.Count = n } } if v := get("unitPrice"); v != "" { if n, e := strconv.ParseFloat(v, 64); e == nil { contract.UnitPrice = n } } if v := get("blNumber"); v != "" { contract.BLNumber = v } contract.DeliveryTime = get("deliveryTime") contract.PickUpTime = get("pickUpTime") contract.Packaging = get("packaging") contract.Remarks = get("remarks") contract.UpdateTime = time.Now() return s.repo.UpdateWithFiles(contract, keepFileIDs, newFileModels) } func (s *contractService) Delete(id uint) error { return s.repo.Delete(id) } func saveUploadedFile(file *multipart.FileHeader, dst string) error { src, err := file.Open() if err != nil { return err } defer src.Close() out, err := os.Create(dst) if err != nil { return err } defer out.Close() _, err = io.Copy(out, src) return err }