package repositories import ( "encoding/json" "log" "time" "github.com/niangaodev/art-code/config" "github.com/niangaodev/art-code/models" "gorm.io/gorm" ) // GetWorks 获取所有作品 func GetWorks() ([]models.Work, error) { var works []models.Work err := config.DB.Model(&models.Work{}). Where("deleted_at = ?", 0). Order("id DESC"). Find(&works).Error if err != nil { log.Printf("Error querying works: %v", err) return nil, err } return works, nil } // GetWorkByID 根据ID获取作品 func GetWorkByID(id string) (*models.Work, error) { var work models.Work err := config.DB.Model(&models.Work{}). Where("id = ? AND deleted_at = ?", id, 0). First(&work).Error if err != nil { if err == gorm.ErrRecordNotFound { return nil, nil } log.Printf("Error getting work by ID: %v", err) return nil, err } return &work, nil } // GetWorkTechStack 获取作品的技术栈 func GetWorkTechStack(workID string) ([]models.WorkTechStack, error) { var techStacks []models.WorkTechStack err := config.DB.Model(&models.WorkTechStack{}). Where("work_id = ? AND deleted_at = ?", workID, 0). Find(&techStacks).Error if err != nil { log.Printf("Error querying work tech stack: %v", err) return nil, err } return techStacks, nil } // GetWorkGallery 获取作品的图库 func GetWorkGallery(workID string) ([]models.WorkGallery, error) { var galleries []models.WorkGallery err := config.DB.Model(&models.WorkGallery{}). Where("work_id = ? AND deleted_at = ?", workID, 0). Order("sort_order"). Find(&galleries).Error if err != nil { log.Printf("Error querying work gallery: %v", err) return nil, err } return galleries, nil } // BuildWorkResponse 构建作品响应,包含关联数据 func BuildWorkResponse(work *models.Work) (*models.WorkResponse, error) { // 获取技术栈 techStacks, err := GetWorkTechStack(work.ID) if err != nil { return nil, err } // 按类别分组技术栈 techStackMap := make(map[string][]string) for _, ts := range techStacks { techStackMap[ts.Category] = append(techStackMap[ts.Category], ts.Item) } // 转换为前端期望的格式 var techStackResponse []map[string]interface{} for category, items := range techStackMap { techStackResponse = append(techStackResponse, map[string]interface{}{ "category": category, "items": items, }) } // 获取图库 galleries, err := GetWorkGallery(work.ID) if err != nil { return nil, err } // 提取图片URL var galleryImages []string for _, g := range galleries { galleryImages = append(galleryImages, g.ImageURL) } // 解析links JSON var linksData map[string]interface{} if work.Links != "" { if err := json.Unmarshal([]byte(work.Links), &linksData); err != nil { log.Printf("Error parsing links JSON: %v", err) linksData = map[string]interface{}{"live": ""} } } else { linksData = map[string]interface{}{"live": ""} } // 获取下一个作品ID nextWorkID, err := GetNextWorkID(work.ID) if err != nil { log.Printf("Error getting next work ID: %v", err) nextWorkID = "" } // 解析视频播放地址:优先 video_id,否则 hero_video videoURL := "" if work.VideoID != "" { videoURL = ResolveVideoURL(work.VideoID) } if videoURL == "" { videoURL = work.HeroVideo } return &models.WorkResponse{ ID: work.ID, Title: work.Title, Category: work.Category, Year: work.Year, HeroImg: work.HeroImg, HeroVideo: work.HeroVideo, VideoID: work.VideoID, VideoURL: videoURL, Desc: work.Description, TechStack: techStackResponse, Gallery: galleryImages, Links: linksData, Next: nextWorkID, }, nil } // GetNextWorkID 获取下一个作品ID(简单实现,实际可能需要更复杂的逻辑) func GetNextWorkID(currentID string) (string, error) { var ids []string err := config.DB.Model(&models.Work{}). Select("id"). Where("deleted_at = ?", 0). Pluck("id", &ids).Error if err != nil { return "", err } // 找到当前ID的索引 index := -1 for i, id := range ids { if id == currentID { index = i break } } // 如果没找到或者是最后一个,返回第一个 if index == -1 || index == len(ids)-1 { if len(ids) > 0 { return ids[0], nil } return "", nil } // 返回下一个 return ids[index+1], nil } // CreateWorkTechStack 创建作品技术栈 func CreateWorkTechStack(workID string, techStack []map[string]interface{}) error { // 先删除旧的技术栈(软删除) err := config.DB.Model(&models.WorkTechStack{}). Where("work_id = ?", workID). Update("deleted_at", time.Now().Unix()).Error if err != nil { log.Printf("Error deleting old tech stack: %v", err) } // 创建新的技术栈 for _, categoryData := range techStack { category, ok := categoryData["category"].(string) if !ok { continue } items, ok := categoryData["items"].([]interface{}) if !ok { continue } for _, item := range items { itemStr, ok := item.(string) if !ok || itemStr == "" { continue } techStackItem := models.WorkTechStack{ WorkID: workID, Category: category, Item: itemStr, CreatedAt: time.Now().Unix(), DeletedAt: 0, } if err := config.DB.Create(&techStackItem).Error; err != nil { log.Printf("Error creating tech stack item: %v", err) return err } } } return nil } // CreateWorkGallery 创建作品图库 func CreateWorkGallery(workID string, gallery []string) error { // 先删除旧的图库(软删除) err := config.DB.Model(&models.WorkGallery{}). Where("work_id = ?", workID). Update("deleted_at", time.Now().Unix()).Error if err != nil { log.Printf("Error deleting old gallery: %v", err) } // 创建新的图库 for index, imageURL := range gallery { if imageURL == "" { continue } galleryItem := models.WorkGallery{ WorkID: workID, ImageURL: imageURL, SortOrder: uint(index + 1), Description: "", CreatedAt: time.Now().Unix(), DeletedAt: 0, } if err := config.DB.Create(&galleryItem).Error; err != nil { log.Printf("Error creating gallery item: %v", err) return err } } return nil } // CreateWork 创建作品 func CreateWork(work *models.Work) error { err := config.DB.Create(work).Error if err != nil { log.Printf("Error creating work: %v", err) return err } return nil } // UpdateWork 更新作品 func UpdateWork(work *models.Work) error { updateData := map[string]interface{}{ "title": work.Title, "category": work.Category, "year": work.Year, "hero_img": work.HeroImg, "hero_video": work.HeroVideo, "video_id": work.VideoID, "description": work.Description, "is_featured": work.IsFeatured, "updated_at": time.Now().Unix(), } if work.Links != "" { updateData["links"] = work.Links } err := config.DB.Model(&models.Work{}). Where("id = ? AND deleted_at = ?", work.ID, 0). Updates(updateData).Error if err != nil { log.Printf("Error updating work: %v", err) return err } return nil } // DeleteWork 删除作品 (Soft Delete) func DeleteWork(id string) error { err := config.DB.Model(&models.Work{}). Where("id = ?", id). Update("deleted_at", time.Now().Unix()).Error if err != nil { log.Printf("Error deleting work: %v", err) return err } return nil } // GetAdminWorks 获取后台作品列表 (分页) func GetAdminWorks(page, pageSize int) ([]models.Work, int, error) { offset := (page - 1) * pageSize var works []models.Work var total int64 // 获取总数 err := config.DB.Model(&models.Work{}). Where("deleted_at = ?", 0). Count(&total).Error if err != nil { log.Printf("Error getting work count: %v", err) return nil, 0, err } // 获取列表 err = config.DB.Model(&models.Work{}). Where("deleted_at = ?", 0). Order("created_at DESC"). Limit(pageSize). Offset(offset). Find(&works).Error if err != nil { log.Printf("Error querying admin works: %v", err) return nil, 0, err } return works, int(total), nil } // BuildWorksResponse 构建作品列表响应 func BuildWorksResponse(works []models.Work) []models.WorkResponse { var responses []models.WorkResponse for _, work := range works { // 这里不包含详情,简化处理 responses = append(responses, models.WorkResponse{ ID: work.ID, Title: work.Title, Category: work.Category, Year: work.Year, HeroImg: work.HeroImg, Desc: work.Description, }) } return responses } // GetWorkCount 获取作品总数 func GetWorkCount() (int, error) { var count int64 err := config.DB.Model(&models.Work{}). Where("deleted_at = ?", 0). Count(&count).Error if err != nil { log.Printf("Error getting work count: %v", err) return 0, err } return int(count), nil }