Files
nl-blogs/server/repositories/work_repository.go
2026-01-16 17:03:34 +08:00

383 lines
8.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package repositories
import (
"database/sql"
"log"
"time"
"github.com/niangaodev/art-code/config"
"github.com/niangaodev/art-code/models"
)
// GetWorks 获取所有作品
func GetWorks() ([]models.Work, error) {
query := "SELECT id, title, category, year, hero_img, description, is_featured, created_at, updated_at, deleted_at FROM works WHERE deleted_at = 0"
rows, err := config.DB.Query(query)
if err != nil {
log.Printf("Error querying works: %v", err)
return nil, err
}
defer rows.Close()
var works []models.Work
for rows.Next() {
var work models.Work
if err := rows.Scan(
&work.ID,
&work.Title,
&work.Category,
&work.Year,
&work.HeroImg,
&work.Description,
&work.IsFeatured,
&work.CreatedAt,
&work.UpdatedAt,
&work.DeletedAt,
); err != nil {
log.Printf("Error scanning work: %v", err)
continue
}
works = append(works, work)
}
return works, nil
}
// GetWorkByID 根据ID获取作品
func GetWorkByID(id string) (*models.Work, error) {
query := "SELECT id, title, category, year, hero_img, description, is_featured, created_at, updated_at, deleted_at FROM works WHERE id = ? AND deleted_at = 0"
row := config.DB.QueryRow(query, id)
var work models.Work
if err := row.Scan(
&work.ID,
&work.Title,
&work.Category,
&work.Year,
&work.HeroImg,
&work.Description,
&work.IsFeatured,
&work.CreatedAt,
&work.UpdatedAt,
&work.DeletedAt,
); err != nil {
if err == sql.ErrNoRows {
return nil, nil
}
log.Printf("Error scanning work by ID: %v", err)
return nil, err
}
return &work, nil
}
// GetWorkTechStack 获取作品的技术栈
func GetWorkTechStack(workID string) ([]models.WorkTechStack, error) {
// work_tech_stack has deleted_at? I added it to all tables.
query := "SELECT id, work_id, category, item, created_at, deleted_at FROM work_tech_stack WHERE work_id = ? AND deleted_at = 0"
rows, err := config.DB.Query(query, workID)
if err != nil {
log.Printf("Error querying work tech stack: %v", err)
return nil, err
}
defer rows.Close()
var techStacks []models.WorkTechStack
for rows.Next() {
var techStack models.WorkTechStack
if err := rows.Scan(
&techStack.ID,
&techStack.WorkID,
&techStack.Category,
&techStack.Item,
&techStack.CreatedAt,
&techStack.DeletedAt,
); err != nil {
log.Printf("Error scanning work tech stack: %v", err)
continue
}
techStacks = append(techStacks, techStack)
}
return techStacks, nil
}
// GetWorkGallery 获取作品的图库
func GetWorkGallery(workID string) ([]models.WorkGallery, error) {
// work_gallery has deleted_at
query := "SELECT id, work_id, image_url, sort_order, description, created_at, deleted_at FROM work_gallery WHERE work_id = ? AND deleted_at = 0 ORDER BY sort_order"
rows, err := config.DB.Query(query, workID)
if err != nil {
log.Printf("Error querying work gallery: %v", err)
return nil, err
}
defer rows.Close()
var galleries []models.WorkGallery
for rows.Next() {
var gallery models.WorkGallery
if err := rows.Scan(
&gallery.ID,
&gallery.WorkID,
&gallery.ImageURL,
&gallery.SortOrder,
&gallery.Description,
&gallery.CreatedAt,
&gallery.DeletedAt,
); err != nil {
log.Printf("Error scanning work gallery: %v", err)
continue
}
galleries = append(galleries, gallery)
}
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)
}
// 获取下一个作品ID
nextWorkID, err := GetNextWorkID(work.ID)
if err != nil {
log.Printf("Error getting next work ID: %v", err)
nextWorkID = ""
}
return &models.WorkResponse{
ID: work.ID,
Title: work.Title,
Category: work.Category,
Year: work.Year,
HeroImg: work.HeroImg,
Desc: work.Description,
TechStack: techStackResponse,
Gallery: galleryImages,
Links: map[string]interface{}{
"live": "#",
},
Next: nextWorkID,
}, nil
}
// GetNextWorkID 获取下一个作品ID(简单实现,实际可能需要更复杂的逻辑)
func GetNextWorkID(currentID string) (string, error) {
// 获取所有作品ID
query := "SELECT id FROM works WHERE deleted_at = 0"
rows, err := config.DB.Query(query)
if err != nil {
return "", err
}
defer rows.Close()
var ids []string
for rows.Next() {
var id string
if err := rows.Scan(&id); err != nil {
continue
}
ids = append(ids, id)
}
// 找到当前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
}
// CreateWork 创建作品
func CreateWork(work *models.Work) error {
now := time.Now().Unix()
query := `
INSERT INTO works (id, title, category, year, hero_img, description, is_featured, created_at, updated_at, deleted_at)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 0)
`
_, err := config.DB.Exec(
query,
work.ID,
work.Title,
work.Category,
work.Year,
work.HeroImg,
work.Description,
work.IsFeatured,
now,
now,
)
if err != nil {
log.Printf("Error creating work: %v", err)
return err
}
return nil
}
// UpdateWork 更新作品
func UpdateWork(work *models.Work) error {
now := time.Now().Unix()
query := `
UPDATE works SET title = ?, category = ?, year = ?, hero_img = ?, description = ?, is_featured = ?, updated_at = ?
WHERE id = ? AND deleted_at = 0
`
_, err := config.DB.Exec(
query,
work.Title,
work.Category,
work.Year,
work.HeroImg,
work.Description,
work.IsFeatured,
now,
work.ID,
)
if err != nil {
log.Printf("Error updating work: %v", err)
return err
}
return nil
}
// DeleteWork 删除作品 (Soft Delete)
func DeleteWork(id string) error {
now := time.Now().Unix()
query := "UPDATE works SET deleted_at = ? WHERE id = ?"
_, err := config.DB.Exec(query, now, id)
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 total int
countQuery := "SELECT COUNT(*) FROM works WHERE deleted_at = 0"
err := config.DB.QueryRow(countQuery).Scan(&total)
if err != nil {
log.Printf("Error getting work count: %v", err)
return nil, 0, err
}
query := `
SELECT id, title, category, year, hero_img, description, is_featured, created_at, updated_at, deleted_at
FROM works
WHERE deleted_at = 0
ORDER BY created_at DESC
LIMIT ? OFFSET ?
`
rows, err := config.DB.Query(query, pageSize, offset)
if err != nil {
log.Printf("Error querying admin works: %v", err)
return nil, 0, err
}
defer rows.Close()
var works []models.Work
for rows.Next() {
var work models.Work
if err := rows.Scan(
&work.ID,
&work.Title,
&work.Category,
&work.Year,
&work.HeroImg,
&work.Description,
&work.IsFeatured,
&work.CreatedAt,
&work.UpdatedAt,
&work.DeletedAt,
); err != nil {
log.Printf("Error scanning work: %v", err)
continue
}
works = append(works, work)
}
return works, 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 int
query := "SELECT COUNT(*) FROM works WHERE deleted_at = 0"
row := config.DB.QueryRow(query)
err := row.Scan(&count)
if err != nil {
log.Printf("Error getting work count: %v", err)
return 0, err
}
return count, nil
}