package customer import ( "backend/internal/dto" "backend/internal/model" "errors" "gorm.io/gorm" ) // CustomerService 客户业务逻辑层 // Logan.Li type CustomerService struct { db *gorm.DB } // NewCustomerService 创建 service 实例 // Logan.Li func NewCustomerService(db *gorm.DB) *CustomerService { return &CustomerService{db: db} } // List 分页查询客户(可按产品筛选通知群体) // Logan.Li func (s *CustomerService) List(page, pageSize int, keyword string, productID uint) ([]dto.CustomerResponse, int64, error) { var customers []model.Customer var total int64 query := s.db.Model(&model.Customer{}).Preload("Products") if keyword != "" { query = query.Where("name LIKE ? OR email LIKE ? OR company LIKE ?", "%"+keyword+"%", "%"+keyword+"%", "%"+keyword+"%") } if productID > 0 { sub := s.db.Table("customer_products").Select("customer_id").Where("product_id = ?", productID) query = query.Where("id IN (?)", sub) } query.Count(&total) if err := query.Order("created_at DESC"). Offset((page - 1) * pageSize).Limit(pageSize). Find(&customers).Error; err != nil { return nil, 0, err } results := make([]dto.CustomerResponse, 0, len(customers)) for _, c := range customers { results = append(results, toCustomerResponse(c)) } return results, total, nil } // GetAll 获取全部启用客户(下拉;可按产品过滤) // Logan.Li func (s *CustomerService) GetAll(productID uint) ([]dto.CustomerResponse, error) { var customers []model.Customer query := s.db.Where("status = ?", 1).Preload("Products") if productID > 0 { sub := s.db.Table("customer_products").Select("customer_id").Where("product_id = ?", productID) query = query.Where("id IN (?)", sub) } if err := query.Order("created_at DESC").Find(&customers).Error; err != nil { return nil, err } results := make([]dto.CustomerResponse, 0, len(customers)) for _, c := range customers { results = append(results, toCustomerResponse(c)) } return results, nil } // GetByID 根据 ID 获取客户 // Logan.Li func (s *CustomerService) GetByID(id uint) (*dto.CustomerResponse, error) { var customer model.Customer if err := s.db.Preload("Products").First(&customer, id).Error; err != nil { return nil, errors.New("客户不存在") } resp := toCustomerResponse(customer) return &resp, nil } // Create 创建客户并关联产品 // Logan.Li func (s *CustomerService) Create(req dto.CustomerCreate) (*dto.CustomerResponse, error) { status := 1 if req.Status != nil { status = *req.Status } customer := model.Customer{ Name: req.Name, Company: req.Company, Email: req.Email, Phone: req.Phone, Address: req.Address, Notes: req.Notes, Status: status, } if err := s.db.Create(&customer).Error; err != nil { return nil, errors.New("创建客户失败") } if err := s.replaceProducts(customer.ID, req.ProductIDs); err != nil { return nil, err } return s.GetByID(customer.ID) } // Update 更新客户及产品关联 // Logan.Li func (s *CustomerService) Update(id uint, req dto.CustomerUpdate) (*dto.CustomerResponse, error) { var customer model.Customer if err := s.db.First(&customer, id).Error; err != nil { return nil, errors.New("客户不存在") } updates := map[string]interface{}{ "name": req.Name, "company": req.Company, "email": req.Email, "phone": req.Phone, "address": req.Address, "notes": req.Notes, } if req.Status != nil { updates["status"] = *req.Status } if err := s.db.Model(&customer).Updates(updates).Error; err != nil { return nil, errors.New("更新客户失败") } // ProductIDs 为 nil 时不改关联;非 nil(含空切片)则全量替换 // Logan.Li if req.ProductIDs != nil { if err := s.replaceProducts(id, *req.ProductIDs); err != nil { return nil, err } } return s.GetByID(id) } // Delete 删除客户(软删除) // Logan.Li func (s *CustomerService) Delete(id uint) error { var count int64 s.db.Model(&model.License{}).Where("customer_id = ?", id).Count(&count) if count > 0 { return errors.New("该客户下存在 License,无法删除") } _ = s.db.Where("customer_id = ?", id).Delete(&model.CustomerProduct{}).Error return s.db.Delete(&model.Customer{}, id).Error } // UpdateStatus 切换客户状态 // Logan.Li func (s *CustomerService) UpdateStatus(id uint, status int) error { return s.db.Model(&model.Customer{}).Where("id = ?", id).Update("status", status).Error } // AttachProduct 为客户追加产品关联(发证/下单时调用,幂等) // Logan.Li func AttachProduct(db *gorm.DB, customerID, productID uint) error { if db == nil || customerID == 0 || productID == 0 { return nil } var n int64 db.Model(&model.CustomerProduct{}). Where("customer_id = ? AND product_id = ?", customerID, productID). Count(&n) if n > 0 { return nil } return db.Create(&model.CustomerProduct{CustomerID: customerID, ProductID: productID}).Error } // replaceProducts 全量替换客户产品关联 // Logan.Li func (s *CustomerService) replaceProducts(customerID uint, productIDs []uint) error { if err := s.db.Where("customer_id = ?", customerID).Delete(&model.CustomerProduct{}).Error; err != nil { return errors.New("更新产品关联失败") } seen := map[uint]struct{}{} for _, pid := range productIDs { if pid == 0 { continue } if _, ok := seen[pid]; ok { continue } seen[pid] = struct{}{} var product model.Product if err := s.db.First(&product, pid).Error; err != nil { return errors.New("关联产品不存在") } if err := s.db.Create(&model.CustomerProduct{CustomerID: customerID, ProductID: pid}).Error; err != nil { return errors.New("更新产品关联失败") } } return nil } // toCustomerResponse 模型转响应 DTO // Logan.Li func toCustomerResponse(c model.Customer) dto.CustomerResponse { products := make([]dto.CustomerProductBrief, 0, len(c.Products)) ids := make([]uint, 0, len(c.Products)) for _, p := range c.Products { products = append(products, dto.CustomerProductBrief{ID: p.ID, Name: p.Name, Code: p.Code}) ids = append(ids, p.ID) } return dto.CustomerResponse{ ID: c.ID, Name: c.Name, Company: c.Company, Email: c.Email, Phone: c.Phone, Address: c.Address, Notes: c.Notes, Status: c.Status, ProductIDs: ids, Products: products, CreatedAt: c.CreatedAt.Format("2006-01-02 15:04:05"), UpdatedAt: c.UpdatedAt.Format("2006-01-02 15:04:05"), } }