1. 增加了几种模板
This commit is contained in:
@@ -6,6 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/niangaodev/art-code/config"
|
||||
"github.com/niangaodev/art-code/models"
|
||||
)
|
||||
|
||||
// MigrateToBigInt performs schema migration to BigInt timestamps
|
||||
@@ -332,6 +333,77 @@ func MigratePptTemplates() {
|
||||
EnsureSystemPptTemplate()
|
||||
}
|
||||
|
||||
// MigrateTemplates 创建 templates 表并种入内置模板(classic / ubuntu-terminal)
|
||||
func MigrateTemplates() {
|
||||
log.Printf("Migrating templates...")
|
||||
|
||||
if !tableExists("templates") {
|
||||
execSQL(`CREATE TABLE templates (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '模板ID',
|
||||
slug VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '唯一标识(classic/ubuntu-terminal/自定义slug)',
|
||||
name VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '模板显示名称',
|
||||
type VARCHAR(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'custom' COMMENT '类型(builtin内置/custom自定义)',
|
||||
description TEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT '模板描述',
|
||||
manifest LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT 'manifest.json 内容(custom)',
|
||||
layout_json LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL COMMENT 'layout.json 内容(custom)',
|
||||
skin_css_path VARCHAR(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '皮肤CSS相对路径(/uploads/templates/{slug}/skin.css)',
|
||||
is_system TINYINT(1) NOT NULL DEFAULT 0 COMMENT '是否系统内置模板(0否 1是,不可删除)',
|
||||
is_active TINYINT(1) NOT NULL DEFAULT 1 COMMENT '是否启用(0否 1是)',
|
||||
sort_order INT NOT NULL DEFAULT 0 COMMENT '排序(越小越靠前)',
|
||||
deleted_at BIGINT NOT NULL DEFAULT 0 COMMENT '软删除时间戳',
|
||||
created_at BIGINT NOT NULL DEFAULT 0 COMMENT '创建时间(Unix秒)',
|
||||
updated_at BIGINT NOT NULL DEFAULT 0 COMMENT '更新时间(Unix秒)',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE INDEX idx_slug (slug)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='前端页面模板表'`)
|
||||
}
|
||||
|
||||
ensureBuiltinTemplate(BuiltinTemplateClassic, "经典", "系统内置经典布局", 0)
|
||||
ensureBuiltinTemplate(BuiltinTemplateTerminal, "Ubuntu 终端", "系统内置终端风格(ls/search/cat 命令交互)", 1)
|
||||
ensureBuiltinTemplate(BuiltinTemplatePixel, "像素", "系统内置像素风(8-bit 游戏机界面)", 2)
|
||||
ensureBuiltinTemplate(BuiltinTemplateMagazine, "杂志", "系统内置杂志风(衬线多栏编辑排版)", 3)
|
||||
ensureBuiltinTemplate(BuiltinTemplateNewspaper, "报纸", "系统内置报纸风(报头多栏纸感排版)", 4)
|
||||
ensureBuiltinTemplate(BuiltinTemplateBento, "Bento 宫格", "系统内置 Bento 宫格风(圆角几何色块)", 5)
|
||||
ensureBuiltinTemplate(BuiltinTemplateGlass, "玻璃拟态", "系统内置玻璃拟态(毛玻璃光感)", 6)
|
||||
ensureBuiltinTemplate(BuiltinTemplateRetro, "复古印刷", "系统内置复古印刷(旧印刷烫金质感)", 7)
|
||||
ensureBuiltinTemplate(BuiltinTemplateGuofeng, "国风水墨", "系统内置国风水墨(宣纸印章山水)", 8)
|
||||
|
||||
// 种入 site_template 默认配置
|
||||
if s, err := GetSettingByKey(SettingKeySiteTemplate); err == nil && s == nil {
|
||||
_ = CreateSetting(&models.Setting{
|
||||
KeyName: SettingKeySiteTemplate,
|
||||
Value: DefaultSiteTemplateSlug,
|
||||
Description: "当前启用的前端页面模板 slug",
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ensureBuiltinTemplate 幂等种入内置模板
|
||||
func ensureBuiltinTemplate(slug, name, desc string, sortOrder int) {
|
||||
var count int64
|
||||
config.DB.Model(&models.Template{}).
|
||||
Where("slug = ? AND deleted_at = ?", slug, 0).
|
||||
Count(&count)
|
||||
if count > 0 {
|
||||
return
|
||||
}
|
||||
now := time.Now().Unix()
|
||||
t := models.Template{
|
||||
Slug: slug,
|
||||
Name: name,
|
||||
Type: TemplateTypeBuiltin,
|
||||
Description: desc,
|
||||
IsSystem: true,
|
||||
IsActive: true,
|
||||
SortOrder: sortOrder,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
if err := config.DB.Create(&t).Error; err != nil {
|
||||
log.Printf("Failed to seed builtin template %s: %v", slug, err)
|
||||
}
|
||||
}
|
||||
|
||||
// MigrateOSSConfigFields 为 oss_configs 补齐各云厂商专用列(幂等)
|
||||
func MigrateOSSConfigFields() {
|
||||
log.Printf("Migrating oss_configs provider fields...")
|
||||
|
||||
145
server/repositories/template_repository.go
Normal file
145
server/repositories/template_repository.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/niangaodev/art-code/config"
|
||||
"github.com/niangaodev/art-code/models"
|
||||
)
|
||||
|
||||
// 内置模板 slug(保留字,自定义上传不可占用)
|
||||
const (
|
||||
BuiltinTemplateClassic = "classic"
|
||||
BuiltinTemplateTerminal = "ubuntu-terminal"
|
||||
BuiltinTemplatePixel = "pixel"
|
||||
BuiltinTemplateMagazine = "magazine"
|
||||
BuiltinTemplateNewspaper = "newspaper"
|
||||
BuiltinTemplateBento = "bento"
|
||||
BuiltinTemplateGlass = "glass"
|
||||
BuiltinTemplateRetro = "retro"
|
||||
BuiltinTemplateGuofeng = "guofeng"
|
||||
DefaultSiteTemplateSlug = "classic"
|
||||
TemplateTypeBuiltin = "builtin"
|
||||
TemplateTypeCustom = "custom"
|
||||
SettingKeySiteTemplate = "site_template"
|
||||
)
|
||||
|
||||
var ErrTemplateSystemDelete = errors.New("system template cannot be deleted")
|
||||
var ErrTemplateInUse = errors.New("template is currently active and cannot be deleted")
|
||||
|
||||
// GetActiveTemplates 获取所有启用模板(公开)
|
||||
func GetActiveTemplates() ([]models.Template, error) {
|
||||
var list []models.Template
|
||||
err := config.DB.Model(&models.Template{}).
|
||||
Where("deleted_at = ? AND is_active = ?", 0, true).
|
||||
Order("sort_order ASC, id ASC").
|
||||
Find(&list).Error
|
||||
return list, err
|
||||
}
|
||||
|
||||
// GetAllTemplates 获取全部模板(后台)
|
||||
func GetAllTemplates() ([]models.Template, error) {
|
||||
var list []models.Template
|
||||
err := config.DB.Model(&models.Template{}).
|
||||
Where("deleted_at = ?", 0).
|
||||
Order("sort_order ASC, id ASC").
|
||||
Find(&list).Error
|
||||
return list, err
|
||||
}
|
||||
|
||||
// GetTemplateByID 按 ID 获取模板
|
||||
func GetTemplateByID(id uint) (*models.Template, error) {
|
||||
var t models.Template
|
||||
err := config.DB.Model(&models.Template{}).
|
||||
Where("id = ? AND deleted_at = ?", id, 0).
|
||||
First(&t).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &t, nil
|
||||
}
|
||||
|
||||
// GetTemplateBySlug 按 slug 获取模板(含未启用,内部使用)
|
||||
func GetTemplateBySlug(slug string) (*models.Template, error) {
|
||||
var t models.Template
|
||||
err := config.DB.Model(&models.Template{}).
|
||||
Where("slug = ? AND deleted_at = ?", slug, 0).
|
||||
First(&t).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &t, nil
|
||||
}
|
||||
|
||||
// GetActiveTemplateBySlug 按 slug 获取启用模板(公开接口,未启用返回 404)
|
||||
func GetActiveTemplateBySlug(slug string) (*models.Template, error) {
|
||||
var t models.Template
|
||||
err := config.DB.Model(&models.Template{}).
|
||||
Where("slug = ? AND deleted_at = ? AND is_active = ?", slug, 0, true).
|
||||
First(&t).Error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &t, nil
|
||||
}
|
||||
|
||||
// CreateTemplate 创建模板
|
||||
func CreateTemplate(t *models.Template) error {
|
||||
return config.DB.Create(t).Error
|
||||
}
|
||||
|
||||
// UpdateTemplate 更新模板基础信息
|
||||
func UpdateTemplate(t *models.Template) error {
|
||||
return config.DB.Model(&models.Template{}).
|
||||
Where("id = ? AND deleted_at = ?", t.ID, 0).
|
||||
Updates(map[string]interface{}{
|
||||
"name": t.Name,
|
||||
"description": t.Description,
|
||||
"is_active": t.IsActive,
|
||||
"updated_at": time.Now().Unix(),
|
||||
}).Error
|
||||
}
|
||||
|
||||
// DeleteTemplate 物理删除自定义模板(内置模板禁止删除)
|
||||
func DeleteTemplate(id uint) error {
|
||||
t, err := GetTemplateByID(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if t.IsSystem {
|
||||
return ErrTemplateSystemDelete
|
||||
}
|
||||
if t.Slug == GetCurrentSiteTemplateSlug() {
|
||||
return ErrTemplateInUse
|
||||
}
|
||||
return config.DB.Model(&models.Template{}).
|
||||
Where("id = ?", id).
|
||||
Delete(&models.Template{}).Error
|
||||
}
|
||||
|
||||
// GetCurrentSiteTemplateSlug 读取当前启用的站点模板 slug(缺省 classic)
|
||||
func GetCurrentSiteTemplateSlug() string {
|
||||
s, err := GetSettingByKey(SettingKeySiteTemplate)
|
||||
if err != nil || s == nil || s.Value == "" {
|
||||
return DefaultSiteTemplateSlug
|
||||
}
|
||||
return s.Value
|
||||
}
|
||||
|
||||
// ActivateTemplate 将模板设为站点当前模板
|
||||
func ActivateTemplate(slug string) error {
|
||||
s, err := GetSettingByKey(SettingKeySiteTemplate)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if s == nil {
|
||||
return CreateSetting(&models.Setting{
|
||||
KeyName: SettingKeySiteTemplate,
|
||||
Value: slug,
|
||||
Description: "当前启用的前端页面模板 slug",
|
||||
})
|
||||
}
|
||||
s.Value = slug
|
||||
return UpdateSetting(s)
|
||||
}
|
||||
Reference in New Issue
Block a user