feat: 实现分类管理功能,包括数据模型、仓库层、服务层和数据库初始化脚本
This commit is contained in:
106
internal/models/default_category.go
Normal file
106
internal/models/default_category.go
Normal file
@@ -0,0 +1,106 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// DefaultCategory represents a category template for new user initialization
|
||||
// These templates are copied to users' categories table when they first access categories
|
||||
type DefaultCategory struct {
|
||||
ID uint `gorm:"primarykey" json:"id"`
|
||||
Name string `gorm:"size:50;not null" json:"name"`
|
||||
Icon string `gorm:"size:100" json:"icon"` // Iconify format: mdi:icon-name
|
||||
Color string `gorm:"size:20" json:"color"` // HEX color code (e.g., #FF6B35)
|
||||
Type CategoryType `gorm:"size:20;not null" json:"type"` // income or expense
|
||||
ParentID *uint `gorm:"index" json:"parent_id,omitempty"`
|
||||
SortOrder int `gorm:"default:0" json:"sort_order"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
|
||||
// Relationships
|
||||
Parent *DefaultCategory `gorm:"foreignKey:ParentID" json:"parent,omitempty"`
|
||||
Children []DefaultCategory `gorm:"foreignKey:ParentID" json:"children,omitempty"`
|
||||
}
|
||||
|
||||
// TableName specifies the table name for DefaultCategory
|
||||
func (DefaultCategory) TableName() string {
|
||||
return "default_categories"
|
||||
}
|
||||
|
||||
// GetAllDefaultCategories retrieves all active default categories from the database
|
||||
func GetAllDefaultCategories(db *gorm.DB) ([]DefaultCategory, error) {
|
||||
var categories []DefaultCategory
|
||||
err := db.Where("is_active = ?", true).Order("sort_order ASC").Find(&categories).Error
|
||||
return categories, err
|
||||
}
|
||||
|
||||
// GetDefaultCategoriesWithChildren retrieves all active root categories with their children
|
||||
func GetDefaultCategoriesWithChildren(db *gorm.DB) ([]DefaultCategory, error) {
|
||||
var categories []DefaultCategory
|
||||
err := db.Where("is_active = ? AND parent_id IS NULL", true).
|
||||
Preload("Children", "is_active = ?", true).
|
||||
Order("sort_order ASC").
|
||||
Find(&categories).Error
|
||||
return categories, err
|
||||
}
|
||||
|
||||
// CopyToUserCategories copies default categories to a user's categories
|
||||
// Returns a map of old DefaultCategory ID to new Category ID for parent-child mapping
|
||||
func CopyDefaultCategoriesToUser(db *gorm.DB, userID uint) error {
|
||||
// Get all default categories
|
||||
var defaults []DefaultCategory
|
||||
if err := db.Where("is_active = ?", true).Order("sort_order ASC").Find(&defaults).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(defaults) == 0 {
|
||||
return nil // No default categories to copy
|
||||
}
|
||||
|
||||
// Map to track old ID -> new ID for parent references
|
||||
idMap := make(map[uint]uint)
|
||||
|
||||
// First pass: create all root categories (no parent)
|
||||
for _, dc := range defaults {
|
||||
if dc.ParentID == nil {
|
||||
cat := Category{
|
||||
UserID: userID,
|
||||
Name: dc.Name,
|
||||
Icon: dc.Icon,
|
||||
Color: dc.Color,
|
||||
Type: dc.Type,
|
||||
ParentID: nil,
|
||||
SortOrder: dc.SortOrder,
|
||||
}
|
||||
if err := db.Create(&cat).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
idMap[dc.ID] = cat.ID
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass: create all child categories
|
||||
for _, dc := range defaults {
|
||||
if dc.ParentID != nil {
|
||||
newParentID := idMap[*dc.ParentID]
|
||||
cat := Category{
|
||||
UserID: userID,
|
||||
Name: dc.Name,
|
||||
Icon: dc.Icon,
|
||||
Color: dc.Color,
|
||||
Type: dc.Type,
|
||||
ParentID: &newParentID,
|
||||
SortOrder: dc.SortOrder,
|
||||
}
|
||||
if err := db.Create(&cat).Error; err != nil {
|
||||
return err
|
||||
}
|
||||
idMap[dc.ID] = cat.ID
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user