Files
jiang13-forum/templates/admin/settings.tmpl
freefire f0358e0f71 feat: 完整内容 Limits 与伪静态 Admin
设置页可配字数/编辑窗/分页与伪静态后缀;公开帖/板/用户链接走规范路径并 301。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-30 04:12:43 +08:00

200 lines
12 KiB
Cheetah
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{{define "admin/settings"}}
{{template "base/head" .}}
{{template "base/navbar" .}}
<main class="j13-main j13-admin">
<h1>站点设置</h1>
{{template "admin/nav" .}}
{{template "base/alert" .}}
<h2>品牌</h2>
<form method="post" action="/admin/settings/brand" class="j13-form j13-admin-form">
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
<label>站点名称 <input name="name" required value="{{.Brand.Name}}"/></label>
<label>标语 <input name="slogan" value="{{.Brand.Slogan}}"/></label>
<label>简介 <textarea name="description" rows="3">{{.Brand.Description}}</textarea></label>
<label>关键词 <input name="keywords" value="{{.Brand.Keywords}}"/></label>
<label>Logo 字标(单字) <input name="logo_mark" maxlength="4" value="{{.Brand.LogoMark}}"/></label>
<label>ICP 备案号 <input name="icp_beian" value="{{.Brand.ICPBeian}}"/></label>
<label>ICP 链接 <input name="icp_beian_url" value="{{.Brand.ICPBeianURL}}"/></label>
<button type="submit">保存品牌</button>
</form>
<h3>品牌图片</h3>
<p class="j13-muted">Logo / Favicon / 默认 Open Graph 图;单文件不超过 2MB。</p>
<div class="j13-admin-brand-assets">
<div class="j13-admin-brand-asset">
<strong>Logo</strong>
{{if .Brand.Logo}}
<p><img class="j13-admin-brand-preview" src="{{.Brand.Logo}}" alt="Logo"/></p>
<p class="j13-muted"><code>{{.Brand.Logo}}</code></p>
<form method="post" action="/admin/settings/brand/clear" class="j13-inline-form" onsubmit="return confirm('清除 Logo');">
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
<input type="hidden" name="kind" value="logo"/>
<button type="submit" class="j13-linkbtn">清除</button>
</form>
{{else}}
<p class="j13-muted">未设置(导航使用字标)</p>
{{end}}
<form method="post" action="/admin/settings/brand/upload" enctype="multipart/form-data" class="j13-form j13-admin-form">
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
<input type="hidden" name="kind" value="logo"/>
<label>上传 <input type="file" name="file" accept="image/*" required/></label>
<button type="submit">上传 Logo</button>
</form>
</div>
<div class="j13-admin-brand-asset">
<strong>Favicon</strong>
{{if .Brand.Favicon}}
<p><img class="j13-admin-brand-preview j13-admin-brand-preview--sm" src="{{.Brand.Favicon}}" alt="Favicon"/></p>
<form method="post" action="/admin/settings/brand/clear" class="j13-inline-form" onsubmit="return confirm('清除 Favicon');">
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
<input type="hidden" name="kind" value="favicon"/>
<button type="submit" class="j13-linkbtn">清除</button>
</form>
{{else}}
<p class="j13-muted">未设置</p>
{{end}}
<form method="post" action="/admin/settings/brand/upload" enctype="multipart/form-data" class="j13-form j13-admin-form">
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
<input type="hidden" name="kind" value="favicon"/>
<label>上传 <input type="file" name="file" accept="image/*" required/></label>
<button type="submit">上传 Favicon</button>
</form>
</div>
<div class="j13-admin-brand-asset">
<strong>默认 OG 图</strong>
{{if .Brand.OGImage}}
<p><img class="j13-admin-brand-preview" src="{{.Brand.OGImage}}" alt="OG"/></p>
<form method="post" action="/admin/settings/brand/clear" class="j13-inline-form" onsubmit="return confirm('清除 OG 图?');">
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
<input type="hidden" name="kind" value="og_image"/>
<button type="submit" class="j13-linkbtn">清除</button>
</form>
{{else}}
<p class="j13-muted">未设置(回落 Logo / Favicon</p>
{{end}}
<form method="post" action="/admin/settings/brand/upload" enctype="multipart/form-data" class="j13-form j13-admin-form">
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
<input type="hidden" name="kind" value="og_image"/>
<label>上传 <input type="file" name="file" accept="image/*" required/></label>
<button type="submit">上传 OG 图</button>
</form>
</div>
</div>
<h2>基础限流</h2>
<p class="j13-muted">窗口内允许的操作次数(秒)。</p>
<form method="post" action="/admin/settings/limits" class="j13-form j13-admin-form">
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
<label>发帖 <input name="rate_limit_post" type="number" min="1" value="{{.RatePost}}"/></label>
<label>评论 <input name="rate_limit_comment" type="number" min="1" value="{{.RateComment}}"/></label>
<label>注册 <input name="rate_limit_register" type="number" min="1" value="{{.RateReg}}"/></label>
<label>登录 <input name="rate_limit_login" type="number" min="1" value="{{.RateLogin}}"/></label>
<label>窗口秒数 <input name="rate_limit_window_sec" type="number" min="10" value="{{.RateWindow}}"/></label>
<button type="submit">保存限流</button>
</form>
<h2>内容限制</h2>
<p class="j13-muted">字数、编辑时间窗、分页与账号相关上限。</p>
<form method="post" action="/admin/settings/content-limits" class="j13-form j13-admin-form">
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
<label>帖标题最大字数 <input name="post_title_max" type="number" min="1" value="{{.Limits.PostTitleMax}}"/></label>
<label>标签最大字数 <input name="post_tags_max" type="number" min="0" value="{{.Limits.PostTagsMax}}"/></label>
<label>帖正文最大字数 <input name="post_content_max" type="number" min="0" value="{{.Limits.PostContentMax}}"/></label>
<label>评论最大字数 <input name="comment_max" type="number" min="1" value="{{.Limits.CommentMax}}"/></label>
<label>搜索关键词最短 <input name="search_keyword_min" type="number" min="0" value="{{.Limits.SearchKeywordMin}}"/></label>
<label>搜索关键词最长 <input name="search_keyword_max" type="number" min="1" value="{{.Limits.SearchKeywordMax}}"/></label>
<label>默认分页大小 <input name="page_size_default" type="number" min="1" value="{{.Limits.PageSizeDefault}}"/></label>
<label>发帖可编辑(小时) <input name="post_edit_window_hours" type="number" min="0" value="{{.Limits.PostEditWindowHours}}"/></label>
<label>评论可编辑(分钟) <input name="comment_edit_window_minutes" type="number" min="0" value="{{.Limits.CommentEditWindowMinutes}}"/></label>
<label>密码最短长度 <input name="password_min_len" type="number" min="4" value="{{.Limits.PasswordMinLen}}"/></label>
<label>头像最大 MB <input name="avatar_max_mb" type="number" min="1" value="{{.Limits.AvatarMaxMB}}"/></label>
<label>签名最大字数 <input name="signature_max" type="number" min="0" value="{{.Limits.SignatureMax}}"/></label>
<label>Feed 列表样式
<select name="feed_list_style">
<option value="title"{{if eq .Limits.FeedListStyle "title"}} selected{{end}}>仅标题</option>
<option value="excerpt"{{if eq .Limits.FeedListStyle "excerpt"}} selected{{end}}>摘要</option>
<option value="thumbnail"{{if eq .Limits.FeedListStyle "thumbnail"}} selected{{end}}>缩略图</option>
</select>
</label>
<label class="j13-check"><input type="checkbox" name="open_posts_in_new_tab" value="1"{{if .Limits.OpenPostsInNewTab}} checked{{end}}/> 帖子链接新标签打开</label>
<label class="j13-check"><input type="checkbox" name="open_content_links_in_new_tab" value="1"{{if .Limits.OpenContentLinksInNewTab}} checked{{end}}/> 正文外链新标签打开</label>
<button type="submit">保存内容限制</button>
</form>
<h2>伪静态</h2>
<p class="j13-muted">启用后公开路径形如 <code>/post/123.{{.Limits.PermalinkExt}}</code>;无后缀请求会 301 到规范 URL。</p>
<form method="post" action="/admin/settings/permalink" class="j13-form j13-admin-form">
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
<label class="j13-check"><input type="checkbox" name="permalink_enabled" value="1"{{if .Limits.PermalinkEnabled}} checked{{end}}/> 启用伪静态后缀</label>
<label>后缀(不含点) <input name="permalink_ext" maxlength="16" pattern="[A-Za-z0-9]{1,16}" value="{{.Limits.PermalinkExt}}" placeholder="html"/></label>
<button type="submit">保存伪静态</button>
</form>
<h2>侧栏组件</h2>
<p class="j13-muted">控制首页与帖详情右栏可选块的显示与顺序(热门帖为固定块,不在此列)。友链页「侧栏显示」与此共用同一配置。</p>
<form method="post" action="/admin/settings/aside-widgets" class="j13-form j13-admin-form">
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
<ul class="j13-admin-aside-widgets">
{{range .AsideWidgets}}
<li>
<input type="hidden" name="order" value="{{.ID}}"/>
<label class="j13-check"><input type="checkbox" name="enabled" value="{{.ID}}"{{if .Enabled}} checked{{end}}/> {{.Label}}</label>
<span class="j13-admin-aside-move">
{{if .CanMoveUp}}<button type="submit" name="move" value="up:{{.ID}}" class="j13-btn-secondary">上移</button>{{end}}
{{if .CanMoveDown}}<button type="submit" name="move" value="down:{{.ID}}" class="j13-btn-secondary">下移</button>{{end}}
</span>
</li>
{{end}}
</ul>
<button type="submit">保存侧栏</button>
</form>
<h2>敏感词(有效 {{.FilterCount}} 个)</h2>
<p class="j13-muted">每行一个词,# 开头为注释。保存后立即热更新。</p>
<form method="post" action="/admin/settings/filter-words" class="j13-form j13-admin-form">
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
<label>词表 <textarea name="filter_words" rows="12">{{.FilterWords}}</textarea></label>
<button type="submit">保存敏感词</button>
</form>
<h2>邮件 SMTP</h2>
<p class="j13-muted">启用后可用于注册验证码、忘记密码重置与通知。{{if .MailReady}}当前:已就绪。{{else}}当前:未就绪。{{end}}{{if .Mail.HasPassword}} 已保存密码。{{end}}</p>
<form method="post" action="/admin/settings/mail" class="j13-form j13-admin-form">
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
<label class="j13-check"><input type="checkbox" name="enabled" value="1"{{if .Mail.Enabled}} checked{{end}}/> 启用邮件</label>
<label>SMTP Host <input name="host" value="{{.Mail.Host}}" placeholder="smtp.example.com"/></label>
<label>端口 <input name="port" type="number" min="1" value="{{.Mail.Port}}"/></label>
<label>加密
<select name="encryption">
<option value="ssl"{{if eq .Mail.Encryption "ssl"}} selected{{end}}>SSL</option>
<option value="starttls"{{if eq .Mail.Encryption "starttls"}} selected{{end}}>STARTTLS</option>
<option value="none"{{if eq .Mail.Encryption "none"}} selected{{end}}>无</option>
</select>
</label>
<label>用户名 <input name="username" value="{{.Mail.Username}}" autocomplete="off"/></label>
<label>密码 <input name="password" type="password" value="" autocomplete="new-password" placeholder="留空表示不修改"/></label>
<label>发件人 From <input name="from" type="email" value="{{.Mail.From}}"/></label>
<label>发件人显示名 <input name="from_name" value="{{.Mail.FromName}}"/></label>
<button type="submit">保存邮件设置</button>
</form>
<form method="post" action="/admin/settings/mail/test" class="j13-form j13-admin-form">
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
<label>测试收件邮箱 <input name="test_to" type="email" required placeholder="you@example.com"/></label>
<button type="submit" class="j13-btn-secondary">发送测试信</button>
</form>
<h2>SQLite 备份</h2>
<p class="j13-muted">将当前数据库文件复制到 data 目录并下载。备份含用户哈希、私信等全库数据,请妥善保管。仅支持 SQLite其它引擎请使用库方工具。</p>
{{if .CanBackup}}
<form method="post" action="/admin/settings/backup" class="j13-form j13-admin-form">
<input type="hidden" name="_csrf" value="{{.CSRF}}"/>
<button type="submit">立即备份并下载</button>
</form>
{{else}}
<p class="j13-muted">当前不是 SQLite一键文件备份不可用。</p>
{{end}}
</main>
{{template "base/footer" .}}
{{end}}