调整后台模板和js、css文件位置

This commit is contained in:
2026-08-20 00:00:54 +08:00
parent abee7e86aa
commit d4d009f8b2
5 changed files with 6 additions and 6 deletions
+528
View File
@@ -0,0 +1,528 @@
{{define "admin_index"}}<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>后台管理 - GoBlog</title>
<link rel="icon" href="/static/images/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="/static/css/adminstyle.css?v=3">
</head>
<body>
<div id="app">
<aside class="sidebar">
<div class="logo">
<h2>GoBlog</h2>
<p>后台管理</p>
</div>
<nav class="menu">
{{range .Menus}}{{if eq .Group ""}}{{range $i, $item := .Items}}<a href="#{{$item.Key}}" class="menu-item{{if eq $item.Key "dashboard"}} active{{end}}" data-page="{{$item.Key}}">{{$item.Name}}</a>
{{end}}{{else}}
<div class="menu-group open">
<button class="menu-group-header" type="button">{{.Group}}</button>
<div class="menu-sub">
{{range .Items}}<a href="#{{.Key}}" class="menu-item" data-page="{{.Key}}">{{.Name}}</a>
{{end}}
</div>
</div>
{{end}}{{end}}
</nav>
<div class="user-info">
<span id="username">{{.DisplayName}}</span>
<button id="logout-btn">退出</button>
</div>
</aside>
<main class="main-content">
{{if index .PageSet "dashboard"}}{{template "admin_page_dashboard" .}}{{end}}
{{if index .PageSet "posts"}}{{template "admin_page_posts" .}}{{template "admin_page_post_form" .}}{{end}}
{{if index .PageSet "categories"}}{{template "admin_page_categories" .}}{{end}}
{{if index .PageSet "tags"}}{{template "admin_page_tags" .}}{{end}}
{{if index .PageSet "pages"}}{{template "admin_page_pages" .}}{{end}}
{{if index .PageSet "comments"}}{{template "admin_page_comments" .}}{{end}}
{{if index .PageSet "users"}}{{template "admin_page_users" .}}{{end}}
{{if index .PageSet "settings"}}{{template "admin_page_settings" .}}{{end}}
{{if index .PageSet "files"}}{{template "admin_page_files" .}}{{end}}
{{if index .PageSet "themes"}}{{template "admin_page_themes" .}}{{template "admin_page_theme_editor" .}}{{end}}
</main>
</div>
{{if or (index .PageSet "categories") (index .PageSet "tags") (index .PageSet "pages")}}{{template "admin_modal_common" .}}{{end}}
{{if index .PageSet "users"}}{{template "admin_modal_user" .}}{{end}}
{{if index .PageSet "themes"}}{{template "admin_modal_theme" .}}{{end}}
<script>window.__currentUser = {{.CurrentUser }}</script>
<script src="/static/js/admin.js?v=21"></script>
</body>
</html>
{{end}}
{{define "admin_page_dashboard"}}
<!-- 仪表盘 -->
<div id="dashboard-page" class="page">
<h1>仪表盘</h1>
<div class="stats-grid">
<a href="#posts" class="stat-card" data-page="posts" onclick="showPage('posts')">
<h3>文章总数</h3>
<p class="stat-number" id="stat-posts">0</p>
</a>
<a href="#categories" class="stat-card" data-page="categories" onclick="showPage('categories')">
<h3>分类总数</h3>
<p class="stat-number" id="stat-categories">0</p>
</a>
<a href="#tags" class="stat-card" data-page="tags" onclick="showPage('tags')">
<h3>标签总数</h3>
<p class="stat-number" id="stat-tags">0</p>
</a>
<a href="#comments" class="stat-card" data-page="comments" onclick="showPage('comments')">
<h3>待审核评论</h3>
<p class="stat-number" id="stat-comments">0</p>
</a>
</div>
</div>
{{end}}
{{define "admin_page_posts"}}
<!-- 文章管理 -->
<div id="posts-page" class="page hidden">
<div class="page-header">
<h1>文章管理</h1>
<button class="btn-primary" onclick="showPostForm()">新建文章</button>
</div>
<table class="data-table">
<thead>
<tr>
<th>标题</th>
<th>作者</th>
<th>分类</th>
<th>状态</th>
<th>浏览量</th>
<th>发布时间</th>
<th>操作</th>
</tr>
</thead>
<tbody id="posts-list"></tbody>
</table>
<div id="posts-pagination" class="pagination"></div>
</div>
{{end}}
{{define "admin_page_post_form"}}
<!-- 文章表单 -->
<div id="post-form-page" class="page hidden">
<div class="page-header">
<h1 id="post-form-title">新建文章</h1>
<button class="btn-secondary" onclick="showPage('posts')">返回</button>
</div>
<form id="post-form">
<input type="hidden" id="post-id">
<div class="form-group">
<label>标题</label>
<input type="text" id="post-title" required>
</div>
<div class="form-row">
<div class="form-group">
<label>分类</label>
<select id="post-category" required></select>
</div>
<div class="form-group">
<label>状态</label>
<select id="post-status">
<option value="draft">草稿</option>
<option value="published">已发布</option>
<option value="private">私密</option>
</select>
</div>
</div>
<div class="form-group">
<label>标签(用逗号分隔)</label>
<input type="text" id="post-tags" placeholder="标签1, 标签2, 标签3">
</div>
<div class="form-group">
<label>封面图</label>
<input type="hidden" id="post-cover">
<input type="file" id="post-cover-file" accept="image/jpeg,image/png,image/gif,image/webp" style="display:none">
<div class="cover-uploader">
<img id="post-cover-preview" class="cover-preview hidden" src="" alt="封面预览">
<div class="cover-uploader-actions">
<button type="button" class="btn-secondary" onclick="document.getElementById('post-cover-file').click()">选择图片</button>
<button type="button" class="btn-danger hidden" id="post-cover-remove" onclick="removeCover()">移除</button>
<span class="upload-hint">支持 jpg/png/gif/webp,最大 5MB</span>
</div>
</div>
</div>
<div class="form-group">
<label>摘要</label>
<textarea id="post-summary" rows="3"></textarea>
</div>
<div class="form-group">
<label>内容 (支持 Markdown 语法)</label>
<div class="md-editor">
<div class="md-toolbar">
<div class="md-tools" id="md-tools">
<button type="button" title="加粗" onclick="mdWrap('**','**','粗体文字')"><b>B</b></button>
<button type="button" title="斜体" onclick="mdWrap('*','*','斜体文字')"><i>I</i></button>
<button type="button" title="删除线" onclick="mdWrap('~~','~~','删除线文字')"><s>S</s></button>
<button type="button" title="标题" onclick="mdInsertLine('## ','标题')">H</button>
<button type="button" title="链接" onclick="mdWrap('[','](https://)','链接文字')">🔗</button>
<button type="button" title="图片" onclick="mdInsertImage()">🖼</button>
<button type="button" title="行内代码" onclick="mdWrap('`','`','代码')">&lt;/&gt;</button>
<button type="button" title="代码块" onclick="mdWrap('\n```\n','\n```\n','代码块')">{ }</button>
<button type="button" title="引用" onclick="mdInsertLine('> ','引用内容')">”</button>
<button type="button" title="无序列表" onclick="mdInsertLine('- ','列表项')">•</button>
<button type="button" title="有序列表" onclick="mdInsertLine('1. ','列表项')">1.</button>
<button type="button" title="表格" onclick="mdInsertTable()">⊞</button>
</div>
<div class="md-tabs">
<button type="button" id="md-tab-edit" class="active" onclick="mdShowEdit()">编辑</button>
<button type="button" id="md-tab-preview" onclick="mdShowPreview()">预览</button>
</div>
</div>
<div class="md-body">
<textarea id="post-content" required placeholder="支持 Markdown 语法,也兼容 HTML 内容"></textarea>
<div id="md-preview" class="md-preview hidden"></div>
</div>
</div>
</div>
<div class="form-group">
<label>
<input type="checkbox" id="post-istop"> 置顶文章
</label>
</div>
<button type="submit" class="btn-primary" onclick="mdShowEdit()">保存</button>
</form>
</div>
<!-- 图片插入对话框 -->
<div id="image-modal" class="modal hidden">
<div class="modal-content" style="max-width:420px">
<h3>插入图片</h3>
<div class="form-group">
<label>图片描述</label>
<input type="text" id="img-desc" placeholder="输入图片描述(alt 文本)">
</div>
<div class="form-group">
<label>选择图片</label>
<div style="display:flex;gap:8px;align-items:center">
<button type="button" class="btn-secondary" onclick="document.getElementById('img-file-input').click()">选择文件</button>
<input type="file" id="img-file-input" accept="image/jpeg,image/png,image/gif,image/webp" style="display:none" onchange="onImageFileSelected(this)">
<span id="img-file-name" style="color:#888;font-size:13px">未选择</span>
</div>
<div id="img-preview-box" style="margin-top:8px;display:none">
<img id="img-preview-thumb" style="max-width:100%;max-height:200px;border-radius:4px;border:1px solid #ddd">
</div>
</div>
<div class="modal-actions">
<button type="button" class="btn-secondary" onclick="hideImageModal()">取消</button>
<button type="button" class="btn-primary" id="img-upload-btn" onclick="confirmInsertImage()" disabled>上传并插入</button>
</div>
</div>
</div>
{{end}}
{{define "admin_page_categories"}}
<!-- 分类管理 -->
<div id="categories-page" class="page hidden">
<div class="page-header">
<h1>分类管理</h1>
<button class="btn-primary" onclick="showCategoryForm()">新建分类</button>
</div>
<table class="data-table">
<thead>
<tr>
<th>名称</th>
<th>别名</th>
<th>文章数</th>
<th>操作</th>
</tr>
</thead>
<tbody id="categories-list"></tbody>
</table>
</div>
{{end}}
{{define "admin_page_tags"}}
<!-- 标签管理 -->
<div id="tags-page" class="page hidden">
<div class="page-header">
<h1>标签管理</h1>
<button class="btn-primary" onclick="showTagForm()">新建标签</button>
</div>
<table class="data-table">
<thead>
<tr>
<th>名称</th>
<th>别名</th>
<th>文章数</th>
<th>操作</th>
</tr>
</thead>
<tbody id="tags-list"></tbody>
</table>
</div>
{{end}}
{{define "admin_page_pages"}}
<!-- 页面管理 -->
<div id="pages-page" class="page hidden">
<div class="page-header">
<h1>页面管理</h1>
<button class="btn-primary" onclick="showPageForm()">新建页面</button>
</div>
<table class="data-table">
<thead>
<tr>
<th>标题</th>
<th>别名</th>
<th>状态</th>
<th>排序</th>
<th>操作</th>
</tr>
</thead>
<tbody id="pages-list"></tbody>
</table>
</div>
{{end}}
{{define "admin_page_comments"}}
<!-- 评论管理 -->
<div id="comments-page" class="page hidden">
<div class="page-header">
<h1>评论管理</h1>
<select id="comment-post-filter" class="comment-post-filter" onchange="filterCommentsByPost()">
<option value="">全部文章</option>
</select>
</div>
<table class="data-table">
<thead>
<tr>
<th>作者</th>
<th>内容</th>
<th>文章</th>
<th>状态</th>
<th>时间</th>
<th>操作</th>
</tr>
</thead>
<tbody id="comments-list"></tbody>
</table>
</div>
{{end}}
{{define "admin_page_users"}}
<!-- 用户管理 -->
<div id="users-page" class="page hidden">
<div class="page-header">
<h1>用户管理</h1>
<button class="btn-primary" onclick="showUserForm()">新建用户</button>
</div>
<table class="data-table">
<thead>
<tr>
<th>用户名</th>
<th>昵称</th>
<th>邮箱</th>
<th>角色</th>
<th>状态</th>
<th>最后登录</th>
<th>操作</th>
</tr>
</thead>
<tbody id="users-list"></tbody>
</table>
</div>
{{end}}
{{define "admin_page_settings"}}
<!-- 基础设置 -->
<div id="settings-page" class="page hidden">
<div class="page-header">
<h1>基础设置</h1>
</div>
<form id="settings-form" class="settings-form">
<div class="form-group">
<label>站点名称</label>
<input type="text" id="setting-site-name" required>
</div>
<div class="form-group">
<label>站点描述</label>
<textarea id="setting-site-desc" rows="3"></textarea>
</div>
<div class="form-group">
<label class="checkbox-label">
<input type="checkbox" id="setting-show-comments">
前台显示评论
</label>
</div>
<div class="form-group">
<label>评论每页显示条数</label>
<input type="number" id="setting-comments-per-page" min="1" max="100" required>
</div>
<button type="submit" class="btn-primary">保存设置</button>
</form>
</div>
{{end}}
{{define "admin_page_files"}}
<!-- 文件管理 -->
<div id="files-page" class="page hidden">
<div class="page-header">
<h1>文件管理</h1>
<div>
<input type="file" id="file-upload-input" accept="image/jpeg,image/png,image/gif,image/webp" style="display:none" multiple>
<button class="btn-primary" onclick="document.getElementById('file-upload-input').click()">上传图片</button>
</div>
</div>
<p class="upload-hint">支持 jpg/png/gif/webp 格式,单个文件最大 5MB</p>
<div class="file-grid" id="file-grid"></div>
</div>
{{end}}
{{define "admin_page_themes"}}
<!-- 主题管理 -->
<div id="themes-page" class="page hidden">
<div class="page-header">
<h1>主题管理</h1>
<button class="btn-primary" onclick="showCreateThemeModal()">新建主题</button>
</div>
<div class="theme-settings">
<div class="form-group">
<label>当前主题</label>
<select id="theme-select" class="theme-selector">
<option value="">加载中...</option>
</select>
<button class="btn-primary" onclick="switchTheme()">切换主题</button>
</div>
<div id="theme-message" class="theme-message"></div>
</div>
<div class="theme-list" id="theme-list">
<!-- 主题列表将动态加载 -->
</div>
</div>
{{end}}
{{define "admin_page_theme_editor"}}
<!-- 主题编辑器 -->
<div id="theme-editor-page" class="page hidden">
<div class="page-header">
<h1>编辑主题: <span id="editor-theme-name"></span></h1>
<div>
<button class="btn-secondary" onclick="showPage('themes')">返回</button>
<button class="btn-primary" onclick="saveCurrentFile()">保存文件</button>
</div>
</div>
<div class="theme-editor-container">
<div class="theme-file-list">
<h3>文件列表</h3>
<div id="theme-files"></div>
</div>
<div class="theme-editor-content">
<div class="editor-header">
<h3 id="current-file-name">选择文件进行编辑</h3>
</div>
<textarea id="theme-file-editor" class="code-editor" placeholder="选择左侧文件进行编辑..."></textarea>
</div>
</div>
</div>
{{end}}
{{define "admin_modal_common"}}
<!-- 分类/标签/页面 表单弹窗 -->
<div id="modal" class="modal hidden">
<div class="modal-content">
<h3 id="modal-title">标题</h3>
<form id="modal-form">
<input type="hidden" id="modal-id">
<input type="hidden" id="modal-type">
<div class="form-group">
<label>名称</label>
<input type="text" id="modal-name" required>
</div>
<div class="form-group">
<label>别名(可选,用于 URL)</label>
<input type="text" id="modal-slug">
</div>
<div class="form-group modal-extra">
<!-- 动态内容 -->
</div>
<div class="modal-actions">
<button type="button" class="btn-secondary" onclick="hideModal()">取消</button>
<button type="submit" class="btn-primary">保存</button>
</div>
</form>
</div>
</div>
{{end}}
{{define "admin_modal_user"}}
<!-- 用户表单弹窗 -->
<div id="user-modal" class="modal hidden">
<div class="modal-content">
<h3 id="user-modal-title">新建用户</h3>
<form id="user-form">
<input type="hidden" id="user-id">
<div class="form-group">
<label>用户名</label>
<input type="text" id="user-username" required minlength="3" maxlength="50">
</div>
<div class="form-group" id="user-password-group">
<label>密码</label>
<input type="password" id="user-password" minlength="6" placeholder="至少 6 位">
</div>
<div class="form-group">
<label>昵称</label>
<input type="text" id="user-nickname">
</div>
<div class="form-group">
<label>邮箱</label>
<input type="email" id="user-email" required>
</div>
<div class="form-row">
<div class="form-group">
<label>角色</label>
<select id="user-role">
<option value="user">普通用户</option>
<option value="admin">管理员</option>
</select>
</div>
<div class="form-group">
<label>状态</label>
<select id="user-status">
<option value="1">启用</option>
<option value="0">禁用</option>
</select>
</div>
</div>
<div class="modal-actions">
<button type="button" class="btn-secondary" onclick="hideUserModal()">取消</button>
<button type="submit" class="btn-primary">保存</button>
</div>
</form>
</div>
</div>
{{end}}
{{define "admin_modal_theme"}}
<!-- 创建主题弹窗 -->
<div id="theme-modal" class="modal hidden">
<div class="modal-content modal-large">
<h3>新建主题</h3>
<form id="create-theme-form">
<div class="form-group">
<label>主题名称 *</label>
<input type="text" id="new-theme-name" required placeholder="例如: mytheme">
<small>只能包含字母、数字和下划线</small>
</div>
<div class="form-group">
<label>基于模板创建</label>
<select id="theme-template">
<option value="">加载中...</option>
</select>
</div>
<div class="modal-actions">
<button type="button" class="btn-secondary" onclick="hideThemeModal()">取消</button>
<button type="submit" class="btn-primary">创建主题</button>
</div>
</form>
</div>
</div>
{{end}}
+78
View File
@@ -0,0 +1,78 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登录 - GoBlog 后台管理</title>
<link rel="icon" href="/static/images/favicon.ico" type="image/x-icon">
<link rel="stylesheet" href="/static/css/adminstyle.css?v=3">
</head>
<body>
<div id="login-page">
<div class="login-box">
<h2>管理员登录</h2>
<form id="login-form">
<div class="form-group">
<label>用户名</label>
<input type="text" id="login-username" required autocomplete="username">
</div>
<div class="form-group">
<label>密码</label>
<input type="password" id="login-password" required autocomplete="current-password">
</div>
<div id="login-error" class="login-error hidden"></div>
<button type="submit" id="login-submit">登录</button>
</form>
</div>
</div>
<script>
// 已登录则直接进入后台(通过 Cookie 自动认证,调用接口验证有效性)
(async function () {
try {
var res = await fetch('/api/auth/me');
if (res.ok) {
location.replace('/admin');
}
} catch (e) { /* 网络异常继续显示登录页 */ }
})();
function showError(msg) {
const el = document.getElementById('login-error');
el.textContent = msg;
el.classList.remove('hidden');
}
document.getElementById('login-form').addEventListener('submit', async (e) => {
e.preventDefault();
const btn = document.getElementById('login-submit');
btn.disabled = true;
btn.textContent = '登录中...';
const username = document.getElementById('login-username').value;
const password = document.getElementById('login-password').value;
try {
const res = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
});
const data = await res.json();
if (res.ok) {
// 服务端已通过 Set-Cookie 写入 JWT,直接跳转即可
location.href = '/admin';
} else {
showError(data.error || '登录失败');
btn.disabled = false;
btn.textContent = '登录';
}
} catch (err) {
showError('网络错误,请稍后重试');
btn.disabled = false;
btn.textContent = '登录';
}
});
</script>
</body>
</html>