feat: render question exports as assets

This commit is contained in:
Codex
2026-06-29 17:07:24 +08:00
parent 1bcd887731
commit 506d7015a0
23 changed files with 2038 additions and 85 deletions

View File

@@ -1015,7 +1015,10 @@ failed导入结果和目标表不一致必须提示管理员排查
## 题库导出对接
租户后台题库导出统一走后端生成结构化 payload前端不要直接查 Supabase 表拼导出文件。当前后端支持 JSON、`paper_json``print_payload` 三类基础导出,适合先做后台“导出 JSON/试卷预览”功能PDF/Word 二进制、水印和发布到资料下载后续由 worker 增强。
租户后台题库导出统一走后端生成结构化 payload前端不要直接查 Supabase 表拼导出文件。当前后端支持两种交付形态:
- 同步结构化导出:`json``paper_json``print_payload`,接口直接返回 base64 JSON/payload。
- 异步二进制导出:`pdf``docx`,接口先返回 `pending` job`apps/worker --job exports` 渲染 PDF/Word、水印并写入 `content_assets`,前端轮询 job 后再走资源签名下载或预览。
可用接口:
@@ -1066,6 +1069,27 @@ GET /api/tenant-content/exports/jobs
}
```
PDF/Word 异步导出:
```json
{
"scopeType": "collection",
"scopeId": "<questionCollectionId>",
"format": "pdf",
"exportType": "paper",
"includeAnswers": false,
"includeExplanations": false,
"options": {
"title": "天津专升本模拟试卷",
"watermarkText": "仅供内部使用",
"publishToAssets": true,
"assetVisibility": "tenant"
}
}
```
`format` 可为 `pdf``docx``publishToAssets=true` 表示导出文件可作为资料资源展示给对应可见范围用户;不传时默认生成后台私有资源,仅后台可下载。`assetVisibility` 支持 `public``tenant``members``svip``private`,生产默认建议用 `tenant/private/svip`,不要轻易公开带题目的文件。
响应关键结构:
```json
@@ -1102,14 +1126,54 @@ GET /api/tenant-content/exports/jobs
}
```
异步二进制导出初始响应:
```json
{
"job": {
"id": "...",
"status": "pending",
"questionCount": 20,
"outputHash": "..."
},
"export": null
}
```
worker 完成后,`GET /api/tenant-content/exports/jobs` 返回:
```json
{
"items": [
{
"id": "...",
"format": "pdf",
"status": "completed",
"assetId": "...",
"attemptCount": 1,
"outputMetadata": {
"delivery": "content_asset",
"fileName": "天津专升本模拟试卷.pdf",
"mimeType": "application/pdf",
"sizeBytes": 123456,
"checksumSha256": "...",
"assetId": "..."
}
}
]
}
```
前端处理规则:
- 导出按钮只给具备租户内容编辑权限的后台成员展示;接口仍以后端 `TENANT_CONTENT_EDITOR_REQUIRED` 为准。
- 下载 JSON 时使用 `files[0].contentBase64` 生成 Blob文件名使用后端返回的 `filename`
- `includeAnswers=false` 时,顶层答案字段和阅读理解/案例分析的子题答案都会被后端脱敏;前端不要在本地重新合并答案。
- `includeExplanations=false` 时,不展示解析,也不要从题目详情接口额外补解析。
- `paper_json`用于后台试卷预览和打印;正式 PDF/Word 导出等后端 worker 完成后再接二进制文件下载
- `GET /api/tenant-content/exports/jobs?scopeType=collection&scopeId=...` 用于后台导出历史;当前记录 metadata 和输出 hash不长期保存完整导出内容
- `paper_json` 可用于后台试卷预览和打印;`pdf/docx` 用于正式文件下载、资料发布和带水印留档
- `GET /api/tenant-content/exports/jobs?scopeType=collection&scopeId=...` 用于后台导出历史;结构化导出只记录 metadata 和输出 hash二进制导出记录 `assetId`、文件名、大小和 checksum
- `status=pending/rendering` 时展示生成中;`completed` 且存在 `assetId` 后,后台可调用 `POST /api/tenant-content/assets/sign-download` 下载PDF 也可调用 `POST /api/tenant-content/assets/sign-preview` 预览。
- 学生资料页只展示 `content_assets.status=active` 且非 `private` 的资源;后台私有导出不会出现在学生资料列表。
- 跨租户导出会返回 404 或 403前端不要重试其它租户 ID。
## 公共题库采纳对接