hl-api-changelog/changelogs/2026-07/12_feat_grassland_guide_admin_mp_vod.md

19 KiB

草原指南管理、VOD 素材与小程序接口

服务: hl-user-servicehl-resource-servicehl-mp-servicehl-gateway
PR: #4916#4917#4918
Issue: #4914
日期: 2026-07-12
影响范围: 管理后台草原指南内容维护、素材库草原指南分类、小程序草原指南列表/详情/播放


一、前端必须先确认的结论

  1. 草原指南是独立内容模块,不是“小程序专用素材库列表”;页面不做内容分类筛选。
  2. 素材库新增固定顶级分类:
    • 名称:草原指南
    • 编码:grassland_guide
    • 编码固定,不能删除、停用或修改;显示名称和排序可以调整。
  3. 视频、可选自定义封面、富文本图片都由后台管理员上传;小程序用户没有上传接口
  4. 视频文件走阿里云 VOD,确认后自动注册为 grassland_guide 分类的视频素材。
  5. 视频封面规则:
    • customCoverMaterialId:使用管理员上传的图片,coverSource=CUSTOM
    • 不传或传 null:使用阿里云 VOD 自动截帧封面,coverSource=AUTO
  6. 本次没有新增 /mp/material/miniprogram/page,小程序草原指南只调用本文的 /mp/grassland-guide/**
  7. 所有业务失败仍可能返回 HTTP 200;前端必须判断响应体 code / success

二、管理后台菜单与权限

配置
菜单名 草原指南管理
路由 /grassland-guide
组件路径 grassland-guide/GrasslandGuideList
图标 VideocamOutline
列表权限 grassland-guide:list
新增权限 grassland-guide:create
编辑权限 grassland-guide:edit
发布权限 grassland-guide:publish
下线权限 grassland-guide:offline
设置精选权限 grassland-guide:featured
上传视频权限 grassland-guide:vod:upload

菜单及按钮已分配给 SUPER_ADMINOPERATOR

  • 所有管理端接口均要求管理员登录。
  • 列表、详情没有额外业务角色限制。
  • 创建、更新、发布、下线、VOD 上传仅允许 SUPER_ADMINOPERATOR
  • 当前没有“删除草原指南内容”接口,只允许下线。

三、接口总表

管理端内容接口

方法 路径 说明
GET /admin/grassland-guide/videos 分页查询
GET /admin/grassland-guide/videos/{videoId} 内容详情
POST /admin/grassland-guide/videos 创建草稿
PUT /admin/grassland-guide/videos/{videoId} 全量更新
PUT /admin/grassland-guide/videos/{videoId}/publish 发布/重新发布
PUT /admin/grassland-guide/videos/{videoId}/offline 下线

管理端 VOD 接口

方法 路径 说明
POST /admin/grassland-guide/vod/upload/create 创建 VOD 上传会话
POST /admin/grassland-guide/vod/upload/refresh 刷新上传凭证
POST /admin/grassland-guide/vod/upload/confirm 确认上传并注册素材
GET /admin/grassland-guide/vod/materials/{materialId}/play-auth 后台预览播放凭证

小程序只读接口

方法 路径 说明
GET /mp/grassland-guide/home 精选区 + 视频分页
GET /mp/grassland-guide/videos 视频分页
GET /mp/grassland-guide/videos/{videoId} 视频详情
GET /mp/grassland-guide/videos/{videoId}/play-auth 短效播放凭证

小程序仅放行以上精确 GET 路径;同路径的 POSTPUTDELETE 不放行。


四、管理端视频内容契约

4.1 分页查询 GET /admin/grassland-guide/videos

Query

字段 类型 必填 默认/约束 说明
keyword String - 标题、摘要模糊匹配
status String DRAFT/PUBLISHED/OFFLINE 状态精确过滤
featured Boolean - 是否精选
page Integer 默认 1,最小 1 页码
pageSize Integer 默认 20,范围 1–100 每页条数

固定排序:publishTime DESC, videoId DESC。管理列表不按 sortWeight 排序。

PageResult<GrasslandGuideVideoListVO>

分页对象只有 recordstotalpagepageSize,没有 totalPages

列表项字段 类型 说明
videoId String 内容 ID
title String 标题
summary String 摘要
effectiveCoverUrl String 实际生效的封面
coverSource String AUTO/CUSTOM
durationSeconds Long 视频时长(秒)
featured Boolean 是否精选
showProducedBadge Boolean 是否显示“呼籁出品”角标
sortWeight Integer 精选排序权重
status String DRAFT/PUBLISHED/OFFLINE
publishTime LocalDateTime 首次发布时间
linkedProductId String 预留关联产品 ID,一期不做跳转

所有雪花 ID 在响应中按 String 返回,前端不要转成 JavaScript Number

4.2 详情 GET /admin/grassland-guide/videos/{videoId}

详情包含列表项全部字段,并增加:

字段 类型 说明
videoMaterialId String VOD 视频素材 ID
customCoverMaterialId String 自定义封面素材 ID,可空
coverMaterialId String 一期兼容字段,值同 customCoverMaterialId
contentHtml String 白名单清洗后的正文 HTML
contentImageMaterialIds String[] 正文图片素材 ID
version Integer 乐观锁版本
createdBy String 创建管理员 ID
updatedBy String 最后更新管理员 ID
createdAt LocalDateTime 创建时间
updatedAt LocalDateTime 更新时间
relatedVideos GrasslandGuideVideoListVO[] 按手工顺序返回的相关推荐

4.3 创建草稿 POST /admin/grassland-guide/videos

创建允许字段暂不完整,返回的初始状态固定为 DRAFTversion=1

4.4 全量更新 PUT /admin/grassland-guide/videos/{videoId}

创建和更新共用以下字段;更新时额外必传 version

字段 类型 DTO 必填 约束/语义
title String 最长 200;空白按 null
summary String 最长 1000;空白按 null
videoMaterialId Long/String grassland_guide 分类的可播放 VOD 素材
customCoverMaterialId Long/String 自定义图片封面;兼容输入别名 coverMaterialId
contentHtml String 富文本正文
contentImageMaterialIds Long[]/String[] 正文图片素材 ID,元素不能为 null
featured Boolean 未传按 false
showProducedBadge Boolean 未传按 false
sortWeight Integer 未传按 0
publishTime LocalDateTime 首次发布未传时由服务端补当前时间
linkedProductId Long/String 二期预留,一期不做产品跳转
relatedVideoIds Long[]/String[] 最多 3 条,保持数组顺序
version Integer 更新必填 必须等于详情返回的当前版本

更新是全量覆盖,不是 PATCH。 未传布尔值会写为 false,未传 sortWeight 会写为 0,未传正文图片/相关推荐会清空,未传自定义封面会切回 AUTO

示例:

{
  "title": "呼伦贝尔草原上的风为什么特别大?",
  "summary": "从地形和季节理解草原的风。",
  "videoMaterialId": "2030000000000001",
  "customCoverMaterialId": null,
  "contentHtml": "<p>正文内容</p>",
  "contentImageMaterialIds": [],
  "featured": true,
  "showProducedBadge": true,
  "sortWeight": 100,
  "publishTime": null,
  "linkedProductId": null,
  "relatedVideoIds": ["2030000000000002", "2030000000000003"],
  "version": 1
}

4.5 发布/下线

请求体一致:

{ "version": 2 }

允许的状态流转只有:

DRAFT -> PUBLISHED -> OFFLINE -> PUBLISHED
  • 不允许退回 DRAFT
  • 全量更新、发布、下线成功后都会 version + 1
  • 首次从草稿发布且 publishTime 为空时,服务端自动填当前时间。
  • 下线后重新发布保留首次发布时间。

4.6 发布门禁

发布前必须同时满足:

  • 标题非空;
  • 有效 VOD 视频素材,媒体状态为 Normal,时长大于 0;
  • 有生效封面;
  • 正文至少有有效文字或一张图片;
  • 有发布时间;
  • 有 2–3 条相关推荐。

相关推荐不能为 null、不能重复、不能指向自身,且目标内容必须存在。管理端按请求数组顺序保存;小程序详情只返回其中仍为 PUBLISHED 的内容,不自动补位。

富文本会做白名单清洗;img.src 只允许 HTTP/HTTPS,并且必须与 contentImageMaterialIds 对应素材 URL 集合完全一致。


五、VOD 上传与素材注册

5.1 创建上传会话

POST /admin/grassland-guide/vod/upload/create

{
  "title": "草原指南测试视频",
  "fileName": "grassland-guide.mp4"
}
入参字段 类型 必填 约束
title String 1–128 字符
fileName String 1–255 字符,保留真实扩展名;支持 mp4/mov/avi/mkv/wmv/flv/webm

返回 data

字段 类型 说明
uploadSessionId String 后续 refresh/confirm 使用
vodFileId String 阿里云 VideoId
uploadAddress String 阿里云上传地址,按不透明字符串处理
uploadAuth String 阿里云上传凭证,按不透明敏感字符串处理

uploadAddressuploadAuth 禁止写日志、LocalStorage 或业务数据库。

5.2 刷新上传凭证

POST /admin/grassland-guide/vod/upload/refresh

{ "uploadSessionId": "会话ID" }

返回结构同创建接口。阿里云浏览器上传 SDK 触发凭证过期回调时调用此接口,并把新凭证交回 SDK。

5.3 确认上传并注册素材

POST /admin/grassland-guide/vod/upload/confirm

{
  "uploadSessionId": "会话ID",
  "materialName": "草原指南测试视频"
}
字段 类型 必填 约束
uploadSessionId String 非空
materialName String 最长 200

只有阿里云媒体状态为 Normal 时才会确认成功。若视频仍在转码/截图处理中,前端保留会话 ID,稍后重试 confirm,不要重新创建上传会话。重复 confirm 是幂等的,会返回同一个 fileId/materialId,并刷新异步生成的时长和封面。

成功响应:

{
  "code": 200,
  "message": "成功",
  "data": {
    "file": {
      "fileId": "...",
      "storageProvider": "VOD",
      "providerFileId": "阿里云VideoId",
      "durationSeconds": 125,
      "mediaStatus": "Normal",
      "thumbnailUrl": "阿里云自动封面URL"
    },
    "material": {
      "materialId": "...",
      "categoryCode": "grassland_guide",
      "fileType": "VIDEO",
      "storageProvider": "VOD",
      "providerFileId": "阿里云VideoId",
      "durationSeconds": 125,
      "mediaStatus": "Normal",
      "thumbnailUrl": "阿里云自动封面URL"
    }
  },
  "success": true
}

前端保存 data.material.materialId,作为内容表单的 videoMaterialId

5.4 推荐的浏览器上传顺序

选择本地视频
  -> create 获取 uploadAddress/uploadAuth/uploadSessionId
  -> 使用阿里云 VOD 浏览器上传 SDK 直传
  -> 凭证过期时调用 refresh
  -> SDK 报告上传完成后调用 confirm
  -> confirm 返回 materialId
  -> 创建/更新草原指南草稿

不要把视频二进制提交给 HL 后端;后端只签发上传凭证、确认媒体状态并登记素材。

5.5 后台预览播放凭证

GET /admin/grassland-guide/vod/materials/{materialId}/play-auth

返回:

字段 类型 说明
vodFileId String 阿里云 VideoId
playAuth String 短效播放凭证
expiresInSeconds Long 本次凭证有效期,以返回值为准
durationSeconds Long 时长(秒)
coverUrl String 播放器封面

每次打开播放器或凭证即将过期时重新请求;不要缓存、持久化 playAuth


六、自定义封面与正文图片上传

图片继续复用现有素材库 OSS 上传流程:

  1. POST /admin/material/upload/token
  2. 浏览器按返回凭证直传 OSS
  3. POST /admin/material/upload/confirm

请求上传凭证时固定传:

{
  "categoryCode": "grassland_guide",
  "materialName": "视频自定义封面",
  "filename": "cover.jpg",
  "fileSize": 123456,
  "md5": "32位十六进制MD5",
  "contentType": "image/jpeg"
}
  • 自定义封面、正文图片必须是 grassland_guide 分类的有效图片素材。
  • 有自定义封面时传 customCoverMaterialId;不传/null 时后端使用 VOD 自动封面。
  • 自动封面读取顺序为阿里云 coverURL,为空时取 snapshots 中第一张有效图片;后端当前不主动发起截图任务。
  • 如果阿里云自动封面仍未生成,草稿可以保存,但发布会因缺少生效封面返回 371004;稍后重试发布会先刷新 VOD 元数据。
  • 删除、批量删除或移出分类时,如果素材正在被草原指南引用,返回 371009
  • 固定顶级分类本身不能删除、停用或修改编码,保护错误码为 210405

七、小程序接口详情

7.1 首页 GET /mp/grassland-guide/home

Querypage 默认 1;pageSize 默认 20、最大 100。

返回:

{
  "code": 200,
  "message": "成功",
  "data": {
    "featuredVideos": [],
    "videos": {
      "records": [],
      "total": 0,
      "page": 1,
      "pageSize": 20
    }
  },
  "success": true
}
  • featuredVideos 最多 5 条,只取已发布且 featured=true 的内容。
  • 精选排序:sortWeight DESC -> publishTime DESC -> videoId DESC
  • 没有精选时返回空数组,不使用普通视频兜底。
  • videos 返回全部已发布内容,排序为 publishTime DESC -> videoId DESC

7.2 视频分页 GET /mp/grassland-guide/videos

Query 同首页:pagepageSize

卡片字段:

字段 类型 说明
videoId String 内容 ID
title String 标题
summary String 摘要
coverUrl String 生效封面
coverSource String AUTO/CUSTOM
durationSeconds Long 时长(秒)

精选项在卡片字段基础上增加 showProducedBadge

7.3 视频详情 GET /mp/grassland-guide/videos/{videoId}

在卡片字段基础上增加:

字段 类型 说明
publishTime LocalDateTime 发布时间
contentHtml String 已清洗正文
relatedVideos 视频卡片数组 只包含仍在线的推荐内容,保持手工顺序
showProducedBadge Boolean 是否显示“呼籁出品”角标

7.4 播放凭证 GET /mp/grassland-guide/videos/{videoId}/play-auth

返回字段与后台预览一致:vodFileIdplayAuthexpiresInSecondsdurationSecondscoverUrl

  • 仅已发布内容可获取。
  • 接口不缓存,避免返回过期凭证。
  • 前端不得把 playAuth 当成长期播放 URL。

八、主要错误码

code 说明 前端动作
400 DTO 校验、枚举或 JSON 格式错误 展示具体 message
401 未登录/小程序写请求被拦截 走登录或停止请求
403 SUPER_ADMIN/OPERATOR 执行写操作 隐藏操作并提示无权限
371001 草原指南视频不存在或未发布 返回列表/显示已下线
371002 version 冲突 重新拉详情后再编辑
371003 非法状态流转 刷新状态
371004 发布条件不完整 按 message 补齐字段
371005 视频/封面/正文图片素材无效 重新选择素材
371006 相关推荐无效 检查数量、重复、自身和目标 ID
371007 正文图片 URL 与素材声明不一致 同步 contentHtml 和图片 ID
371009 素材正被草原指南引用 先解除内容引用
210405 固定素材分类受保护 不提供删除/停用/改编码入口
250507 VOD 媒体尚未处理完成 稍后重试 confirm
250511 VOD 确认处理中 防重复点击,稍后重试
503 user/resource 下游暂不可用 允许重试,不要当业务空数据

九、前端实施检查单

  • 新建 grassland-guide/GrasslandGuideList 并接入动态菜单。
  • 内容列表不增加“内容分类”筛选,只保留关键词、状态、精选筛选。
  • ID 全程按 String 保存和回传,避免精度丢失。
  • 编辑前先拉详情,更新/发布/下线始终提交最新 version
  • 更新接口按全量表单提交,不使用局部 PATCH 心智。
  • VOD 采用 create -> SDK 直传 -> refresh按需-> confirm 流程。
  • 上传凭证只保存在当前上传任务内,不落 LocalStorage、不打印。
  • 图片上传固定使用 categoryCode=grassland_guide
  • 自定义封面可清空;清空后展示后端返回的 VOD 自动封面。
  • 小程序播放器按需调用 play-auth,并按 expiresInSeconds 管理凭证。
  • 小程序实现列表骨架屏、空态、加载失败重试;接口空态为 200 + 空数组/空分页。
  • 不给小程序增加任何视频、封面或正文图片上传入口。

十、测试环境已验证

测试分支:dev-v3,合并提交:4d4f090dcc47527e247177277313eec636ec0ada

hl-user-service      8081 / 8181  Nacos healthy=true ✓
hl-resource-service  8082 / 8182  Nacos healthy=true ✓
hl-mp-service        8085 / 8185  Nacos healthy=true ✓
hl-gateway           8080 / 8180  Nacos healthy=true ✓

GET  /mp/grassland-guide/home                         -> 200,精选空数组 + 空分页 ✓
GET  /mp/grassland-guide/videos                       -> 200,PageResult total=0 ✓
GET  /mp/grassland-guide/videos/{不存在ID}             -> code=371001 ✓
POST /mp/grassland-guide/home                         -> code=401 ✓
GET  /admin/grassland-guide/videos未登录            -> code=401 ✓
GET  /admin/grassland-guide/videos管理员            -> 200,total=0 ✓
GET  /admin/menu/my                                   -> 草原指南菜单及组件路径存在 ✓
GET  /admin/dict/data/material_category               -> grassland_guide=ACTIVE ✓
POST /admin/grassland-guide/vod/upload/create空请求 -> code=400,路由与校验生效 ✓
阿里云 VOD GetCategories                              -> HTTP 200,当前 AK 具备 VOD 访问权限 ✓

Flyway

  • User V20260712_002V20260712_004 成功;
  • Resource V20260712_001 成功;
  • 菜单 7 条、固定分类 1 条、VOD 会话表、3 张草原指南内容表均已落库。

本轮没有创建真实云端测试视频,以免产生孤儿 VideoId/上传会话;真实大文件上传仍需前端联调时用测试视频执行一次 create -> 直传 -> confirm。


十一、不影响范围

  • 不修改现有通用素材列表接口。
  • 不增加小程序素材库上传或分页接口。
  • 不修改 hl-ui 现有代码;本文为前端实施契约。
  • linkedProductId 仅持久化,产品跳转留到二期。