feat: 编辑器锁定文章提示 - 禁用编辑,显示明确提示
- /studio/write?id=X 路由:文章被锁定时,页面显示紫色锁定横幅,标题/编辑器只读,提交按钮替换为锁定提示 - studio-editor.js:锁定态下 Vditor 设为 readonly 模式,隐藏工具栏,禁用 Ctrl+S 快捷键 - 新增 .studio-locked-banner / .locked-submit-hint 样式
This commit is contained in:
@ -154,6 +154,7 @@ func (ctrl *StudioController) WritePage(c *gin.Context) {
|
|||||||
"Post": post,
|
"Post": post,
|
||||||
"ActiveTab": "write",
|
"ActiveTab": "write",
|
||||||
"ExtraCSS": "/static/css/studio.css",
|
"ExtraCSS": "/static/css/studio.css",
|
||||||
|
"StatusNames": common.PostStatusDisplayNames,
|
||||||
}))
|
}))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,9 +8,20 @@
|
|||||||
|
|
||||||
<main class="studio-main">
|
<main class="studio-main">
|
||||||
<div class="editor-layout">
|
<div class="editor-layout">
|
||||||
|
{{if and .Post .Post.IsLocked}}
|
||||||
|
<div class="studio-locked-banner">
|
||||||
|
<div class="locked-banner-icon">🔒</div>
|
||||||
|
<div>
|
||||||
|
<strong>这篇文章已被锁定,无法编辑。</strong>
|
||||||
|
<p>如需解锁请联系管理员。当前状态:{{if $.StatusNames}}{{index $.StatusNames .Post.Status}}、已锁定{{end}}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
<form id="postForm" class="editor-form">
|
<form id="postForm" class="editor-form">
|
||||||
<input type="hidden" id="postId" value="{{if .Post}}{{.Post.ID}}{{end}}">
|
<input type="hidden" id="postId" value="{{if .Post}}{{.Post.ID}}{{end}}">
|
||||||
{{if .Post}}
|
{{if .Post}}
|
||||||
|
<input type="hidden" id="isLocked" value="{{if .Post.IsLocked}}1{{else}}0{{end}}">
|
||||||
<textarea id="editBody" style="display:none">{{.Post.Body}}</textarea>
|
<textarea id="editBody" style="display:none">{{.Post.Body}}</textarea>
|
||||||
{{end}}
|
{{end}}
|
||||||
|
|
||||||
@ -18,7 +29,8 @@
|
|||||||
<input type="text" id="postTitle" class="editor-title-input"
|
<input type="text" id="postTitle" class="editor-title-input"
|
||||||
value="{{if .Post}}{{.Post.Title}}{{end}}"
|
value="{{if .Post}}{{.Post.Title}}{{end}}"
|
||||||
placeholder="输入文章标题..."
|
placeholder="输入文章标题..."
|
||||||
maxlength="200" required autofocus>
|
maxlength="200" required autofocus
|
||||||
|
{{if and .Post .Post.IsLocked}}disabled{{end}}>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="editor-main">
|
<div class="editor-main">
|
||||||
@ -55,7 +67,11 @@
|
|||||||
<span class="status-item" id="wordCount">0 字</span>
|
<span class="status-item" id="wordCount">0 字</span>
|
||||||
<span class="status-item status-draft" id="draftStatus" style="display:none">草稿已保存</span>
|
<span class="status-item status-draft" id="draftStatus" style="display:none">草稿已保存</span>
|
||||||
<span class="status-spacer"></span>
|
<span class="status-spacer"></span>
|
||||||
|
{{if and .Post .Post.IsLocked}}
|
||||||
|
<span class="locked-submit-hint">🔒 此文已锁定,无法修改</span>
|
||||||
|
{{else}}
|
||||||
<button type="submit" class="btn btn-primary btn-submit">{{if .Post}}保存修改{{else}}发布帖子{{end}}</button>
|
<button type="submit" class="btn btn-primary btn-submit">{{if .Post}}保存修改{{else}}发布帖子{{end}}</button>
|
||||||
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -460,6 +460,44 @@
|
|||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---------- 锁定提示 ---------- */
|
||||||
|
.studio-locked-banner {
|
||||||
|
display: flex;
|
||||||
|
gap: 14px;
|
||||||
|
align-items: center;
|
||||||
|
padding: 16px 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background: #f3e5f5;
|
||||||
|
border: 1px solid #ce93d8;
|
||||||
|
border-radius: var(--radius);
|
||||||
|
color: #6a1b9a;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.studio-locked-banner p {
|
||||||
|
margin: 4px 0 0;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #8e24aa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.studio-locked-banner strong {
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.locked-banner-icon {
|
||||||
|
font-size: 28px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.locked-submit-hint {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #6a1b9a;
|
||||||
|
font-weight: 600;
|
||||||
|
padding: 8px 16px;
|
||||||
|
background: #f3e5f5;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
/* ---------- 占位提示 ---------- */
|
/* ---------- 占位提示 ---------- */
|
||||||
.studio-placeholder {
|
.studio-placeholder {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
@ -18,6 +18,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
const postId = document.getElementById('postId')?.value
|
const postId = document.getElementById('postId')?.value
|
||||||
const isEdit = !!postId
|
const isEdit = !!postId
|
||||||
|
const isLocked = document.getElementById('isLocked')?.value === '1'
|
||||||
|
|
||||||
let initialMD = ''
|
let initialMD = ''
|
||||||
const editBodyEl = document.getElementById('editBody')
|
const editBodyEl = document.getElementById('editBody')
|
||||||
@ -30,9 +31,10 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
cdn: '/static/vditor',
|
cdn: '/static/vditor',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
lang: 'zh_CN',
|
lang: 'zh_CN',
|
||||||
placeholder: '在此输入正文...',
|
placeholder: isLocked ? '此文已锁定,不可编辑' : '在此输入正文...',
|
||||||
|
readonly: isLocked,
|
||||||
|
|
||||||
toolbar: [
|
toolbar: isLocked ? [] : [
|
||||||
'headings', 'bold', 'italic', 'strike', '|',
|
'headings', 'bold', 'italic', 'strike', '|',
|
||||||
'line', 'code', 'inline-code', 'link', 'quote', '|',
|
'line', 'code', 'inline-code', 'link', 'quote', '|',
|
||||||
'list', 'ordered-list', 'check', 'outdent', 'indent', '|',
|
'list', 'ordered-list', 'check', 'outdent', 'indent', '|',
|
||||||
@ -100,12 +102,14 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
document.getElementById('postForm')?.addEventListener('submit', handleSubmit)
|
document.getElementById('postForm')?.addEventListener('submit', handleSubmit)
|
||||||
|
|
||||||
|
if (!isLocked) {
|
||||||
document.addEventListener('keydown', (e) => {
|
document.addEventListener('keydown', (e) => {
|
||||||
if ((e.ctrlKey || e.metaKey) && e.key === 's') {
|
if ((e.ctrlKey || e.metaKey) && e.key === 's') {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
document.getElementById('postForm')?.dispatchEvent(new Event('submit'))
|
document.getElementById('postForm')?.dispatchEvent(new Event('submit'))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
function updateWordCount() {
|
function updateWordCount() {
|
||||||
|
|||||||
Reference in New Issue
Block a user