hl-api-changelog/changelogs/2026-04/2026-04-18_home-screen2-config.md

7.5 KiB

小程序首页第二屏配置 - 品牌故事 + 主题卡片入口

  • 日期: 2026-04-18
  • PR: #811 (Closes #810)
  • 服务: hl-user-service (8081) + hl-mp-service (8085)
  • 状态: 已合并到 dev,待测试环境部署

背景

小程序首页分两屏:

  • 第一屏Hero 大图/轮播(现有 sys_banner,不变)
  • 第二屏(本次新增):品牌故事文案 + 大主图 + 2 张主题卡片入口

原型节点:用户端页面(5).pen / M57M7 首页 / Screen2 plwfj


1. 管理端接口Admin

1.1 查询品牌故事(含草稿)

GET /admin/home-config/brand-story
Authorization: Bearer <admin token>

响应 Result<AdminBrandStoryRespVO>

{
  "code": 200,
  "data": {
    "id": "2045369223068311553",
    "title": "每一条线路,我们都亲自走过。",
    "subtitle": null,
    "description": "整个呼伦贝尔...",
    "coverUrl": "https://cdn.example.com/home/team-photo.jpg",
    "coverMaskType": "WHITE_TOP",
    "version": 1,
    "status": "ACTIVE",
    "createTime": "2026-04-18 13:09:59",
    "updateTime": "2026-04-18 13:09:59",
    "createdBy": "1002",
    "updatedBy": "1002",
    "createdByName": null,
    "updatedByName": null
  },
  "success": true
}

字段说明

字段 类型 说明
id String 主键雪花ID,JS 精度防护用 String
title String 主标题,支持 \n 换行
subtitle String? 副标题(预留,当前可为 null
description String 描述文案
coverUrl String? 主图 URL草稿可空;发布时必填
coverMaskType String 蒙层类型:WHITE_TOP=上白下透 / NONE=无
version Integer 版本号,publish 每次 +1
status String DRAFT=草稿 / ACTIVE=已发布 / ARCHIVED=已归档
createdBy/updatedBy String 操作人 adminIdString 防 JS 精度)

语义

  • 返回当前最新一条非删除记录(按 id 降序,包含 DRAFT
  • 管理端打开页面即可编辑当前状态,不管是草稿还是已发布
  • 无数据时返回 data: null(首次部署时可能出现)

1.2 保存或发布品牌故事

PUT /admin/home-config/brand-story
Authorization: Bearer <admin token>
Content-Type: application/json

请求体 AdminBrandStorySaveReqVO

{
  "id": null,
  "title": "每一条线路,我们都亲自走过。",
  "subtitle": null,
  "description": "整个呼伦贝尔...",
  "coverUrl": "https://cdn.example.com/home/team-photo.jpg",
  "coverMaskType": "WHITE_TOP",
  "publish": true
}

字段校验

字段 校验 说明
id 选填 有值=更新指定记录,null=新建
title @NotBlank, @Length(max=100) 必填
subtitle @Length(max=200) 选填
description @NotBlank, @Length(max=1000) 必填
coverUrl @NotBlank, @URL(protocol="https") 必填(只接受 https 链接)
coverMaskType @NotBlank 必填,值同上
publish Boolean true=直接发布(归档旧 ACTIVE,新记录设为 ACTIVEfalse=保存草稿

行为

  • publish=falsesaveDraft 插入/更新 status=DRAFT 记录
  • publish=truepublisharchiveAllActive() 把当前 ACTIVE 改 ARCHIVED,再插入 ACTIVE 新记录;@Lock4j 防并发;自动 evict Redis 缓存

响应 Result<Void>{"code":200, "message":"成功", "data":null, "success":true}

幂等保护@Idempotent(timeout=5, keyPrefix="admin-brand-story"),5 秒内重复请求返回缓存结果。

审计@OperationLog("发布小程序首页第二屏品牌故事"),操作日志自动写入。


2. 小程序端接口MP

2.1 获取首页第二屏数据(聚合)

GET /mp/home-config/screen2

不需要 tokenGateway 设为 X-Auth-Level=SKIP,匿名可访问)。

响应 Result<MpHomeScreen2VO>

{
  "code": 200,
  "data": {
    "brandStory": {
      "title": "每一条线路,我们都亲自走过。",
      "subtitle": null,
      "description": "整个呼伦贝尔...",
      "coverUrl": "https://cdn.example.com/home/team-photo.jpg",
      "coverMaskType": "WHITE_TOP"
    },
    "topics": [
      {
        "id": "XXXX",
        "title": "季节之旅",
        "subtitle": "夏/秋/冬三季体验",
        "coverUrl": "https://cdn.example.com/topics/season.jpg",
        "linkType": "PRODUCT_LIST",
        "linkTarget": "theme=SEASON"
      }
    ]
  },
  "success": true
}

字段说明

字段 类型 说明
brandStory Object? 品牌故事块,无数据时为 null
brandStory.title String 主标题,支持 \n 换行
brandStory.subtitle String? 副标题
brandStory.description String 描述
brandStory.coverUrl String? 主图 URL
brandStory.coverMaskType String 蒙层类型 WHITE_TOP/NONE
topics Array 主题卡片列表(按 sort_order 升序)
topics[].id String 主题 ID
topics[].title String 卡片标题
topics[].subtitle String? 卡片副标题
topics[].coverUrl String 卡片封面图
topics[].linkType String 跳转类型,如 PRODUCT_LIST / TOPIC_DETAIL
topics[].linkTarget String 跳转目标(路径/ID/参数)

关键:响应不包含 fromFallback 字段(内部 Feign 协议字段,VO 层已过滤)。


3. 缓存策略

Key home:screen2:mp:{env}env=dev/test/prod
TTL 30 分钟1800s
空值 TTL 60 秒(防穿透)
Evict 触发 brand PUT / topic CUD 任一发生

前端渲染建议:小程序可本地缓存 5 分钟减少重复请求;发现数据变化再 pull。


4. 错误处理

所有错误走项目统一错误码,HTTP 始终 200,业务码在 code 字段:

code 含义 常见场景
200 成功
400 参数校验失败 title 缺失 / coverUrl 非 https
401 未登录 admin token 过期
403 无权限 非 admin 访问 /admin/**
409 状态冲突 禁止 ACTIVE → DRAFT 回退
500 服务器错误 DB/Redis 异常

5. 管理端前端需要做的

  1. 页面:首页配置 / 第二屏
  2. 表单字段title / subtitle / description / coverUrl走素材库 system 分类上传) / coverMaskType下拉 WHITE_TOP/NONE
  3. 操作按钮保存草稿 (publish=false) / 立即发布 (publish=true,需二次确认弹窗)
  4. 首次打开:调 GET 接口,有数据则回填表单,无数据则空表单
  5. 发布后提示:调 GET 验证 status=ACTIVE,提示"发布成功,小程序缓存最多 30 分钟后生效"

6. 小程序前端需要做的

  1. 首页渲染:调 GET /mp/home-config/screen2
  2. 数据位置
    • brandStory.coverUrl 作为第二屏大图背景375×497 区)
    • brandStory.title + brandStory.description 浮于大图之上(位置 x=20, y=50 参考原型)
    • topics 渲染为 2 个横向卡片(位置 x=20, y=520, 335×220 参考原型)
  3. 空态brandStory=null 时第二屏隐藏;topics=[] 时卡片区隐藏
  4. shimmer/skeleton:请求中显示骨架屏

7. 变更影响

  • 现有 /admin/banner/* 接口不变(第一屏轮播独立)
  • 现有 /mp/banner/active 接口不变
  • 现有 /admin/topic/* 接口不变(本期复用 sys_topic,不动表结构
  • TopicService 新增方法:仅内部调用,不暴露接口