/** * 批量创建测试帖子,用于验证编辑器渲染、列表滚动、登录可见等功能 */ const BASE = 'http://localhost:8080'; const TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6InRlc3R1Iiwicm9sZSI6ImFkbWluIiwiZXhwIjoxNzgyMDYyODI2LCJpYXQiOjE3ODE0NTgwMjZ9.QmsRTyj_2YqmGHw_Mw7_gwmo-WbHtTeyqkWrTRfccV4'; const longBody = Array.from({ length: 30 }, (_, i) => { const n = i + 1; return `
虚拟滚动测试段落 ${n}:Lorem ipsum 论坛长文压测内容,包含中英文混排 Mixed Content 以及标点符号——「」、『』、…、!?。重复文本有助于观察滚动条、已读标记与列表项高度是否稳定。
`; }).join(''); const posts = [ { board_id: '1', title: '【测试】富文本排版大全', tags: '测试,排版,富文本', content: `这是一段普通正文,包含 加粗、斜体、下划线 和 删除线 样式。
引用块:论坛的价值在于记录,而不只是展示。
行内代码示例:npm run build,多行代码块:
func main() {
fmt.Println("Hello Jiang13 Forum")
}
外链测试:姜十三论坛仓库
分隔线以上,排版元素应全部正常显示。
`, }, { board_id: '2', title: '【测试】登录可见区块', tags: '测试,会员专属', content: `以下内容对游客隐藏,登录后可完整阅读。
这是会员专属段落:包含内部讨论纪要、未公开方案和敏感数据摘要。游客应看到模糊占位与登录引导按钮。
公开结尾:欢迎登录后查看上文隐藏内容。
`, }, { board_id: '1', title: '【测试】图片与图文混排', tags: '测试,图片', content: `下图使用占位图服务,用于验证图片自适应与懒加载:
图片下方继续正文,检查间距与圆角是否正常。
两张不同尺寸图片混排,移动端不应溢出容器。
`, }, { board_id: '2', title: '【测试】超长帖子 · 虚拟滚动压测', tags: '测试,长文', content: `本帖用于测试首页虚拟滚动与详情页渲染性能,正文重复段落以撑满屏幕。
${longBody}长文结束,如滚动流畅则通过。
`, }, { board_id: '1', title: '【测试】短帖 · 单行标题', tags: '测试', content: '极简短帖,仅一句话,用于测试列表项最小高度与摘要截取。
', }, { board_id: '2', title: '【测试】多级标题 H2~H6', tags: '测试,标题', content: `H2 下方正文。
H3 下方正文。
H4 下方正文。
H5 下方正文。
H6 下方正文,六级标题字号应明显小于 H2。
`, }, { board_id: '1', title: '【测试】混合登录可见 + 富文本', tags: '测试,会员专属,排版', content: `所有人可见的导读部分。
隐藏区 加粗 与 斜体:
members-only 标签`, }, { board_id: '2', title: '【测试】特殊字符与 Emoji', tags: '测试,编码', content: `公开引用:登录后上文应展开为完整富文本。
特殊符号:<script>alert(1)</script> 应被转义或过滤,不可执行。
Emoji:🎉 🚀 ✅ ❤️ 🔥 中日韩:姜十三论坛
数学符号:α + β = γ,箭头 → ← ↑ ↓
全角标点:,。!?;:""''【】
`, }, { board_id: '1', title: '【测试】多标签帖子', tags: 'Go,React,SQLite,部署,开源', content: `本帖携带五个标签,用于测试标签展示、搜索与筛选。
技术栈:Go + Gin + GORM + SQLite + React + TipTap。
`, }, { board_id: '2', title: '【测试】空行与换行保留', tags: '测试,换行', content: `第一段,后面有两个空行。
第二段,中间有
手动换行
应保留。
第三段结束。
`, }, ]; async function createPost(post) { const fd = new FormData(); fd.append('board_id', post.board_id); fd.append('title', post.title); fd.append('content', post.content); fd.append('tags', post.tags || ''); const res = await fetch(`${BASE}/api/posts`, { method: 'POST', headers: { Cookie: `jiang13_token=${TOKEN}` }, body: fd, }); const data = await res.json(); if (!res.ok || data.error) throw new Error(data.error || res.statusText); console.log(` OK post_id=${data.post_id} ${post.title}`); return data.post_id; } async function pinPost(postId) { const res = await fetch(`${BASE}/api/admin/posts/${postId}/pin`, { method: 'POST', headers: { Cookie: `jiang13_token=${TOKEN}`, 'Content-Type': 'application/json', }, body: JSON.stringify({ pinned: true }), }); const data = await res.json(); if (!res.ok || data.error) throw new Error(data.error || res.statusText); console.log(` PIN post_id=${postId}`); } async function main() { console.log(`开始创建 ${posts.length} 篇测试帖子...`); const ids = []; for (const post of posts) { ids.push(await createPost(post)); await new Promise((r) => setTimeout(r, 150)); } if (ids.length > 0) await pinPost(ids[0]); const list = await fetch(`${BASE}/api/posts?page=1&size=50`).then((r) => r.json()); console.log(`\n完成!当前帖子总数:${list.total}`); console.log(`新建帖子 ID:${ids.join(', ')}`); } main().catch((err) => { console.error('失败:', err.message); process.exit(1); });