feat(wiki): add community image upload for wiki entities

Support uploading images for Pokemon, Items, and Habitats
Track upload history in new entity_image_uploads table
Update entity cards to display uploaded images and usage ribbons
This commit is contained in:
2026-05-03 01:08:45 +08:00
parent 36e10a06b0
commit 784cbdacd1
23 changed files with 1407 additions and 102 deletions

View File

@@ -148,6 +148,34 @@
- 详情页展示最后编辑者、最后编辑时间和编辑历史面板。
- 编辑历史中的用户信息只展示必要署名不暴露邮箱、token、hash 或内部元数据。
## Wiki 图片上传
- 已验证用户可以为以下 Wiki 实体上传图片:
- Pokemon
- 物品图标
- 栖息地
- 上传图片只支持 `png``jpg/jpeg``webp``gif`
- 上传图片由服务端保存到受控上传目录,不接受任意外部 URL也不信任客户端传入的最终文件路径。
- 上传路径由服务端按实体类型、实体展示名称和时间戳生成,格式示例:
- `items/甜蜜蜜/20260501002000.png`
- `pokemon/Pikachu/20260501002000.png`
- `habitats/森林/20260501002000.png`
- 路径中的实体名称仅用于资源归档和可读性,实体关联仍以数据库 ID 为准。
- 每次上传都会写入 `entity_image_uploads` 历史记录:
- `entity_type`
- `entity_id`
- `entity_name`
- `path`
- `original_filename`
- `mime_type`
- `byte_size`
- `created_by_user_id`
- `created_at`
- 实体表只保存当前显示图片的相对路径;历史上传记录不会因为切换当前图片而删除。
- API 对外返回图片展示所需字段:`path``url`、上传时间和上传者必要署名;不返回服务器绝对文件路径或内部存储元数据。
- 图片上传本身不直接改变实体内容;用户仍需保存实体编辑表单后,当前图片选择才成为实体行为并写入现有编辑审计。
- Docker 运行时上传目录必须使用 volume 持久化,避免重新 build 后丢失用户上传图片。
## 实体讨论
- Pokemon、物品、材料单、栖息地详情页支持讨论。
@@ -260,6 +288,7 @@ Pokemon 编辑表单使用标签页组织字段:
- 图片选择不直接创建或更新 Pokemon用户仍需通过 Save 保存,保存时沿用现有编辑审计。
- 图片选择界面使用 Pokédex 风格:上方显示当前选择的大图,大图下方显示版本、状态和描述,再下方以缩略图网格展示同一 Pokemon 的不同风格 / 版本 / 状态。
- Pokemon 保存显示图片的相对路径、风格、版本、状态和描述API 对外返回可直接展示的图片 URL但不暴露内部校验状态。
- Pokemon 也支持社区上传图片;上传图片使用通用 Wiki 图片上传历史,当前显示图片可在静态候选和上传图片之间切换。
- 基础标签页:
- 第一行ID、名称
- 第二行:喜欢的环境、特长
@@ -321,6 +350,7 @@ Pokemon 详情页展示:
- 可改花纹
- 无材料单:`no_recipe`
- 标签:使用喜欢的东西配置,可多选
- 图标图片:通过通用 Wiki 图片上传维护当前图标和历史上传记录
- 翻译
- 排序
@@ -331,10 +361,14 @@ Pokemon 详情页展示:
- 按用途筛选
- 按标签筛选
- 按自定义排序展示
- 物品列表卡片使用与 Pokemon 列表一致的居中图鉴式布局,只展示物品图标、名称和分类;不展示标签、入手方式或编辑元信息。
- 有用途的物品在卡片左上角以斜 Ribbon 展示用途名称。
- 已配置图标时,物品卡片展示图标缩略图;未配置图标时保留默认物品标记。
物品详情页展示:
- 基本信息
- 图标图片和图片上传历史
- 分类
- 用途
- 入手方式
@@ -369,6 +403,9 @@ Pokemon 详情页展示:
- 独立于物品列表展示
- 按结果物品分类展示
- 按自定义排序展示
- 材料单列表卡片使用与 Pokemon 列表一致的居中图鉴式布局,按结果物品展示图标、名称和分类;不展示编辑元信息。
- 有用途的结果物品在卡片左上角以斜 Ribbon 展示用途名称。
- Create Recipe 按钮展示在结果物品名称下方;已有材料单的卡片保留同等按钮空间但不显示按钮;标记为无材料单的物品展示禁用按钮;可创建材料单的物品展示可点击按钮并进入创建流程。
材料单详情页展示:
@@ -386,6 +423,7 @@ Pokemon 详情页展示:
- 名称
- 配方:多项物品 + 数量
- 可出现的 Pokemon
- 图片:通过通用 Wiki 图片上传维护当前图片和历史上传记录
- 翻译
- 排序
@@ -407,10 +445,12 @@ Pokemon 出现配置:
栖息地列表功能:
- 按自定义排序展示
- 展示配方摘要可能出现的 Pokemon 摘要
- 栖息地列表卡片使用与 Pokemon 列表一致的居中图鉴式布局,只展示栖息地图片和名称;不展示配方摘要可能出现的 Pokemon 摘要或编辑元信息。
- 已配置图片时,栖息地卡片展示图片缩略图;未配置图片时保留默认栖息地标记。
栖息地详情页展示:
- 图片和图片上传历史
- 配方列表
- 可能出现的 Pokemon 列表
- 出现时间
@@ -559,6 +599,7 @@ API 暴露边界:
- `GET /api/pokemon/fetch-options`:按搜索词返回 Pokemon CSV data 搜索结果;需要已验证用户;只返回 `id``identifier``name`
- `POST /api/pokemon/fetch`:按 data identifier 或 Pokemon ID 查询 CSV 资料并填充 Pokemon 编辑表单;需要已验证用户;不直接保存 Pokemon。
- `POST /api/pokemon/image-options`:按 data identifier 或 Pokemon ID 查询 pokesprite 可用图片候选;需要已验证用户;只返回 `id``identifier` 和图片候选列表。
- `POST /api/uploads/:entityType`:上传 Wiki 图片;需要已验证用户;`entityType` 支持 `pokemon``items``habitats`;返回图片历史记录项和可展示 URL。
- Life Post 的创建,以及作者本人对 Life Post 的更新、删除。
- `POST /api/life-posts`
- `PUT /api/life-posts/:id`