qoder优化。

This commit is contained in:
2026-02-12 15:45:11 +08:00
parent bc59f616fd
commit d448e48ba3
6 changed files with 131 additions and 314 deletions

View File

@@ -44,7 +44,11 @@ func Home(c *gin.Context) {
}
var items []models.Content
db.Select("*").Limit(5).Find(&items, "type = ?", "post")
result := db.Select("*").Limit(5).Find(&items, "type = ?", "post")
if result.Error != nil {
c.String(http.StatusInternalServerError, "Database error: "+result.Error.Error())
return
}
tpl := themeManager.GetTemplate("index")
if tpl == nil {
@@ -52,9 +56,13 @@ func Home(c *gin.Context) {
return
}
c.Header("Content-Type", "text/html; charset=utf-8")
tpl.Execute(c.Writer, gin.H{
data := gin.H{
"Items": items,
"Title": "首页",
})
}
c.Header("Content-Type", "text/html; charset=utf-8")
if err := tpl.Execute(c.Writer, data); err != nil {
c.String(http.StatusInternalServerError, "Template render error: "+err.Error())
}
}

View File

@@ -139,48 +139,40 @@ func fileExists(path string) (bool, error) {
func (m *ThemeManager) parseTemplates(themePath string) (map[string]*template.Template, error) {
templates := make(map[string]*template.Template)
// 加载公共基础模板(可选)
baseTpl := template.New("base").Funcs(template.FuncMap{
"safeHTML": func(s string) template.HTML { return template.HTML(s) },
})
// 从主题目录加载模板
tplDir := filepath.Join(themePath, "templates")
// 首先读取所有模板文件内容
type tplFile struct {
name string
path string
content []byte
}
var tplFiles []tplFile
err := filepath.WalkDir(tplDir, func(path string, d fs.DirEntry, err error) error {
if err != nil {
return err // 返回错误以停止 WalkDir
return err
}
if d.IsDir() {
return nil // 跳过目录
return nil
}
// 支持 .html 和 .tmpl 扩展名
lowerPath := strings.ToLower(path)
if !strings.HasSuffix(lowerPath, ".html") && !strings.HasSuffix(lowerPath, ".tmpl") {
return nil // 非模板文件,跳过
return nil
}
// 读取模板内容
content, err := readFile(path)
if err != nil {
return fmt.Errorf("failed to read template file %s: %w", path, err)
}
// 生成模板名称(相对路径,不含扩展名)
name := strings.TrimPrefix(path, tplDir+string(filepath.Separator))
name = strings.TrimSuffix(name, filepath.Ext(name))
// 克隆基础模板并解析
tpl, err := baseTpl.Clone()
if err != nil {
return fmt.Errorf("failed to clone base template for %s: %w", name, err)
}
tpl, err = tpl.Parse(string(content))
if err != nil {
return fmt.Errorf("parse error in %s (file: %s): %w", name, path, err)
}
templates[name] = tpl
tplFiles = append(tplFiles, tplFile{name: name, path: path, content: content})
return nil
})
@@ -188,10 +180,53 @@ func (m *ThemeManager) parseTemplates(themePath string) (map[string]*template.Te
return nil, err
}
if len(templates) == 0 {
if len(tplFiles) == 0 {
return nil, ErrNoValidTemplates
}
// 创建包含所有模板的根模板
funcMap := template.FuncMap{
"safeHTML": func(s string) template.HTML { return template.HTML(s) },
}
// 首先解析基础模板base.tmpl 和 header.tmpl
var baseContent strings.Builder
for _, tf := range tplFiles {
if tf.name == "base" || tf.name == "header" {
baseContent.WriteString(string(tf.content))
baseContent.WriteString("\n")
}
}
rootTpl, err := template.New("root").Funcs(funcMap).Parse(baseContent.String())
if err != nil {
return nil, fmt.Errorf("failed to parse base templates: %w", err)
}
// 为每个页面模板单独解析,继承基础模板
for _, tf := range tplFiles {
// 跳过基础模板,它们已经在 rootTpl 中
if tf.name == "base" || tf.name == "header" {
templates[tf.name] = rootTpl
continue
}
// 克隆基础模板并添加页面特定内容
tpl, err := rootTpl.Clone()
if err != nil {
return nil, fmt.Errorf("failed to clone base template for %s: %w", tf.name, err)
}
// 解析页面特定内容,使用页面名称作为 define 名称
pageContent := string(tf.content)
_, err = tpl.Parse(pageContent)
if err != nil {
return nil, fmt.Errorf("failed to parse template %s: %w", tf.name, err)
}
templates[tf.name] = tpl
}
return templates, nil
}

View File

@@ -1,13 +1,12 @@
package utils // 示例:插件接口
import (
"go_blog/models"
"strings"
"github.com/gin-gonic/gin"
)
type Plugin interface {
OnArticleCreate(article *models.Article) // 文章创建钩子
//OnArticleCreate(article *models.Article) // 文章创建钩子
RegisterRoutes(r *gin.Engine) // 添加新路由
}

View File

@@ -1,138 +1,27 @@
<!-- templates/base.tmpl -->
{{ define "base" }}
<!DOCTYPE html>
<html>
<head>
<title>{{ .Title}}</title>
<title>{{ .Title }}</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style type="text/css">
body{
background: #f8f8f8;
}
.layui-main {
width: 1140px;
margin: 0 auto;
}
.container {
width: 1170px;
margin: 0 auto;
}
.header .layui-nav {
position: absolute;
right: 0;
top: 0;
padding: 0;
background: none;
}
.post-list {
width: 75%;
float: left;
display: block;
}
.list-card {
background: #fff;
overflow: hidden;
padding: 20px 20px 10px 20px;
position: relative;
border-radius: 10px;
margin-bottom: 10px;
height: 200px;
}
.sidebar {
float: left;
width: 25%;
}
.header {}
body { background: #f8f8f8; margin: 0; padding: 0; }
.layui-main { width: 1140px; margin: 0 auto; }
.container { width: 1170px; margin: 0 auto; overflow: hidden; }
.header .layui-nav { position: absolute; right: 0; top: 0; padding: 0; background: none; }
.post-list { width: 75%; float: left; display: block; }
.list-card { background: #fff; overflow: hidden; padding: 20px; position: relative; border-radius: 10px; margin-bottom: 10px; }
.sidebar { float: left; width: 25%; padding-left: 20px; box-sizing: border-box; }
.page-navigator { margin: 20px 0; }
.pagination a { margin-right: 10px; }
</style>
</head>
<body>
{{ template "header" . }}
<main>{{ block "content" . }}{{ end }}</main>
<div class="page-navigator">
共 {{ .Total }} 条,每页 {{ .PageSize }} 条,当前第 {{ .Page }} 页</div>
<div class="pagination">
{{ if .PrevPage }}
<a href="/page/{{ .PrevPage }}">上一页</a>
{{ end }}
{{ if .NextPage }}
<a href="/page/{{ .NextPage }}">下一页</a>
{{ end }}
<a href="/">首页</a>
<a href="/page/{{ .Total }}">尾页</a>
</div>
</div>
<div class="sidebar">
<div class="column">
<h3 class="title-sidebar"><i class="layui-icon"></i> 博客信息</h3>
<div class="personal-information">
<div class="user">
<img src="https://www.hanxiaonuan.cn/usr/uploads/2021/07/3991382612.jpg" alt="韩小暖的博客的头像"
class="rounded-circle avatar">
<div class="p-2">
<a class="user-name" target="_blank" href="https://www.hanxiaonuan.cn/">
韩小暖的博客</a>
<p class="introduction mt-1">这里是小暖的日常记录,欢迎!</p>
</div>
</div>
</div>
</div>
<div class="component">
<form class="layui-form" id="search" method="post" action="https://www.hanxiaonuan.cn/"
role="search">
<div class="layui-inline input">
<input type="text" id="s" name="s" class="layui-input" required="" lay-verify="required"
placeholder="输入关键字搜索">
</div>
<div class="layui-inline">
<button class="layui-btn layui-btn-sm layui-btn-primary"><i
class="layui-icon"></i></button>
</div>
</form>
</div>
<div class="column">
<h3 class="title-sidebar"><i class="layui-icon"></i> 栏目分类</h3>
<ul class="layui-row layui-col-space5">
<li class="layui-col-md12 layui-col-xs6"><a
href="https://www.hanxiaonuan.cn/category/default/"><i class="layui-icon"></i>
默认分类<span class="layui-badge layui-bg-gray">12</span></a></li>
<li class="layui-col-md12 layui-col-xs6"><a href="https://www.hanxiaonuan.cn/category/zc/"><i
class="layui-icon"></i> 日常随想<span class="layui-badge layui-bg-gray">2</span></a>
</li>
<li class="layui-col-md12 layui-col-xs6"><a
href="https://www.hanxiaonuan.cn/category/%E5%85%B3%E4%BA%8E%E6%88%BF%E5%AD%90/"><i
class="layui-icon"></i> 关于房子<span class="layui-badge layui-bg-gray">1</span></a>
</li>
<li class="layui-col-md12 layui-col-xs6"><a
href="https://www.hanxiaonuan.cn/category/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/"><i
class="layui-icon"></i> 工作日志<span class="layui-badge layui-bg-gray">0</span></a>
</li>
</ul>
</div>
<div class="tags">
<h3 class="title-sidebar"><i class="layui-icon"></i>标签云</h3>
<div>
<a class="layui-btn layui-btn-xs layui-btn-primary" style="color: rgb(231, 229, 26)"
href="https://www.hanxiaonuan.cn/tag/%E5%B0%8F%E6%9A%96/" title="小暖">小暖</a>
<a class="layui-btn layui-btn-xs layui-btn-primary" style="color: rgb(125, 196, 207)"
href="https://www.hanxiaonuan.cn/tag/%E6%84%9F%E6%82%9F/" title="感悟">感悟</a>
</div>
</div>
<div class="tags">
<h3 class="title-sidebar"><i class="layui-icon"></i>系统</h3>
<div>
<li class="last"><a href="https://www.hanxiaonuan.cn/admin/">进入后台 (admin)</a></li>
<li><a href="https://www.hanxiaonuan.cn/action/logout?_=5b09b0e1048bbd45bdddc56fc43667b2">退出</a>
</li>
</div>
</div>
</div>
<div class="container">
<main>{{ block "content" . }}{{ end }}</main>
</div>
</body>
</html>
{{ end }}

View File

@@ -1,102 +1,23 @@
<!-- templates/about.html -->
{{ define "content" }}
<div class="container">
<div class="post-list">
{{ range .Items }}
<div class="list-card">
<div><a href="/post/{{ .Cid }}">
<h1>Title: {{ .Title }}</h1>
</a>
<p> Slug: {{ .Slug }}</p>
<p>Text: {{ .Text }}</p>
<div>Created: {{ .Created }},</div>
</div>
</div>
{{ end }}
<div class="page-navigator">
共 {{ .Total }} 条,每页 {{ .PageSize }} 条,当前第 {{ .Page }} 页</div>
<div class="pagination">
{{ if .PrevPage }}
<a href="/page/{{ .PrevPage }}">上一页</a>
{{ end }}
{{ if .NextPage }}
<a href="/page/{{ .NextPage }}">下一页</a>
{{ end }}
<a href="/">首页</a>
<a href="/page/{{ .Total }}">尾页</a>
</div>
</div>
<div class="sidebar">
<div class="column">
<h3 class="title-sidebar"><i class="layui-icon"></i> 博客信息</h3>
<div class="personal-information">
<div class="user">
<img src="https://www.hanxiaonuan.cn/usr/uploads/2021/07/3991382612.jpg" alt="韩小暖的博客的头像"
class="rounded-circle avatar">
<div class="p-2">
<a class="user-name" target="_blank" href="https://www.hanxiaonuan.cn/">
韩小暖的博客</a>
<p class="introduction mt-1">这里是小暖的日常记录,欢迎!</p>
</div>
</div>
</div>
</div>
<div class="component">
<form class="layui-form" id="search" method="post" action="https://www.hanxiaonuan.cn/"
role="search">
<div class="layui-inline input">
<input type="text" id="s" name="s" class="layui-input" required="" lay-verify="required"
placeholder="输入关键字搜索">
</div>
<div class="layui-inline">
<button class="layui-btn layui-btn-sm layui-btn-primary"><i
class="layui-icon"></i></button>
</div>
</form>
</div>
<div class="column">
<h3 class="title-sidebar"><i class="layui-icon"></i> 栏目分类</h3>
<ul class="layui-row layui-col-space5">
<li class="layui-col-md12 layui-col-xs6"><a
href="https://www.hanxiaonuan.cn/category/default/"><i class="layui-icon"></i>
默认分类<span class="layui-badge layui-bg-gray">12</span></a></li>
<li class="layui-col-md12 layui-col-xs6"><a href="https://www.hanxiaonuan.cn/category/zc/"><i
class="layui-icon"></i> 日常随想<span class="layui-badge layui-bg-gray">2</span></a>
</li>
<li class="layui-col-md12 layui-col-xs6"><a
href="https://www.hanxiaonuan.cn/category/%E5%85%B3%E4%BA%8E%E6%88%BF%E5%AD%90/"><i
class="layui-icon"></i> 关于房子<span class="layui-badge layui-bg-gray">1</span></a>
</li>
<li class="layui-col-md12 layui-col-xs6"><a
href="https://www.hanxiaonuan.cn/category/%E5%B7%A5%E4%BD%9C%E6%97%A5%E5%BF%97/"><i
class="layui-icon"></i> 工作日志<span class="layui-badge layui-bg-gray">0</span></a>
</li>
</ul>
</div>
<div class="tags">
<h3 class="title-sidebar"><i class="layui-icon"></i>标签云</h3>
<div>
<a class="layui-btn layui-btn-xs layui-btn-primary" style="color: rgb(231, 229, 26)"
href="https://www.hanxiaonuan.cn/tag/%E5%B0%8F%E6%9A%96/" title="小暖">小暖</a>
<a class="layui-btn layui-btn-xs layui-btn-primary" style="color: rgb(125, 196, 207)"
href="https://www.hanxiaonuan.cn/tag/%E6%84%9F%E6%82%9F/" title="感悟">感悟</a>
</div>
</div>
<div class="tags">
<h3 class="title-sidebar"><i class="layui-icon"></i>系统</h3>
<div>
<li class="last"><a href="https://www.hanxiaonuan.cn/admin/">进入后台 (admin)</a></li>
<li><a href="https://www.hanxiaonuan.cn/action/logout?_=5b09b0e1048bbd45bdddc56fc43667b2">退出</a>
</li>
</div>
</div>
</div>
<div class="post-list">
{{ range .Items }}
<div class="list-card">
<a href="/post/{{ .Cid }}">
<h2>{{ .Title }}</h2>
</a>
<p>{{ .Text }}</p>
<small>创建于: {{ .Created }}</small>
</div>
{{ else }}
<div class="list-card">
<p>暂无文章</p>
</div>
{{ end }}
</div>
<div class="sidebar">
<h3>博客信息</h3>
<p>欢迎访问个人博客</p>
</div>
{{ end }}
<!--继承基础模板内容-->
{{ template "base.tmpl" . }}
{{ template "base" . }}

View File

@@ -1,64 +1,29 @@
<!DOCTYPE html>
<html>
<head>
<title>Page 1</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style type="text/css">
.container {
width: 1170px;
margin: 0 auto;
}
.post-list {
width: 75%;
float: left;
display: block;
}
.sidebar {
float: left;
width: 25%;
}
.header {}
</style>
</head>
<body>
<div class="container">
<div class="layui-col-md9 layui-col-lg9">
<div class="title-article">
<h1>{{.Title}}</h1>
<div class="title-msg">
<span><i class="layui-icon">&#xe612;</i> {{.AuthorID}} </span>
<span><i class="layui-icon">&#xe60e;</i> {{.Created}}</span>
<span><i class="layui-icon">&#xe63a;</i> {{.CommentsNum}}</span>
</div>
</div>
<div class="text" itemprop="articleBody">
{{.Text}}
</div>
<div class="tags-text">
<i class="layui-icon">&#xe66e;</i>标签:{{.Type}}
</div>
<div class="copy-text">
<div>
<p>非特殊说明,本博所有文章均为博主原创。</p>
<p class="hidden-xs">如若转载,请注明出处: </p>
</div>
</div>
<div class="page-text">
<div>
<span class="layui-badge layui-bg-gray">上一篇</span>
</div>
<div>
<span class="layui-badge layui-bg-gray">下一篇</span>
</div>
</div>
<div class="comment-text layui-form">
</div>
{{ define "content" }}
<div class="post-list">
<div class="list-card">
<h1>{{ .Title }}</h1>
<div class="meta">
<span>作者: {{ .AuthorID }}</span> |
<span>时间: {{ .Created }}</span> |
<span>评论: {{ .CommentsNum }}</span>
</div>
<hr>
<div class="content">
{{ .Text }}
</div>
<div class="tags">
<span>标签: {{ .Type }}</span>
</div>
<hr>
<div class="nav">
<a href="/">← 返回首页</a>
</div>
</div>
</div>
</body>
</html>
<div class="sidebar">
<h3>文章详情</h3>
<p><a href="/">返回首页</a></p>
</div>
{{ end }}
{{ template "base" . }}