装修视角(Theme View)
在同一主题、同一页面下,按访客条件(设备、国家、UTM 等)决定展示哪些积木块。
与 组装修(按商品/专辑对象分装修)正交:组装修选「哪套 blocks」;视角在已选 blocks 内做「显隐」。
上级文档:theme-decoration-and-liquid-rendering.md
一、概念
| 概念 | 说明 |
|---|---|
| 视角(Theme View) | 一条 o_theme_view 记录,含名称 + 受众条件 params |
| 积木 display 绑定 | 单个 block 的 params.display 存「在哪些视角下显示」 |
| 当前视角 | 前台运行时解析出的 view_id;决定每个 block 是否渲染 |
视角 不是 另一套完整装修数据,而是对现有 blocks 的 条件显隐。
每主题最多 20 个视角(ThemeViewService::STORE_THEME_MAX_VIEWER)。
二、数据表 o_theme_view
Model:ThemeViewModel → 表 o_theme_view
| 字段 | 说明 |
|---|---|
store_id / theme_id | 租户 + 主题 |
name | 视角名称(同 theme 下不可重名) |
params | JSON 字符串,受众条件(见 § 四) |
position | 排序(列表 order by position desc) |
不单独存积木;积木仍在 o_theme_block,通过 params.display 关联视角 ID。
三、积木上的 display 字段
存在 o_theme_block.params / preview_params 内,与 section settings 同级。
| display 值 | 含义 |
|---|---|
未设置 / true(bool) | 所有视角都显示(无视角限制) |
"3,5,7"(字符串,逗号分隔 view id) | 仅在视角 3、5、7 下显示;其他视角隐藏 |
3.1 运行时如何变成显隐
TagGetBlocks::view() 在拉完 blocks 后处理:
正常访客(is_theme_edit != 1):
currentViewId= URLview_id或ThemeViewService::getPatchViewId()- 若 block 的
display为非空字符串:- 当前视角 不在 display 列表 → 设
params.display = true→ 隐藏 - 当前视角 在 列表 → 设
params.display = false→ 显示
- 当前视角 不在 display 列表 → 设
装修模式(is_theme_edit=1):
- 同上,但当「当前视角在 display 列表」时,额外读该视角的
params.device,与 URL?device=比较;设备不匹配则仍 隐藏(便于编辑器内按 PC/移动预览)。
3.2 前台 Liquid 如何隐藏
templates/block_main.liquid:
{% unless section.display %}
<div id="block-section-{{block.id}}">...</div>
{% endunless %}display=true → 不输出该 block DOM。
装修预览模式用 display:none 保留 DOM 便于编辑。
四、视角受众条件 params
创建/更新时 JSON 存入 o_theme_view.params(ThemeViewCreateRequest 要求必填)。
匹配逻辑复用 AbPlanService::checkParams()(与 AB 落地页受众相同)。
4.1 字段结构(解码后)
| 字段 | 说明 |
|---|---|
device[] | 允许的设备类型,如 computer、phone;当前设备须在列表内 |
country_type | 1 = 不限制国家;>1 且配置了 country 时校验 IP 国家 |
country[] | { country_code_2: "US" } 等 |
utm_type | 1 = 不限制;2 = 指定 utm_source;3 = 指定 utm_source/utm_medium |
utm_value | 字符串或数组,小写匹配 |
校验顺序:设备 → 国家(若启用)→ UTM(若启用)。全部通过返回 true。
4.2 当前视角 ID 如何确定
ThemeViewService::getPatchViewId():
1. ThemeViewCacheService::getList() 取当前 theme 全部视角(按 position desc)
2. 遍历,对每个 view.params 调 AbPlanService::checkParams()
3. 第一个通过的 view.id 即为 currentViewId
4. 无一通过 → 0
也可 URL 强制:?view_id=123(装修器切换视角预览)。
注意:遍历顺序由 DB position desc, id desc 决定;多个视角同时命中时 先匹配者优先。
五、后台 API(themes-view)
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | / | 列表;params JSON 解码(ThemesViewListResponse) |
| GET | /:id | 详情 |
| POST | / | 新增视角 |
| PUT | /:id | 更新 |
| DELETE | /:id | 删除;可选 display 参数清理 block 绑定 |
Body 示例(POST/PUT):
{
"theme_id": 1,
"name": "美国移动端",
"position": 10,
"params": {
"device": ["phone"],
"country_type": 2,
"country": [{ "country_code_2": "US" }],
"utm_type": 1,
"utm_value": ""
}
}5.1 删除视角
ThemeViewService::del($id, $displayParam=false):
- 扫描该 theme 全部
o_theme_block - 若
params.display/preview_params.display等于 被删 view id(单 id 绑定写法):- 默认:移除
display字段 display=true查询参数:改为display: true(恢复全员可见)
- 默认:移除
- 删
o_theme_view行,清ThemeViewCacheService缓存
复制主题时 ThemeViewService::copy() 会复制 view 行,不会改 block 上 display 绑定(代码注释:暂不处理)。
复制/新增 block 时 themeBlockViewIdHandler() 会把非 bool 的 display 重置为 true(去掉视角绑定)。
六、缓存
| Key | 内容 | TTL |
|---|---|---|
CacheKeyHelper::themeView($themeId) | 该主题视角列表 JSON | 1 天;空列表占位 1 小时 |
增删改视角 → delCache()(expire 等待主从同步)。
删除默认主题的视角时,还会 expire themeData('default')、themeSections('default') 等。
七、完整前台链路
sequenceDiagram participant U as 访客 participant HPV as HomePublicVarsService participant GB as TagGetBlocks participant TD as ThemesService::themeData participant TV as ThemeViewService participant AB as AbPlanService participant BM as block_main.liquid U->>HPV: 请求商品页 HPV->>HPV: theme_id, theme_preview U->>GB: get_blocks GB->>TD: themeData → o_theme_block GB->>TV: getPatchViewId 或 ?view_id= TV->>AB: checkParams 各视角 params AB-->>TV: 命中 view_id GB->>GB: view() 按 display 设显隐 GB->>BM: blocks BM->>U: unless display 输出 HTML
八、后台 UI 对应(推断)
| 后台区域 | 行为 |
|---|---|
| 主题装修 → 视角管理 | GET/POST/PUT/DELETE themes-view |
| 积木块设置 → 显示条件 / 视角 | 写入 block params.display = 选中的 view id(或多 id 逗号分隔,取决于前端实现) |
| 装修预览工具栏 → 切换视角 | ?view_id=&is_theme_edit=1&device= |
| 装修预览工具栏 → 设备 | 与视角 params.device 联动校验 |
九、与组装修的关系
| 维度 | 组装修 | 视角 |
|---|---|---|
| 划分依据 | 业务对象(商品 ID…) | 访客条件(设备/国家/UTM) |
| 数据 | 不同 group_id 的多套 blocks | 同一套 blocks 上的 display |
| 决策点 | ThemesService::themeData 选 group | TagGetBlocks::view 过滤 |
| 表 | o_theme_route_group* + o_theme_block.group_id | o_theme_view + block.params.display |
两者可同时生效:先按 obj 选定 group 的 blocks,再按视角过滤显隐。
十、示例场景
10.1 仅美国移动端看到某 banner block
- 创建视角「US Mobile」:
device=[phone],country_type=2,country=[US] - 在该 block 的装修参数里设置
display: "12"(假设视角 id=12) - 美国手机访客:
getPatchViewId()→ 12,block display 列表含 12 → 显示 - 其他国家或 PC:currentViewId 不是 12 或匹配不到 → 隐藏
10.2 所有访客都看(默认)
block 不设置 display,或 display: true。
十一、关键代码索引
| 组件 | 路径 |
|---|---|
| 视角 CRUD | common/services/ThemeViewService.php |
| 受众匹配 | common/services/AbPlanService.php — checkParams() |
| 缓存 | common/services/ThemeViewCacheService.php |
| 前台过滤 | extend/liquidExtend/tags/TagGetBlocks.php — view() |
| display 重置 | common/services/ThemeBlockService.php — themeBlockViewIdHandler() |
| API | app/api/controller/ThemeView.php |
| 模板显隐 | public/theme/default/templates/block_main.liquid |
十二、排障
| 现象 | 排查 |
|---|---|
| block 所有人都不显示 | display 是否绑定了 view id 但无人命中视角;getPatchViewId 是否恒为 0 |
| 视角条件不生效 | AbPlanService 设备/国家/UTM;Context->sourceDevice |
| 编辑器与线上一致 | 是否带 is_theme_edit=1;device 参数是否与视角 params 一致 |
| 删视角后 block 仍隐藏 | 删除 API 是否清理 display;或 display 存的是逗号多 id 而 del 只处理单 id 相等 |
| 复制主题后视角失效 | block display 未随 view id 映射(copy 未处理绑定) |