17 KiB
小程序配置模块对接方案
模块:小程序配置 (Banner 首页配置 / 我的页面配置 / 协议政策 / FAQ) 后端服务:hl-user-service(Admin + Internal)+ hl-mp-service(小程序透传) 文档日期:2026-04-18 适用:dev 分支当前代码(PR #773 整改后)
0. 通用约定(必读)
0.1 响应包装 Result<T>
{
"code": 200, // 200=成功;非 200=业务异常(HTTP 始终 200)
"message": "成功",
"data": { ... }
}
所有接口 HTTP 状态码始终是 200,业务成败看 code。401 = 未登录/Token 过期;403 = 无权限;500 = 业务/系统异常。
0.2 分页响应 PageResult<T>
{ "records": [...], "total": 0, "page": 1, "pageSize": 20 }
分页请求统一字段:page(默认 1,≥1)、pageSize(默认 20,1~100)。
0.3 Long ID 序列化
所有 Long 类型 ID 通过 @JsonSerialize(ToStringSerializer) 序列化为 字符串(防 JS 大数精度丢失)。前端接收/回传统一按字符串处理。
0.4 富文本 XSS 过滤
content/answer 字段后端会经 XssUtils 过滤:
- 禁用:
<script><iframe><img>on*事件属性 - 允许:常规标签 + 样式属性
- Agreement.content 单字段最大 100KB;Faq.answer 最大 10KB
0.5 幂等保护
管理端 POST/PUT 接口大多带 @Idempotent(timeout=5):5 秒内同参数请求会被拦截。前端无需自行去重。
0.6 小程序端缓存
所有 /mp/** 接口使用 @MpCache 缓存 1800s(30 分钟)。管理端修改后小程序最多 30 分钟生效,无主动失效机制。
0.7 端口/路由
| 类型 | 路径前缀 | 说明 |
|---|---|---|
| 管理端 | /admin/... |
走 gateway → hl-user-service,需 ADMIN Token |
| 小程序 | /mp/... |
走 gateway → hl-mp-service → Feign → hl-user-service,需 USER Token(部分公开) |
| 内部 | /internal/... |
服务间 Feign 专用,外部访问被网关拦截(403) |
1. Banner 首页配置(轮播图)
1.1 业务说明
首页顶部轮播位(图片或视频),支持时间窗、链接跳转(产品/景点/活动/H5/小程序内页)、排序。
1.2 数据库表 sys_banner
关键字段:
| 列 | 类型 | 说明 |
|---|---|---|
| id | BIGINT | 雪花 ID |
| title / subtitle | VARCHAR | 标题/副标题 |
| media_type | VARCHAR(20) | IMAGE / VIDEO(字典 banner_media_type) |
| image_url / video_url | VARCHAR(500) | 资源 URL |
| material_id | BIGINT | 素材库关联 ID |
| tags | VARCHAR(200) | 标签,逗号分隔 |
| link_type | VARCHAR(20) | 字典 banner_link_type |
| link_id / link_url / link_target_name | VARCHAR | 跳转参数 |
| sort_order | INT | 越小越前 |
| status | INT | 0=下线 1=上线(注意:本表 status 是整数,与其他表的字符串不同) |
| start_time / end_time | DATETIME | 上下线时间窗 |
| create_time / update_time / deleted_at | DATETIME | 审计 + 软删 |
1.3 管理端接口(前缀 /admin/banner)
| 方法 | 路径 | 入参 | 返参 |
|---|---|---|---|
| GET | /admin/banner |
Query: page, pageSize, keyword, status | Result<PageResult<BannerVO>> |
| GET | /admin/banner/{id} |
Path: id | Result<BannerVO> |
| POST | /admin/banner |
Body: BannerRequest | Result<BannerVO> |
| PUT | /admin/banner/{id} |
Path: id + Body: BannerRequest | Result<BannerVO> |
| DELETE | /admin/banner/{id} |
Path: id | Result<Void> |
⚠️ Banner 模块的请求体类名是 BannerRequest(历史遗留,未按 XxxSaveReqVO 规范)。
1.4 BannerRequest 字段(创建+更新合一)
| 字段 | 类型 | 必填 | 校验/字典 | 说明 |
|---|---|---|---|---|
| title | String | ✅ | @NotBlank, ≤100 | 标题 |
| subtitle | String | ≤200 | 副标题 | |
| mediaType | String | banner_media_type, ≤20 | IMAGE / VIDEO | |
| imageUrl | String | ✅ | @NotBlank, ≤500 | 图片或视频封面 URL |
| videoUrl | String | ≤500 | 视频 URL(mediaType=VIDEO 时有效) | |
| materialId | Long | 素材库 ID(关联) | ||
| tags | String | ≤200 | 逗号分隔标签 | |
| linkType | String | banner_link_type, ≤20 | 跳转类型,见字典 | |
| linkId | String | ≤50 | 跳转目标 ID(PRODUCT/SCENIC 等用) | |
| linkUrl | String | ≤500 | 外部 URL(WEBVIEW/PAGE 用) | |
| linkTargetName | String | ≤100 | 跳转名称(后台展示用) | |
| sortOrder | Integer | 排序,越小越前 | ||
| status | Integer | 0/1 | 0=下线,1=上线 | |
| startTime | LocalDateTime | ISO 8601 | 展示开始时间 | |
| endTime | LocalDateTime | ISO 8601 | 展示结束时间 |
1.5 BannerVO 返回字段
含上述全部字段 + id(String)、createdAt、tags(返回时为 List<String> 已拆好)。
1.6 小程序端接口(前缀 /mp/banner)
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /mp/banner/active |
公开接口(无需登录),返回当前生效的轮播列表,缓存 30 分钟 |
返回:Result<List<BannerVO>>(结构同管理端 BannerVO,已按 sortOrder 升序,已过滤 status=1 且在 startTime~endTime 时间窗内的)。
2. 我的页面配置 - Contact(联系我们 / 关于我们)
2.1 业务说明
"我的"页面联系方式区块。三种渠道:
- ABOUT:关于我们(用
content富文本) - ONLINE_CS:在线客服(用
value存 URL) - PHONE:电话咨询(用
value存电话号)
2.2 数据库表 sys_contact
| 列 | 类型 | 说明 |
|---|---|---|
| id | BIGINT | 雪花 ID |
| channel_type | VARCHAR(32) | 字典 contact_channel_type |
| name | VARCHAR(100) | 标签文案 |
| subtitle | VARCHAR(200) | 副标题(保留字段,前端可不展示) |
| icon_url | VARCHAR(500) | 图标 URL(来自素材库 SYSTEM 分类) |
| value | VARCHAR(500) | 渠道值(URL/电话) |
| content | TEXT | 富文本(仅 ABOUT 用) |
| sort_order | INT | 排序 |
| status | VARCHAR(32) | ACTIVE / INACTIVE |
| create_time/update_time/created_by/updated_by/deleted_at | 审计 + 软删 |
2.3 管理端接口(前缀 /admin/contact)
| 方法 | 路径 | 入参 | 返参 |
|---|---|---|---|
| GET | /admin/contact |
Query: ContactPageReqVO | Result<PageResult<ContactRespVO>> |
| GET | /admin/contact/{id} |
Path: id | Result<ContactRespVO> |
| POST | /admin/contact |
Body: ContactSaveReqVO | Result<Long>(返回新 ID) |
| PUT | /admin/contact/{id} |
Path: id + Body: ContactSaveReqVO | Result<Void> |
| DELETE | /admin/contact/{id} |
Path: id | Result<Void> |
| GET | /admin/contact/channel-types/enabled |
— | Result<List<{value,label}>> 渠道下拉框 |
2.4 ContactPageReqVO 查询字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
| page / pageSize | Integer | 见 0.2 | |
| keyword | String | 模糊匹配 name/value | |
| status | String | ACTIVE/INACTIVE 不传=全部 | |
| channelType | String | ABOUT/ONLINE_CS/PHONE 不传=全部 |
2.5 ContactSaveReqVO 字段(创建+更新合一)
| 字段 | 类型 | 必填 | 校验/字典 | 说明 |
|---|---|---|---|---|
| id | Long | 不传=创建,传=更新 | ||
| channelType | String | ✅ | @NotBlank, ≤32, contact_channel_type | ABOUT/ONLINE_CS/PHONE |
| name | String | ✅ | @NotBlank, ≤100 | 标签文案 |
| subtitle | String | ≤200 | 副标题 | |
| iconUrl | String | ≤500 | 图标 URL | |
| value | String | ≤500 | 渠道值(ABOUT 可空) | |
| content | String | ≤50000 | 富文本,仅 ABOUT 用 | |
| sortOrder | Integer | 排序,默认 0 |
2.6 ContactRespVO 返回字段
全字段 + status(字典)、createTime、updateTime。
2.7 小程序端接口(前缀 /mp/common)
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /mp/common/contact |
返回全部 ACTIVE 联系方式列表,按 sortOrder 升序,缓存 30 分钟 |
返回:Result<List<MpContactRespVO>>,字段:
| 字段 | 类型 | 说明 |
|---|---|---|
| id | String | |
| channelType | String | ABOUT/ONLINE_CS/PHONE |
| name | String | |
| iconUrl | String | |
| value | String | |
| content | String | 富文本(ABOUT 才有) |
| sortOrder | Integer |
小程序端不返回 subtitle/status/创建时间,瘦身处理。
3. 我的页面配置 - FAQ(常见问题)
3.1 业务说明
两级结构:分类 → 条目。小程序"帮助中心"按分类聚合展示。
3.2 数据库表
sys_faq_category:分类(id / name / sort_order / status / 审计)sys_faq_item:条目(id / category_id / question / answer / sort_order / status / 审计)
3.3 管理端接口 - 分类(前缀 /admin/faq/categories)
| 方法 | 路径 | 入参 | 返参 |
|---|---|---|---|
| GET | /admin/faq/categories |
— | Result<List<FaqCategoryRespVO>> 含全部(含停用),带 itemCount |
| GET | /admin/faq/categories/enabled |
— | Result<List<{value,label}>> 仅启用,下拉框用 |
| GET | /admin/faq/categories/{id} |
Path: id | Result<FaqCategoryRespVO> |
| POST | /admin/faq/categories |
Body: FaqCategorySaveReqVO | Result<FaqCategoryRespVO> |
| PUT | /admin/faq/categories/{id} |
Path + Body | Result<FaqCategoryRespVO> |
| PUT | /admin/faq/categories/{id}/status |
Path + Query: status=ACTIVE/INACTIVE | Result<Void> |
| DELETE | /admin/faq/categories/{id} |
Path: id | Result<Void> 软删,前置校验:分类下不能有条目 |
3.4 管理端接口 - 条目(前缀 /admin/faq/items)
| 方法 | 路径 | 入参 | 返参 |
|---|---|---|---|
| GET | /admin/faq/items |
Query: FaqItemPageReqVO | Result<PageResult<FaqItemRespVO>> |
| GET | /admin/faq/items/{id} |
Path: id | Result<FaqItemRespVO> |
| POST | /admin/faq/items |
Body: FaqItemSaveReqVO | Result<FaqItemRespVO> |
| PUT | /admin/faq/items/{id} |
Path + Body | Result<FaqItemRespVO> |
| PUT | /admin/faq/items/{id}/status |
Path + Query: status=ACTIVE/INACTIVE | Result<Void> |
| DELETE | /admin/faq/items/{id} |
Path: id | Result<Void> 软删 |
3.5 VO 字段
FaqCategorySaveReqVO
| 字段 | 类型 | 必填 | 校验 |
|---|---|---|---|
| id | Long | 不传=创建 | |
| name | String | ✅ | @NotBlank, ≤50 |
| sortOrder | Integer |
FaqCategoryRespVO:id(String) / name / sortOrder / status / statusLabel / itemCount / createTime / updateTime
FaqItemPageReqVO
| 字段 | 类型 | 说明 |
|---|---|---|
| page / pageSize | Integer | |
| categoryId | Long | 可选,按分类筛 |
| keyword | String | 模糊匹配 question |
| status | String | ACTIVE/INACTIVE |
FaqItemSaveReqVO
| 字段 | 类型 | 必填 | 校验 |
|---|---|---|---|
| id | Long | 不传=创建 | |
| categoryId | Long | ✅ | @NotNull |
| question | String | ✅ | @NotBlank, ≤200 |
| answer | String | ✅ | @NotBlank, ≤10000,富文本 XSS 过滤 |
| sortOrder | Integer |
FaqItemRespVO:id(String) / categoryId(String) / categoryName / question / answer / sortOrder / status / statusLabel / createTime / updateTime
3.6 小程序端接口
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /mp/common/faq |
返回全部启用 FAQ(按分类嵌套),缓存 30 分钟 |
返回:Result<List<MpFaqCategoryRespVO>>
MpFaqCategoryRespVO:id(String) /name/items(条目列表)MpFaqItemRespVO:id(String) /question/answer
小程序端只返回启用的分类和条目,按 sortOrder 升序。
4. 协议政策 - Agreement
4.1 业务说明
法律协议,按 type 唯一(每类型最多一条记录)。前端"用户协议"、"隐私政策"链接打开。
UPSERT 模式:管理端只有保存接口(按 type 自动判断创建/更新),无独立 DELETE。
4.2 数据库表 sys_agreement
| 列 | 类型 | 说明 |
|---|---|---|
| agreement_id | BIGINT | 雪花 ID |
| type | VARCHAR(64) | UNIQUE,字典 mp_agreement_type |
| title | VARCHAR(100) | 标题 |
| content | MEDIUMTEXT | 正文,HTML 富文本 |
| update_date | DATE | 显式更新日期,C 端副标题用 |
| version | VARCHAR | 版本号(保留字段,默认 1.0) |
| status | VARCHAR(32) | ACTIVE/INACTIVE |
| sort_order | INT | 排序 |
| create_time/update_time/created_by/updated_by/deleted_at | 审计 + 软删 |
4.3 管理端接口(前缀 /admin/agreement)
| 方法 | 路径 | 入参 | 返参 |
|---|---|---|---|
| GET | /admin/agreement/page |
Query: AgreementPageReqVO | Result<IPage<AgreementRespVO>> |
| GET | /admin/agreement/{id} |
Path: id | Result<AgreementRespVO> |
| GET | /admin/agreement/type/{type} |
Path: type | Result<AgreementRespVO> 按 type 取,编辑页用 |
| POST | /admin/agreement/save-by-type |
Body: AgreementSaveReqVO | Result<Void> UPSERT,幂等 |
没有 DELETE 接口。下线请改 status=INACTIVE。
4.4 AgreementSaveReqVO 字段
| 字段 | 类型 | 必填 | 校验/字典 |
|---|---|---|---|
| type | String | ✅ | @NotBlank, @Pattern `^(USER_AGREEMENT |
| title | String | ✅ | @NotBlank, ≤100 |
| content | String | ✅ | @NotBlank, ≤100000(100KB),HTML 富文本,XSS 白名单过滤 |
| updateDate | LocalDate | 不传默认今天 | |
| sortOrder | Integer | 默认 0 |
4.5 AgreementRespVO 返回字段
id(String) / type / typeLabel / title / content / version / updateDate / sortOrder / status / statusLabel / createTime / updateTime / createdBy(String) / updatedBy(String)
4.6 小程序端接口(前缀 /mp/common)
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /mp/common/agreement/{type} |
取指定类型协议详情(含正文),缓存 30 分钟 |
| GET | /mp/common/agreement/list |
取全部 ACTIVE 协议列表(不含 content,轻量),缓存 30 分钟 |
MpAgreementDetailVO(详情接口):type / title / content / version / updateDate / updateTime MpAgreementSimpleVO(列表接口):type / title / version / updateDate / updateTime
5. 字典完整清单
5.1 banner_media_type
| value | label |
|---|---|
| IMAGE | 图片 |
| VIDEO | 视频 |
5.2 banner_link_type
| value | label |
|---|---|
| NONE | 无跳转 |
| PRODUCT | 产品详情 |
| SCENIC | 景点详情 |
| ACTIVITY | 活动详情 |
| HOTEL | 酒店详情 |
| PAGE | 小程序页面 |
| WEBVIEW | H5 外链 |
说明:linkType=PRODUCT/SCENIC/ACTIVITY/HOTEL 时,
linkId必填(资源 ID)。linkType=WEBVIEW/PAGE 时,linkUrl必填。
5.3 contact_channel_type
| value | label | 用法 |
|---|---|---|
| ABOUT | 关于我们 | content 存富文本 |
| ONLINE_CS | 在线客服 | value 存 URL |
| PHONE | 电话咨询 | value 存电话号 |
5.4 mp_agreement_type
| value | label |
|---|---|
| USER_AGREEMENT | 用户协议 |
| PRIVACY_POLICY | 隐私政策 |
5.5 common_status
| value | label |
|---|---|
| ACTIVE | 启用 |
| INACTIVE | 停用 |
适用:sys_contact / sys_faq_category / sys_faq_item / sys_agreement 的 status 字段。 特例:
sys_banner.status是整数 0/1(0=下线,1=上线),与本字典不同,不要混淆。
6. 前端对接 Checklist
管理端
- 列表/详情页直接调
/admin/...,使用 ADMIN Token - 表单字段按本文档 SaveReqVO 严格对齐(必填项、长度限制)
- 字典下拉用各模块的
/enabled接口(不要硬编码) - Long 类型 ID 接收/回传统一按字符串处理
- 富文本编辑器输出 HTML,后端会过滤危险标签
- 5 秒内同参数提交会被幂等拦截(无需自行去重)
- 软删除后该数据列表自动消失(无需特殊处理)
小程序端
- 调
/mp/...接口,使用 USER Token(部分公开如/mp/banner/active可不传) - 缓存 30 分钟:管理端改完后小程序最多 30 分钟生效,前端体验需告知用户
- Banner/FAQ 已按 sortOrder 排好,前端按返回顺序展示即可
- FAQ 返回结构是嵌套的(分类→条目数组),可直接渲染分组列表
- Agreement 详情页用
/mp/common/agreement/{type}取 content;列表(如登录页同意勾选)用/list节省流量
7. 已知坑/注意事项
- status 字段两种格式:sys_banner 是 0/1 整数;其他三表(contact/faq/agreement)是 ACTIVE/INACTIVE 字符串。前端列表筛选时勿混。
- Banner 用 BannerRequest 类名(历史遗留),不是 BannerSaveReqVO。
- FAQ 删除分类有前置校验:分类下有条目时返回业务异常
code=500,需先清空条目。 - Agreement 不能删:只能 status=INACTIVE 软下线。
- 小程序端 30 分钟缓存无主动失效机制,灰度调试期建议用临时账号清测试用户的 Redis Key。
- OperatorHolder 已修复(PR #777):所有写操作的
created_by/updated_by现在能正确填入操作人 ID(之前是 NULL)。
8. 联系/反馈
后端代码位置:
- Admin Controller:
hl-user-service/src/main/java/com/hulalv/user/controller/Admin{Banner,Contact,Faq,Agreement}Controller.java - Internal Controller:
hl-user-service/src/main/java/com/hulalv/user/controller/Internal{Banner,Contact,Faq,MpCommon}Controller.java - MP Controller:
hl-mp-service/src/main/java/com/hulalv/mp/controller/Mp{Banner,Common}Controller.java - VO:
hl-user-service/src/main/java/com/hulalv/user/vo/{admin,mp}/
如有字段缺失或行为不符,直接反馈到本仓库 Issue(带接口路径 + 实际响应 + 期望响应)。