♻️ Refactor theme module

This commit is contained in:
2025-11-20 23:07:12 +08:00
parent 5584a46ca2
commit fc7c162e2f
8 changed files with 388 additions and 1465 deletions

View File

@@ -5,6 +5,7 @@ import (
"database/sql"
"errors"
"fmt"
"strings"
"time"
"voidraft/internal/models"
@@ -31,12 +32,10 @@ func NewThemeService(databaseService *DatabaseService, logger *log.LogService) *
}
}
// ServiceStartup 服务启动时初始化
// ServiceStartup 服务启动
func (ts *ThemeService) ServiceStartup(ctx context.Context, options application.ServiceOptions) error {
ts.ctx = ctx
// 初始化默认主题
return ts.initializeDefaultThemes()
return nil
}
// getDB 获取数据库连接
@@ -44,141 +43,27 @@ func (ts *ThemeService) getDB() *sql.DB {
return ts.databaseService.db
}
// initializeDefaultThemes 初始化所有预设主题
func (ts *ThemeService) initializeDefaultThemes() error {
// GetThemeByName 通过名称获取主题覆盖,若不存在则返回 nil
func (ts *ThemeService) GetThemeByName(name string) (*models.Theme, error) {
db := ts.getDB()
if db == nil {
return fmt.Errorf("database not available")
return nil, fmt.Errorf("database not available")
}
// 获取所有已存在的主题名称
existingThemes := make(map[string]bool)
rows, err := db.Query("SELECT name FROM themes")
if err != nil {
return fmt.Errorf("failed to query existing themes: %w", err)
}
defer rows.Close()
for rows.Next() {
var name string
if err := rows.Scan(&name); err != nil {
return fmt.Errorf("failed to scan theme name: %w", err)
}
existingThemes[name] = true
trimmed := strings.TrimSpace(name)
if trimmed == "" {
return nil, fmt.Errorf("theme name cannot be empty")
}
// 定义所有预设主题配置
now := time.Now().Format("2006-01-02 15:04:05")
presetThemes := []struct {
config *models.ThemeColorConfig
themeType models.ThemeType
isDefault bool
}{
// 默认主题
{models.NewDefaultDarkTheme(), models.ThemeTypeDark, true},
{models.NewDefaultLightTheme(), models.ThemeTypeLight, true},
// 深色主题预设
{models.NewDraculaTheme(), models.ThemeTypeDark, false},
{models.NewAuraTheme(), models.ThemeTypeDark, false},
{models.NewGitHubDarkTheme(), models.ThemeTypeDark, false},
{models.NewMaterialDarkTheme(), models.ThemeTypeDark, false},
{models.NewOneDarkTheme(), models.ThemeTypeDark, false},
{models.NewSolarizedDarkTheme(), models.ThemeTypeDark, false},
{models.NewTokyoNightTheme(), models.ThemeTypeDark, false},
{models.NewTokyoNightStormTheme(), models.ThemeTypeDark, false},
// 浅色主题预设
{models.NewGitHubLightTheme(), models.ThemeTypeLight, false},
{models.NewMaterialLightTheme(), models.ThemeTypeLight, false},
{models.NewSolarizedLightTheme(), models.ThemeTypeLight, false},
{models.NewTokyoNightDayTheme(), models.ThemeTypeLight, false},
}
// 筛选出需要创建的主题
var themesToCreate []*models.Theme
for _, preset := range presetThemes {
if !existingThemes[preset.config.Name] {
themesToCreate = append(themesToCreate, &models.Theme{
Name: preset.config.Name,
Type: preset.themeType,
Colors: *preset.config,
IsDefault: preset.isDefault,
CreatedAt: now,
UpdatedAt: now,
})
}
}
if len(themesToCreate) == 0 {
return nil
}
// 批量插入主题
tx, err := db.Begin()
if err != nil {
return fmt.Errorf("failed to begin transaction: %w", err)
}
defer tx.Rollback()
stmt, err := tx.Prepare(`
INSERT INTO themes (name, type, colors, is_default, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?)
`)
if err != nil {
return fmt.Errorf("failed to prepare statement: %w", err)
}
defer stmt.Close()
for _, theme := range themesToCreate {
_, err := stmt.Exec(
theme.Name,
theme.Type,
theme.Colors,
theme.IsDefault,
theme.CreatedAt,
theme.UpdatedAt,
)
if err != nil {
return fmt.Errorf("failed to insert theme %s: %w", theme.Name, err)
}
}
if err := tx.Commit(); err != nil {
return fmt.Errorf("failed to commit transaction: %w", err)
}
return nil
}
// GetThemeByID 根据ID或名称获取主题
// 如果 id > 0按ID查询如果 id = 0按名称查询
func (ts *ThemeService) GetThemeByIdOrName(id int, name ...string) (*models.Theme, error) {
var query string
var args []interface{}
if id > 0 {
query = `
SELECT id, name, type, colors, is_default, created_at, updated_at
FROM themes
WHERE id = ?
LIMIT 1
`
args = []interface{}{id}
} else if len(name) > 0 && name[0] != "" {
query = `
SELECT id, name, type, colors, is_default, created_at, updated_at
FROM themes
WHERE name = ?
LIMIT 1
`
args = []interface{}{name[0]}
} else {
return nil, fmt.Errorf("either id or name must be provided")
}
query := `
SELECT id, name, type, colors, is_default, created_at, updated_at
FROM themes
WHERE name = ?
LIMIT 1
`
theme := &models.Theme{}
db := ts.getDB()
err := db.QueryRow(query, args...).Scan(
err := db.QueryRow(query, trimmed).Scan(
&theme.ID,
&theme.Name,
&theme.Type,
@@ -190,133 +75,89 @@ func (ts *ThemeService) GetThemeByIdOrName(id int, name ...string) (*models.Them
if err != nil {
if errors.Is(err, sql.ErrNoRows) {
if id > 0 {
return nil, fmt.Errorf("theme not found with id: %d", id)
}
return nil, fmt.Errorf("theme not found with name: %s", name[0])
return nil, nil
}
return nil, fmt.Errorf("failed to get theme: %w", err)
return nil, fmt.Errorf("failed to query theme: %w", err)
}
return theme, nil
}
// UpdateTheme 更新主题
func (ts *ThemeService) UpdateTheme(id int, colors models.ThemeColorConfig) error {
query := `
UPDATE themes
SET colors = ?, updated_at = ?
WHERE id = ?
`
// UpdateTheme 保存或更新主题覆盖
func (ts *ThemeService) UpdateTheme(name string, colors models.ThemeColorConfig) error {
db := ts.getDB()
result, err := db.Exec(query, colors, time.Now().Format("2006-01-02 15:04:05"), id)
if db == nil {
return fmt.Errorf("database not available")
}
trimmed := strings.TrimSpace(name)
if trimmed == "" {
return fmt.Errorf("theme name cannot be empty")
}
if colors == nil {
colors = models.ThemeColorConfig{}
}
colors["themeName"] = trimmed
themeType := models.ThemeTypeDark
if raw, ok := colors["dark"].(bool); ok && !raw {
themeType = models.ThemeTypeLight
}
now := time.Now().Format("2006-01-02 15:04:05")
existing, err := ts.GetThemeByName(trimmed)
if err != nil {
return err
}
if existing == nil {
_, err = db.Exec(
`INSERT INTO themes (name, type, colors, is_default, created_at, updated_at) VALUES (?, ?, ?, 0, ?, ?)`,
trimmed,
themeType,
colors,
now,
now,
)
if err != nil {
return fmt.Errorf("failed to insert theme: %w", err)
}
return nil
}
_, err = db.Exec(
`UPDATE themes SET type = ?, colors = ?, updated_at = ? WHERE name = ?`,
themeType,
colors,
now,
trimmed,
)
if err != nil {
return fmt.Errorf("failed to update theme: %w", err)
}
rowsAffected, err := result.RowsAffected()
if err != nil {
return fmt.Errorf("failed to get rows affected: %w", err)
}
if rowsAffected == 0 {
return fmt.Errorf("theme not found with id: %d", id)
}
return nil
}
// ResetTheme 重置主题为预设配置
func (ts *ThemeService) ResetTheme(id int, name ...string) error {
// 先获取主题信息
theme, err := ts.GetThemeByIdOrName(id, name...)
if err != nil {
return err
}
// 根据主题名称获取预设配置
var presetConfig *models.ThemeColorConfig
switch theme.Name {
// 默认主题
case "default-dark":
presetConfig = models.NewDefaultDarkTheme()
case "default-light":
presetConfig = models.NewDefaultLightTheme()
// 深色主题预设
case "dracula":
presetConfig = models.NewDraculaTheme()
case "aura":
presetConfig = models.NewAuraTheme()
case "github-dark":
presetConfig = models.NewGitHubDarkTheme()
case "material-dark":
presetConfig = models.NewMaterialDarkTheme()
case "one-dark":
presetConfig = models.NewOneDarkTheme()
case "solarized-dark":
presetConfig = models.NewSolarizedDarkTheme()
case "tokyo-night":
presetConfig = models.NewTokyoNightTheme()
case "tokyo-night-storm":
presetConfig = models.NewTokyoNightStormTheme()
// 浅色主题预设
case "github-light":
presetConfig = models.NewGitHubLightTheme()
case "material-light":
presetConfig = models.NewMaterialLightTheme()
case "solarized-light":
presetConfig = models.NewSolarizedLightTheme()
case "tokyo-night-day":
presetConfig = models.NewTokyoNightDayTheme()
default:
return fmt.Errorf("no preset configuration found for theme: %s", theme.Name)
}
return ts.UpdateTheme(id, *presetConfig)
}
// GetAllThemes 获取所有主题
func (ts *ThemeService) GetAllThemes() ([]*models.Theme, error) {
query := `
SELECT id, name, type, colors, is_default, created_at, updated_at
FROM themes
ORDER BY is_default DESC, type DESC, name ASC
`
// ResetTheme 删除指定主题的覆盖配置
func (ts *ThemeService) ResetTheme(name string) error {
db := ts.getDB()
rows, err := db.Query(query)
if err != nil {
return nil, fmt.Errorf("failed to query themes: %w", err)
}
defer rows.Close()
var themes []*models.Theme
for rows.Next() {
theme := &models.Theme{}
err := rows.Scan(
&theme.ID,
&theme.Name,
&theme.Type,
&theme.Colors,
&theme.IsDefault,
&theme.CreatedAt,
&theme.UpdatedAt,
)
if err != nil {
return nil, fmt.Errorf("failed to scan theme: %w", err)
}
themes = append(themes, theme)
if db == nil {
return fmt.Errorf("database not available")
}
if err := rows.Err(); err != nil {
return nil, fmt.Errorf("failed to iterate themes: %w", err)
trimmed := strings.TrimSpace(name)
if trimmed == "" {
return fmt.Errorf("theme name cannot be empty")
}
return themes, nil
if _, err := db.Exec(`DELETE FROM themes WHERE name = ?`, trimmed); err != nil {
return fmt.Errorf("failed to reset theme: %w", err)
}
return nil
}
// ServiceShutdown 服务关闭