package service import ( "encoding/json" "errors" "gorm.io/gorm" "log" "math" "psi/database" "psi/models" "psi/models/request" "psi/models/response" "strconv" "time" ) type LogisticsService struct{} // GetLogisticsList 获取物流模板列表 func (s *LogisticsService) GetLogisticsList(req request.QueryLogisticsRequest, db ...*gorm.DB) ([]response.LogisticsResponse, int64, error) { databaseConn := database.OptionalDB(db...) if req.Page < 1 { req.Page = 1 } if req.PageSize < 1 || req.PageSize > 100 { req.PageSize = 20 } // 如果提供了 about_id,先查询该租户下的所有仓库 var warehouseIDs []int64 if req.AboutID > 0 { if err := databaseConn.Model(&models.Warehouse{}). Where("about_id = ? AND is_del = ?", req.AboutID, 0). Pluck("id", &warehouseIDs).Error; err != nil { return nil, 0, errors.New("查询仓库信息失败") } // 如果没有找到仓库,直接返回空结果 if len(warehouseIDs) == 0 { return []response.LogisticsResponse{}, 0, nil } } query := databaseConn.Model(&models.Logistics{}).Where("del_flag = ?", "0") // 如果有仓库ID列表,只查询这些仓库关联的物流模板 if len(warehouseIDs) > 0 { query = query.Where("id IN (?)", warehouseIDs) } if req.Keyword != "" { query = query.Where("template_name LIKE ? OR delivery_province LIKE ? OR delivery_city LIKE ?", "%"+req.Keyword+"%", "%"+req.Keyword+"%", "%"+req.Keyword+"%") } if req.Status != nil { query = query.Where("status = ?", *req.Status) } // === debug: 打印完整SQL === log.Printf("[GetLogisticsList] 请求参数 page=%d pageSize=%d keyword=%q about_id=%d", req.Page, req.PageSize, req.Keyword, req.AboutID) // === debug end === var total int64 if err := query.Debug().Count(&total).Error; err != nil { return nil, 0, errors.New("查询物流模板总数失败") } var logistics []models.Logistics offset := (req.Page - 1) * req.PageSize if err := query.Debug().Order("id DESC").Offset(offset).Limit(req.PageSize).Find(&logistics).Error; err != nil { return nil, 0, errors.New("查询物流模板列表失败") } responses := make([]response.LogisticsResponse, 0, len(logistics)) for _, item := range logistics { resp := response.ConvertLogisticsToResponse(item) responses = append(responses, resp) } return responses, total, nil } // GetLogisticsByID 获取物流模板详情 func (s *LogisticsService) GetLogisticsByID(id uint64, db ...*gorm.DB) (*response.LogisticsResponse, error) { databaseConn := database.OptionalDB(db...) var logistics models.Logistics if err := databaseConn.Where("id = ? AND del_flag = ?", id, "0").First(&logistics).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, errors.New("物流模板不存在") } return nil, errors.New("查询物流模板失败") } resp := response.ConvertLogisticsToResponse(logistics) return &resp, nil } // CreateLogistics 创建物流模板 // calculateMinFirstFee 从 shipping_range JSON 中计算最小首费 func (s *LogisticsService) calculateMinFirstFee(shippingRange string) (float64, error) { if shippingRange == "" { return 0, errors.New("运送范围不能为空") } var rangeMap map[string][]interface{} if err := json.Unmarshal([]byte(shippingRange), &rangeMap); err != nil { return 0, errors.New("运送范围格式错误") } minFee := math.MaxFloat64 found := false for _, values := range rangeMap { if len(values) < 2 { continue } // values[1] 是首费,可能是 string 或 float64 var fee float64 switch v := values[1].(type) { case float64: fee = v case string: var err error fee, err = strconv.ParseFloat(v, 64) if err != nil { continue } default: continue } if fee < minFee { minFee = fee } found = true } if !found { return 0, errors.New("运送范围数据格式错误") } return minFee, nil } // CreateLogistics 创建物流模板 func (s *LogisticsService) CreateLogistics(req request.CreateLogisticsRequest, db ...*gorm.DB) (uint64, error) { databaseConn := database.OptionalDB(db...) var count int64 databaseConn.Model(&models.Logistics{}). Where("template_name = ? AND del_flag = ?", req.TemplateName, "0"). Count(&count) if count > 0 { return 0, errors.New("物流模板名称已存在") } // 计算最小首费 minFirPrice, err := s.calculateMinFirstFee(req.ShippingRange) if err != nil { return 0, err } now := time.Now() logistics := models.Logistics{ TemplateName: req.TemplateName, DeliveryProvince: req.DeliveryProvince, DeliveryCity: req.DeliveryCity, DeliveryArea: req.DeliveryArea, DeliveryAddress: req.DeliveryAddress, PricingMethod: req.PricingMethod, Shipping: req.Shipping, FirWbv: req.FirWbv, FirPrice: minFirPrice, ContinueWbv: req.ContinueWbv, ContinuePrice: req.ContinuePrice, Contact: req.Contact, PhoneNumber: req.PhoneNumber, FullAddress: req.FullAddress, ShippingRange: req.ShippingRange, WarehouseId: req.WarehouseId, Remark: req.Remark, Status: req.Status, DelFlag: "0", CreateTime: &now, UpdateTime: &now, } if logistics.Status == "" { logistics.Status = "0" } if err := databaseConn.Create(&logistics).Error; err != nil { return 0, errors.New("创建物流模板失败") } return logistics.Id, nil } // UpdateLogistics 修改物流模板 func (s *LogisticsService) UpdateLogistics(req request.UpdateLogisticsRequest, db ...*gorm.DB) error { databaseConn := database.OptionalDB(db...) var logistics models.Logistics if err := databaseConn.Where("id = ? AND del_flag = ?", req.Id, "0").First(&logistics).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return errors.New("物流模板不存在") } return errors.New("查询物流模板失败") } var count int64 databaseConn.Model(&models.Logistics{}). Where("template_name = ? AND id != ? AND del_flag = ?", req.TemplateName, req.Id, "0"). Count(&count) if count > 0 { return errors.New("物流模板名称已存在") } // 计算最小首费 minFirPrice, err := s.calculateMinFirstFee(req.ShippingRange) if err != nil { return err } now := time.Now() updates := map[string]interface{}{ "template_name": req.TemplateName, "delivery_province": req.DeliveryProvince, "delivery_city": req.DeliveryCity, "delivery_area": req.DeliveryArea, "delivery_address": req.DeliveryAddress, "pricing_method": req.PricingMethod, "shipping": req.Shipping, "fir_wbv": req.FirWbv, "fir_price": minFirPrice, "continue_wbv": req.ContinueWbv, "continue_price": req.ContinuePrice, "contact": req.Contact, "phone_number": req.PhoneNumber, "full_address": req.FullAddress, "shipping_range": req.ShippingRange, "warehouse_id": req.WarehouseId, "remark": req.Remark, "status": req.Status, "update_time": &now, } if err := databaseConn.Model(&logistics).Updates(updates).Error; err != nil { return errors.New("更新物流模板失败") } return nil } // DeleteLogistics 删除物流模板 func (s *LogisticsService) DeleteLogistics(id uint64, db ...*gorm.DB) error { databaseConn := database.OptionalDB(db...) if id == 0 { return errors.New("物流模板ID不能为空") } var logistics models.Logistics if err := databaseConn.Where("id = ? AND del_flag = ?", id, "0").First(&logistics).Error; err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return errors.New("物流模板不存在") } return errors.New("查询物流模板失败") } now := time.Now() if err := databaseConn.Model(&logistics).Update("del_flag", "1").Update("update_time", &now).Error; err != nil { return errors.New("删除物流模板失败") } return nil }