Files
ai_dianshang/server/internal/service/product.go

858 lines
23 KiB
Go
Raw Normal View History

2025-11-17 14:11:46 +08:00
package service
import (
"dianshang/internal/model"
"dianshang/internal/repository"
"dianshang/pkg/utils"
"errors"
"fmt"
"strconv"
"time"
)
// ProductService 产品服务
type ProductService struct {
productRepo *repository.ProductRepository
userRepo *repository.UserRepository
}
// NewProductService 创建产品服务
func NewProductService(productRepo *repository.ProductRepository, userRepo *repository.UserRepository) *ProductService {
return &ProductService{
productRepo: productRepo,
userRepo: userRepo,
}
}
// GetProductList 获取产品列表(前端用户)
2025-11-28 15:18:10 +08:00
func (s *ProductService) GetProductList(page, pageSize int, categoryID uint, keyword string, minPrice, maxPrice float64, inStock *bool, sort, sortType string) ([]model.Product, *utils.Pagination, error) {
2025-11-17 14:11:46 +08:00
if page <= 0 {
page = 1
}
if pageSize <= 0 || pageSize > 100 {
pageSize = 20
}
offset := (page - 1) * pageSize
conditions := make(map[string]interface{})
if categoryID > 0 {
conditions["category_id"] = categoryID
}
if keyword != "" {
conditions["keyword"] = keyword
}
if minPrice > 0 {
conditions["min_price"] = minPrice
}
if maxPrice > 0 {
conditions["max_price"] = maxPrice
}
2025-11-28 15:18:10 +08:00
if inStock != nil {
conditions["in_stock"] = *inStock
}
2025-11-17 14:11:46 +08:00
if sort != "" {
conditions["sort"] = sort
}
if sortType != "" {
conditions["sort_type"] = sortType
}
products, total, err := s.productRepo.GetList(offset, pageSize, conditions)
if err != nil {
return nil, nil, err
}
pagination := utils.NewPagination(page, pageSize)
pagination.Total = total
return products, pagination, nil
}
// GetProductListForAdmin 获取产品列表(管理系统)
func (s *ProductService) GetProductListForAdmin(page, pageSize int, categoryID uint, keyword string, minPrice, maxPrice float64, sort, sortType, status, isHot, isNew, isRecommend string) ([]model.Product, *utils.Pagination, error) {
if page <= 0 {
page = 1
}
if pageSize <= 0 || pageSize > 100 {
pageSize = 20
}
offset := (page - 1) * pageSize
conditions := make(map[string]interface{})
if categoryID > 0 {
conditions["category_id"] = categoryID
}
if keyword != "" {
conditions["keyword"] = keyword
}
if minPrice > 0 {
conditions["min_price"] = minPrice
}
if maxPrice > 0 {
conditions["max_price"] = maxPrice
}
if sort != "" {
conditions["sort"] = sort
}
if sortType != "" {
conditions["sort_type"] = sortType
}
// 添加状态条件,支持获取所有状态的商品
if status != "" {
conditions["status"] = status
}
// 添加热门、新品、推荐筛选条件
if isHot != "" {
conditions["is_hot"] = isHot
}
if isNew != "" {
conditions["is_new"] = isNew
}
if isRecommend != "" {
conditions["is_recommend"] = isRecommend
}
products, total, err := s.productRepo.GetList(offset, pageSize, conditions)
if err != nil {
return nil, nil, err
}
pagination := utils.NewPagination(page, pageSize)
pagination.Total = total
return products, pagination, nil
}
// GetProductDetail 获取产品详情
func (s *ProductService) GetProductDetail(id uint) (*model.Product, error) {
return s.productRepo.GetByID(id)
}
// CreateProduct 创建产品
func (s *ProductService) CreateProduct(product *model.Product) error {
// 验证分类是否存在
2025-11-28 15:18:10 +08:00
if len(product.CategoryID) > 0 {
for _, catID := range product.CategoryID {
_, err := s.productRepo.GetCategoryByID(catID)
if err != nil {
return errors.New("分类ID" + strconv.Itoa(int(catID)) + "不存在")
}
2025-11-17 14:11:46 +08:00
}
}
return s.productRepo.Create(product)
}
// UpdateProduct 更新产品
func (s *ProductService) UpdateProduct(id uint, updates map[string]interface{}) error {
// 检查产品是否存在
_, err := s.productRepo.GetByID(id)
if err != nil {
return errors.New("产品不存在")
}
// 处理 detail_images 字段 - 确保正确转换为 JSONSlice 类型
if detailImages, ok := updates["detail_images"]; ok {
switch v := detailImages.(type) {
case []interface{}:
// 将 []interface{} 转换为 []string
var stringSlice []string
for _, item := range v {
if str, ok := item.(string); ok {
stringSlice = append(stringSlice, str)
}
}
updates["detail_images"] = model.JSONSlice(stringSlice)
case []string:
updates["detail_images"] = model.JSONSlice(v)
}
}
// 处理 images 字段 - 确保正确转换为 JSONSlice 类型
if images, ok := updates["images"]; ok {
switch v := images.(type) {
case []interface{}:
// 将 []interface{} 转换为 []string
var stringSlice []string
for _, item := range v {
if str, ok := item.(string); ok {
stringSlice = append(stringSlice, str)
}
}
updates["images"] = model.JSONSlice(stringSlice)
case []string:
updates["images"] = model.JSONSlice(v)
}
}
// 处理SKU数据
var skusData []interface{}
if skus, ok := updates["skus"]; ok {
skusData, _ = skus.([]interface{})
// 从updates中移除skus避免直接更新到Product表
delete(updates, "skus")
}
// 更新商品基本信息
if err := s.productRepo.Update(id, updates); err != nil {
return err
}
// 处理SKU数据
if len(skusData) > 0 {
if err := s.handleProductSKUs(id, skusData); err != nil {
return err
}
}
return nil
}
// handleProductSKUs 处理商品SKU数据
func (s *ProductService) handleProductSKUs(productID uint, skusData []interface{}) error {
// 获取当前商品的所有现有SKU
existingSKUs, err := s.productRepo.GetProductSKUs(productID)
if err != nil {
return err
}
// 收集前端发送的SKU ID列表
var submittedSKUIDs []uint
// 处理前端发送的SKU数据
for _, skuData := range skusData {
skuMap, ok := skuData.(map[string]interface{})
if !ok {
continue
}
// 创建SKU对象
sku := &model.ProductSKU{
ProductID: productID,
}
// 处理SKU字段
if skuCode, ok := skuMap["sku_code"].(string); ok {
sku.SKUCode = skuCode
}
if price, ok := skuMap["price"].(float64); ok {
sku.Price = price
}
if stock, ok := skuMap["stock"]; ok {
switch v := stock.(type) {
case float64:
sku.Stock = int(v)
case int:
sku.Stock = v
case string:
if stockInt, err := strconv.Atoi(v); err == nil {
sku.Stock = stockInt
}
}
}
// 处理spec_values
if specValues, ok := skuMap["spec_values"]; ok {
if specMap, ok := specValues.(map[string]interface{}); ok {
sku.SpecValues = model.JSONMap(specMap)
}
}
// 处理image字段
if image, ok := skuMap["image"].(string); ok {
sku.Image = image
}
// 检查是否是更新还是创建
var isUpdate bool
var skuIDValue uint
if skuID, ok := skuMap["id"]; ok && skuID != nil {
switch v := skuID.(type) {
case float64:
if v > 0 {
isUpdate = true
skuIDValue = uint(v)
submittedSKUIDs = append(submittedSKUIDs, skuIDValue)
}
case int:
if v > 0 {
isUpdate = true
skuIDValue = uint(v)
submittedSKUIDs = append(submittedSKUIDs, skuIDValue)
}
}
}
if isUpdate {
// 更新现有SKU
updates := make(map[string]interface{})
if sku.SKUCode != "" {
updates["sku_code"] = sku.SKUCode
}
updates["price"] = sku.Price
updates["stock"] = sku.Stock
// 直接传递JSONMap类型让GORM处理序列化
updates["spec_values"] = sku.SpecValues
// 添加image字段的更新
if sku.Image != "" {
updates["image"] = sku.Image
}
if err := s.productRepo.UpdateSKU(skuIDValue, updates); err != nil {
return err
}
} else {
// 创建新SKU - 确保不设置ID字段
sku.ID = 0 // 明确设置为0让数据库自动生成
if sku.SKUCode == "" {
// 生成默认SKU代码
sku.SKUCode = fmt.Sprintf("SKU-%d-%d", productID, time.Now().Unix())
}
if err := s.productRepo.CreateSKU(sku); err != nil {
return err
}
}
}
// 删除不在前端提交列表中的现有SKU
for _, existingSKU := range existingSKUs {
shouldDelete := true
for _, submittedID := range submittedSKUIDs {
if existingSKU.ID == submittedID {
shouldDelete = false
break
}
}
if shouldDelete {
if err := s.productRepo.DeleteSKU(existingSKU.ID); err != nil {
return fmt.Errorf("删除SKU失败 - SKU ID: %d, 错误: %v", existingSKU.ID, err)
}
}
}
// 处理完所有SKU后同步商品库存
if err := s.productRepo.SyncProductStockFromSKUs(productID); err != nil {
// 记录错误但不阻止操作
fmt.Printf("同步商品库存失败 - 商品ID: %d, 错误: %v\n", productID, err)
}
return nil
}
// DeleteProduct 删除产品
func (s *ProductService) DeleteProduct(id uint) error {
// 检查产品是否存在
_, err := s.productRepo.GetByID(id)
if err != nil {
return errors.New("产品不存在")
}
return s.productRepo.Delete(id)
}
// GetCategories 获取分类列表
func (s *ProductService) GetCategories() ([]model.Category, error) {
return s.productRepo.GetCategories()
}
2025-11-28 15:18:10 +08:00
// GetCategoriesByPlatform 根据平台获取分类列表
func (s *ProductService) GetCategoriesByPlatform(platform string) ([]model.Category, error) {
return s.productRepo.GetCategoriesByPlatform(platform)
}
2025-11-17 14:11:46 +08:00
// CreateCategory 创建分类
func (s *ProductService) CreateCategory(category *model.Category) error {
return s.productRepo.CreateCategory(category)
}
// UpdateCategory 更新分类
func (s *ProductService) UpdateCategory(id uint, updates map[string]interface{}) error {
// 检查分类是否存在
_, err := s.productRepo.GetCategoryByID(id)
if err != nil {
return errors.New("分类不存在")
}
return s.productRepo.UpdateCategory(id, updates)
}
// DeleteCategory 删除分类
func (s *ProductService) DeleteCategory(id uint) error {
// 检查分类是否存在
_, err := s.productRepo.GetCategoryByID(id)
if err != nil {
return errors.New("分类不存在")
}
// 检查分类下是否有商品
productCount, err := s.productRepo.CountProductsByCategory(id)
if err != nil {
return errors.New("检查分类商品数量失败")
}
if productCount > 0 {
return errors.New("该分类下还有商品,无法删除")
}
// 检查是否有子分类
var childCategories []model.Category
err = s.productRepo.GetDB().Where("parent_id = ?", id).Find(&childCategories).Error
if err != nil {
return errors.New("检查子分类失败")
}
if len(childCategories) > 0 {
return errors.New("该分类下还有子分类,请先删除子分类")
}
return s.productRepo.DeleteCategory(id)
}
// GetProductReviews 获取产品评价列表
func (s *ProductService) GetProductReviews(productID uint, page, pageSize int) ([]model.ProductReview, *utils.Pagination, error) {
if page <= 0 {
page = 1
}
if pageSize <= 0 || pageSize > 100 {
pageSize = 20
}
offset := (page - 1) * pageSize
reviews, total, err := s.productRepo.GetReviews(productID, offset, pageSize)
if err != nil {
return nil, nil, err
}
pagination := utils.NewPagination(page, pageSize)
pagination.Total = total
return reviews, pagination, nil
}
// CreateReview 创建评价
func (s *ProductService) CreateReview(userID uint, review *model.ProductReview) error {
// 检查用户是否存在
_, err := s.userRepo.GetByID(userID)
if err != nil {
return errors.New("用户不存在")
}
// 检查产品是否存在
_, err = s.productRepo.GetByID(review.ProductID)
if err != nil {
return errors.New("产品不存在")
}
// 检查是否已经评价过
if review.OrderID != nil {
existingReview, _ := s.productRepo.GetReviewByOrderID(userID, *review.OrderID)
if existingReview != nil {
return errors.New("已经评价过该商品")
}
}
review.UserID = userID
return s.productRepo.CreateReview(review)
}
// GetHotProducts 获取热门产品
func (s *ProductService) GetHotProducts(limit int) ([]model.Product, error) {
if limit <= 0 || limit > 50 {
limit = 10
}
return s.productRepo.GetHotProducts(limit)
}
// GetRecommendProducts 获取推荐产品
func (s *ProductService) GetRecommendProducts(limit int) ([]model.Product, error) {
if limit <= 0 || limit > 50 {
limit = 10
}
return s.productRepo.GetRecommendProducts(limit)
}
// SearchProducts 搜索产品(支持价格与排序)
func (s *ProductService) SearchProducts(keyword string, page, pageSize int, minPrice, maxPrice float64, sort, sortType string) ([]model.Product, *utils.Pagination, error) {
if keyword == "" {
return []model.Product{}, utils.NewPagination(page, pageSize), nil
}
2025-11-28 15:18:10 +08:00
// 搜索不筛选库存,传递 nil
return s.GetProductList(page, pageSize, 0, keyword, minPrice, maxPrice, nil, sort, sortType)
2025-11-17 14:11:46 +08:00
}
// UpdateStock 更新库存
func (s *ProductService) UpdateStock(id uint, quantity int) error {
// 检查产品是否存在
product, err := s.productRepo.GetByID(id)
if err != nil {
return errors.New("产品不存在")
}
// 检查库存是否足够(减库存时)
if quantity < 0 && product.Stock < -quantity {
return errors.New("库存不足")
}
return s.productRepo.UpdateStock(id, quantity)
}
// GetProductSKUs 获取产品SKU列表
func (s *ProductService) GetProductSKUs(productID uint) ([]model.ProductSKU, error) {
return s.productRepo.GetProductSKUs(productID)
}
// GetSKUByID 根据SKU ID获取SKU详情
func (s *ProductService) GetSKUByID(skuID uint) (*model.ProductSKU, error) {
return s.productRepo.GetSKUByID(skuID)
}
// GetProductTags 获取产品标签列表
func (s *ProductService) GetProductTags() ([]model.ProductTag, error) {
return s.productRepo.GetProductTags()
}
// GetStores 获取店铺列表
func (s *ProductService) GetStores() ([]model.Store, error) {
return s.productRepo.GetStores()
}
// GetStoreByID 根据ID获取店铺信息
func (s *ProductService) GetStoreByID(id uint) (*model.Store, error) {
return s.productRepo.GetStoreByID(id)
}
// GetProductReviewCount 获取产品评价统计
func (s *ProductService) GetProductReviewCount(productID uint) (map[string]interface{}, error) {
// 检查产品是否存在
_, err := s.productRepo.GetByID(productID)
if err != nil {
return nil, errors.New("产品不存在")
}
return s.productRepo.GetReviewCount(productID)
}
// GetProductStatistics 获取产品统计
func (s *ProductService) GetProductStatistics() (map[string]interface{}, error) {
// 使用ProductRepository的GetProductStatistics方法
return s.productRepo.GetProductStatistics()
}
// GetProductSalesRanking 获取产品销售排行
func (s *ProductService) GetProductSalesRanking(startDate, endDate, limit string) ([]map[string]interface{}, error) {
// 简化实现,返回基础排行数据
var results []map[string]interface{}
// 这里应该根据订单数据统计产品销量,暂时返回模拟数据
products, _, err := s.productRepo.GetList(0, 10, map[string]interface{}{"status": 1})
if err != nil {
return nil, err
}
for i, product := range products {
if i >= 10 { // 限制返回数量
break
}
results = append(results, map[string]interface{}{
"product_id": product.ID,
"product_name": product.Name,
"sales_count": 100 - i*5, // 模拟销量数据
"sales_amount": float64(1000 - i*50),
})
}
return results, nil
}
// GetCategorySalesRanking 获取分类销售排行
func (s *ProductService) GetCategorySalesRanking(startDate, endDate, limit string) ([]map[string]interface{}, error) {
// 解析limit参数
limitInt := 10 // 默认值
if limit != "" {
if parsedLimit, err := strconv.Atoi(limit); err == nil && parsedLimit > 0 {
limitInt = parsedLimit
}
}
// 如果没有提供日期范围使用最近30天
if startDate == "" || endDate == "" {
now := time.Now()
endDate = now.Format("2006-01-02")
startDate = now.AddDate(0, 0, -30).Format("2006-01-02")
}
// 使用真实的数据库查询
return s.productRepo.GetCategorySalesStatistics(startDate, endDate, limitInt)
}
// BatchUpdateProductStatus 批量更新商品状态
func (s *ProductService) BatchUpdateProductStatus(ids []uint, status int) error {
if len(ids) == 0 {
return errors.New("商品ID列表不能为空")
}
return s.productRepo.BatchUpdateStatus(ids, status)
}
// BatchUpdateProductPrice 批量更新商品价格
func (s *ProductService) BatchUpdateProductPrice(updates []map[string]interface{}) error {
if len(updates) == 0 {
return errors.New("更新数据不能为空")
}
return s.productRepo.BatchUpdatePrice(updates)
}
// BatchDeleteProducts 批量删除商品
func (s *ProductService) BatchDeleteProducts(ids []uint) error {
if len(ids) == 0 {
return errors.New("商品ID列表不能为空")
}
return s.productRepo.BatchDelete(ids)
}
// CreateProductSKU 创建商品SKU
func (s *ProductService) CreateProductSKU(sku *model.ProductSKU) error {
// 验证商品是否存在
_, err := s.productRepo.GetByID(sku.ProductID)
if err != nil {
return errors.New("商品不存在")
}
return s.productRepo.CreateSKU(sku)
}
// UpdateProductSKU 更新商品SKU
func (s *ProductService) UpdateProductSKU(id uint, updates map[string]interface{}) error {
// 检查SKU是否存在
_, err := s.productRepo.GetSKUByID(id)
if err != nil {
return errors.New("SKU不存在")
}
return s.productRepo.UpdateSKU(id, updates)
}
// DeleteProductSKU 删除商品SKU
func (s *ProductService) DeleteProductSKU(id uint) error {
// 检查SKU是否存在包括已软删除的
var sku model.ProductSKU
err := s.productRepo.GetDB().Where("id = ?", id).First(&sku).Error
if err != nil {
return errors.New("SKU不存在")
}
// 如果SKU已经被软删除直接返回成功
if sku.Status == 0 {
fmt.Printf("SKU ID %d 已经被软删除,无需重复操作\n", id)
return nil
}
// 检查SKU是否被订单引用
var count int64
err = s.productRepo.GetDB().Table("order_items").Where("sk_uid = ?", id).Count(&count).Error
if err != nil {
return fmt.Errorf("检查SKU引用关系失败: %v", err)
}
if count > 0 {
// 如果被订单引用,执行软删除
err = s.productRepo.DeleteSKU(id)
if err != nil {
return fmt.Errorf("删除SKU失败: %v", err)
}
// 软删除成功,记录日志但不返回错误
fmt.Printf("SKU ID %d 已被 %d 个订单引用,已执行软删除(设置为不可用状态)\n", id, count)
return nil
}
// 如果没有被引用,执行硬删除
err = s.productRepo.DeleteSKU(id)
if err != nil {
return fmt.Errorf("删除SKU失败: %v", err)
}
// 同步更新商品库存
if err := s.productRepo.SyncProductStockFromSKUs(sku.ProductID); err != nil {
// 记录错误但不阻止删除操作
fmt.Printf("同步商品库存失败 - 商品ID: %d, 错误: %v\n", sku.ProductID, err)
}
return nil
}
// GetProductImages 获取商品图片列表
func (s *ProductService) GetProductImages(productID uint) ([]model.ProductImage, error) {
return s.productRepo.GetProductImages(productID)
}
// CreateProductImage 创建商品图片
func (s *ProductService) CreateProductImage(image *model.ProductImage) error {
// 验证商品是否存在
_, err := s.productRepo.GetByID(image.ProductID)
if err != nil {
return errors.New("商品不存在")
}
return s.productRepo.CreateProductImage(image)
}
// UpdateProductImageSort 更新商品图片排序
func (s *ProductService) UpdateProductImageSort(id uint, sort int) error {
return s.productRepo.UpdateProductImageSort(id, sort)
}
// DeleteProductImage 删除商品图片
func (s *ProductService) DeleteProductImage(id uint) error {
return s.productRepo.DeleteProductImage(id)
}
// CreateProductSpec 创建商品规格
func (s *ProductService) CreateProductSpec(spec *model.ProductSpec) error {
// 验证商品是否存在
_, err := s.productRepo.GetByID(spec.ProductID)
if err != nil {
return errors.New("商品不存在")
}
return s.productRepo.CreateProductSpec(spec)
}
// UpdateProductSpec 更新商品规格
func (s *ProductService) UpdateProductSpec(id uint, updates map[string]interface{}) error {
return s.productRepo.UpdateProductSpec(id, updates)
}
// DeleteProductSpec 删除商品规格
func (s *ProductService) DeleteProductSpec(id uint) error {
return s.productRepo.DeleteProductSpec(id)
}
// GetProductSpecs 获取商品规格列表
func (s *ProductService) GetProductSpecs(productID uint) ([]model.ProductSpec, error) {
return s.productRepo.GetProductSpecs(productID)
}
// CreateProductTag 创建商品标签
func (s *ProductService) CreateProductTag(tag *model.ProductTag) error {
return s.productRepo.CreateProductTag(tag)
}
// UpdateProductTag 更新商品标签
func (s *ProductService) UpdateProductTag(id uint, updates map[string]interface{}) error {
return s.productRepo.UpdateProductTag(id, updates)
}
// DeleteProductTag 删除商品标签
func (s *ProductService) DeleteProductTag(id uint) error {
return s.productRepo.DeleteProductTag(id)
}
// AssignTagsToProduct 为商品分配标签
func (s *ProductService) AssignTagsToProduct(productID uint, tagIDs []uint) error {
// 验证商品是否存在
_, err := s.productRepo.GetByID(productID)
if err != nil {
return errors.New("商品不存在")
}
return s.productRepo.AssignTagsToProduct(productID, tagIDs)
}
// GetLowStockProducts 获取低库存商品
func (s *ProductService) GetLowStockProducts(threshold int) ([]model.Product, error) {
if threshold <= 0 {
threshold = 10 // 默认阈值
}
return s.productRepo.GetLowStockProducts(threshold)
}
// GetInventoryStatistics 获取库存统计
func (s *ProductService) GetInventoryStatistics() (map[string]interface{}, error) {
return s.productRepo.GetInventoryStatistics()
}
// ExportProducts 导出商品数据
func (s *ProductService) ExportProducts(conditions map[string]interface{}) ([]model.Product, error) {
return s.productRepo.GetProductsForExport(conditions)
}
// ImportProducts 导入商品数据
func (s *ProductService) ImportProducts(products []model.Product) (map[string]interface{}, error) {
successCount := 0
failCount := 0
var errors []string
for _, product := range products {
// 验证商品数据
if product.Name == "" {
errors = append(errors, "商品名称不能为空")
failCount++
continue
}
if product.Price <= 0 {
errors = append(errors, "商品价格必须大于0")
failCount++
continue
}
// 创建商品
err := s.productRepo.Create(&product)
if err != nil {
errors = append(errors, err.Error())
failCount++
} else {
successCount++
}
}
return map[string]interface{}{
"success_count": successCount,
"fail_count": failCount,
"errors": errors,
}, nil
}
// SyncProductStock 同步商品库存根据SKU库存计算
func (s *ProductService) SyncProductStock(productID uint) error {
return s.productRepo.SyncProductStockFromSKUs(productID)
}
// SyncAllProductsStock 同步所有商品库存
func (s *ProductService) SyncAllProductsStock() error {
// 获取所有有SKU的商品
products, _, err := s.productRepo.GetList(0, 0, map[string]interface{}{})
if err != nil {
return err
}
var syncErrors []string
for _, product := range products {
// 检查商品是否有SKU
skus, err := s.productRepo.GetProductSKUs(product.ID)
if err != nil {
continue
}
if len(skus) > 0 {
// 如果有SKU同步库存
err = s.productRepo.SyncProductStockFromSKUs(product.ID)
if err != nil {
syncErrors = append(syncErrors, fmt.Sprintf("商品ID %d 同步失败: %v", product.ID, err))
}
}
}
if len(syncErrors) > 0 {
return fmt.Errorf("部分商品同步失败: %v", syncErrors)
}
return nil
}