feat: 定时发布系统 — Phase 5 完成

- Post ScheduledAt 字段
- Scheduler goroutine 每分钟扫描到期文章
- Create/Update 校验最短 30min 定时
- Approve 审核晚于定时则即时发布
- public 列表+空间页过滤未到期文章
- 写文章页 datetime-local 选择器(min=now+30min)
- AutoMigrate 追加新表
This commit is contained in:
2026-06-22 00:39:04 +08:00
parent 0b8f6f890d
commit e9b7401dc9
14 changed files with 132 additions and 15 deletions

View File

@ -98,6 +98,13 @@ document.addEventListener('DOMContentLoaded', () => {
document.getElementById('postForm')?.addEventListener('submit', handleSubmit)
// 定时发布时间选择器 min 设为 now+30min
const scheduledAt = document.getElementById('scheduledAt');
if (scheduledAt) {
const min = new Date(Date.now() + 30 * 60 * 1000)
scheduledAt.setAttribute('min', min.toISOString().slice(0, 16))
}
// 类型切换联动:转载→显示来源,原创→显示禁止转载
const typeRadios = document.querySelectorAll('input[name="post_type"]')
const reprintSourceArea = document.getElementById('reprintSourceArea')
@ -192,6 +199,7 @@ async function handleSubmit(e) {
const reprintProhibited = document.getElementById('reprintProhibited')?.checked || false
const categoryId = document.getElementById('categoryId')?.value || ''
const tags = document.getElementById('tagInput')?.value.trim() || ''
const scheduledAt = document.getElementById('scheduledAt')?.value || ''
const isEdit = !!postId
const url = isEdit ? '/api/studio/posts/' + postId : '/api/studio/posts'
@ -211,6 +219,7 @@ async function handleSubmit(e) {
reprint_prohibited: reprintProhibited,
category_id: categoryId,
tags,
scheduled_at: scheduledAt,
}),
})
const data = await resp.json()