feat: 文章属性前端完成 — Phase 3

- 写文章页:可见性/类型/转载来源/创作声明/禁止转载 属性表单
- 类型切换联动(转载显示来源,原创显示禁止转载复选框)
- 文章详情页:私密角标、置顶标记、创作声明横幅、转载来源
- 管理后台:置顶/取消置顶操作按钮
- PostService Create/Update 签名扩展接受文章属性
- DTO/接口同步更新
This commit is contained in:
2026-06-22 00:20:52 +08:00
parent 9c452afb40
commit 977c52513a
13 changed files with 225 additions and 18 deletions

View File

@ -98,6 +98,16 @@ document.addEventListener('DOMContentLoaded', () => {
document.getElementById('postForm')?.addEventListener('submit', handleSubmit)
// 类型切换联动:转载→显示来源,原创→显示禁止转载
const typeRadios = document.querySelectorAll('input[name="post_type"]')
const reprintSourceArea = document.getElementById('reprintSourceArea')
const reprintProhibitArea = document.getElementById('reprintProhibitArea')
typeRadios.forEach(r => r.addEventListener('change', () => {
const isReprint = document.querySelector('input[name="post_type"]:checked')?.value === 'reprint'
if (reprintSourceArea) reprintSourceArea.style.display = isReprint ? '' : 'none'
if (reprintProhibitArea) reprintProhibitArea.style.display = isReprint ? 'none' : ''
}))
if (!isLocked) {
document.addEventListener('keydown', (e) => {
if ((e.ctrlKey || e.metaKey) && e.key === 's') {
@ -174,6 +184,13 @@ async function handleSubmit(e) {
const body = vditor ? vditor.getValue() : ''
if (!body.trim()) { showToast('请输入正文', 'warning'); return }
// 读取文章属性
const visibility = document.querySelector('input[name="visibility"]:checked')?.value || 'public'
const postType = document.querySelector('input[name="post_type"]:checked')?.value || 'original'
const reprintSource = document.getElementById('reprintSource')?.value.trim() || ''
const declaration = document.getElementById('declaration')?.value || ''
const reprintProhibited = document.getElementById('reprintProhibited')?.checked || false
const isEdit = !!postId
const url = isEdit ? '/api/studio/posts/' + postId : '/api/studio/posts'
const method = isEdit ? 'PUT' : 'POST'
@ -184,7 +201,13 @@ async function handleSubmit(e) {
'Content-Type': 'application/json',
'X-CSRF-Token': getCSRFToken(),
},
body: JSON.stringify({ title, body }),
body: JSON.stringify({
title, body,
visibility, post_type: postType,
reprint_source: reprintSource,
declaration,
reprint_prohibited: reprintProhibited,
}),
})
const data = await resp.json()