fix typo error

This commit is contained in:
tamakyi
2026-09-10 19:27:21 +08:00
parent 8e2325eda5
commit e683e798aa
9 changed files with 176 additions and 109 deletions
+48
View File
@@ -333,3 +333,51 @@ RAM 子账号授予 `AliyunYundunGreenWebFullAccess`;②CHANGELOG 条目仍未
- 沙箱内若要用 overlay,注意 **overlay.json 的 Replace 键盘符必须小写**(`c:/...`), - 沙箱内若要用 overlay,注意 **overlay.json 的 Replace 键盘符必须小写**(`c:/...`),
大写 `C:/...` 会被 Go 规范化成 `c:\` 后匹配不上、报 `deleted in overlay`;stub 在 大写 `C:/...` 会被 Go 规范化成 `c:\` 后匹配不上、报 `deleted in overlay`;stub 在
`dev/s3stub/s3_stub.go`。本次用 `C:/Users/Tamakyi Gekka/AppData/Local/Temp/tb-overlay2.json` 跑通。 `dev/s3stub/s3_stub.go`。本次用 `C:/Users/Tamakyi Gekka/AppData/Local/Temp/tb-overlay2.json` 跑通。
---
## 第六轮:设置面板聚合(新增「防护设置」tab)+ 审核严格度排版修复
用户诉求:① 把防骚扰、屏蔽词、审核严格度、提问密码聚合到 `/user/profile` 下一个独立 tab;
② 审核严格度档位处「一个字就换行」很难看。
### 决策(AskUserQuestion 已确认)
- 新 tab 名称:**防护设置**(i18n 键 `admin.tabSecurity`,tab id `security`)。
- **「页面访问密码」一并迁入**(原先在「用户设置」面板)。
- 旧位置**完全移除,不留跳转提示**。
### 改动
**后端**
- `route/user/features.go`:新增 `ProfileTabSecurity = "security"`,并纳入 `ProfileTab()` 白名单
(不加入的话回跳会落到 account 面板)。
- `route/user/password.go`:`UpdateAskPassword` / `UpdatePagePassword` 的硬编码回跳
(`profileURLWithTab(ProfileTabQuestion)`、`"/user/profile"`)全部改为 `returnTab(ctx)`,
跟随表单携带的 `?tab=`。
**模板**
- `templates/user/profile.html`:tab 栏新增「防护设置」按钮;新增
`<div class="profile-panel" data-profile-panel="security">`,内含 防骚扰 / 屏蔽词 /
审核严格度 / 页面访问密码 / 提问密码 五个表单(action 均带 `?tab=security`)。
提问/私聊/投票面板中这些表单全部删除(**原先屏蔽词与审核严格度被重复渲染 3 份**)。
account 面板移除「页面访问密码」卡(原编号 7 让位,账号操作改为 7)。
JS 面板切换是全泛型(`[data-profile-tab]` / `[data-profile-panel]`),无需改动。
- `templates/user/moderation-strictness.html`(**只用 shell/脚本改,禁用 Write/Edit**):
1. 档位表格:档位列 `uk-table-shrink` + `white-space:nowrap`、范围列 `uk-table-expand`
—— 修掉右侧长文案把 4 字档位名(畅所欲言/正常水平/不听坏话)挤成逐字折行。
2. 选择区改三行:标题(显式 `display:block`)→ 下拉(独立 div)→
「未设置时跟随站点默认档位。」(独立 div)。
**i18n**:四语字典新增 `admin.tabSecurity`(防护设置 / 防護設置 / Protection / 防護設定),
插在「功能管理」组之后的**独立组**,未切开任何既有对齐组(避免 gofmt 重排污染 diff)。
### 验证
- `go test ./templates/`(含 profile 渲染、严格度回显断言 `selectedStrictnessOptions`)ok;
`./internal/i18n/` ok(四语键一致)。
- `go build` + `go vet` `./route/user/` 均 0。
- ⚠️ **gofmt 提醒(重要,易误判)**:`gofmt -l` 会列出**所有 CRLF 文件**(含本次完全没碰的
`route/user/moderation.go`、`vote.go`),因为 gofmt 把 CRLF 规范成 LF。
剥离 CR 后比对,本次改动**零格式差异** → 格式是对的。
**切勿跑 `gofmt -w`**,那会把文件转成 LF、造成全量 diff 污染。
+3
View File
@@ -634,6 +634,9 @@ var enDict = map[string]string{
"admin.featureResetQuota": "Reset counter", "admin.featureResetQuota": "Reset counter",
"admin.featureSave": "Save this feature", "admin.featureSave": "Save this feature",
// Protection panel: aggregates anti-harassment / blocked words / moderation strictness / page password / ask password
"admin.tabSecurity": "Protection",
// Feature management: states and messages // Feature management: states and messages
"feature.name.question": "Questions", "feature.name.question": "Questions",
"feature.name.chat": "Chats", "feature.name.chat": "Chats",
+3
View File
@@ -634,6 +634,9 @@ var jaDict = map[string]string{
"admin.featureResetQuota": "カウントをリセット", "admin.featureResetQuota": "カウントをリセット",
"admin.featureSave": "この機能を保存", "admin.featureSave": "この機能を保存",
// コンテンツ保護パネル:防骚扰 / 屏蔽詞 / 審核の厳格度 / ページアクセスパスワード / 質問パスワード を集約
"admin.tabSecurity": "防護設定",
// 機能管理:状態とメッセージ // 機能管理:状態とメッセージ
"feature.name.question": "質問", "feature.name.question": "質問",
"feature.name.chat": "チャット", "feature.name.chat": "チャット",
+3
View File
@@ -634,6 +634,9 @@ var zhCNDict = map[string]string{
"admin.featureResetQuota": "重置计数", "admin.featureResetQuota": "重置计数",
"admin.featureSave": "保存该功能设置", "admin.featureSave": "保存该功能设置",
// 内容防护面板:聚合防骚扰 / 屏蔽词 / 审核严格度 / 页面访问密码 / 提问密码
"admin.tabSecurity": "防护设置",
// 功能管理:状态与提示 // 功能管理:状态与提示
"feature.name.question": "提问", "feature.name.question": "提问",
"feature.name.chat": "私聊", "feature.name.chat": "私聊",
+3
View File
@@ -634,6 +634,9 @@ var zhTWDict = map[string]string{
"admin.featureResetQuota": "重設計數", "admin.featureResetQuota": "重設計數",
"admin.featureSave": "儲存該功能設定", "admin.featureSave": "儲存該功能設定",
// 內容防護面板:聚合防騷擾 / 屏蔽詞 / 審核嚴格度 / 頁面訪問密碼 / 提問密碼
"admin.tabSecurity": "防護設置",
// 功能管理:狀態與提示 // 功能管理:狀態與提示
"feature.name.question": "提問", "feature.name.question": "提問",
"feature.name.chat": "私聊", "feature.name.chat": "私聊",
+5 -1
View File
@@ -28,6 +28,10 @@ const (
ProfileTabQuestion = db.FeatureQuestion ProfileTabQuestion = db.FeatureQuestion
ProfileTabChat = db.FeatureChat ProfileTabChat = db.FeatureChat
ProfileTabVote = db.FeatureVote ProfileTabVote = db.FeatureVote
// ProfileTabSecurity 与受控功能无关:聚合「内容防护」类设置
// (防骚扰、屏蔽词、审核严格度、页面访问密码、提问密码),
// 这些设置横跨多个功能,原先散落在提问/私聊/投票面板(屏蔽词与审核严格度还被重复渲染 3 份)。
ProfileTabSecurity = "security"
) )
// profileURLWithTab 账号设置页 + 指定面板的回跳地址,用于保存后停留在原面板。 // profileURLWithTab 账号设置页 + 指定面板的回跳地址,用于保存后停留在原面板。
@@ -38,7 +42,7 @@ func profileURLWithTab(tab string) string {
// ProfileTab 归一化账号设置页的 tab 参数,非法值回落到用户设置面板。 // ProfileTab 归一化账号设置页的 tab 参数,非法值回落到用户设置面板。
func ProfileTab(tab string) string { func ProfileTab(tab string) string {
switch tab { switch tab {
case ProfileTabQuestion, ProfileTabChat, ProfileTabVote: case ProfileTabQuestion, ProfileTabChat, ProfileTabVote, ProfileTabSecurity:
return tab return tab
} }
return ProfileTabAccount return ProfileTabAccount
+7 -5
View File
@@ -17,7 +17,8 @@ import (
func UpdatePagePassword(ctx context.Context, f form.UpdatePagePassword) { func UpdatePagePassword(ctx context.Context, f form.UpdatePagePassword) {
// 反序列化失败(如请求体超限)时零值 Password="" 会把密码静默解除——先中止, // 反序列化失败(如请求体超限)时零值 Password="" 会把密码静默解除——先中止,
// 不触碰现有密码。govalid 校验失败(如密码超长)同样在此拦截,避免绕过前端限制。 // 不触碰现有密码。govalid 校验失败(如密码超长)同样在此拦截,避免绕过前端限制。
if abortOnFormError(ctx, "/user/profile") { // 该表单已随「内容防护」聚合迁入 security 面板,回跳地址跟随表单携带的 ?tab=。
if abortOnFormError(ctx, returnTab(ctx)) {
return return
} }
@@ -31,13 +32,14 @@ func UpdatePagePassword(ctx context.Context, f form.UpdatePagePassword) {
ctx.SetSuccessFlash(i18n.T(ctx.Lang(), "admin.flash.pagePwdUpdated")) ctx.SetSuccessFlash(i18n.T(ctx.Lang(), "admin.flash.pagePwdUpdated"))
} }
} }
ctx.Redirect("/user/profile") ctx.Redirect(returnTab(ctx))
} }
// UpdateAskPassword 更新提问密码 // UpdateAskPassword 更新提问密码
func UpdateAskPassword(ctx context.Context, f form.UpdateAskPassword) { func UpdateAskPassword(ctx context.Context, f form.UpdateAskPassword) {
// 同上:反序列化失败或校验失败时零值 Password="" 会把提问密码静默解除。 // 同上:反序列化失败或校验失败时零值 Password="" 会把提问密码静默解除。
if abortOnFormError(ctx, profileURLWithTab(ProfileTabQuestion)) { // 回跳地址跟随表单携带的 ?tab=(该表单已迁入「内容防护」security 面板)。
if abortOnFormError(ctx, returnTab(ctx)) {
return return
} }
@@ -51,6 +53,6 @@ func UpdateAskPassword(ctx context.Context, f form.UpdateAskPassword) {
ctx.SetSuccessFlash(i18n.T(ctx.Lang(), "admin.flash.askPwdUpdated")) ctx.SetSuccessFlash(i18n.T(ctx.Lang(), "admin.flash.askPwdUpdated"))
} }
} }
// 提问密码属于提问功能的专属设置,保存后回到「提问」面板 // 保存后回到提交时所在的面板(内容防护面板)
ctx.Redirect(profileURLWithTab(ProfileTabQuestion)) ctx.Redirect(returnTab(ctx))
} }
+42 -36
View File
@@ -8,59 +8,65 @@
本模板只负责展示,不重复实现判定。 本模板只负责展示,不重复实现判定。
--> -->
{{ $root := .Root }} {{ $root := .Root }}
<div class="uk-margin"> <div class="uk-margin" data-page-node-id="0VziNJMvvostIMmOJAfJ5g">
<form method="post" action="{{ .Action }}"> <form method="post" action="{{ .Action }}" data-page-node-id="ko4Nj1yDJIUUpsEoILiYAb">
{{ $root.CSRFTokenHTML }} {{ $root.CSRFTokenHTML }}
<legend class="uk-legend">{{t $root.LangCode "admin.moderationStrictness"}}</legend> <legend class="uk-legend" data-page-node-id="2usTgd9N8PHPO95MFzvct7">{{t $root.LangCode "admin.moderationStrictness"}}</legend>
<p class="uk-text-meta uk-text-small">{{t $root.LangCode "admin.moderationStrictnessHint"}}</p> <p class="uk-text-meta uk-text-small" data-page-node-id="GF3aXisM5hvonHBGY2m69p">{{t $root.LangCode "admin.moderationStrictnessHint"}}</p>
<p class="uk-text-meta uk-text-small">{{t $root.LangCode "admin.moderationStrictnessBaseline"}}</p> <p class="uk-text-meta uk-text-small" data-page-node-id="AoSpxE29Qnz8tgDhTEX8SU">{{t $root.LangCode "admin.moderationStrictnessBaseline"}}</p>
<table class="uk-table uk-table-small uk-table-divider"> <!-- 档位列必须 uk-table-shrink + nowrap:右侧「拦截范围」文案很长,
<thead> 自动布局会把该列压到极窄,导致 4 字档位名被逐字折行。 -->
<tr> <table class="uk-table uk-table-small uk-table-divider" data-page-node-id="NHmbNbedxyS9p1zF1xh04X">
<th>{{t $root.LangCode "admin.moderationStrictnessColumnLevel"}}</th> <thead data-page-node-id="E11Y0hvt2TJsKSaJncgwgf">
<th>{{t $root.LangCode "admin.moderationStrictnessColumnScope"}}</th> <tr data-page-node-id="aMFSpdotgCq0r6J2L8rCdq">
<th class="uk-table-shrink" style="white-space: nowrap;" data-page-node-id="2jACHZBk0oxOkr47BNuZ0v">{{t $root.LangCode "admin.moderationStrictnessColumnLevel"}}</th>
<th class="uk-table-expand" data-page-node-id="2Zo97ZXwvrdRT5Y7SGGDbC">{{t $root.LangCode "admin.moderationStrictnessColumnScope"}}</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody data-page-node-id="j0rtD87L017rNi73VtGNZI">
<tr> <tr data-page-node-id="z3H6fvsm60FhSmhmHt9lUf">
<td>{{t $root.LangCode "admin.moderationStrictnessOption.lax"}}</td> <td class="uk-table-shrink" style="white-space: nowrap;" data-page-node-id="fy0gR7lZnunOcjwbZdm363">{{t $root.LangCode "admin.moderationStrictnessOption.lax"}}</td>
<td>{{t $root.LangCode "admin.moderationStrictnessScope.lax"}}</td> <td class="uk-table-expand" data-page-node-id="7Z1Up9Su7AUn5Trl69aG6h">{{t $root.LangCode "admin.moderationStrictnessScope.lax"}}</td>
</tr> </tr>
<tr> <tr data-page-node-id="HAeGyGZcyJoKAsHwzGbLc0">
<td>{{t $root.LangCode "admin.moderationStrictnessOption.standard"}}</td> <td class="uk-table-shrink" style="white-space: nowrap;" data-page-node-id="vW3L2l6uS8eueDU9BTFpfV">{{t $root.LangCode "admin.moderationStrictnessOption.standard"}}</td>
<td>{{t $root.LangCode "admin.moderationStrictnessScope.standard"}}</td> <td class="uk-table-expand" data-page-node-id="luI6WgZHZuZ7imRc7Zfy0s">{{t $root.LangCode "admin.moderationStrictnessScope.standard"}}</td>
</tr> </tr>
<tr> <tr data-page-node-id="wARdw1jBaCI6hH31TZPIjC">
<td>{{t $root.LangCode "admin.moderationStrictnessOption.strict"}}</td> <td class="uk-table-shrink" style="white-space: nowrap;" data-page-node-id="0MTeu5eoZ1GRO8q4f7Skaw">{{t $root.LangCode "admin.moderationStrictnessOption.strict"}}</td>
<td>{{t $root.LangCode "admin.moderationStrictnessScope.strict"}}</td> <td class="uk-table-expand" data-page-node-id="7ZvrruLq1FQ9FOyDsmjA9C">{{t $root.LangCode "admin.moderationStrictnessScope.strict"}}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
<div class="uk-margin"> <div class="uk-margin" data-page-node-id="c3SODOKZkDUTm0moKYnNJz">
<label class="uk-form-label">{{t $root.LangCode "admin.moderationStrictness"}}</label> <label class="uk-form-label" style="display: block;" data-page-node-id="IBc6LpxtWpQxECLCOcNzlZ">{{t $root.LangCode "admin.moderationStrictness"}}</label>
{{/* 回显「最终生效」档位而非原始字段值:字段为空(跟随站点默认)时若直接比较, {{/* 回显「最终生效」档位而非原始字段值:字段为空(跟随站点默认)时若直接比较,
三个 option 都不匹配,浏览器会默认选中第一项(宽松),与实际生效的严格档不符。 三个 option 都不匹配,浏览器会默认选中第一项(宽松),与实际生效的严格档不符。
解析走 internal/template 的 moderationStrictness 函数(同一份事实来源)。 */}} 解析走 internal/template 的 moderationStrictness 函数(同一份事实来源)。 */}}
{{ $current := moderationStrictness $root.LoggedUser.ModerationStrictness }} {{ $current := moderationStrictness $root.LoggedUser.ModerationStrictness }}
<select name="strictness" class="uk-select uk-width-medium"> <div class="uk-margin-small-top" data-page-node-id="HIWMgKH7FXZ9BYygBQ23A8">
<option value="lax"{{ if eq $current "lax" }} selected{{ end }}> <select name="strictness" class="uk-select uk-width-medium" style="max-width: 100%;" data-page-node-id="43cBp9IvsqBOUUpcIqISNq">
{{t $root.LangCode "admin.moderationStrictnessOption.lax"}} <option value="lax"{{ if eq $current "lax" }} selected{{ end }} data-page-node-id="XLfr3E5HDhGCCe27M9DQQX">
</option> {{t $root.LangCode "admin.moderationStrictnessOption.lax"}}
<option value="standard"{{ if eq $current "standard" }} selected{{ end }}> </option>
{{t $root.LangCode "admin.moderationStrictnessOption.standard"}} <option value="standard"{{ if eq $current "standard" }} selected{{ end }} data-page-node-id="bucHVmBTgVGR93Hhja4Dl9">
</option> {{t $root.LangCode "admin.moderationStrictnessOption.standard"}}
<option value="strict"{{ if eq $current "strict" }} selected{{ end }}> </option>
{{t $root.LangCode "admin.moderationStrictnessOption.strict"}} <option value="strict"{{ if eq $current "strict" }} selected{{ end }} data-page-node-id="kbcP6ka4VLHBgNqUrQL3jV">
</option> {{t $root.LangCode "admin.moderationStrictnessOption.strict"}}
</select> </option>
<span class="uk-text-muted uk-text-small">{{t $root.LangCode "admin.moderationStrictnessUnsetHint"}}</span> </select>
</div>
<div class="uk-margin-small-top" data-page-node-id="x0HenJ4S8MklMYn0KwF3nP">
<span class="uk-text-muted uk-text-small" data-page-node-id="wjCCL3LYk3jbKWgng8IQQS">{{t $root.LangCode "admin.moderationStrictnessUnsetHint"}}</span>
</div>
</div> </div>
<div class="tb-card-save"> <div class="tb-card-save" data-page-node-id="vmD40ecSRAGLrWqlz5F2c5">
<button type="submit" class="uk-button uk-button-primary">{{t $root.LangCode "admin.updateModerationStrictness"}}</button> <button type="submit" class="uk-button uk-button-primary" data-page-node-id="r04SFvzxXIgjRvgG0xaQIw">{{t $root.LangCode "admin.updateModerationStrictness"}}</button>
</div> </div>
</form> </form>
</div> </div>
+62 -67
View File
@@ -501,6 +501,7 @@
<button type="button" class="profile-tab{{ if eq .ActiveProfileTab "question" }} is-active{{ end }}" data-profile-tab="question" role="tab" aria-selected="{{ if eq .ActiveProfileTab "question" }}true{{ else }}false{{ end }}">{{t .LangCode "explore.questionsTab"}}</button> <button type="button" class="profile-tab{{ if eq .ActiveProfileTab "question" }} is-active{{ end }}" data-profile-tab="question" role="tab" aria-selected="{{ if eq .ActiveProfileTab "question" }}true{{ else }}false{{ end }}">{{t .LangCode "explore.questionsTab"}}</button>
<button type="button" class="profile-tab{{ if eq .ActiveProfileTab "chat" }} is-active{{ end }}" data-profile-tab="chat" role="tab" aria-selected="{{ if eq .ActiveProfileTab "chat" }}true{{ else }}false{{ end }}">{{t .LangCode "qlist.chatsTab"}}</button> <button type="button" class="profile-tab{{ if eq .ActiveProfileTab "chat" }} is-active{{ end }}" data-profile-tab="chat" role="tab" aria-selected="{{ if eq .ActiveProfileTab "chat" }}true{{ else }}false{{ end }}">{{t .LangCode "qlist.chatsTab"}}</button>
<button type="button" class="profile-tab{{ if eq .ActiveProfileTab "vote" }} is-active{{ end }}" data-profile-tab="vote" role="tab" aria-selected="{{ if eq .ActiveProfileTab "vote" }}true{{ else }}false{{ end }}">{{t .LangCode "explore.votesTab"}}</button> <button type="button" class="profile-tab{{ if eq .ActiveProfileTab "vote" }} is-active{{ end }}" data-profile-tab="vote" role="tab" aria-selected="{{ if eq .ActiveProfileTab "vote" }}true{{ else }}false{{ end }}">{{t .LangCode "explore.votesTab"}}</button>
<button type="button" class="profile-tab{{ if eq .ActiveProfileTab "security" }} is-active{{ end }}" data-profile-tab="security" role="tab" aria-selected="{{ if eq .ActiveProfileTab "security" }}true{{ else }}false{{ end }}">{{t .LangCode "admin.tabSecurity"}}</button>
</div> </div>
<!-- ===================== 用户设置面板 ===================== --> <!-- ===================== 用户设置面板 ===================== -->
@@ -764,22 +765,8 @@
</form> </form>
</section> </section>
<!-- 7 页面访问密码:独立表单 --> <!-- 7 账号操作:导出两按钮同行;退出登录与停用我的账号同行
<section class="tb-pcard"> (原「页面访问密码」已迁入「防护设置」面板,此处不再重复) -->
<h3 class="tb-pcard-title">{{t .LangCode "admin.pagePassword"}}</h3>
<form method="post" action="/user/profile/update-page-password">
{{ .CSRFTokenHTML }}
<div class="uk-margin">
<label class="uk-form-label">{{t .LangCode "admin.pagePasswordHint"}}</label>
<input name="password" class="uk-input" type="password" placeholder="{{t .LangCode "admin.pagePasswordPlaceholder"}}">
</div>
<div class="tb-card-save">
<button type="submit" class="uk-button uk-button-primary">{{t .LangCode "admin.updatePagePassword"}}</button>
</div>
</form>
</section>
<!-- 8 账号操作:导出两按钮同行;退出登录与停用我的账号同行 -->
<section class="tb-pcard"> <section class="tb-pcard">
<h3 class="tb-pcard-title">{{t .LangCode "admin.account"}}</h3> <h3 class="tb-pcard-title">{{t .LangCode "admin.account"}}</h3>
<div class="tb-account-actions"> <div class="tb-account-actions">
@@ -811,46 +798,6 @@
<!-- ===================== 提问功能管理面板 ===================== --> <!-- ===================== 提问功能管理面板 ===================== -->
<div class="profile-panel" data-profile-panel="question"{{ if ne .ActiveProfileTab "question" }} hidden{{ end }}> <div class="profile-panel" data-profile-panel="question"{{ if ne .ActiveProfileTab "question" }} hidden{{ end }}>
{{ with .FeatureQuestion }}{{template "user/feature-control-form" .}}{{ end }} {{ with .FeatureQuestion }}{{template "user/feature-control-form" .}}{{ end }}
<hr>
<div class="uk-margin">
<form method="post" action="/user/harassment/update?tab=question">
{{ $.CSRFTokenHTML }}
<legend class="uk-legend">{{t $.LangCode "admin.harassment"}}</legend>
<div class="uk-margin">
<label class="uk-form-label">{{t $.LangCode "admin.askLimit"}}</label><br>
<label>
<input name="register_only" class="uk-checkbox" type="checkbox"
{{ if eq $.LoggedUser.HarassmentSetting "register_only"}}checked{{end}} >
<span class="uk-text-small"> {{t $.LangCode "admin.registerOnly"}}</span>
</label>
</div>
<div class="tb-card-save">
<button type="submit" class="uk-button uk-button-primary">{{t $.LangCode "admin.updateHarassment"}}</button>
</div>
</form>
</div>
<!-- 全局屏蔽词:三个功能面板共用同一份(见 user/global-blockwords 部分模板) -->
{{ template "user/global-blockwords" (dict "Root" $ "Action" "/user/blockwords/update?tab=question") }}
<!-- 审核严格度:三个功能面板共用同一份(见 user/moderation-strictness 部分模板) -->
{{ template "user/moderation-strictness" (dict "Root" $ "Action" "/user/moderation-strictness/update?tab=question") }}
<hr>
<div class="uk-margin">
<form method="post" action="/user/profile/update-ask-password">
{{ $.CSRFTokenHTML }}
<legend class="uk-legend">{{t $.LangCode "admin.askPassword"}}</legend>
<div class="uk-margin">
<label class="uk-form-label">{{t $.LangCode "admin.askPasswordHint"}}</label>
<input name="password" class="uk-input" type="password" placeholder="{{t $.LangCode "admin.askPasswordPlaceholder"}}">
</div>
<div class="tb-card-save">
<button type="submit" class="uk-button uk-button-primary">{{t $.LangCode "admin.updateAskPassword"}}</button>
</div>
</form>
</div>
</div><!-- /提问功能管理面板 --> </div><!-- /提问功能管理面板 -->
<!-- ===================== 私聊功能管理面板 ===================== --> <!-- ===================== 私聊功能管理面板 ===================== -->
@@ -881,25 +828,73 @@
</div> </div>
</form> </form>
</section> </section>
<hr>
<!-- 全局屏蔽词:提问/私聊/投票三面板共用同一份(见 user/global-blockwords 部分模板) -->
{{ template "user/global-blockwords" (dict "Root" $ "Action" "/user/blockwords/update?tab=chat") }}
<!-- 审核严格度:同样三面板共用一份(见 user/moderation-strictness 部分模板) -->
{{ template "user/moderation-strictness" (dict "Root" $ "Action" "/user/moderation-strictness/update?tab=chat") }}
</div><!-- /私聊功能管理面板 --> </div><!-- /私聊功能管理面板 -->
<!-- ===================== 投票功能管理面板 ===================== --> <!-- ===================== 投票功能管理面板 ===================== -->
<div class="profile-panel" data-profile-panel="vote"{{ if ne .ActiveProfileTab "vote" }} hidden{{ end }}> <div class="profile-panel" data-profile-panel="vote"{{ if ne .ActiveProfileTab "vote" }} hidden{{ end }}>
{{ with .FeatureVote }}{{template "user/feature-control-form" .}}{{ end }} {{ with .FeatureVote }}{{template "user/feature-control-form" .}}{{ end }}
</div><!-- /投票功能管理面板 -->
<!-- ===================== 内容防护面板 =====================
聚合「内容防护」相关设置:防骚扰、屏蔽词、审核严格度、页面访问密码、提问密码。
原先散落在提问/私聊/投票三个面板(屏蔽词与审核严格度还被重复渲染 3 份),
现统一收拢到本面板;各表单 action 携带 ?tab=security,保存后回到此处。 -->
<div class="profile-panel" data-profile-panel="security"{{ if ne .ActiveProfileTab "security" }} hidden{{ end }}>
<div class="uk-margin">
<form method="post" action="/user/harassment/update?tab=security">
{{ $.CSRFTokenHTML }}
<legend class="uk-legend">{{t $.LangCode "admin.harassment"}}</legend>
<div class="uk-margin">
<label class="uk-form-label">{{t $.LangCode "admin.askLimit"}}</label><br>
<label>
<input name="register_only" class="uk-checkbox" type="checkbox"
{{ if eq $.LoggedUser.HarassmentSetting "register_only"}}checked{{end}} >
<span class="uk-text-small"> {{t $.LangCode "admin.registerOnly"}}</span>
</label>
</div>
<div class="tb-card-save">
<button type="submit" class="uk-button uk-button-primary">{{t $.LangCode "admin.updateHarassment"}}</button>
</div>
</form>
</div>
<hr> <hr>
<!-- 全局屏蔽词:三个功能面板共用同一份(见 user/global-blockwords 部分模板) --> <!-- 全局屏蔽词:提问/私聊/投票共用同一份词表(见 user/global-blockwords 部分模板) -->
{{ template "user/global-blockwords" (dict "Root" $ "Action" "/user/blockwords/update?tab=vote") }} {{ template "user/global-blockwords" (dict "Root" $ "Action" "/user/blockwords/update?tab=security") }}
<!-- 审核严格度:三个功能面板共用同一份(见 user/moderation-strictness 部分模板) --> <!-- 审核严格度:提问/私聊/投票三条链路共用同一档位(见 user/moderation-strictness 部分模板) -->
{{ template "user/moderation-strictness" (dict "Root" $ "Action" "/user/moderation-strictness/update?tab=vote") }} {{ template "user/moderation-strictness" (dict "Root" $ "Action" "/user/moderation-strictness/update?tab=security") }}
</div><!-- /投票功能管理面板 -->
<hr>
<div class="uk-margin">
<form method="post" action="/user/profile/update-page-password?tab=security">
{{ $.CSRFTokenHTML }}
<legend class="uk-legend">{{t $.LangCode "admin.pagePassword"}}</legend>
<div class="uk-margin">
<label class="uk-form-label">{{t $.LangCode "admin.pagePasswordHint"}}</label>
<input name="password" class="uk-input" type="password" placeholder="{{t $.LangCode "admin.pagePasswordPlaceholder"}}">
</div>
<div class="tb-card-save">
<button type="submit" class="uk-button uk-button-primary">{{t $.LangCode "admin.updatePagePassword"}}</button>
</div>
</form>
</div>
<hr>
<div class="uk-margin">
<form method="post" action="/user/profile/update-ask-password?tab=security">
{{ $.CSRFTokenHTML }}
<legend class="uk-legend">{{t $.LangCode "admin.askPassword"}}</legend>
<div class="uk-margin">
<label class="uk-form-label">{{t $.LangCode "admin.askPasswordHint"}}</label>
<input name="password" class="uk-input" type="password" placeholder="{{t $.LangCode "admin.askPasswordPlaceholder"}}">
</div>
<div class="tb-card-save">
<button type="submit" class="uk-button uk-button-primary">{{t $.LangCode "admin.updateAskPassword"}}</button>
</div>
</form>
</div>
</div><!-- /内容防护面板 -->
<script> <script>
(function() { (function() {