Files
hfb_sys/docs/首页轮播图配置说明.md
T

129 lines
8.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 首页轮播图配置说明
> 适用范围:PC 首页 Hero 轮播(`HomeBanner.vue`)、移动端首页 Banner 轮播(`MobileHomeView.vue`)、主站后台「首页轮播图」弹窗(`HomeBannersDialog.vue`),以及分销站点后台「品牌装修 → 首页轮播横幅」(`distribution-admin/src/pages/SiteSettings.tsx`)。
> 配置存储位置:主站为系统配置表 `mobile.home_banners`(JSON 字符串),前台接口 `GET /api/mobile-home-config`;分销站点为 `distribution_sites.banners_json`,随 `GET /api/distribution/site-info` 下发。
## 一、出图规范(两端容器严格等比,按规范出图不裁切)
| 端 | 展示容器比例 | 建议出图尺寸 | 说明 |
| --- | --- | --- | --- |
| PC | 4:1 | **1600×400** | Hero 卡片宽度自适应,高度由 `aspect-ratio: 1600 / 400` 推导 |
| 移动端 | 2:1 | **750×375**(或 720×360) | 只要有一条配图,整条轮播统一按 `aspect-ratio: 2 / 1` 展示 |
两端使用**不同的图片字段**,必须分别出图:
- PC 端只用 `pc.image_url`;
- 移动端只用 `mobile.image_url`;
- 若该端未配图,会退回文字卡片(眉标 + 主标题 + 胶囊文案),不会用另一端的图硬撑(避免严重裁切)。
历史数据兼容:早期只有扁平 `image_url` 的轮播,读取时会自动并入 `pc.image_url` 与 `mobile.image_url`,不会丢图。
## 二、数据结构
```json
[
{
"eyebrow": "三角洲行动账号专区",
"title": "高哈夫币 · 安全交接 · 随租随玩",
"badge": "HOT",
"pill": "新人领券最高减 20 元",
"tone": "blue",
"enabled": true,
"pc": {
"image_url": "https://cdn.example/banner-pc.jpg",
"alt": "首页活动横幅",
"action": { "type": "route", "target": "/listings", "open_new_tab": false },
"hotspots": [
{
"id": "hotspot-1",
"label": "租币教程",
"x": 6,
"y": 20,
"width": 20,
"height": 24,
"action": { "type": "route", "target": "/m/add-home-guide", "open_new_tab": false }
}
]
},
"mobile": { "image_url": "...", "action": {}, "hotspots": [] }
}
]
```
字段说明:
- `enabled`:`false` 时前台不展示该条轮播(后台仍保留配置)。
- `pc` / `mobile`:两端独立配置,结构相同(图片、整图点击行为、热区)。
- `action.type`:`none` 不跳转 / `route` 站内路径 / `link` 外部链接 / `preview` 查看大图。
- `action.open_new_tab`:仅 `route`、`link` 有意义。
- `hotspots[].x/y/width/height`:**相对图片的百分比(0-100)**,与出图分辨率解耦,改分辨率不会跑位。
- `hotspots[].image_url`:热区按钮图(透明 PNG)。配了图就渲染成海报上的「胶囊按钮」,留空则用半透明高亮框提示可点击。
- `hotspots[].hover_scale`:鼠标悬浮时按钮图的放大倍数,默认 `1.06`,范围 `1-1.5`(`1` = 不放大)。
## 三、热区按钮图导出踩坑(重要)
热区按钮图**必须是带 alpha 透明通道的 PNG**,否则整个矩形会盖住海报。最常见的坑:
- 把设计工具/Figma/PS 里显示「透明区域」的**灰白棋盘格预览截图或另存**,棋盘格就成了真实像素,前台会照实显示成一块格子;
- 从 AI 出图工具导出时选了不透明背景(或导出成 JPG),透明区域变成白底;
- 直接把整张海报(含按钮)当热区图用,等于又盖了一层。
自查方法:
1. 把 PNG 拖到纯深色背景的窗口里看,如果还能看到灰白格子,就是图里带的;
2. macOS 可用 `sips -g hasAlpha 图片.png` 检查是否真有 alpha 通道(`hasAlpha: yes` 才算透明图)。
后台已经加了兜底提示:上传「热区按钮图」时会做一次像素体检,若**没有任何透明像素**会立刻提示(「只有白/浅灰底色」还会明确点出疑似棋盘格);上传海报底图时也会提示疑似棋盘格的情况。提示只是提醒,不会阻止保存。
修复办法:回到设计源文件,隐藏背景后重新导出为 PNG(不要截图预览图);若只有一张带底纹的图,可在 PS 里用「色彩范围」选中浅灰网格后删除再导出。
> 已修复的历史坑:后台上传前会做一次「压缩优化」,旧实现先给 canvas 铺白底再编码,会把透明区域压成白底方块(透明按钮图上传后变白色矩形)。现在改为:检测到原图带透明像素时**不铺白底**并输出 `image/png`(无损保留 alpha),不透明图仍走 WebP 压缩。代码:`frontend/src/shared/utils/imageUpload.ts`。修复前上传过的图需要重新上传。
## 四、点击行为与悬浮反馈
1. 命中热区(且热区配置了真实跳转)→ 执行该热区的跳转;
2. 未命中热区 → 执行该端「整图点击」行为(`none` 时不跳转);
3. 完全没有配置跳转(整图 `none` 且无有效热区)→ 保留原有「点击查看大图」能力。
`preview` 类型会打开大图预览:PC 用 Element Plus `el-image-viewer`,移动端用内置 lightbox(2:1 框 + `object-fit: contain`,整图完整可见)。
悬浮反馈分两种:
- 热区配了 `image_url`:渲染透明 PNG 按钮图,鼠标悬浮时按 `hover_scale` 轻微放大(`transform: scale()` + `0.2s` 过渡)并加投影,按下时轻微回缩;
- 热区没配图:悬浮显示半透明高亮框,提示「这里可点」。
这正是海报型轮播的常见做法:把海报上的按钮单独切透明 PNG 叠在底图上,既能点击跳转,又有「按钮浮起来」的手感。运营操作要点:
1. 底图(PC 1600×400 / 移动 750×375)里**不要**烘焙按钮,按钮留空;
2. 把按钮单独导出为透明 PNG(尺寸与海报上的位置匹配);
3. 后台在同一端的预览图上拖框对齐,再填该按钮的跳转。
## 五、后台怎么配
后台 → 系统配置 → `mobile.home_banners` → 「编辑首页轮播图」:
1. 每条轮播是一张卡片,可启用/停用、上移/下移、删除;卡片内先填文案(眉标/主标题/角标/胶囊/色调),无图时按文字卡片展示。
2. 切到「PC 端 1600×400(4:1)」或「移动端 750×375(2:1)」页签,上传/填写该端图片,并配置「整图点击」行为。
3. 在预览图上**单击**新增热区 → **拖动**移动 → 拖右下角小方块缩放;下方可为选中热区设置名称、精确坐标、跳转,以及**热区按钮图**与**悬浮放大倍数**(后台预览图会把按钮图半透明铺在框内,所见即所得)。
4. 保存时写入 `mobile.home_banners`,后台会顺带把旧的扁平 `image_url` 结构升级为 `pc` / `mobile` 结构。
## 六、分销站点后台
分销站点与主站使用**完全相同**的 `pc` / `mobile` 数据结构,但独立保存在 `distribution_sites.banners_json`,不影响主站配置。
入口:分销后台 → 品牌装修 → 「首页轮播横幅」。每条轮播同样支持:
1. 启用/停用、上移/下移、删除,以及眉标/主标题/角标/胶囊/色调;
2. PC 端与移动端分别上传图片、填写图片 URL、配置整图点击行为;
3. 每端独立配置热区:单击新增、拖动移动、拖右下角缩放,热区可设置透明 PNG 按钮图、悬浮放大、坐标与跳转;
4. 某一端留空时,该端前台回退为文字卡片,不会拿另一端的图强行裁切。
历史兼容:早期分销后台保存的扁平 `{ image_url, title, link }` 或 `{ image_url, link_url }` 会自动升级为两端共图;其中旧字段 `link` 与 `link_url` 都会被识别。分销前台归一化实现:`frontend/src/stores/distributionSite.ts`(`mapDistributionHomeBanners`)。
## 七、校验与兜底
- 前后端都会归一化配置:坐标收敛到 `0-100` 且不越界,宽高为 0 的热区直接丢弃;`route` / `link` 缺少目标时退化为 `none`(避免「点了没反应」的死热区)。
- 后端归一化实现:`backend/internal/modules/systemconfig/normalize.go`(`normalizeHomeBanners`)。
- 前端归一化实现:`frontend/src/features/listings/api/homeConfig.ts`(`normalizeHomeBanner`);分销站点为 `distribution-admin/src/homeBanner.ts`。
- 相关测试:`frontend/src/features/listings/api/homeConfig.spec.ts`、`frontend/src/stores/distributionHomeBanner.spec.ts`、`backend/internal/modules/systemconfig/home_banners_test.go`。