feat(文档库): 打通模板正文真实模式并新增渲染验证

模板列表接口不返回正文,展示、编辑与发起签署前需再取版本详情获取 contentHtml,
为此新增 getTemplateContent、createTemplateWithContent、updateTemplateContent 与
deleteTemplate(归档),并在签署端按 contentSha256 缓存正文快照。

同时新增 scripts/login.cjs 与 scripts/verify-pages.cjs,通过真实登录与 CDP
渲染截图、断言关键内容并收集运行时错误,并补充 .gitignore、eslint 忽略与文档说明。
This commit is contained in:
yelan
2026-09-17 14:10:45 +08:00
parent 0d271d90be
commit 81922d774f
20 changed files with 1640 additions and 187 deletions
+105
View File
@@ -0,0 +1,105 @@
/**
* 登录并保存会话,供页面渲染验证脚本复用。
*
* 为什么不 stub 接口:MEDISIGN 后端对无效 token 返回 401,
* utils/request.ts 的响应拦截器收到 401 会 clearAuthStorage() + 跳登录页,
* 伪造会话很容易被踢出去。走真实登录最省事。
*
* 验证码是强制的(不传会报「验证码错误或已过期」)。用法:
*
* node scripts/login.cjs # 第一步:抓验证码图片
* (用看图工具认出图片里的数字)
* node scripts/login.cjs 5274 # 第二步:带验证码登录,写 .session.json
*
* 结果写到 scripts/.session.json(已在 .gitignore 里,不会提交 token)。
*
* 文件用 .cjs 后缀:package.json 里的 "type": "module" 会把 .js 当 ES 模块,
* 而这里用 require 更简单,所以显式声明成 CommonJS。
*
* 依赖:Node 18+(内置 fetch)。无需额外安装依赖。
*/
const fs = require('fs')
const path = require('path')
const BASE_URL = process.env.VERIFY_BASE_URL || 'http://127.0.0.1:5173'
const USERNAME = process.env.VERIFY_USERNAME || 'admin'
const PASSWORD = process.env.VERIFY_PASSWORD || 'admin'
const OUT_DIR = __dirname
const CAPTCHA_JSON = path.join(OUT_DIR, '.captcha.json')
const CAPTCHA_PNG = path.join(OUT_DIR, '.captcha.png')
const SESSION_FILE = path.join(OUT_DIR, '.session.json')
async function fetchCaptcha() {
const res = await fetch(`${BASE_URL}/api/v1/auth/captcha`)
const json = await res.json()
if (json.code !== '0' && json.code !== 0) {
throw new Error('获取验证码失败: ' + json.message)
}
const { captchaId, imageBase64 } = json.data
fs.writeFileSync(CAPTCHA_JSON, JSON.stringify(json))
fs.writeFileSync(
CAPTCHA_PNG,
Buffer.from(String(imageBase64).replace(/^data:image\/\w+;base64,/, ''), 'base64'),
)
console.log('验证码已保存,请打开图片认出里面的数字:')
console.log(' ' + CAPTCHA_PNG)
console.log('captchaId = ' + captchaId)
console.log('')
console.log('然后执行: node scripts/login.cjs <识别出的数字>')
}
async function login(captchaCode) {
if (!fs.existsSync(CAPTCHA_JSON)) {
throw new Error('没有找到验证码,请先执行 node scripts/login.cjs 抓取验证码')
}
const { data } = JSON.parse(fs.readFileSync(CAPTCHA_JSON, 'utf8'))
const res = await fetch(`${BASE_URL}/api/v1/auth/login`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username: USERNAME,
password: PASSWORD,
captchaId: data.captchaId,
captchaCode,
}),
})
const json = await res.json()
if (json.code !== '0' && json.code !== 0) {
throw new Error(
'登录失败: ' + json.message + '(验证码可能已过期,重新执行 node scripts/login.cjs)',
)
}
fs.writeFileSync(SESSION_FILE, JSON.stringify(json.data, null, 2))
console.log('登录成功')
console.log(
' 用户 = ' + json.data.user.displayName + ' (' + json.data.user.username + ')',
)
console.log(' campusId = ' + json.data.user.campusId)
console.log(' dataScope = ' + json.data.user.dataScope)
console.log(' permissions = ' + json.data.user.permissions.length + ' 项')
console.log(' 会话已写入 ' + SESSION_FILE)
}
async function main() {
const captchaCode = process.argv[2]
if (captchaCode) {
await login(captchaCode.trim())
} else {
await fetchCaptcha()
}
}
main().catch((err) => {
console.error(err.message)
process.exit(1)
})