Преглед на файлове

提交权益原型和需求文档更新

csk преди 3 седмици
родител
ревизия
94aeaadec5
променени са 18 файла, в които са добавени 4598 реда и са изтрити 256 реда
  1. 11 13
      .agents/skills/lark-approval/SKILL.md
  2. 95 59
      .agents/skills/lark-calendar/SKILL.md
  3. 13 14
      .agents/skills/lark-sheets/references/lark-sheets-batch-set-style.md
  4. 17 20
      .claude/skills/pc-demo/SKILL.md
  5. 0 1
      工作空间/产研/权益/汇丰全行/产品原型/h5-demo/Untitled.md
  6. 715 0
      工作空间/产研/权益/汇丰全行/产品原型/h5-demo/移动端.html
  7. 651 0
      工作空间/产研/权益/汇丰全行/产品原型/h5-demo/移动端一期.html
  8. 285 0
      工作空间/产研/权益/汇丰全行/产品原型/h5-demo/组装页.html
  9. 4 1
      工作空间/产研/权益/汇丰全行/产品原型/pc-demo/src/views/PageZoneConfig.vue
  10. BIN
      工作空间/产研/权益/汇丰全行/测试用例/组装页_测试用例.xlsx
  11. 436 0
      工作空间/产研/权益/汇丰全行/需求文档/prd-generator-from-demo/SKILL.md
  12. 4 0
      工作空间/产研/权益/汇丰全行/需求文档/prd-generator-from-demo/agents/openai.yaml
  13. 496 0
      工作空间/产研/权益/汇丰全行/需求文档/权益介绍页.md
  14. 618 0
      工作空间/产研/权益/汇丰全行/需求文档/权益首页.md
  15. 38 148
      工作空间/产研/权益/汇丰全行/需求文档/汇丰借记卡移动端——权益.md
  16. BIN
      工作空间/产研/权益/汇丰全行/需求文档/汇丰需求文档 (1).pdf
  17. 514 0
      工作空间/产研/权益/汇丰全行/需求文档/组装页.md
  18. 701 0
      工作空间/产研/权益/汇丰全行/需求文档/组装页2.md

+ 11 - 13
.agents/skills/lark-approval/SKILL.md

@@ -7,10 +7,9 @@ metadata:
     bins: ["lark-cli"]
   cliHelp: "lark-cli approval --help"
 ---
-
 # approval (v4)
 
-**CRITICAL — 开始前 MUST 先用 Read 工具读取 [`../lark-shared/SKILL.md`](../lark-shared/SKILL.md),其中包含认证、权限处理**
+**CRITICAL — 开始前 MUST 先用 Read 工具读取** `../lark-shared/SKILL.md`**,其中包含认证、权限处理**
 
 ## API Resources
 
@@ -23,26 +22,25 @@ lark-cli approval <resource> <method> [flags] # 调用 API
 
 ### instances
 
-  - `get` — 获取单个审批实例详情
-  - `cancel` — 撤回审批实例
-  - `cc` — 抄送审批实例
+-   `get` — 获取单个审批实例详情
+-   `cancel` — 撤回审批实例
+-   `cc` — 抄送审批实例
 
 ### tasks
 
-  - `approve` — 同意审批任务
-  - `reject` — 拒绝审批任务
-  - `transfer` — 转交审批任务
-  - `query` — 查询用户的任务列表
+-   `approve` — 同意审批任务
+-   `reject` — 拒绝审批任务
+-   `transfer` — 转交审批任务
+-   `query` — 查询用户的任务列表
 
 ## 权限表
 
-| 方法 | 所需 scope |
-|------|-----------|
+| 方法  | 所需 scope |
+| --- | --- |
 | `instances.get` | `approval:instance:read` |
 | `instances.cancel` | `approval:instance:write` |
 | `instances.cc` | `approval:instance:write` |
 | `tasks.approve` | `approval:task:write` |
 | `tasks.reject` | `approval:task:write` |
 | `tasks.transfer` | `approval:task:write` |
-| `tasks.query` | `approval:task:read` |
-
+| `tasks.query` | `approval:task:read` |

+ 95 - 59
.agents/skills/lark-calendar/SKILL.md

@@ -7,48 +7,83 @@ metadata:
     bins: ["lark-cli"]
   cliHelp: "lark-cli calendar --help"
 ---
-
 # calendar (v4)
 
-**CRITICAL — 开始前 MUST 先用 Read 工具读取 [`../lark-shared/SKILL.md`](../lark-shared/SKILL.md),其中包含认证、权限处理**
+**CRITICAL — 开始前 MUST 先用 Read 工具读取** `../lark-shared/SKILL.md`**,其中包含认证、权限处理**
+
+<br>
+
 **CRITICAL — 所有的 Shortcuts 在执行之前,务必先使用 Read 工具读取其对应的说明文档,禁止直接盲目调用命令。**
-**CRITICAL — 凡涉及【预约日程/会议】或【查询/搜索会议室】,第一步 MUST 强制使用 Read 工具读取 [`references/lark-calendar-schedule-meeting.md`](references/lark-calendar-schedule-meeting.md)。禁止跳过此步直接调用 API 或 Shortcut!**
-**CRITICAL — 术语约束:用户日常表达中常说的“帮我约个日历”、“查一下今天的日历”等,其实际意图通常是针对 日程(Event) 的创建或查询,而非操作 日历(Calendar) 容器本身。请自动将口语化的“日历”意图映射为“日程”操作(如 `+create`, `+agenda`)。**
+
+<br>
+
+**CRITICAL — 凡涉及【预约日程/会议】或【查询/搜索会议室】,第一步 MUST 强制使用 Read 工具读取** `references/lark-calendar-schedule-meeting.md`**。禁止跳过此步直接调用 API 或 Shortcut!**
+
+<br>
+
+**CRITICAL — 术语约束:用户日常表达中常说的“帮我约个日历”、“查一下今天的日历”等,其实际意图通常是针对 日程(Event) 的创建或查询,而非操作 日历(Calendar) 容器本身。请自动将口语化的“日历”意图映射为“日程”操作(如** `+create`**,** `+agenda`**)。**
+
+<br>
+
 **CRITICAL — 会议与日程的意图路由:**
-- **查询过去时间的会议**:如果用户明确查询过去时间的会议(如“昨天的会议”、“上周的会议”),**优先使用 [`../lark-vc/SKILL.md`](../lark-vc/SKILL.md) 搜索会议记录**。因为会议数据不仅包含从日程发起的视频会议,还包含即时会议,仅查询日程数据会导致结果不全。
-- **查询日历/日程或未来时间的会议**:如果用户明确表达的是“日历”、“日程”,或者涉及**未来时间**的安排,则属于本技能(lark-calendar)的业务域,请继续使用本技能处理。
 
+<br>
+
+-   **查询过去时间的会议**:如果用户明确查询过去时间的会议(如“昨天的会议”、“上周的会议”),**优先使用** `../lark-vc/SKILL.md` **搜索会议记录**。因为会议数据不仅包含从日程发起的视频会议,还包含即时会议,仅查询日程数据会导致结果不全。
+-   **查询日历/日程或未来时间的会议**:如果用户明确表达的是“日历”、“日程”,或者涉及**未来时间**的安排,则属于本技能(lark-calendar)的业务域,请继续使用本技能处理。
 
-**时间与日期推断规范:**
+**时间与日期推断规范:**  
 为确保准确性,在涉及时间推断时,请严格遵循以下规则:
-- **星期的定义**:周一是一周的第一天,周日是一周的最后一天。计算`下周一`等相对日期时,务必基于当前真实日期和星期基准进行推算,避免算错日期。
-- **一天的范围**:当用户提到`明天`、`今天`等泛指某一天时,时间范围应默认覆盖整天时间范围。**切勿**自行缩减查询范围,以免遗漏晚上的时间安排。
-- **历史时间约束**:不能预约已经完全过去的时间。唯一的例外情况是“跨越当前时间”的日程,即日程的开始时间在过去,但结束时间在未来。
+
+-   **星期的定义**:周一是一周的第一天,周日是一周的最后一天。计算`下周一`等相对日期时,务必基于当前真实日期和星期基准进行推算,避免算错日期。
+-   **一天的范围**:当用户提到`明天`、`今天`等泛指某一天时,时间范围应默认覆盖整天时间范围。**切勿**自行缩减查询范围,以免遗漏晚上的时间安排。
+-   **历史时间约束**:不能预约已经完全过去的时间。唯一的例外情况是“跨越当前时间”的日程,即日程的开始时间在过去,但结束时间在未来。
 
 ## 核心场景
 
-### 1. 预约日程/会议、查询/搜索可用会议室
-**BLOCKING REQUIREMENT (阻塞性要求): 只要用户的意图包含“预约日程/会议”或“查询/搜索可用会议室”,你必须立即停止其他思考,优先使用 Read 工具完整读取 [`references/lark-calendar-schedule-meeting.md`](references/lark-calendar-schedule-meeting.md)!未读取该文件前,绝对禁止执行任何日程创建或会议室查询操作。**
+### 1\. 预约日程/会议、查询/搜索可用会议室
+
+**BLOCKING REQUIREMENT (阻塞性要求): 只要用户的意图包含“预约日程/会议”或“查询/搜索可用会议室”,你必须立即停止其他思考,优先使用 Read 工具完整读取** `references/lark-calendar-schedule-meeting.md`**!未读取该文件前,绝对禁止执行任何日程创建或会议室查询操作。**
+
+<br>
+
 **CRITICAL: 必须严格按照上述文档中定义的工作流(Workflow)执行后续操作。处理该场景时,默认做“智能助理”,不要做“表单填写机”。能补全的默认值先补全,只有在时间冲突、结果无法唯一确定、时间语义存在歧义时才主动追问。**
+
+<br>
+
 **CRITICAL: 执行顺序必须固定为:先补默认值,再判断时间是否明确,再进入“明确时间”或“模糊时间/无时间信息”分支。不要跳步。**
-**CRITICAL: 明确时间且需要会议室时,先 `+room-find`,再 `+freebusy`;模糊时间或无时间信息时,先 `+suggestion`,如需会议室再批量 `+room-find`。**
-**CRITICAL: 当用户说“查会议室”“找会议室”“搜可用会议室”或“推荐常用会议室”时,默认是查会议室可用性,不是查会议室资源名录,更严禁拉取历史日程做统计分析。完整规则以 [lark-calendar-schedule-meeting.md](references/lark-calendar-schedule-meeting.md) 为准。**
-**BLOCKING REQUIREMENT: 即使用户的核心诉求是“查会议室”,只要【没有提供明确的起止时间】,绝对禁止直接调用 `+room-find`!必须先进入【无时间/模糊时间】分支,调用 `+suggestion` 拿到候选时间块后,再将时间块传给 `+room-find`。**
-**BLOCKING REQUIREMENT: 只要面临时间方案或会议室方案的选择(如模糊时间、无时间或需要会议室),在调用 `+create` 创建日程之前,必须先向用户展示候选方案并等待用户明确确认。绝对禁止擅自替用户做决定。**
+
+<br>
+
+**CRITICAL: 明确时间且需要会议室时,先** `+room-find`**,再** `+freebusy`**;模糊时间或无时间信息时,先** `+suggestion`**,如需会议室再批量** `+room-find`**。**
+
+<br>
+
+**CRITICAL: 当用户说“查会议室”“找会议室”“搜可用会议室”或“推荐常用会议室”时,默认是查会议室可用性,不是查会议室资源名录,更严禁拉取历史日程做统计分析。完整规则以 lark-calendar-schedule-meeting.md 为准。**
+
+<br>
+
+**BLOCKING REQUIREMENT: 即使用户的核心诉求是“查会议室”,只要【没有提供明确的起止时间】,绝对禁止直接调用** `+room-find`**!必须先进入【无时间/模糊时间】分支,调用** `+suggestion` **拿到候选时间块后,再将时间块传给** `+room-find`**。**
+
+<br>
+
+**BLOCKING REQUIREMENT: 只要面临时间方案或会议室方案的选择(如模糊时间、无时间或需要会议室),在调用** `+create` **创建日程之前,必须先向用户展示候选方案并等待用户明确确认。绝对禁止擅自替用户做决定。**
+
+<br>
 
 ## 核心概念
 
-- **日历(Calendar)**:日程的容器。每个用户有一个主日历(primary calendar),也可以创建或订阅共享日历。
-- **日程(Event)**:日历中的单个日程,包含起止时间、地点、标题、参与人等属性。支持单次日程和重复日程,遵循RFC5545 iCalendar国际标准。
-- ***全天日程(All-day Event)***: 只按日期占用、没有具体起止时刻的日程,结束日期是包含在日程时间内的。
-- **日程实例(Instance)**:日程的具体时间实例,本质是对日程的展开。普通日程和例外日程对应1个Instance,重复性日程对应N个Instance。在按时间段查询时,可通过实例视图将重复日程展开为独立的实例返回,以便在时间线上准确展示和管理。
-- **重复规则(Rrule/Recurrence Rule)**:定义重复性日程的重复规则,比如`FREQ=DAILY;UNTIL=20230307T155959Z;INTERVAL=14`表示每14天重复一次。
-- **例外日程(Exception)**:重复性日程中与原重复性日程不一致的日程。
-- **参会人(Attendee)**:日程的参与者,可以是用户、群、会议室资源、外部邮箱地址等。每个参与人有独立的RSVP状态。
-- **响应状态(RSVP)**:参与人对日程邀请的回复状态(接受/拒绝/待定)。
-- **忙闲时间(FreeBusy)**:查询用户在指定时间段的忙闲状态,用于会议时间协调。
-- **会议室(Room)**:“room”不是“房间”,是“会议室”。请在理解和处理意图时将“room”和“房间”准确映射为“会议室”及其相关操作。
-- **时间块(Time Slot / Time Block)**:指一个**具体且确定**的连续时间段(如 `14:00~15:00`)。在文档中,它与泛指的“时间范围/区间”(如“今天下午”、“下周”)有严格区别。在调用预定、查询可用会议室等确切操作时,必须基于确定的“时间块”而非模糊的“时间范围”。
+-   **日历(Calendar)**:日程的容器。每个用户有一个主日历(primary calendar),也可以创建或订阅共享日历。
+-   **日程(Event)**:日历中的单个日程,包含起止时间、地点、标题、参与人等属性。支持单次日程和重复日程,遵循RFC5545 iCalendar国际标准。
+-   **\*全天日程(All-day Event)**\*: 只按日期占用、没有具体起止时刻的日程,结束日期是包含在日程时间内的。
+-   **日程实例(Instance)**:日程的具体时间实例,本质是对日程的展开。普通日程和例外日程对应1个Instance,重复性日程对应N个Instance。在按时间段查询时,可通过实例视图将重复日程展开为独立的实例返回,以便在时间线上准确展示和管理。
+-   **重复规则(Rrule/Recurrence Rule)**:定义重复性日程的重复规则,比如`FREQ=DAILY;UNTIL=20230307T155959Z;INTERVAL=14`表示每14天重复一次。
+-   **例外日程(Exception)**:重复性日程中与原重复性日程不一致的日程。
+-   **参会人(Attendee)**:日程的参与者,可以是用户、群、会议室资源、外部邮箱地址等。每个参与人有独立的RSVP状态。
+-   **响应状态(RSVP)**:参与人对日程邀请的回复状态(接受/拒绝/待定)。
+-   **忙闲时间(FreeBusy)**:查询用户在指定时间段的忙闲状态,用于会议时间协调。
+-   **会议室(Room)**:“room”不是“房间”,是“会议室”。请在理解和处理意图时将“room”和“房间”准确映射为“会议室”及其相关操作。
+-   **时间块(Time Slot / Time Block)**:指一个**具体且确定**的连续时间段(如 `14:00~15:00`)。在文档中,它与泛指的“时间范围/区间”(如“今天下午”、“下周”)有严格区别。在调用预定、查询可用会议室等确切操作时,必须基于确定的“时间块”而非模糊的“时间范围”。
 
 ## 资源关系
 
@@ -63,21 +98,21 @@ Calendar (日历)
 
 Shortcut 是对常用操作的高级封装(`lark-cli calendar +<verb> [flags]`)。有 Shortcut 的操作优先使用。
 
-| Shortcut | 说明 |
-|----------|------|
-| [`+agenda`](references/lark-calendar-agenda.md) | 查看日程安排(默认今天) |
-| [`+create`](references/lark-calendar-create.md) | 创建日程并邀请参会人(ISO 8601 时间) |
-| [`+freebusy`](references/lark-calendar-freebusy.md) | 查询用户主日历的忙闲信息和rsvp的状态 |
-| [`+room-find`](references/lark-calendar-room-find.md) | 针对一个或多个**明确的**时间块查找可用会议室(**无明确时间时禁止直接调用,需先走 +suggestion**) |
-| [`+rsvp`](references/lark-calendar-rsvp.md) | 回复日程(接受/拒绝/待定) |
-| [`+suggestion`](references/lark-calendar-suggestion.md) | 根据非明确时间或一段时间范围,推荐多个可用时间块方案 |
+| Shortcut | 说明  |
+| --- | --- |
+| `+agenda` | 查看日程安排(默认今天) |
+| `+create` | 创建日程并邀请参会人(ISO 8601 时间) |
+| `+freebusy` | 查询用户主日历的忙闲信息和rsvp的状态 |
+| `+room-find` | 针对一个或多个**明确的**时间块查找可用会议室(**无明确时间时禁止直接调用,需先走 +suggestion**) |
+| `+rsvp` | 回复日程(接受/拒绝/待定) |
+| `+suggestion` | 根据非明确时间或一段时间范围,推荐多个可用时间块方案 |
 
 ## 会议室相关规则
 
-- **会议室是日程的一种参与人(resource attendee),不能脱离日程单独存在或单独预定。**
-- **凡是用户意图是“预定/查询/搜索可用会议室”时,都必须进入 `references/lark-calendar-schedule-meeting.md` 工作流处理。**
-- `+room-find` 的时间输入必须是**确定时间块**,不能是时间区间搜索。
-- **强制约束:如果用户仅要求“查询会议室”但未提供明确时间,必须先调用 `+suggestion` 获取可用时间块,然后再将时间块交给 `+room-find` 批量查询。严禁直接猜测时间并盲目调用 `+room-find`。**
+-   **会议室是日程的一种参与人(resource attendee),不能脱离日程单独存在或单独预定。**
+-   **凡是用户意图是“预定/查询/搜索可用会议室”时,都必须进入** `references/lark-calendar-schedule-meeting.md` **工作流处理。**
+-   `+room-find` 的时间输入必须是**确定时间块**,不能是时间区间搜索。
+-   **强制约束:如果用户仅要求“查询会议室”但未提供明确时间,必须先调用** `+suggestion` **获取可用时间块,然后再将时间块交给** `+room-find` **批量查询。严禁直接猜测时间并盲目调用** `+room-find`**。**
 
 ## API Resources
 
@@ -90,37 +125,37 @@ lark-cli calendar <resource> <method> [flags] # 调用 API
 
 ### calendars
 
-  - `create` — 创建共享日历
-  - `delete` — 删除共享日历
-  - `get` — 查询日历信息
-  - `list` — 查询日历列表
-  - `patch` — 更新日历信息
-  - `primary` — 查询用户主日历
-  - `search` — 搜索日历
+-   `create` — 创建共享日历
+-   `delete` — 删除共享日历
+-   `get` — 查询日历信息
+-   `list` — 查询日历列表
+-   `patch` — 更新日历信息
+-   `primary` — 查询用户主日历
+-   `search` — 搜索日历
 
 ### event.attendees
 
-  - `batch_delete` — 删除日程参与人
-  - `create` — 添加日程参与人
-  - `list` — 获取日程参与人列表
+-   `batch_delete` — 删除日程参与人
+-   `create` — 添加日程参与人
+-   `list` — 获取日程参与人列表
 
 ### events
 
-  - `create` — 创建日程
-  - `delete` — 删除日程
-  - `get` — 获取日程
-  - `instance_view` — 查询日程视图
-  - `patch` — 更新日程
-  - `search` — 搜索日程
+-   `create` — 创建日程
+-   `delete` — 删除日程
+-   `get` — 获取日程
+-   `instance_view` — 查询日程视图
+-   `patch` — 更新日程
+-   `search` — 搜索日程
 
 ### freebusys
 
-  - `list` — 查询主日历日程忙闲信息
+-   `list` — 查询主日历日程忙闲信息
 
 ## 权限表
 
-| 方法 | 所需 scope |
-|------|-----------|
+| 方法  | 所需 scope |
+| --- | --- |
 | `calendars.create` | `calendar:calendar:create` |
 | `calendars.delete` | `calendar:calendar:delete` |
 | `calendars.get` | `calendar:calendar:read` |
@@ -140,4 +175,5 @@ lark-cli calendar <resource> <method> [flags] # 调用 API
 | `freebusys.list` | `calendar:calendar.free_busy:read` |
 
 **注意(强制性):**
-- 涉及日期(时间)字符串与时间戳的相互转换时,务必调用系统命令或脚本代码等外部工具进行处理,以确保转换的绝对准确。违者将导致严重的逻辑错误!
+
+-   涉及日期(时间)字符串与时间戳的相互转换时,务必调用系统命令或脚本代码等外部工具进行处理,以确保转换的绝对准确。违者将导致严重的逻辑错误!

+ 13 - 14
.agents/skills/lark-sheets/references/lark-sheets-batch-set-style.md

@@ -1,13 +1,12 @@
-
 # sheets +batch-set-style(批量设置单元格样式)
 
-> **前置条件:** 先阅读 [`../lark-shared/SKILL.md`](../../lark-shared/SKILL.md) 了解认证、全局参数和安全规则。
+> **前置条件:** 先阅读 `../lark-shared/SKILL.md` 了解认证、全局参数和安全规则。
 
 本 skill 对应 shortcut:`lark-cli sheets +batch-set-style`。
 
 对多个范围批量设置不同的单元格样式,一次请求可包含多组范围和样式。
 
-> [!CAUTION]
+> \[!CAUTION\]  
 > 这是**写入操作** —— 执行前必须确认用户意图。可以先用 `--dry-run` 预览。
 
 ## 命令
@@ -28,12 +27,12 @@ lark-cli sheets +batch-set-style --spreadsheet-token "shtxxxxxxxx" \
 
 ## 参数
 
-| 参数 | 必填 | 说明 |
-|------|------|------|
-| `--url <url>` | 否 | 电子表格 URL(与 `--spreadsheet-token` 二选一) |
-| `--spreadsheet-token <token>` | 否 | 表格 token(与 `--url` 二选一) |
-| `--data <json>` | 是 | JSON 数组,每项包含 `ranges`(字符串数组)和 `style`(样式对象) |
-| `--dry-run` | 否 | 仅打印参数,不执行请求 |
+| 参数  | 必填  | 说明  |
+| --- | --- | --- |
+| `--url <url>` | 否   | 电子表格 URL(与 `--spreadsheet-token` 二选一) |
+| `--spreadsheet-token <token>` | 否   | 表格 token(与 `--url` 二选一) |
+| `--data <json>` | 是   | JSON 数组,每项包含 `ranges`(字符串数组)和 `style`(样式对象) |
+| `--dry-run` | 否   | 仅打印参数,不执行请求 |
 
 ### style 对象字段
 
@@ -43,11 +42,11 @@ lark-cli sheets +batch-set-style --spreadsheet-token "shtxxxxxxxx" \
 
 JSON,包含:
 
-- `totalUpdatedRows/totalUpdatedColumns/totalUpdatedCells`:汇总更新量
-- `revision`:工作表版本号
-- `responses[]`:每个范围的更新详情
+-   `totalUpdatedRows/totalUpdatedColumns/totalUpdatedCells`:汇总更新量
+-   `revision`:工作表版本号
+-   `responses[]`:每个范围的更新详情
 
 ## 参考
 
-- [lark-sheets-set-style](lark-sheets-set-style.md) — 单范围设置样式
-- [lark-shared](../../lark-shared/SKILL.md) — 认证和全局参数
+-   [lark-sheets-set-style](lark-sheets-set-style.md) — 单范围设置样式
+-   [lark-shared](../../lark-shared/SKILL.md) — 认证和全局参数

+ 17 - 20
.claude/skills/pc-demo/SKILL.md

@@ -12,7 +12,7 @@ description: PC端管理后台构建专家。使用 Vue 3 + Element Plus + Vite
 
 ## 技术栈
 
-| 技术 | 用途 |
+| 技术  | 用途  |
 | --- | --- |
 | Vue 3.5 + Composition API | 视图层 |
 | Vue Router 4 | 路由(createRouter + createWebHashHistory) |
@@ -51,7 +51,7 @@ pc-demo/src/
 
 ## 核心规范索引
 
-| 规范 | 文件 |
+| 规范  | 文件  |
 | --- | --- |
 | 项目初始化 | [references/pc-init.md](./references/pc-init.md) |
 | 菜单配置 | [references/menu-config.md](./references/menu-config.md) |
@@ -67,13 +67,10 @@ pc-demo/src/
 
 新增页面时按以下步骤执行:
 
-1. **确认需求**:页面类型(列表/详情/看板)、所属菜单位置、核心字段
-
-2. **创建文件**:在 `src/views/` 下创建页面 `.vue` 文件,在 `src/mock/index.js` 中添加 Mock 数据
-
-3. **注册路由**:`src/router/index.js` 中添加路由,设置 `meta.title` 用于面包屑
-
-4. **注册菜单**:`src/components/Layout.vue` 的 `<el-menu>` 中添加菜单项
+1.  **确认需求**:页面类型(列表/详情/看板)、所属菜单位置、核心字段
+2.  **创建文件**:在 `src/views/` 下创建页面 `.vue` 文件,在 `src/mock/index.js` 中添加 Mock 数据
+3.  **注册路由**:`src/router/index.js` 中添加路由,设置 `meta.title` 用于面包屑
+4.  **注册菜单**:`src/components/Layout.vue` 的 `<el-menu>` 中添加菜单项
 
 * * *
 
@@ -89,17 +86,17 @@ cd 工作空间/产研/权益/汇丰全行/产品原型/pc-demo && npm run dev
 
 ## Element Plus 使用约定
 
-- 图标:`<el-icon><Plus /></el-icon>`,所有图标已全局注册,无需逐文件 import
-- 弹窗:`el-dialog` / `el-drawer` 用 `v-model="visible"`
-- 子菜单:使用 `<el-sub-menu>`(非 `el-submenu`)
-- 插槽:`<template #xxx>` 替代 `slot="xxx"`;`<template #default="scope">` 替代 `slot-scope`
-- 尺寸:`size="small"` 替代 `size="mini"`;无需写 `size="medium"`(用默认)
-- 消息:`ElMessage.xxx()` 替代 `this.$message`;`ElMessageBox.confirm()` 替代 `this.$confirm`
+-   图标:`<el-icon><Plus /></el-icon>`,所有图标已全局注册,无需逐文件 import
+-   弹窗:`el-dialog` / `el-drawer` 用 `v-model="visible"`
+-   子菜单:使用 `<el-sub-menu>`(非 `el-submenu`)
+-   插槽:`<template #xxx>` 替代 `slot="xxx"`;`<template #default="scope">` 替代 `slot-scope`
+-   尺寸:`size="small"` 替代 `size="mini"`;无需写 `size="medium"`(用默认)
+-   消息:`ElMessage.xxx()` 替代 `this.$message`;`ElMessageBox.confirm()` 替代 `this.$confirm`
 
 ## 注意事项
 
-- 这是一个 demo 项目,重点在于界面展示和交互体验,不需要真实后端接口
-- 所有数据使用 Mock.js 模拟,mock 数据要贴合业务实际
-- Mock 返回体必须遵循 `{ code: 200, data, msg }` 结构
-- 新增页面时必须同步更新菜单配置和路由配置
-- 保持代码简洁,避免过度工程化
+-   这是一个 demo 项目,重点在于界面展示和交互体验,不需要真实后端接口
+-   所有数据使用 Mock.js 模拟,mock 数据要贴合业务实际
+-   Mock 返回体必须遵循 `{ code: 200, data, msg }` 结构
+-   新增页面时必须同步更新菜单配置和路由配置
+-   保持代码简洁,避免过度工程化

+ 0 - 1
工作空间/产研/权益/汇丰全行/产品原型/h5-demo/Untitled.md

@@ -1 +0,0 @@
-111

+ 715 - 0
工作空间/产研/权益/汇丰全行/产品原型/h5-demo/移动端.html

@@ -0,0 +1,715 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
+    <title>权益专区</title>
+    <script src="https://cdn.tailwindcss.com"></script>
+    <style>
+        /* 隐藏滚动条但保留滚动功能 */
+        .no-scrollbar::-webkit-scrollbar {
+            display: none;
+        }
+        .no-scrollbar {
+            -ms-overflow-style: none;
+            scrollbar-width: none;
+        }
+        
+        /* 选中态的红线动画过渡 */
+        .tab-indicator {
+            transition: all 0.3s ease;
+        }
+        
+        /* 视图切换动画 */
+        .view-transition {
+            transition: transform 0.35s cubic-bezier(0.4, 0.0, 0.2, 1);
+        }
+    </style>
+</head>
+<body class="bg-gray-100 flex justify-center h-screen overflow-hidden font-sans">
+
+    <!-- 侧边全局控制面板 -->
+    <div class="fixed top-[20%] right-0 z-50 flex items-start max-w-sm">
+        <button onclick="toggleSimPanel()" class="bg-black/60 text-white text-[11px] py-1.5 px-2 rounded-l-md shadow-md flex items-center gap-1 backdrop-blur-sm">
+            <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="3"/></svg>
+            状态
+        </button>
+        
+        <div id="sim-panel" class="absolute top-8 right-2 bg-white/95 backdrop-blur-md border border-gray-200 p-2 rounded-lg shadow-xl w-[140px] text-[11px] transition-all origin-top-right scale-0 opacity-0 pointer-events-none">
+            <div class="font-bold mb-1.5 text-gray-800 border-b pb-1 text-center">切换等级</div>
+            <div class="flex flex-col gap-1.5">
+                <button onclick="setUserLevel('prospect')" id="btn-state-prospect" class="px-2 py-1.5 rounded bg-gray-100 text-gray-700 transition">潜客</button>
+                <button onclick="setUserLevel('credit_only')" id="btn-state-credit_only" class="px-2 py-1.5 rounded bg-gray-100 text-gray-700 transition">仅持有信用卡客户</button>
+                <button onclick="setUserLevel('advance')" id="btn-state-advance" class="px-2 py-1.5 rounded bg-gray-100 text-gray-700 transition">运筹理财</button>
+                <button onclick="setUserLevel('premier')" id="btn-state-premier" class="px-2 py-1.5 rounded bg-gray-100 text-gray-700 transition">卓越理财</button>
+                <button onclick="setUserLevel('elite')" id="btn-state-elite" class="px-2 py-1.5 rounded bg-gray-100 text-gray-700 transition">卓越理财·尊尚</button>
+                <button onclick="setUserLevel('global')" id="btn-state-global" class="px-2 py-1.5 rounded bg-gray-100 text-gray-700 transition">环球私人银行</button>
+            </div>
+        </div>
+    </div>
+
+    <!-- 移动端模拟容器 -->
+    <div class="w-full max-w-[400px] h-full bg-white flex flex-col relative shadow-2xl overflow-hidden">
+        
+        <!-- 顶部状态栏 -->
+        <div class="h-11 w-full flex justify-between items-center px-5 text-black bg-white z-30 relative shrink-0">
+            <span class="text-[15px] font-medium">9:41</span>
+            <div class="flex gap-1.5 items-center">
+                <svg width="18" height="12" viewBox="0 0 18 12" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1.5 12V9H3.5V12H1.5ZM6 12V6.5H8V12H6ZM10.5 12V3.5H12.5V12H10.5ZM15 12V0H17V12H15Z" fill="black"/></svg>
+                <svg width="16" height="12" viewBox="0 0 16 12" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8 12C9.10457 12 10 11.1046 10 10C10 8.89543 9.10457 8 8 8C6.89543 8 6 8.89543 6 10C6 11.1046 6.89543 12 8 12Z" fill="black"/><path d="M2.34315 5.65685C5.46734 2.53266 10.5327 2.53266 13.6569 5.65685" stroke="black" stroke-width="1.5" stroke-linecap="round"/><path d="M5.17157 8.48528C6.73367 6.92318 9.26633 6.92318 10.8284 8.48528" stroke="black" stroke-width="1.5" stroke-linecap="round"/></svg>
+                <svg width="25" height="12" viewBox="0 0 25 12" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="0.5" y="0.5" width="21" height="11" rx="2.5" stroke="black"/><rect x="2" y="2" width="18" height="8" rx="1" fill="black"/><path d="M23 4V8" stroke="black" stroke-width="1.5" stroke-linecap="round"/></svg>
+            </div>
+        </div>
+
+        <!-- ====== 视图 A: 权益介绍页 (Home View) ====== -->
+        <div id="home-view" class="flex flex-col h-[calc(100%-44px)] w-full absolute top-[44px] left-0 bg-white view-transition translate-x-0 z-10">
+            <header class="h-11 flex items-center justify-between px-4 bg-white z-20 shrink-0">
+                <button class="text-gray-800 p-1">
+                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg>
+                </button>
+                <h1 class="text-[17px] font-medium text-gray-900 absolute left-1/2 -translate-x-1/2">权益介绍页</h1>
+                <div class="w-8"></div>
+            </header>
+
+            <div class="flex-1 overflow-y-auto no-scrollbar pb-8 relative">
+                <div id="no-tier-banner" onclick="showZone()" class="px-4 py-3 bg-[#fdfaf8] border-b border-gray-100 flex items-center justify-between cursor-pointer active:bg-gray-50 transition">
+                    <div class="flex items-center gap-3">
+                        <div class="w-10 h-10 rounded-full bg-gray-100 flex items-center justify-center border border-gray-200">
+                            <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#666" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="14" x="3" y="8" rx="2"/><path d="M12 5a3 3 0 1 0-3 3"/><path d="M15 8a3 3 0 1 0-3-3"/><path d="M12 8v10"/><path d="M3 12h18"/></svg>
+                        </div>
+                        <div>
+                            <div class="text-[15px] text-gray-900">权益首页</div>
+                            <div class="text-[12px] text-gray-500">一键查看您的所有权益</div>
+                        </div>
+                    </div>
+                    <button class="text-[13px] text-gray-500 flex items-center pointer-events-none">
+                        立即查看
+                        <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
+                    </button>
+                </div>
+
+                <div class="flex justify-between px-2 pt-2 border-b border-gray-200 relative">
+                    <button onclick="switchTab('premier')" class="flex-1 py-3 text-[14px] font-medium relative text-gray-900" id="tab-btn-premier">
+                        卓越理财
+                    </button>
+                    <button onclick="switchTab('elite')" class="flex-1 py-3 text-[14px] font-medium relative text-gray-500" id="tab-btn-elite">
+                        卓越理财·尊尚
+                    </button>
+                    <button onclick="switchTab('global')" class="flex-1 py-3 text-[14px] font-medium relative text-gray-500" id="tab-btn-global">
+                        环球私人银行
+                    </button>
+                    
+                    <div id="tab-indicator" class="absolute bottom-0 h-[2px] bg-[#d70014] tab-indicator" style="width: 33.33%; left: 0%;"></div>
+                </div>
+
+                <div id="content-area" class="px-5 pt-5 pb-10">
+                </div>
+            </div>
+        </div>
+
+        <!-- ====== 视图 B: 权益首页/专区 (Zone View) ====== -->
+        <div id="zone-view" class="flex flex-col h-[calc(100%-44px)] w-full absolute top-[44px] left-0 bg-[#f4f5f8] view-transition translate-x-full z-20">
+            <header class="h-11 flex items-center justify-between px-4 bg-white z-20 shrink-0 border-b border-gray-100">
+                <button onclick="hideZone()" class="text-gray-800 p-1">
+                    <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg>
+                </button>
+                <h1 class="text-[17px] font-medium text-gray-900 absolute left-1/2 -translate-x-1/2">权益首页</h1>
+                <div class="w-8"></div>
+            </header>
+
+            <div class="flex-1 overflow-y-auto no-scrollbar pb-8 relative" id="zone-content-area">
+            </div>
+        </div>
+
+        <!-- 积分规则弹窗 (Rule Modal) -->
+        <div id="rule-modal-backdrop" class="absolute inset-0 bg-black/50 z-[60] opacity-0 pointer-events-none transition-opacity duration-300" onclick="closeRuleModal()"></div>
+        <div id="rule-modal" class="absolute bottom-0 left-0 w-full bg-white z-[70] rounded-t-2xl transform translate-y-full transition-transform duration-300 flex flex-col" style="height: 85%;">
+            <div class="flex justify-between items-center px-5 py-4 border-b border-gray-100 shrink-0">
+                <h2 class="text-[17px] font-medium text-gray-900">积分规则</h2>
+                <button onclick="closeRuleModal()" class="text-gray-500 p-1 hover:bg-gray-100 rounded-full transition">
+                    <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
+                </button>
+            </div>
+            <div class="flex-1 overflow-y-auto px-5 py-5 no-scrollbar">
+                <h3 class="text-[14px] font-medium text-gray-800 mb-4">汇丰银行(中国)有限公司积分使用规则</h3>
+                <div class="text-[13px] text-gray-600 leading-[1.8] space-y-4 text-justify">
+                    <p>本积分使用规则(“本规则”)为汇丰银行(中国)有限公司(“本行”)的客户(“客户”)使用本行信用卡及借记卡积分(即“汇友荟”汇丰客户关系积分)(简称“汇友荟积分”)兑换本行提供的礼品、里程或刷卡金等项目(具体以本行积分换礼平台正式公布的有效兑换项目为准,以下称“兑换项目”)等需要遵守的使用规则。</p>
+                    <p class="font-medium text-gray-800 pt-2">一、 兑换及使用渠道</p>
+                    <p>1. 除本规则以下相关兑换项目项下有特别说明外,客户可使用信用卡积分及“汇友荟”汇丰客户关系积分在积分换礼平台兑换相关项目,具体兑换渠道如下:<br>
+                    (1) 登录“汇丰中国客户服务”微信服务号,点击“我的汇丰”—“我的积分”—“积分商城”页面兑换;或<br>
+                    (2) 登录汇丰银行App,在“我的”点击“我的积分”—“积分商城”页面兑换礼品;<br>
+                    (3) 人工服务申请兑换:拨打本行24小时客服热线95366或4008695366(该渠道仅限本行信用卡主卡持卡人兑换部分项目申请时使用)兑换。</p>
+                    <p>2. 积分一旦兑换成功,不可撤销、更改或退还。若因系统或网络原因导致兑换失败,积分将自动退回账户。</p>
+                    <p class="font-medium text-gray-800 pt-2">二、 积分有效期</p>
+                    <p>信用卡积分有效期与信用卡有效期一致。如客户在信用卡有效期届满前未消耗完毕,积分将于信用卡到期次月清零。“汇友荟”积分有效期详见对应活动的具体规则。请客户关注积分到期日并及时兑换。</p>
+                    <p class="pt-10 pb-10 text-center text-gray-300">-- 到底了 --</p>
+                </div>
+            </div>
+        </div>
+
+        <!-- 余额计算规则弹窗 (Balance Rule Modal) -->
+        <div id="balance-rule-modal-backdrop" class="absolute inset-0 bg-black/50 z-[60] opacity-0 pointer-events-none transition-opacity duration-300" onclick="closeBalanceRuleModal()"></div>
+        <div id="balance-rule-modal" class="absolute bottom-0 left-0 w-full bg-white z-[70] rounded-t-2xl transform translate-y-full transition-transform duration-300 flex flex-col min-h-[220px]">
+            <div class="flex justify-between items-center px-5 py-4 shrink-0 border-b border-gray-50">
+                <h2 class="text-[18px] font-medium text-gray-900">提示</h2>
+                <button onclick="closeBalanceRuleModal()" class="text-gray-500 p-1 hover:bg-gray-100 rounded-full transition">
+                    <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
+                </button>
+            </div>
+            <div class="flex-1 px-5 pb-8 pt-4">
+                <div class="text-[15px] text-gray-700 leading-[1.6]">
+                    月内日均余额 = 当月内每日账户余额之和 / 当月天数。
+                </div>
+            </div>
+        </div>
+
+        <!-- 底部 Home Indicator (iOS风格) -->
+        <div class="h-8 w-full flex justify-center items-center z-[80] absolute bottom-0 pointer-events-none">
+            <div class="w-32 h-1 bg-gray-900 rounded-full"></div>
+        </div>
+    </div>
+
+    <script>
+        // --- 核心 SVG 图标库 ---
+        const icons = {
+            cap: `<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 10v6M2 10l10-5 10 5-10 5z"/><path d="M6 12v5c3 3 9 3 12 0v-5"/></svg>`,
+            heart: `<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z"/></svg>`,
+            bulb: `<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.9 1.2 1.5 1.5 2.5"/><path d="M9 18h6"/><path d="M10 22h4"/></svg>`,
+            gift: `<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="8" width="18" height="14" rx="2"/><path d="M12 5a3 3 0 1 0-3 3"/><path d="M15 8a3 3 0 1 0-3-3"/><path d="M12 8v14"/><path d="M3 12h18"/></svg>`,
+            diamond: `<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 3h12l4 6-10 13L2 9Z"/></svg>`,
+            medbox: `<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="8" width="16" height="12" rx="2"/><path d="M8 8V6a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><path d="M12 11v4M10 13h4"/></svg>`,
+            car: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 17h2c.6 0 1-.4 1-1v-3c0-.9-.7-1.7-1.5-1.9C18.7 10.6 16 10 12 10s-6.7.6-8.5 1.1C2.7 11.3 2 12.1 2 13v3c0 .6.4 1 1 1h2"/><rect width="16" height="8" x="4" y="10" rx="2"/><path d="M7 14h.01"/><path d="M17 14h.01"/><path d="m10 10-1.5-4h7l-1.5 4"/></svg>`,
+            plane: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><path d="M17.8 19.2 16 11l3.5-3.5C21 6 21.5 4 21 3c-1-.5-3 0-4.5 1.5L13 8 4.8 6.2c-.5-.1-.9.2-1.1.7l-1.2 3.6 7.7 4.4-4.2 4.2-3.1-.8c-.4-.1-.8.1-1 .5l-.8 2.3 5.4 1.8 1.8 5.4 2.3-.8c.4-.2.6-.6.5-1l-.8-3.1 4.2-4.2 4.4 7.7 3.6-1.2c.5-.2.8-.6.7-1.1Z"/></svg>`,
+            globe: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/><path d="M2 12h20"/></svg>`,
+            coffee: `<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="#ba6534" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M17 8h1a4 4 0 1 1 0 8h-1"/><path d="M3 8h14v9a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4Z"/><line x1="6" x2="6" y1="2" y2="4"/><line x1="10" x2="10" y1="2" y2="4"/><line x1="14" x2="14" y1="2" y2="4"/></svg>`,
+            planeRed: `<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="#d70014" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M17.8 19.2 16 11l3.5-3.5C21 6 21.5 4 21 3c-1-.5-3 0-4.5 1.5L13 8 4.8 6.2c-.5-.1-.9.2-1.1.7l-1.2 3.6 7.7 4.4-4.2 4.2-3.1-.8c-.4-.1-.8.1-1 .5l-.8 2.3 5.4 1.8 1.8 5.4 2.3-.8c.4-.2.6-.6.5-1l-.8-3.1 4.2-4.2 4.4 7.7 3.6-1.2c.5-.2.8-.6.7-1.1Z"/></svg>`,
+            help: `<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="#999" stroke-width="1.5" class="ml-1 inline-block"><circle cx="12" cy="12" r="10"></circle><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>`,
+            copy: `<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="#999" stroke-width="1.5" class="ml-1 inline-block cursor-pointer"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`,
+            doc: `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" class="mr-1 inline-block"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline></svg>`
+        };
+
+        // --- 权益主页数据 (Home Page Data) ---
+        const tabData = {
+            premier: {
+                id: 'premier', title: '卓越理财', subtitle: '为您和您的家人提供尊崇专属礼遇和权益',
+                imageSrc: 'https://images.unsplash.com/photo-1518893494013-481c1d8ed3fd?q=80&w=800&auto=format&fit=crop',
+                imageStyle: 'filter: sepia(0.4) hue-rotate(330deg);',
+                features: [
+                    { title: '国际教育', desc: '享专属国际化学校优惠及背景提升项目' },
+                    { title: '酒店礼遇', desc: '高端酒店及商场会籍匹配' },
+                    { title: '环球礼遇', desc: '汇丰中国信用卡持卡人,尊享机场贵宾厅及礼宾车等礼遇' },
+                    { title: '优选健康荟', desc: '享香港私立医院体检专属折扣' }
+                ]
+            },
+            elite: {
+                id: 'elite', title: '卓越理财·尊尚', subtitle: '开启尊尚体验,享受环球出行、高端运动、国际教育等VIP礼遇。',
+                imageSrc: 'https://images.unsplash.com/photo-1610701596007-11502861dcfa?q=80&w=800&auto=format&fit=crop',
+                imageStyle: 'filter: sepia(0.6) hue-rotate(330deg) saturate(1.5);',
+                features: [
+                    { title: '国际教育', desc: '享多项升学规划指导、专属国际化学校优惠及背景提升项目' },
+                    { title: '专属礼宾服务', desc: '高端酒店及商场会籍匹配、高尔夫练习场畅' },
+                    { title: '尊尚生日礼', desc: '尊享体验任选其一' },
+                    { title: '「汇享健康」', desc: '三重健康保障,包括专属健保管家、公立医院门诊预约及就医陪同服务等权益' }
+                ]
+            },
+            global: {
+                id: 'global', title: '环球私人银行', subtitle: '开启环球「创臻享」及「汇佑健康」之旅。',
+                imageSrc: 'https://images.unsplash.com/photo-1550684848-fac1c5b4e853?q=80&w=800&auto=format&fit=crop',
+                imageStyle: '',
+                features: [
+                    { title: '高尔夫权益', desc: '练习场畅达及VIP高尔夫俱乐部免会籍预约' },
+                    { title: '臻享体验', desc: '享高端酒店及商场会籍匹配、米其林级别私宴预定服务等' },
+                    { title: '环球旅行', desc: '境外礼宾接送机服务及酒店升房礼遇' },
+                    { title: '私人生日礼', desc: '尊享体验任选其一' },
+                    { title: '「汇佑健康」', desc: '一站式健康管理,包括专属家庭医师团队、公立医院门诊预约及就医陪同服务等权益' }
+                ]
+            }
+        };
+
+        const bottomBannerData = {
+            tag: '精选活动', title: '汇丰卓越理财新户达标礼-东方航空', subtitle: '报名参加汇丰活动,体验更多精彩礼遇',
+            imageSrc: 'https://images.unsplash.com/photo-1436491865332-7a61a109cc05?q=80&w=800&auto=format&fit=crop'
+        };
+
+        // --- 权益专区数据 (Zone Page Data) ---
+        const baseAdvanceExclusives = [
+            { icon: icons.gift, label: '卓越理财迎<br>新礼' }
+        ];
+
+        const zoneData = {
+            'prospect': { 
+                hasAd: false, hasDotsExclusives: false, hasDotsCredit: true, hideIdentity: true,
+                exclusives: baseAdvanceExclusives
+            },
+            'credit_only': { 
+                hasAd: false, hasDotsExclusives: false, hasDotsCredit: true, hideIdentity: true,
+                exclusives: baseAdvanceExclusives
+            },
+            'advance': { 
+                headerBannerUrl: 'https://images.unsplash.com/photo-1477959858617-67f85cf4f1df?w=800&auto=format&fit=crop', 
+                tierTitle: 'HSBC Advance', tierSub: '汇丰运筹理财',
+                hasAd: false, hasDotsExclusives: false, hasDotsCredit: true, hideIdentity: false,
+                accountHtml: `
+                    <div class="flex justify-between items-end pt-1">
+                        <div>
+                            <div class="text-[14px] text-gray-800 flex items-center font-medium">账户月内日均余额 <span onclick="openBalanceRuleModal()" class="cursor-pointer ml-1 flex items-center">${icons.help}</span></div>
+                            <div class="text-[12px] text-gray-500 mt-1.5">截止日期 XXXX年X月X日</div>
+                        </div>
+                        <div class="text-[14px] text-gray-600 mb-1.5">8,000,000 人民币元</div>
+                    </div>
+                `,
+                exclusives: baseAdvanceExclusives
+            },
+            'premier': { // 卓越理财
+                headerBannerUrl: 'https://images.unsplash.com/photo-1574678170884-cbabaf60df08?w=800&auto=format&fit=crop', 
+                tierTitle: 'HSBC Premier', tierSub: '汇丰卓越理财',
+                hasAd: true, hasDotsExclusives: false, hasDotsCredit: true, hideIdentity: false,
+                accountHtml: `
+                    <div class="border-b border-gray-100 pb-3.5 mb-3.5">
+                        <div class="text-[14px] text-gray-800 font-medium flex items-center">卓越理财客户</div>
+                        <div class="text-[12px] text-gray-500 mt-1 flex items-center">合格(上月日均余额)<span onclick="openBalanceRuleModal()" class="cursor-pointer ml-1 flex items-center">${icons.help}</span></div>
+                    </div>
+                    <div class="flex justify-between items-end">
+                        <div>
+                            <div class="text-[14px] text-gray-800 flex items-center font-medium">账户月内日均余额 <span onclick="openBalanceRuleModal()" class="cursor-pointer ml-1 flex items-center">${icons.help}</span></div>
+                            <div class="text-[12px] text-gray-500 mt-1.5">截止日期 XXXX年X月X日</div>
+                        </div>
+                        <div class="text-[14px] text-gray-600 mb-1.5">8,000,000 人民币元</div>
+                    </div>
+                `,
+                exclusives: [
+                    { icon: icons.cap, label: '国际教育' },
+                    { icon: icons.heart, label: '优选健康荟' },
+                    { icon: icons.bulb, label: '酒店礼遇' }
+                ]
+            },
+            'elite': { // 卓越理财·尊尚
+                headerBannerUrl: 'https://images.unsplash.com/photo-1610701596007-11502861dcfa?w=800&auto=format&fit=crop', 
+                tierTitle: 'HSBC Premier Elite', tierSub: '汇丰卓越理财·尊尚',
+                hasAd: true, hasDotsExclusives: true, hasDotsCredit: true, hideIdentity: false,
+                accountHtml: `
+                    <div class="flex justify-between items-center border-b border-gray-100 pb-3.5 mb-3.5">
+                        <div>
+                            <div class="text-[14px] text-gray-800 font-medium flex items-center">卓越理财尊尚客户</div>
+                            <div class="text-[12px] text-gray-500 mt-1 flex items-center">合格(上月日均余额)<span onclick="openBalanceRuleModal()" class="cursor-pointer ml-1 flex items-center">${icons.help}</span></div>
+                        </div>
+                        <div class="text-[14px] text-gray-600 flex items-center">C1234567890 ${icons.copy}</div>
+                    </div>
+                    <div class="flex justify-between items-end">
+                        <div>
+                            <div class="text-[14px] text-gray-800 flex items-center font-medium">账户月内日均余额 <span onclick="openBalanceRuleModal()" class="cursor-pointer ml-1 flex items-center">${icons.help}</span></div>
+                            <div class="text-[12px] text-gray-500 mt-1.5">截止日期 XXXX年X月X日</div>
+                        </div>
+                        <div class="text-[14px] text-gray-600 mb-1.5">8,000,000 人民币元</div>
+                    </div>
+                `,
+                exclusives: [
+                    { icon: icons.cap, label: '国际教育' },
+                    { icon: icons.gift, label: '生日礼' },
+                    { icon: icons.diamond, label: '礼宾服务' },
+                    { icon: icons.heart, label: '汇享健康' }
+                ]
+            },
+            'global': { // 环球私人银行
+                headerBannerUrl: 'https://images.unsplash.com/photo-1634024344558-8b20d7d3b0c6?w=800&auto=format&fit=crop', 
+                tierTitle: 'HSBC Private Bank', tierSub: '汇丰环球私人银行',
+                hasAd: true, hasDotsExclusives: false, hasDotsCredit: true, hideIdentity: false,
+                accountHtml: `
+                    <div class="flex justify-between items-center py-1">
+                        <div>
+                            <div class="text-[14px] text-gray-800 font-medium flex items-center">私行业务ID<span onclick="openBalanceRuleModal()" class="cursor-pointer ml-1 flex items-center">${icons.help}</span></div>
+                            <div class="text-[12px] text-gray-500 mt-1">银辉</div>
+                        </div>
+                        <div class="text-[14px] text-gray-600 flex items-center">C1234567890 ${icons.copy}</div>
+                    </div>
+                `,
+                exclusives: [
+                    { icon: icons.cap, label: '国际教育' },
+                    { icon: icons.heart, label: '创臻享礼宾<br>服务' },
+                    { icon: icons.medbox, label: '汇佑健康' },
+                    { icon: icons.heart, label: '优选健康荟' }
+                ]
+            }
+        };
+
+        // 信用卡权益数据 (通用)
+        const creditCardsData = [
+            { icon: icons.car, title: '境外礼宾车', sub: '共2次', badge: '0/2' },
+            { icon: icons.car, title: '境内礼宾车', sub: '共2次', badge: '0/2' },
+            { icon: icons.plane, title: '贵宾厅', sub: '共2次', badge: '0/2' },
+            { icon: icons.globe, title: '境外消费', sub: '点击查看' }
+        ];
+
+        // --- 状态管理 ---
+        let currentUserLevel = 'advance'; // 'prospect', 'credit_only', 'advance', 'premier', 'elite', 'global'
+        let currentActiveTab = 'premier';
+
+        // --- 初始化 ---
+        document.addEventListener('DOMContentLoaded', () => {
+            renderHomePage();
+            updateControlPanelUI();
+        });
+
+        // --- ====== 主页视图逻辑 ====== ---
+        function renderHomePage() {
+            renderHeaderBanner();
+            renderTabsNav();
+            renderContentArea();
+        }
+
+        function renderHeaderBanner() {
+            const banner = document.getElementById('no-tier-banner');
+            const isBasic = ['prospect', 'credit_only', 'advance'].includes(currentUserLevel);
+            banner.style.display = isBasic ? 'flex' : 'none';
+        }
+
+        function renderTabsNav() {
+            const tabs = ['premier', 'elite', 'global'];
+            tabs.forEach((tab) => {
+                const btn = document.getElementById(`tab-btn-${tab}`);
+                if (tab === currentActiveTab) {
+                    btn.className = "flex-1 py-3 text-[14px] font-medium relative text-gray-900";
+                } else {
+                    btn.className = "flex-1 py-3 text-[14px] font-medium relative text-gray-500";
+                }
+            });
+            const indicator = document.getElementById('tab-indicator');
+            indicator.style.left = `${tabs.indexOf(currentActiveTab) * 33.33}%`;
+        }
+
+        function renderContentArea() {
+            const container = document.getElementById('content-area');
+            const data = tabData[currentActiveTab];
+            
+            const levelWeights = { 'prospect': 0, 'credit_only': 0, 'advance': 0, 'premier': 1, 'elite': 2, 'global': 3 };
+            const isUnlocked = levelWeights[currentUserLevel] >= levelWeights[currentActiveTab];
+
+            let buttonHTML = isUnlocked ? `
+                <button onclick="showZone()" class="w-full py-3 mt-4 mb-6 border border-gray-300 rounded text-[15px] font-medium text-gray-900 bg-white active:bg-gray-50 transition">
+                    进入权益专区
+                </button>
+            ` : `
+                <button class="w-full py-3 mt-4 mb-6 rounded text-[15px] font-medium text-[#b3b3b3] bg-[#f7f7f7] cursor-not-allowed">
+                    待解锁
+                </button>
+            `;
+
+            let featuresHTML = data.features.map(f => `
+                <li class="flex items-start mb-3 relative pl-3">
+                    <span class="absolute left-0 top-[8px] w-1 h-1 bg-gray-600 rounded-full"></span>
+                    <div>
+                        <span class="text-gray-900 font-medium text-[13px] mr-1">${f.title}</span>
+                        <p class="text-gray-500 text-[12px] leading-relaxed mt-0.5">${f.desc}</p>
+                    </div>
+                </li>
+            `).join('');
+
+            const cards = [bottomBannerData, bottomBannerData, bottomBannerData];
+            let carouselItemsHTML = cards.map(card => `
+                <div class="min-w-full flex-none snap-center pb-2 px-0.5">
+                    <div class="rounded-sm border border-gray-200 shadow-sm bg-white overflow-hidden">
+                        <div class="relative h-[150px] w-full">
+                            <img src="${card.imageSrc}" class="w-full h-full object-cover">
+                            <div class="absolute top-0 left-0 bg-[#3b5988] text-white text-[13px] px-2.5 py-1.5 z-10">${card.tag}</div>
+                        </div>
+                        <div class="p-5">
+                            <h4 class="text-[17px] text-[#333] font-medium mb-3 leading-snug">${card.title}</h4>
+                            <p class="text-[13px] text-[#666] tracking-wide">${card.subtitle}</p>
+                        </div>
+                    </div>
+                </div>
+            `).join('');
+
+            container.innerHTML = `
+                <div class="w-full h-[150px] overflow-hidden mb-4 rounded-sm">
+                    <img src="${data.imageSrc}" style="${data.imageStyle}" class="w-full h-full object-cover">
+                </div>
+                <h2 class="text-xl font-medium text-gray-900 mb-1.5">${data.title}</h2>
+                <p class="text-[13px] text-gray-500 leading-snug">${data.subtitle}</p>
+                ${buttonHTML}
+                <ul class="text-sm">${featuresHTML}</ul>
+                <div class="mt-8 relative -mx-0.5">
+                    <div id="banner-carousel" class="flex overflow-x-auto snap-x snap-mandatory no-scrollbar w-full" onscroll="handleCarouselScroll(this, 'carousel-dots')">
+                        ${carouselItemsHTML}
+                    </div>
+                    <div class="flex justify-center items-center gap-2 mt-3 mb-2" id="carousel-dots">
+                        <div class="w-[6px] h-[6px] rounded-full bg-black transition-colors"></div>
+                        <div class="w-[6px] h-[6px] rounded-full border border-black transition-colors"></div>
+                        <div class="w-[6px] h-[6px] rounded-full border border-black transition-colors"></div>
+                    </div>
+                </div>
+            `;
+        }
+
+        // --- ====== 专区内页视图逻辑 (Zone View) ====== ---
+        function renderZonePage() {
+            // **关键点**:基于用户的真实等级 currentUserLevel 渲染内容
+            const data = zoneData[currentUserLevel];
+            const container = document.getElementById('zone-content-area');
+
+            // 专属礼遇图标组合
+            const exclusiveHtml = data.exclusives.map(item => `
+                <div class="flex flex-col items-center min-w-[70px]">
+                    <div class="w-12 h-12 rounded-full border border-gray-200 flex items-center justify-center text-gray-500 mb-2.5 shadow-sm bg-gray-50">
+                        ${item.icon}
+                    </div>
+                    <span class="text-[12px] text-gray-700 text-center leading-tight">${item.label}</span>
+                </div>
+            `).join('');
+
+            // 信用卡权益图标组合
+            const creditHtml = creditCardsData.map(item => `
+                <div class="flex flex-col items-center relative min-w-[70px]">
+                    ${item.badge ? `<div class="absolute -top-1 right-0 bg-[#d70014] text-white text-[10px] px-1.5 py-0.5 rounded-full z-10 border-2 border-white font-bold tracking-tighter">${item.badge}</div>` : ''}
+                    <div class="w-12 h-12 rounded-full border border-gray-200 flex items-center justify-center text-gray-500 mb-2.5 shadow-sm bg-gray-50">
+                        ${item.icon}
+                    </div>
+                    <span class="text-[12px] text-gray-800 text-center leading-tight">${item.title}</span>
+                    <span class="text-[11px] text-gray-400 text-center leading-tight mt-1">${item.sub}</span>
+                </div>
+            `).join('');
+
+            let html = '';
+
+            // 如果不隐藏客户身份模块,则渲染头图和账号信息
+            if (!data.hideIdentity) {
+                html += `
+                    <div class="w-full h-[140px] relative shrink-0">
+                        <img src="${data.headerBannerUrl}" class="w-full h-full object-cover">
+                        <div class="absolute inset-0 bg-gradient-to-r from-black/60 to-transparent"></div>
+                        <div class="absolute bottom-5 left-5 text-white">
+                            <div class="text-[14px] font-bold opacity-90 tracking-wide">${data.tierTitle}</div>
+                            <div class="text-[16px] font-medium tracking-widest mt-0.5">${data.tierSub}</div>
+                        </div>
+                    </div>
+
+                    <div class="bg-white px-5 py-4 mb-2">
+                        ${data.accountHtml}
+                    </div>
+                `;
+            } else {
+                // 如果隐藏身份模块,为了布局美观,顶部加一点空白
+                html += `<div class="w-full h-2 bg-transparent shrink-0"></div>`;
+            }
+
+            html += `
+                <div class="bg-white px-5 py-5 mb-2">
+                    <div class="flex justify-between items-center mb-6">
+                        <h3 class="text-[16px] font-medium text-gray-900">专属礼遇</h3>
+                        <div class="text-[13px] text-gray-900 font-medium flex items-center">我的权益 <svg class="w-4 h-4 ml-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M9 18l6-6-6-6"/></svg></div>
+                    </div>
+                    <div class="flex ${data.exclusives.length < 4 ? 'justify-start gap-8' : 'justify-between'} px-1">
+                        ${exclusiveHtml}
+                    </div>
+                    ${data.hasDotsExclusives ? `
+                    <div class="flex justify-center gap-2 mt-6">
+                        <div class="w-[5px] h-[5px] bg-black rounded-full"></div>
+                        <div class="w-[5px] h-[5px] border border-black rounded-full"></div>
+                    </div>` : ''}
+                </div>
+
+                <div class="bg-white px-5 py-5 mb-2">
+                    <h3 class="text-[16px] font-medium text-gray-900 mb-6">信用卡权益</h3>
+                    <div class="flex justify-between px-1">
+                        ${creditHtml}
+                    </div>
+                    ${data.hasDotsCredit ? `
+                    <div class="flex justify-center gap-2 mt-6">
+                        <div class="w-[5px] h-[5px] bg-black rounded-full"></div>
+                        <div class="w-[5px] h-[5px] border border-black rounded-full"></div>
+                    </div>` : ''}
+                </div>
+            `;
+
+            if (data.hasAd) {
+                html += `
+                <div class="bg-white px-5 py-5 mb-2">
+                    <div class="w-full bg-gray-100 mb-4 h-[150px]">
+                        <img src="https://images.unsplash.com/photo-1556742049-0cfed4f6a45d?w=800&auto=format&fit=crop" class="w-full h-full object-cover">
+                    </div>
+                    <h4 class="text-[18px] text-gray-900 font-medium mb-1.5">文案文案文案文案</h4>
+                    <p class="text-[13px] text-gray-500">报名参加汇丰活动,体验更多精彩礼遇</p>
+                </div>
+                `;
+            }
+
+            const isPointsExpanded = !['prospect', 'credit_only', 'advance'].includes(currentUserLevel);
+            
+            html += `
+                <div class="bg-white px-5 py-5 pb-8">
+                    <div class="flex justify-between items-center mb-5">
+                        <h3 class="text-[16px] font-medium text-gray-900">积分商城</h3>
+                        <div class="text-[13px] text-gray-900 font-medium flex items-center">进入积分商城 <svg class="w-4 h-4 ml-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M9 18l6-6-6-6"/></svg></div>
+                    </div>
+                    
+                    <div class="flex justify-between items-center py-2 cursor-pointer border-b border-transparent" onclick="togglePoints()">
+                        <div>
+                            <div class="text-[20px] font-medium text-gray-800">3,000,000</div>
+                            <div class="text-[12px] text-gray-400 mt-1">我的总积分</div>
+                        </div>
+                        <svg id="points-chevron" class="w-5 h-5 text-gray-500 transition-transform duration-300 ${isPointsExpanded ? 'rotate-180' : ''}" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"/></svg>
+                    </div>
+                    
+                    <div id="points-details" class="overflow-hidden transition-all duration-300 ${isPointsExpanded ? 'h-[120px]' : 'h-0'}">
+                        <div class="border-t border-gray-100 pt-4 mt-2 text-[13px] space-y-4 pb-2">
+                            <div class="flex justify-between text-gray-600"><span>汇友荟积分</span><span class="font-medium text-gray-800">9,000 积分</span></div>
+                            <div class="flex justify-between text-gray-600"><span>信用卡积分</span><span class="font-medium text-gray-800">9,000 积分</span></div>
+                            <div class="flex justify-between text-gray-600"><span>2025年5月24日到期积分</span><span class="font-medium text-gray-800">5,000 积分</span></div>
+                        </div>
+                    </div>
+
+                    <div class="mt-6">
+                        <div class="flex justify-between items-center mb-4">
+                            <h3 class="text-[16px] font-medium text-gray-900">常用兑换</h3>
+                            <div class="text-[13px] text-gray-800 flex items-center font-medium">${icons.doc}积分明细</div>
+                        </div>
+                        
+                        <div class="flex overflow-x-auto no-scrollbar gap-3 pb-2 snap-x" onscroll="handleCarouselScroll(this, 'exchange-dots')">
+                            <div class="min-w-[100px] bg-white border border-gray-200 rounded-sm flex flex-col items-center snap-start shadow-sm">
+                                <div class="w-full h-[65px] bg-[#f7fbff] flex items-center justify-center">${icons.planeRed}</div>
+                                <div class="text-[13px] text-gray-700 py-2.5">航空里程</div>
+                            </div>
+                            <div class="min-w-[100px] bg-white border border-gray-200 rounded-sm flex flex-col items-center snap-start shadow-sm">
+                                <div class="w-full h-[65px] bg-[#fffaf5] flex items-center justify-center">${icons.coffee}</div>
+                                <div class="text-[13px] text-gray-700 py-2.5">贵宾厅</div>
+                            </div>
+                            <div class="min-w-[100px] bg-white border border-gray-200 rounded-sm flex flex-col items-center snap-start shadow-sm">
+                                <div class="w-full h-[65px] bg-[#fffdf5] flex items-center justify-center"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#d5aa11" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M19 17h2c.6 0 1-.4 1-1v-3c0-.9-.7-1.7-1.5-1.9C18.7 10.6 16 10 12 10s-6.7.6-8.5 1.1C2.7 11.3 2 12.1 2 13v3c0 .6.4 1 1 1h2"/><rect width="16" height="8" x="4" y="10" rx="2"/><path d="M7 14h.01"/><path d="M17 14h.01"/><path d="m10 10-1.5-4h7l-1.5 4"/></svg></div>
+                                <div class="text-[13px] text-gray-700 py-2.5">礼宾接送机</div>
+                            </div>
+                            <div class="min-w-[100px] bg-white border border-gray-200 rounded-sm flex flex-col items-center snap-start shadow-sm">
+                                <div class="w-full h-[65px] bg-[#f9fafb] flex items-center justify-center"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#666" stroke-width="1.5"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/></svg></div>
+                                <div class="text-[13px] text-gray-700 py-2.5">年费</div>
+                            </div>
+                        </div>
+                        <div class="flex justify-center gap-2 mt-3" id="exchange-dots">
+                            <div class="w-[5px] h-[5px] bg-black rounded-full transition-colors"></div>
+                            <div class="w-[5px] h-[5px] border border-black rounded-full transition-colors"></div>
+                        </div>
+                        <div class="flex justify-end mt-6">
+                            <div class="text-[12px] text-gray-900 font-medium flex items-center cursor-pointer" onclick="openRuleModal()">${icons.doc} 积分规则</div>
+                        </div>
+                    </div>
+                </div>
+            `;
+            
+            container.innerHTML = html;
+        }
+
+        // --- ====== 交互行为 ====== ---
+
+        function switchTab(tabId) {
+            currentActiveTab = tabId;
+            renderHomePage();
+        }
+
+        function setUserLevel(level) {
+            currentUserLevel = level;
+            const basicLevels = ['prospect', 'credit_only', 'advance'];
+            currentActiveTab = basicLevels.includes(level) ? 'premier' : level;
+            
+            renderHomePage();
+            updateControlPanelUI();
+            
+            if(document.getElementById('zone-view').classList.contains('translate-x-0')) {
+                renderZonePage();
+            }
+
+            if (isSimPanelOpen) toggleSimPanel();
+        }
+
+        function showZone() {
+            renderZonePage();
+            
+            const homeView = document.getElementById('home-view');
+            const zoneView = document.getElementById('zone-view');
+            
+            homeView.classList.remove('translate-x-0');
+            homeView.classList.add('-translate-x-full');
+            
+            zoneView.classList.remove('translate-x-full');
+            zoneView.classList.add('translate-x-0');
+        }
+
+        function hideZone() {
+            const homeView = document.getElementById('home-view');
+            const zoneView = document.getElementById('zone-view');
+            
+            homeView.classList.remove('-translate-x-full');
+            homeView.classList.add('translate-x-0');
+            
+            zoneView.classList.remove('translate-x-0');
+            zoneView.classList.add('translate-x-full');
+        }
+
+        function openRuleModal() {
+            document.getElementById('rule-modal-backdrop').classList.remove('opacity-0', 'pointer-events-none');
+            document.getElementById('rule-modal').classList.remove('translate-y-full');
+        }
+        function closeRuleModal() {
+            document.getElementById('rule-modal-backdrop').classList.add('opacity-0', 'pointer-events-none');
+            document.getElementById('rule-modal').classList.add('translate-y-full');
+        }
+
+        function openBalanceRuleModal() {
+            document.getElementById('balance-rule-modal-backdrop').classList.remove('opacity-0', 'pointer-events-none');
+            document.getElementById('balance-rule-modal').classList.remove('translate-y-full');
+        }
+        function closeBalanceRuleModal() {
+            document.getElementById('balance-rule-modal-backdrop').classList.add('opacity-0', 'pointer-events-none');
+            document.getElementById('balance-rule-modal').classList.add('translate-y-full');
+        }
+
+        function togglePoints() {
+            const details = document.getElementById('points-details');
+            const chevron = document.getElementById('points-chevron');
+            
+            if (details.classList.contains('h-0')) {
+                details.classList.remove('h-0');
+                details.classList.add('h-[120px]'); 
+                chevron.style.transform = 'rotate(180deg)';
+            } else {
+                details.classList.remove('h-[120px]');
+                details.classList.add('h-0');
+                chevron.style.transform = 'rotate(0deg)';
+            }
+        }
+
+        function handleCarouselScroll(ele, dotsContainerId) {
+            const index = Math.round(ele.scrollLeft / ele.clientWidth);
+            const dots = document.getElementById(dotsContainerId)?.children;
+            if(!dots) return;
+            for(let i=0; i<dots.length; i++) {
+                dots[i].className = (i === index) 
+                    ? "w-[5px] h-[5px] rounded-full bg-black transition-colors" 
+                    : "w-[5px] h-[5px] rounded-full border border-black transition-colors";
+            }
+        }
+
+        function updateControlPanelUI() {
+            const levels = ['prospect', 'credit_only', 'advance', 'premier', 'elite', 'global'];
+            levels.forEach(lvl => {
+                const btn = document.getElementById(`btn-state-${lvl}`);
+                if (lvl === currentUserLevel) {
+                    btn.className = 'px-2 py-1.5 rounded bg-[#d70014] text-white transition font-medium';
+                } else {
+                    btn.className = 'px-2 py-1.5 rounded bg-gray-100 text-gray-700 hover:bg-gray-200 transition';
+                }
+            });
+        }
+
+        let isSimPanelOpen = false;
+        function toggleSimPanel() {
+            isSimPanelOpen = !isSimPanelOpen;
+            const panel = document.getElementById('sim-panel');
+            if(isSimPanelOpen) {
+                panel.classList.remove('scale-0', 'opacity-0', 'pointer-events-none');
+                panel.classList.add('scale-100', 'opacity-100');
+            } else {
+                panel.classList.remove('scale-100', 'opacity-100');
+                panel.classList.add('scale-0', 'opacity-0', 'pointer-events-none');
+            }
+        }
+    </script>
+</body>
+</html>

+ 651 - 0
工作空间/产研/权益/汇丰全行/产品原型/h5-demo/移动端一期.html

@@ -0,0 +1,651 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
+    <title>权益专区</title>
+    <script src="https://cdn.tailwindcss.com"></script>
+    <style>
+        .no-scrollbar::-webkit-scrollbar { display: none; }
+        .no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; }
+        .tab-indicator { transition: all 0.3s ease; }
+        .view-transition { transition: transform 0.35s cubic-bezier(0.4, 0.0, 0.2, 1); }
+    </style>
+</head>
+<body class="bg-gray-100 flex justify-center h-screen overflow-hidden font-sans">
+
+    <!-- 侧边全局控制面板 -->
+    <div class="fixed top-[20%] right-0 z-50 flex items-start max-w-sm">
+        <button onclick="toggleSimPanel()" class="bg-black/60 text-white text-[11px] py-1.5 px-2 rounded-l-md shadow-md flex items-center gap-1 backdrop-blur-sm">
+            <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/><circle cx="12" cy="12" r="3"/></svg>
+            状态
+        </button>
+        
+        <div id="sim-panel" class="absolute top-8 right-2 bg-white/95 backdrop-blur-md border border-gray-200 p-2 rounded-lg shadow-xl w-[140px] text-[11px] transition-all origin-top-right scale-0 opacity-0 pointer-events-none">
+            <div class="font-bold mb-1.5 text-gray-800 border-b pb-1 text-center">切换等级</div>
+            <div class="flex flex-col gap-1.5">
+                <button onclick="setUserLevel('prospect')" id="btn-state-prospect" class="px-2 py-1.5 rounded bg-gray-100 text-gray-700 transition">潜客</button>
+                <button onclick="setUserLevel('credit_only')" id="btn-state-credit_only" class="px-2 py-1.5 rounded bg-gray-100 text-gray-700 transition">仅持有信用卡客户</button>
+                <button onclick="setUserLevel('advance')" id="btn-state-advance" class="px-2 py-1.5 rounded bg-gray-100 text-gray-700 transition">运筹理财</button>
+                <button onclick="setUserLevel('premier')" id="btn-state-premier" class="px-2 py-1.5 rounded bg-gray-100 text-gray-700 transition">卓越理财</button>
+                <button onclick="setUserLevel('elite')" id="btn-state-elite" class="px-2 py-1.5 rounded bg-gray-100 text-gray-700 transition">卓越理财·尊尚</button>
+                <button onclick="setUserLevel('global')" id="btn-state-global" class="px-2 py-1.5 rounded bg-gray-100 text-gray-700 transition">环球私人银行</button>
+            </div>
+        </div>
+    </div>
+
+    <!-- 移动端模拟容器 -->
+    <div class="w-full max-w-[400px] h-full bg-white flex flex-col relative shadow-2xl overflow-hidden">
+        
+        <!-- 顶部状态栏 -->
+        <div class="h-11 w-full flex justify-between items-center px-5 text-black bg-white z-30 relative shrink-0">
+            <span class="text-[15px] font-medium">9:41</span>
+            <div class="flex gap-1.5 items-center">
+                <svg width="18" height="12" viewBox="0 0 18 12" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1.5 12V9H3.5V12H1.5ZM6 12V6.5H8V12H6ZM10.5 12V3.5H12.5V12H10.5ZM15 12V0H17V12H15Z" fill="black"/></svg>
+                <svg width="16" height="12" viewBox="0 0 16 12" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8 12C9.10457 12 10 11.1046 10 10C10 8.89543 9.10457 8 8 8C6.89543 8 6 8.89543 6 10C6 11.1046 6.89543 12 8 12Z" fill="black"/><path d="M2.34315 5.65685C5.46734 2.53266 10.5327 2.53266 13.6569 5.65685" stroke="black" stroke-width="1.5" stroke-linecap="round"/><path d="M5.17157 8.48528C6.73367 6.92318 9.26633 6.92318 10.8284 8.48528" stroke="black" stroke-width="1.5" stroke-linecap="round"/></svg>
+                <svg width="25" height="12" viewBox="0 0 25 12" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="0.5" y="0.5" width="21" height="11" rx="2.5" stroke="black"/><rect x="2" y="2" width="18" height="8" rx="1" fill="black"/><path d="M23 4V8" stroke="black" stroke-width="1.5" stroke-linecap="round"/></svg>
+            </div>
+        </div>
+
+        <!-- 视图 A: 权益介绍页 (Home View) -->
+        <div id="home-view" class="flex flex-col h-[calc(100%-44px)] w-full absolute top-[44px] left-0 bg-white view-transition translate-x-0 z-10">
+            <header class="h-11 flex items-center justify-between px-4 bg-white z-20 shrink-0">
+                <button class="text-gray-800 p-1"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg></button>
+                <h1 class="text-[17px] font-medium text-gray-900 absolute left-1/2 -translate-x-1/2">权益介绍页</h1>
+                <div class="w-8"></div>
+            </header>
+
+            <div class="flex-1 overflow-y-auto no-scrollbar pb-8 relative">
+                <div id="no-tier-banner" onclick="showZone()" class="px-4 py-3 bg-[#fdfaf8] border-b border-gray-100 flex items-center justify-between cursor-pointer active:bg-gray-50 transition">
+                    <div class="flex items-center gap-3">
+                        <div class="w-10 h-10 rounded-full bg-gray-100 flex items-center justify-center border border-gray-200">
+                            <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="#666" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="14" x="3" y="8" rx="2"/><path d="M12 5a3 3 0 1 0-3 3"/><path d="M15 8a3 3 0 1 0-3-3"/><path d="M12 8v10"/><path d="M3 12h18"/></svg>
+                        </div>
+                        <div>
+                            <div class="text-[15px] text-gray-900">权益首页</div>
+                            <div class="text-[12px] text-gray-500">一键查看您的所有权益</div>
+                        </div>
+                    </div>
+                    <button class="text-[13px] text-gray-500 flex items-center pointer-events-none">
+                        立即查看 <svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m9 18 6-6-6-6"/></svg>
+                    </button>
+                </div>
+
+                <div class="flex justify-between px-2 pt-2 border-b border-gray-200 relative">
+                    <button onclick="switchTab('premier')" class="flex-1 py-3 text-[14px] font-medium relative text-gray-900" id="tab-btn-premier">卓越理财</button>
+                    <button onclick="switchTab('elite')" class="flex-1 py-3 text-[14px] font-medium relative text-gray-500" id="tab-btn-elite">卓越理财·尊尚</button>
+                    <button onclick="switchTab('global')" class="flex-1 py-3 text-[14px] font-medium relative text-gray-500" id="tab-btn-global">环球私人银行</button>
+                    <div id="tab-indicator" class="absolute bottom-0 h-[2px] bg-[#d70014] tab-indicator" style="width: 33.33%; left: 0%;"></div>
+                </div>
+
+                <div id="content-area" class="px-5 pt-5 pb-10"></div>
+            </div>
+        </div>
+
+        <!-- 视图 B: 权益首页/专区 (Zone View) -->
+        <div id="zone-view" class="flex flex-col h-[calc(100%-44px)] w-full absolute top-[44px] left-0 bg-[#f4f5f8] view-transition translate-x-full z-20">
+            <header class="h-11 flex items-center justify-between px-4 bg-white z-20 shrink-0 border-b border-gray-100">
+                <button onclick="hideZone()" class="text-gray-800 p-1"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg></button>
+                <h1 class="text-[17px] font-medium text-gray-900 absolute left-1/2 -translate-x-1/2">权益首页</h1>
+                <div class="w-8"></div>
+            </header>
+            <div class="flex-1 overflow-y-auto no-scrollbar pb-8 relative" id="zone-content-area"></div>
+        </div>
+
+        <!-- 积分规则弹窗 -->
+        <div id="rule-modal-backdrop" class="absolute inset-0 bg-black/50 z-[60] opacity-0 pointer-events-none transition-opacity duration-300" onclick="closeRuleModal()"></div>
+        <div id="rule-modal" class="absolute bottom-0 left-0 w-full bg-white z-[70] rounded-t-2xl transform translate-y-full transition-transform duration-300 flex flex-col" style="height: 85%;">
+            <div class="flex justify-between items-center px-5 py-4 border-b border-gray-100 shrink-0">
+                <h2 class="text-[17px] font-medium text-gray-900">积分规则</h2>
+                <button onclick="closeRuleModal()" class="text-gray-500 p-1 hover:bg-gray-100 rounded-full transition">
+                    <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
+                </button>
+            </div>
+            <div class="flex-1 overflow-y-auto px-5 py-5 no-scrollbar">
+                <h3 class="text-[14px] font-medium text-gray-800 mb-4">汇丰银行(中国)有限公司积分使用规则</h3>
+                <div class="text-[13px] text-gray-600 leading-[1.8] space-y-4 text-justify">
+                    <p>本积分使用规则(“本规则”)为汇丰银行(中国)有限公司(“本行”)的客户(“客户”)使用本行信用卡及借记卡积分(即“汇友荟”汇丰客户关系积分)(简称“汇友荟积分”)兑换本行提供的礼品、里程或刷卡金等项目(具体以本行积分换礼平台正式公布的有效兑换项目为准,以下称“兑换项目”)等需要遵守的使用规则。</p>
+                    <p class="font-medium text-gray-800 pt-2">一、 兑换及使用渠道</p>
+                    <p>1. 除本规则以下相关兑换项目项下有特别说明外,客户可使用信用卡积分及“汇友荟”汇丰客户关系积分在积分换礼平台兑换相关项目,具体兑换渠道如下:<br>
+                    (1) 登录“汇丰中国客户服务”微信服务号,点击“我的汇丰”—“我的积分”—“积分商城”页面兑换;或<br>
+                    (2) 登录汇丰银行App,在“我的”点击“我的积分”—“积分商城”页面兑换礼品;<br>
+                    (3) 人工服务申请兑换:拨打本行24小时客服热线95366或4008695366(该渠道仅限本行信用卡主卡持卡人兑换部分项目申请时使用)兑换。</p>
+                    <p>2. 积分一旦兑换成功,不可撤销、更改或退还。若因系统或网络原因导致兑换失败,积分将自动退回账户。</p>
+                    <p class="font-medium text-gray-800 pt-2">二、 积分有效期</p>
+                    <p>信用卡积分有效期与信用卡有效期一致。如客户在信用卡有效期届满前未消耗完毕,积分将于信用卡到期次月清零。“汇友荟”积分有效期详见对应活动的具体规则。请客户关注积分到期日并及时兑换。</p>
+                    <p class="pt-10 pb-10 text-center text-gray-300">-- 到底了 --</p>
+                </div>
+            </div>
+        </div>
+
+        <!-- 余额计算规则弹窗 -->
+        <div id="balance-rule-modal-backdrop" class="absolute inset-0 bg-black/50 z-[60] opacity-0 pointer-events-none transition-opacity duration-300" onclick="closeBalanceRuleModal()"></div>
+        <div id="balance-rule-modal" class="absolute bottom-0 left-0 w-full bg-white z-[70] rounded-t-2xl transform translate-y-full transition-transform duration-300 flex flex-col min-h-[220px]">
+            <div class="flex justify-between items-center px-5 py-4 shrink-0 border-b border-gray-50">
+                <h2 class="text-[18px] font-medium text-gray-900">提示</h2>
+                <button onclick="closeBalanceRuleModal()" class="text-gray-500 p-1 hover:bg-gray-100 rounded-full transition">
+                    <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
+                </button>
+            </div>
+            <div class="flex-1 px-5 pb-8 pt-4">
+                <div class="text-[15px] text-gray-700 leading-[1.6]">
+                    月内日均余额 = 当月内每日账户余额之和 / 当月天数。
+                </div>
+            </div>
+        </div>
+
+        <!-- 底部 Home Indicator (iOS风格) -->
+        <div class="h-8 w-full flex justify-center items-center z-[80] absolute bottom-0 pointer-events-none">
+            <div class="w-32 h-1 bg-gray-900 rounded-full"></div>
+        </div>
+    </div>
+
+    <script>
+        // --- 核心 SVG 图标库 ---
+        const icons = {
+            cap: `<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 10v6M2 10l10-5 10 5-10 5z"/><path d="M6 12v5c3 3 9 3 12 0v-5"/></svg>`,
+            heart: `<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 14c1.49-1.46 3-3.21 3-5.5A5.5 5.5 0 0 0 16.5 3c-1.76 0-3 .5-4.5 2-1.5-1.5-2.74-2-4.5-2A5.5 5.5 0 0 0 2 8.5c0 2.3 1.5 4.05 3 5.5l7 7Z"/></svg>`,
+            bulb: `<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.9 1.2 1.5 1.5 2.5"/><path d="M9 18h6"/><path d="M10 22h4"/></svg>`,
+            gift: `<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="8" width="18" height="14" rx="2"/><path d="M12 5a3 3 0 1 0-3 3"/><path d="M15 8a3 3 0 1 0-3-3"/><path d="M12 8v14"/><path d="M3 12h18"/></svg>`,
+            diamond: `<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><path d="M6 3h12l4 6-10 13L2 9Z"/></svg>`,
+            medbox: `<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="8" width="16" height="12" rx="2"/><path d="M8 8V6a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/><path d="M12 11v4M10 13h4"/></svg>`,
+            car: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><path d="M19 17h2c.6 0 1-.4 1-1v-3c0-.9-.7-1.7-1.5-1.9C18.7 10.6 16 10 12 10s-6.7.6-8.5 1.1C2.7 11.3 2 12.1 2 13v3c0 .6.4 1 1 1h2"/><rect width="16" height="8" x="4" y="10" rx="2"/><path d="M7 14h.01"/><path d="M17 14h.01"/><path d="m10 10-1.5-4h7l-1.5 4"/></svg>`,
+            plane: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><path d="M17.8 19.2 16 11l3.5-3.5C21 6 21.5 4 21 3c-1-.5-3 0-4.5 1.5L13 8 4.8 6.2c-.5-.1-.9.2-1.1.7l-1.2 3.6 7.7 4.4-4.2 4.2-3.1-.8c-.4-.1-.8.1-1 .5l-.8 2.3 5.4 1.8 1.8 5.4 2.3-.8c.4-.2.6-.6.5-1l-.8-3.1 4.2-4.2 4.4 7.7 3.6-1.2c.5-.2.8-.6.7-1.1Z"/></svg>`,
+            globe: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z"/><path d="M2 12h20"/></svg>`,
+            coffee: `<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="#ba6534" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M17 8h1a4 4 0 1 1 0 8h-1"/><path d="M3 8h14v9a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4Z"/><line x1="6" x2="6" y1="2" y2="4"/><line x1="10" x2="10" y1="2" y2="4"/><line x1="14" x2="14" y1="2" y2="4"/></svg>`,
+            planeRed: `<svg xmlns="http://www.w3.org/2000/svg" width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="#d70014" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M17.8 19.2 16 11l3.5-3.5C21 6 21.5 4 21 3c-1-.5-3 0-4.5 1.5L13 8 4.8 6.2c-.5-.1-.9.2-1.1.7l-1.2 3.6 7.7 4.4-4.2 4.2-3.1-.8c-.4-.1-.8.1-1 .5l-.8 2.3 5.4 1.8 1.8 5.4 2.3-.8c.4-.2.6-.6.5-1l-.8-3.1 4.2-4.2 4.4 7.7 3.6-1.2c.5-.2.8-.6.7-1.1Z"/></svg>`,
+            help: `<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="#999" stroke-width="1.5" class="ml-1 inline-block"><circle cx="12" cy="12" r="10"></circle><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"></path><line x1="12" y1="17" x2="12.01" y2="17"></line></svg>`,
+            copy: `<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="#999" stroke-width="1.5" class="ml-1 inline-block cursor-pointer"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>`,
+            doc: `<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" class="mr-1 inline-block"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path><polyline points="14 2 14 8 20 8"></polyline><line x1="16" y1="13" x2="8" y2="13"></line><line x1="16" y1="17" x2="8" y2="17"></line><polyline points="10 9 9 9 8 9"></polyline></svg>`,
+            clipboard: `<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>`
+        };
+
+        // --- 权益主页数据 (Home Page Data) ---
+        const tabData = {
+            premier: {
+                id: 'premier', title: '卓越理财', subtitle: '为您和您的家人提供尊崇专属礼遇和权益',
+                imageSrc: 'https://images.unsplash.com/photo-1518893494013-481c1d8ed3fd?q=80&w=800&auto=format&fit=crop',
+                imageStyle: 'filter: sepia(0.4) hue-rotate(330deg);',
+                features: [
+                    { title: '国际教育', desc: '享专属国际化学校优惠及背景提升项目' },
+                    { title: '酒店礼遇', desc: '高端酒店及商场会籍匹配' },
+                    { title: '环球礼遇', desc: '汇丰中国信用卡持卡人,尊享机场贵宾厅及礼宾车等礼遇' },
+                    { title: '优选健康荟', desc: '享香港私立医院体检专属折扣' }
+                ]
+            },
+            elite: {
+                id: 'elite', title: '卓越理财·尊尚', subtitle: '开启尊尚体验,享受环球出行、高端运动、国际教育等VIP礼遇。',
+                imageSrc: 'https://images.unsplash.com/photo-1610701596007-11502861dcfa?q=80&w=800&auto=format&fit=crop',
+                imageStyle: 'filter: sepia(0.6) hue-rotate(330deg) saturate(1.5);',
+                features: [
+                    { title: '国际教育', desc: '享多项升学规划指导、专属国际化学校优惠及背景提升项目' },
+                    { title: '专属礼宾服务', desc: '高端酒店及商场会籍匹配、高尔夫练习场畅' },
+                    { title: '尊尚生日礼', desc: '尊享体验任选其一' },
+                    { title: '「汇享健康」', desc: '三重健康保障,包括专属健保管家、公立医院门诊预约及就医陪同服务等权益' }
+                ]
+            },
+            global: {
+                id: 'global', title: '环球私人银行', subtitle: '开启环球「创臻享」及「汇佑健康」之旅。',
+                imageSrc: 'https://images.unsplash.com/photo-1550684848-fac1c5b4e853?q=80&w=800&auto=format&fit=crop',
+                imageStyle: '',
+                features: [
+                    { title: '高尔夫权益', desc: '练习场畅达及VIP高尔夫俱乐部免会籍预约' },
+                    { title: '臻享体验', desc: '享高端酒店及商场会籍匹配、米其林级别私宴预定服务等' },
+                    { title: '环球旅行', desc: '境外礼宾接送机服务及酒店升房礼遇' },
+                    { title: '私人生日礼', desc: '尊享体验任选其一' },
+                    { title: '「汇佑健康」', desc: '一站式健康管理,包括专属家庭医师团队、公立医院门诊预约及就医陪同服务等权益' }
+                ]
+            }
+        };
+
+        const baseAdvanceExclusives = [
+            { icon: icons.gift, label: '卓越理财迎<br>新礼' }
+        ];
+
+        // 权益首页数据定制
+        const zoneData = {
+            'prospect': { 
+                hasAd: false, hasDotsExclusives: false, hasDotsCredit: true, hideIdentity: true,
+                exclusives: baseAdvanceExclusives
+            },
+            'credit_only': { 
+                hasAd: false, hasDotsExclusives: false, hasDotsCredit: true, hideIdentity: true,
+                exclusives: []
+            },
+            'advance': { 
+                headerBannerUrl: 'https://images.unsplash.com/photo-1477959858617-67f85cf4f1df?w=800&auto=format&fit=crop', 
+                tierTitle: 'HSBC Advance', tierSub: '汇丰运筹理财',
+                hasAd: false, hasDotsExclusives: false, hasDotsCredit: true, hideIdentity: false,
+                accountHtml: `
+                    <div class="flex justify-between items-end pt-1">
+                        <div>
+                            <div class="text-[14px] text-gray-800 flex items-center font-medium">账户月内日均余额 <span onclick="openBalanceRuleModal()" class="cursor-pointer ml-1 flex items-center">${icons.help}</span></div>
+                            <div class="text-[12px] text-gray-500 mt-1.5">截止日期 XXXX年X月X日</div>
+                        </div>
+                        <div class="text-[14px] text-gray-600 mb-1.5">8,000,000 人民币元</div>
+                    </div>
+                `,
+                exclusives: baseAdvanceExclusives
+            },
+            'premier': { 
+                headerBannerUrl: 'https://images.unsplash.com/photo-1574678170884-cbabaf60df08?w=800&auto=format&fit=crop', 
+                tierTitle: 'HSBC Premier', tierSub: '汇丰卓越理财',
+                hasAd: true, hasDotsExclusives: false, hasDotsCredit: true, hideIdentity: false,
+                accountHtml: `
+                    <div class="border-b border-gray-100 pb-3.5 mb-3.5">
+                        <div class="text-[14px] text-gray-800 font-medium flex items-center">卓越理财客户</div>
+                    </div>
+                    <div class="flex justify-between items-end">
+                        <div>
+                            <div class="text-[14px] text-gray-800 flex items-center font-medium">账户月内日均余额 <span onclick="openBalanceRuleModal()" class="cursor-pointer ml-1 flex items-center">${icons.help}</span></div>
+                            <div class="text-[12px] text-gray-500 mt-1.5">截止日期 XXXX年X月X日</div>
+                        </div>
+                        <div class="text-[14px] text-gray-600 mb-1.5">8,000,000 人民币元</div>
+                    </div>
+                `,
+                exclusives: [
+                    { icon: icons.cap, label: '国际教育' },
+                    { icon: icons.heart, label: '优选健康荟' },
+                    { icon: icons.bulb, label: '酒店礼遇' }
+                ]
+            },
+            'elite': { 
+                headerBannerUrl: 'https://images.unsplash.com/photo-1610701596007-11502861dcfa?w=800&auto=format&fit=crop', 
+                tierTitle: 'HSBC Premier Elite', tierSub: '汇丰卓越理财·尊尚',
+                hasAd: true, hasDotsExclusives: true, hasDotsCredit: true, hideIdentity: false,
+                accountHtml: `
+                    <div class="flex justify-between items-center border-b border-gray-100 pb-3.5 mb-3.5">
+                        <div class="text-[14px] text-gray-800 font-medium flex items-center">卓越理财尊尚客户</div>
+                        <div class="text-[14px] text-gray-600 flex items-center">C1234567890 ${icons.copy}</div>
+                    </div>
+                    <div class="flex justify-between items-end">
+                        <div>
+                            <div class="text-[14px] text-gray-800 flex items-center font-medium">账户月内日均余额 <span onclick="openBalanceRuleModal()" class="cursor-pointer ml-1 flex items-center">${icons.help}</span></div>
+                            <div class="text-[12px] text-gray-500 mt-1.5">截止日期 XXXX年X月X日</div>
+                        </div>
+                        <div class="text-[14px] text-gray-600 mb-1.5">8,000,000 人民币元</div>
+                    </div>
+                `,
+                exclusives: [
+                    { icon: icons.cap, label: '国际教育' },
+                    { icon: icons.gift, label: '生日礼' },
+                    { icon: icons.diamond, label: '礼宾服务' },
+                    { icon: icons.heart, label: '汇享健康' }
+                ]
+            },
+            'global': { 
+                headerBannerUrl: 'https://images.unsplash.com/photo-1634024344558-8b20d7d3b0c6?w=800&auto=format&fit=crop', 
+                tierTitle: 'HSBC Private Bank', tierSub: '汇丰环球私人银行',
+                hasAd: true, hasDotsExclusives: false, hasDotsCredit: true, hideIdentity: false,
+                accountHtml: `
+                    <div class="flex justify-between items-center py-1">
+                        <div class="text-[14px] text-gray-800 font-medium flex items-center">私行业务ID</div>
+                        <div class="text-[14px] text-gray-600 flex items-center">C1234567890 ${icons.copy}</div>
+                    </div>
+                `,
+                exclusives: [
+                    { icon: icons.cap, label: '国际教育' },
+                    { icon: icons.heart, label: '创臻享礼宾<br>服务' },
+                    { icon: icons.medbox, label: '汇佑健康' },
+                    { icon: icons.heart, label: '优选健康荟' }
+                ]
+            }
+        };
+
+        const creditCardsData = [
+            { icon: icons.car, title: '境外礼宾车', sub: '共2次', badge: '0/2' },
+            { icon: icons.car, title: '境内礼宾车', sub: '共2次', badge: '0/2' },
+            { icon: icons.plane, title: '贵宾厅', sub: '共2次', badge: '0/2' },
+            { icon: icons.globe, title: '境外消费', sub: '点击查看' }
+        ];
+
+        let currentUserLevel = 'advance'; 
+        let currentActiveTab = 'premier';
+
+        document.addEventListener('DOMContentLoaded', () => {
+            renderHomePage();
+            updateControlPanelUI();
+        });
+
+        function renderHomePage() {
+            renderHeaderBanner();
+            renderTabsNav();
+            renderContentArea();
+        }
+
+        function renderHeaderBanner() {
+            const banner = document.getElementById('no-tier-banner');
+            const isBasic = ['prospect', 'credit_only', 'advance'].includes(currentUserLevel);
+            banner.style.display = isBasic ? 'flex' : 'none';
+        }
+
+        function renderTabsNav() {
+            const tabs = ['premier', 'elite', 'global'];
+            tabs.forEach((tab) => {
+                const btn = document.getElementById(`tab-btn-${tab}`);
+                if (tab === currentActiveTab) {
+                    btn.className = "flex-1 py-3 text-[14px] font-medium relative text-gray-900";
+                } else {
+                    btn.className = "flex-1 py-3 text-[14px] font-medium relative text-gray-500";
+                }
+            });
+            const indicator = document.getElementById('tab-indicator');
+            indicator.style.left = `${tabs.indexOf(currentActiveTab) * 33.33}%`;
+        }
+
+        function renderContentArea() {
+            const container = document.getElementById('content-area');
+            const data = tabData[currentActiveTab];
+            
+            const levelWeights = { 'prospect': 0, 'credit_only': 0, 'advance': 0, 'premier': 1, 'elite': 2, 'global': 3 };
+            const isUnlocked = levelWeights[currentUserLevel] >= levelWeights[currentActiveTab];
+
+            let buttonHTML = isUnlocked ? `
+                <button onclick="showZone()" class="w-full py-3 mt-4 mb-6 border border-gray-300 rounded text-[15px] font-medium text-gray-900 bg-white active:bg-gray-50 transition">
+                    进入权益专区
+                </button>
+            ` : `
+                <button class="w-full py-3 mt-4 mb-6 rounded text-[15px] font-medium text-[#b3b3b3] bg-[#f7f7f7] cursor-not-allowed">
+                    待解锁
+                </button>
+            `;
+
+            let featuresHTML = '';
+            
+            if (currentActiveTab === 'global') {
+                // 环球私人银行使用带图片、标题、描述的图文列表样式
+                featuresHTML = '<div class="flex flex-col border-t border-gray-100 pt-2">' + data.features.map(f => `
+                    <div class="flex items-center gap-4 py-4 border-b border-gray-100 last:border-0">
+                        <div class="w-12 h-12 rounded-full border border-gray-200 bg-[#fbfcfc] flex items-center justify-center text-gray-500 shrink-0">
+                            ${icons.clipboard}
+                        </div>
+                        <div class="flex-1">
+                            <div class="text-[15px] font-medium text-gray-900">${f.title}</div>
+                            <div class="text-[13px] text-gray-500 mt-1">${f.desc}</div>
+                        </div>
+                    </div>
+                `).join('') + '</div>';
+            } else {
+                // 卓越理财 和 卓越理财·尊尚 保持小圆点样式
+                featuresHTML = '<ul class="text-sm">' + data.features.map(f => `
+                    <li class="flex items-start mb-3 relative pl-3">
+                        <span class="absolute left-0 top-[8px] w-1 h-1 bg-gray-600 rounded-full"></span>
+                        <div>
+                            <span class="text-gray-900 font-medium text-[13px] mr-1">${f.title}</span>
+                            <p class="text-gray-500 text-[12px] leading-relaxed mt-0.5">${f.desc}</p>
+                        </div>
+                    </li>
+                `).join('') + '</ul>';
+            }
+
+            container.innerHTML = `
+                <div class="w-full h-[150px] overflow-hidden mb-4 rounded-sm">
+                    <img src="${data.imageSrc}" style="${data.imageStyle}" class="w-full h-full object-cover">
+                </div>
+                <h2 class="text-xl font-medium text-gray-900 mb-1.5">${data.title}</h2>
+                <p class="text-[13px] text-gray-500 leading-snug">${data.subtitle}</p>
+                ${buttonHTML}
+                ${featuresHTML}
+            `;
+        }
+
+        // --- ====== 专区内页视图逻辑 (Zone View) ====== ---
+        function renderZonePage() {
+            const data = zoneData[currentUserLevel];
+            const container = document.getElementById('zone-content-area');
+
+            const exclusiveHtml = data.exclusives.map(item => `
+                <div class="flex flex-col items-center min-w-[70px]">
+                    <div class="w-12 h-12 rounded-full border border-gray-200 flex items-center justify-center text-gray-500 mb-2.5 shadow-sm bg-gray-50">
+                        ${item.icon}
+                    </div>
+                    <span class="text-[12px] text-gray-700 text-center leading-tight">${item.label}</span>
+                </div>
+            `).join('');
+
+            const creditHtml = creditCardsData.map(item => `
+                <div class="flex flex-col items-center relative min-w-[70px]">
+                    ${item.badge ? `<div class="absolute -top-1 right-0 bg-[#d70014] text-white text-[10px] px-1.5 py-0.5 rounded-full z-10 border-2 border-white font-bold tracking-tighter">${item.badge}</div>` : ''}
+                    <div class="w-12 h-12 rounded-full border border-gray-200 flex items-center justify-center text-gray-500 mb-2.5 shadow-sm bg-gray-50">
+                        ${item.icon}
+                    </div>
+                    <span class="text-[12px] text-gray-800 text-center leading-tight">${item.title}</span>
+                    <span class="text-[11px] text-gray-400 text-center leading-tight mt-1">${item.sub}</span>
+                </div>
+            `).join('');
+
+            let html = '';
+
+            if (!data.hideIdentity) {
+                html += `
+                    <div class="w-full h-[140px] relative shrink-0">
+                        <img src="${data.headerBannerUrl}" class="w-full h-full object-cover">
+                        <div class="absolute inset-0 bg-gradient-to-r from-black/60 to-transparent"></div>
+                        <div class="absolute bottom-5 left-5 text-white">
+                            <div class="text-[14px] font-bold opacity-90 tracking-wide">${data.tierTitle}</div>
+                            <div class="text-[16px] font-medium tracking-widest mt-0.5">${data.tierSub}</div>
+                        </div>
+                    </div>
+                    <div class="bg-white px-5 py-4 mb-2">${data.accountHtml}</div>
+                `;
+            } else {
+                html += `<div class="w-full h-2 bg-transparent shrink-0"></div>`;
+            }
+
+            if (data.exclusives && data.exclusives.length > 0) {
+                html += `
+                    <div class="bg-white px-5 py-5 mb-2">
+                        <div class="flex justify-between items-center mb-6">
+                            <h3 class="text-[16px] font-medium text-gray-900">专属礼遇</h3>
+                            <div class="text-[13px] text-gray-900 font-medium flex items-center">我的权益 <svg class="w-4 h-4 ml-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M9 18l6-6-6-6"/></svg></div>
+                        </div>
+                        <div class="flex ${data.exclusives.length < 4 ? 'justify-start gap-8' : 'justify-between'} px-1">
+                            ${exclusiveHtml}
+                        </div>
+                        ${data.hasDotsExclusives ? `
+                        <div class="flex justify-center gap-2 mt-6">
+                            <div class="w-[5px] h-[5px] bg-black rounded-full"></div>
+                            <div class="w-[5px] h-[5px] border border-black rounded-full"></div>
+                        </div>` : ''}
+                    </div>
+                `;
+            }
+
+            html += `
+                <div class="bg-white px-5 py-5 mb-2">
+                    <h3 class="text-[16px] font-medium text-gray-900 mb-6">信用卡权益</h3>
+                    <div class="flex justify-between px-1">
+                        ${creditHtml}
+                    </div>
+                    ${data.hasDotsCredit ? `
+                    <div class="flex justify-center gap-2 mt-6">
+                        <div class="w-[5px] h-[5px] bg-black rounded-full"></div>
+                        <div class="w-[5px] h-[5px] border border-black rounded-full"></div>
+                    </div>` : ''}
+                </div>
+            `;
+
+            if (data.hasAd) {
+                html += `
+                <div class="bg-white px-5 py-5 mb-2">
+                    <div class="w-full bg-gray-100 mb-4 h-[150px]">
+                        <img src="https://images.unsplash.com/photo-1556742049-0cfed4f6a45d?w=800&auto=format&fit=crop" class="w-full h-full object-cover">
+                    </div>
+                    <h4 class="text-[18px] text-gray-900 font-medium mb-1.5">文案文案文案文案</h4>
+                    <p class="text-[13px] text-gray-500">报名参加汇丰活动,体验更多精彩礼遇</p>
+                </div>
+                `;
+            }
+
+            const isPointsExpanded = !['prospect', 'credit_only', 'advance'].includes(currentUserLevel);
+            
+            html += `
+                <div class="bg-white px-5 py-5 pb-8">
+                    <div class="flex justify-between items-center mb-5">
+                        <h3 class="text-[16px] font-medium text-gray-900">积分商城</h3>
+                        <div class="text-[13px] text-gray-900 font-medium flex items-center">进入积分商城 <svg class="w-4 h-4 ml-0.5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M9 18l6-6-6-6"/></svg></div>
+                    </div>
+                    
+                    <div class="flex justify-between items-center py-2 cursor-pointer border-b border-transparent" onclick="togglePoints()">
+                        <div>
+                            <div class="text-[20px] font-medium text-gray-800">3,000,000</div>
+                            <div class="text-[12px] text-gray-400 mt-1">我的总积分</div>
+                        </div>
+                        <svg id="points-chevron" class="w-5 h-5 text-gray-500 transition-transform duration-300 ${isPointsExpanded ? 'rotate-180' : ''}" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" d="M19 9l-7 7-7-7"/></svg>
+                    </div>
+                    
+                    <div id="points-details" class="overflow-hidden transition-all duration-300 ${isPointsExpanded ? 'h-[120px]' : 'h-0'}">
+                        <div class="border-t border-gray-100 pt-4 mt-2 text-[13px] space-y-4 pb-2">
+                            <div class="flex justify-between text-gray-600"><span>汇友荟积分</span><span class="font-medium text-gray-800">9,000 积分</span></div>
+                            <div class="flex justify-between text-gray-600"><span>信用卡积分</span><span class="font-medium text-gray-800">9,000 积分</span></div>
+                            <div class="flex justify-between text-gray-600"><span>2025年5月24日到期积分</span><span class="font-medium text-gray-800">5,000 积分</span></div>
+                        </div>
+                    </div>
+
+                    <div class="mt-6">
+                        <div class="flex justify-between items-center mb-4">
+                            <h3 class="text-[16px] font-medium text-gray-900">常用兑换</h3>
+                            <div class="text-[13px] text-gray-800 flex items-center font-medium">${icons.doc}积分明细</div>
+                        </div>
+                        
+                        <div class="flex overflow-x-auto no-scrollbar gap-3 pb-2 snap-x" onscroll="handleCarouselScroll(this, 'exchange-dots')">
+                            <div class="min-w-[100px] bg-white border border-gray-200 rounded-sm flex flex-col items-center snap-start shadow-sm">
+                                <div class="w-full h-[65px] bg-[#f7fbff] flex items-center justify-center">${icons.planeRed}</div>
+                                <div class="text-[13px] text-gray-700 py-2.5">航空里程</div>
+                            </div>
+                            <div class="min-w-[100px] bg-white border border-gray-200 rounded-sm flex flex-col items-center snap-start shadow-sm">
+                                <div class="w-full h-[65px] bg-[#fffaf5] flex items-center justify-center">${icons.coffee}</div>
+                                <div class="text-[13px] text-gray-700 py-2.5">贵宾厅</div>
+                            </div>
+                            <div class="min-w-[100px] bg-white border border-gray-200 rounded-sm flex flex-col items-center snap-start shadow-sm">
+                                <div class="w-full h-[65px] bg-[#fffdf5] flex items-center justify-center"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#d5aa11" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M19 17h2c.6 0 1-.4 1-1v-3c0-.9-.7-1.7-1.5-1.9C18.7 10.6 16 10 12 10s-6.7.6-8.5 1.1C2.7 11.3 2 12.1 2 13v3c0 .6.4 1 1 1h2"/><rect width="16" height="8" x="4" y="10" rx="2"/><path d="M7 14h.01"/><path d="M17 14h.01"/><path d="m10 10-1.5-4h7l-1.5 4"/></svg></div>
+                                <div class="text-[13px] text-gray-700 py-2.5">礼宾接送机</div>
+                            </div>
+                            <div class="min-w-[100px] bg-white border border-gray-200 rounded-sm flex flex-col items-center snap-start shadow-sm">
+                                <div class="w-full h-[65px] bg-[#f9fafb] flex items-center justify-center"><svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="#666" stroke-width="1.5"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/></svg></div>
+                                <div class="text-[13px] text-gray-700 py-2.5">年费</div>
+                            </div>
+                        </div>
+                        <div class="flex justify-center gap-2 mt-3" id="exchange-dots">
+                            <div class="w-[5px] h-[5px] bg-black rounded-full transition-colors"></div>
+                            <div class="w-[5px] h-[5px] border border-black rounded-full transition-colors"></div>
+                        </div>
+                        <div class="flex justify-end mt-6">
+                            <div class="text-[12px] text-gray-900 font-medium flex items-center cursor-pointer" onclick="openRuleModal()">${icons.doc} 积分规则</div>
+                        </div>
+                    </div>
+                </div>
+            `;
+            
+            container.innerHTML = html;
+        }
+
+        function switchTab(tabId) {
+            currentActiveTab = tabId;
+            renderHomePage();
+        }
+
+        function setUserLevel(level) {
+            currentUserLevel = level;
+            const basicLevels = ['prospect', 'credit_only', 'advance'];
+            currentActiveTab = basicLevels.includes(level) ? 'premier' : level;
+            
+            renderHomePage();
+            updateControlPanelUI();
+            
+            if(document.getElementById('zone-view').classList.contains('translate-x-0')) {
+                renderZonePage();
+            }
+
+            if (isSimPanelOpen) toggleSimPanel();
+        }
+
+        function showZone() {
+            renderZonePage();
+            const homeView = document.getElementById('home-view');
+            const zoneView = document.getElementById('zone-view');
+            homeView.classList.remove('translate-x-0');
+            homeView.classList.add('-translate-x-full');
+            zoneView.classList.remove('translate-x-full');
+            zoneView.classList.add('translate-x-0');
+        }
+
+        function hideZone() {
+            const homeView = document.getElementById('home-view');
+            const zoneView = document.getElementById('zone-view');
+            homeView.classList.remove('-translate-x-full');
+            homeView.classList.add('translate-x-0');
+            zoneView.classList.remove('translate-x-0');
+            zoneView.classList.add('translate-x-full');
+        }
+
+        function openRuleModal() {
+            document.getElementById('rule-modal-backdrop').classList.remove('opacity-0', 'pointer-events-none');
+            document.getElementById('rule-modal').classList.remove('translate-y-full');
+        }
+        function closeRuleModal() {
+            document.getElementById('rule-modal-backdrop').classList.add('opacity-0', 'pointer-events-none');
+            document.getElementById('rule-modal').classList.add('translate-y-full');
+        }
+
+        function openBalanceRuleModal() {
+            document.getElementById('balance-rule-modal-backdrop').classList.remove('opacity-0', 'pointer-events-none');
+            document.getElementById('balance-rule-modal').classList.remove('translate-y-full');
+        }
+        function closeBalanceRuleModal() {
+            document.getElementById('balance-rule-modal-backdrop').classList.add('opacity-0', 'pointer-events-none');
+            document.getElementById('balance-rule-modal').classList.add('translate-y-full');
+        }
+
+        function togglePoints() {
+            const details = document.getElementById('points-details');
+            const chevron = document.getElementById('points-chevron');
+            if (details.classList.contains('h-0')) {
+                details.classList.remove('h-0');
+                details.classList.add('h-[120px]'); 
+                chevron.style.transform = 'rotate(180deg)';
+            } else {
+                details.classList.remove('h-[120px]');
+                details.classList.add('h-0');
+                chevron.style.transform = 'rotate(0deg)';
+            }
+        }
+
+        function handleCarouselScroll(ele, dotsContainerId) {
+            const index = Math.round(ele.scrollLeft / ele.clientWidth);
+            const dots = document.getElementById(dotsContainerId)?.children;
+            if(!dots) return;
+            for(let i=0; i<dots.length; i++) {
+                dots[i].className = (i === index) 
+                    ? "w-[5px] h-[5px] rounded-full bg-black transition-colors" 
+                    : "w-[5px] h-[5px] rounded-full border border-black transition-colors";
+            }
+        }
+
+        function updateControlPanelUI() {
+            const levels = ['prospect', 'credit_only', 'advance', 'premier', 'elite', 'global'];
+            levels.forEach(lvl => {
+                const btn = document.getElementById(`btn-state-${lvl}`);
+                if (lvl === currentUserLevel) {
+                    btn.className = 'px-2 py-1.5 rounded bg-[#d70014] text-white transition font-medium';
+                } else {
+                    btn.className = 'px-2 py-1.5 rounded bg-gray-100 text-gray-700 hover:bg-gray-200 transition';
+                }
+            });
+        }
+
+        let isSimPanelOpen = false;
+        function toggleSimPanel() {
+            isSimPanelOpen = !isSimPanelOpen;
+            const panel = document.getElementById('sim-panel');
+            if(isSimPanelOpen) {
+                panel.classList.remove('scale-0', 'opacity-0', 'pointer-events-none');
+                panel.classList.add('scale-100', 'opacity-100');
+            } else {
+                panel.classList.remove('scale-100', 'opacity-100');
+                panel.classList.add('scale-0', 'opacity-0', 'pointer-events-none');
+            }
+        }
+    </script>
+</body>
+</html>

+ 285 - 0
工作空间/产研/权益/汇丰全行/产品原型/h5-demo/组装页.html

@@ -0,0 +1,285 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
+    <title>组装页</title>
+    <script src="https://cdn.tailwindcss.com"></script>
+    <style>
+        /* 隐藏滚动条但保留滚动功能 */
+        .no-scrollbar::-webkit-scrollbar {
+            display: none;
+        }
+        .no-scrollbar {
+            -ms-overflow-style: none;
+            scrollbar-width: none;
+        }
+        /* iOS 弹窗缩放动画 */
+        @keyframes zoomIn {
+            from { transform: scale(1.1); opacity: 0; }
+            to { transform: scale(1); opacity: 1; }
+        }
+        .animate-zoom-in {
+            animation: zoomIn 0.2s ease-out forwards;
+        }
+    </style>
+</head>
+<body class="bg-gray-100 flex justify-center h-screen overflow-hidden font-sans">
+
+    <!-- 移动端模拟容器 -->
+    <div class="w-full max-w-[400px] h-full bg-white flex flex-col relative shadow-2xl overflow-hidden">
+        
+        <!-- 顶部状态栏 (全局共享) -->
+        <div class="h-11 w-full flex justify-between items-center px-5 text-black bg-white z-30 relative shrink-0">
+            <span class="text-[15px] font-medium">9:41</span>
+            <div class="flex gap-1.5 items-center">
+                <svg width="18" height="12" viewBox="0 0 18 12" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M1.5 12V9H3.5V12H1.5ZM6 12V6.5H8V12H6ZM10.5 12V3.5H12.5V12H10.5ZM15 12V0H17V12H15Z" fill="black"/></svg>
+                <svg width="16" height="12" viewBox="0 0 16 12" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M8 12C9.10457 12 10 11.1046 10 10C10 8.89543 9.10457 8 8 8C6.89543 8 6 8.89543 6 10C6 11.1046 6.89543 12 8 12Z" fill="black"/><path d="M2.34315 5.65685C5.46734 2.53266 10.5327 2.53266 13.6569 5.65685" stroke="black" stroke-width="1.5" stroke-linecap="round"/><path d="M5.17157 8.48528C6.73367 6.92318 9.26633 6.92318 10.8284 8.48528" stroke="black" stroke-width="1.5" stroke-linecap="round"/></svg>
+                <svg width="25" height="12" viewBox="0 0 25 12" fill="none" xmlns="http://www.w3.org/2000/svg"><rect x="0.5" y="0.5" width="21" height="11" rx="2.5" stroke="black"/><rect x="2" y="2" width="18" height="8" rx="1" fill="black"/><path d="M23 4V8" stroke="black" stroke-width="1.5" stroke-linecap="round"/></svg>
+            </div>
+        </div>
+
+        <!-- 导航栏 -->
+        <header class="h-11 flex items-center justify-between px-4 bg-white z-20 shrink-0 border-b border-gray-100">
+            <button class="text-gray-800 p-1">
+                <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m15 18-6-6 6-6"/></svg>
+            </button>
+            <h1 class="text-[17px] font-medium text-gray-900 absolute left-1/2 -translate-x-1/2">标题名称</h1>
+            <div class="w-8"></div>
+        </header>
+
+        <!-- 内容滚动区 -->
+        <div class="flex-1 overflow-y-auto no-scrollbar pb-8 bg-white relative">
+            
+            <!-- 1. 顶部占位大图 -->
+            <div class="w-full h-[220px] bg-[#eef6fc] flex items-center justify-center relative">
+                <!-- 内部占位 Logo 模拟 -->
+                <div class="w-32 h-32 rounded-full bg-[#d5e8f4] flex items-center justify-center relative overflow-hidden">
+                    <svg viewBox="0 0 100 100" class="w-full h-full text-white" fill="currentColor">
+                        <path d="M10,90 L90,90 L50,10 Z" opacity="0.8"/>
+                        <circle cx="50" cy="50" r="40" opacity="0.6"/>
+                    </svg>
+                </div>
+            </div>
+
+            <div class="px-5 pt-6 pb-2 space-y-8">
+                
+                <!-- 2. 主标题模块 -->
+                <section>
+                    <h2 class="text-[20px] font-bold text-gray-900 mb-3 tracking-wide">主标题文案一行字</h2>
+                    <p class="text-[14px] text-gray-600 leading-[1.6] text-justify tracking-wide">
+                        详情文案文案文案文案文案文案文案文案文案文案文案文案文案文案文案文案文案文案文案文案文案文案文案
+                    </p>
+                </section>
+
+                <!-- 3. 权益标题模块 -->
+                <section>
+                    <h3 class="text-[18px] font-bold text-gray-900 mb-2">权益标题</h3>
+                    <div class="flex flex-col">
+                        
+                        <!-- 权益项 1 -->
+                        <div class="flex items-center gap-4 py-4 border-b border-gray-100 active:bg-gray-50 transition cursor-pointer">
+                            <div class="w-12 h-12 rounded-full border border-gray-200 bg-[#fbfcfc] flex items-center justify-center text-gray-500 shrink-0">
+                                <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>
+                            </div>
+                            <div class="flex-1">
+                                <div class="text-[15px] font-medium text-gray-900">权益名称一行字</div>
+                                <div class="text-[13px] text-gray-500 mt-1">权益简介文案权益简介文案</div>
+                            </div>
+                            <svg class="w-5 h-5 text-gray-400 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/></svg>
+                        </div>
+                        
+                        <!-- 权益项 2 -->
+                        <div class="flex items-center gap-4 py-4 border-b border-gray-100 active:bg-gray-50 transition cursor-pointer">
+                            <div class="w-12 h-12 rounded-full border border-gray-200 bg-[#fbfcfc] flex items-center justify-center text-gray-500 shrink-0">
+                                <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>
+                            </div>
+                            <div class="flex-1">
+                                <div class="text-[15px] font-medium text-gray-900">权益名称一行字</div>
+                                <div class="text-[13px] text-gray-500 mt-1">权益简介文案权益简介文案</div>
+                            </div>
+                            <svg class="w-5 h-5 text-gray-400 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/></svg>
+                        </div>
+
+                        <!-- 权益项 3 -->
+                        <div class="flex items-center gap-4 py-4 border-b border-gray-100 active:bg-gray-50 transition cursor-pointer">
+                            <div class="w-12 h-12 rounded-full border border-gray-200 bg-[#fbfcfc] flex items-center justify-center text-gray-500 shrink-0">
+                                <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>
+                            </div>
+                            <div class="flex-1">
+                                <div class="text-[15px] font-medium text-gray-900">权益名称一行字</div>
+                                <div class="text-[13px] text-gray-500 mt-1">权益简介文案权益简介文案</div>
+                            </div>
+                            <svg class="w-5 h-5 text-gray-400 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/></svg>
+                        </div>
+
+                        <!-- 权益项 4 -->
+                        <div class="flex items-center gap-4 py-4 border-b border-gray-100 active:bg-gray-50 transition cursor-pointer">
+                            <div class="w-12 h-12 rounded-full border border-gray-200 bg-[#fbfcfc] flex items-center justify-center text-gray-500 shrink-0">
+                                <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="16" y1="13" x2="8" y2="13"/><line x1="16" y1="17" x2="8" y2="17"/><polyline points="10 9 9 9 8 9"/></svg>
+                            </div>
+                            <div class="flex-1">
+                                <div class="text-[15px] font-medium text-gray-900">权益名称一行字</div>
+                                <div class="text-[13px] text-gray-500 mt-1">权益简介文案权益简介文案</div>
+                            </div>
+                            <svg class="w-5 h-5 text-gray-400 shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5"><path stroke-linecap="round" stroke-linejoin="round" d="M9 5l7 7-7 7"/></svg>
+                        </div>
+                    </div>
+                </section>
+
+                <!-- 活动标题模块已按照要求跳过不写 -->
+
+                <!-- 4. 副标题模块 1 -->
+                <section>
+                    <h3 class="text-[18px] font-bold text-gray-900 mb-3 tracking-wide">副标题名称一行字</h3>
+                    <p class="text-[14px] text-gray-600 leading-[1.6] text-justify tracking-wide">
+                        详情文案文案文案文案文案文案文案文案文案文案文案文案文案文案文案文案文案文案文案文案文案文案文案文案
+                    </p>
+                </section>
+
+                <!-- 5. 副标题模块 2 (带外链图标排版) -->
+                <section>
+                    <h3 class="text-[18px] font-bold text-gray-900 mb-3 tracking-wide">副标题名称一行字</h3>
+                    <div class="text-[14px] text-gray-600 leading-[1.8] text-justify tracking-wide">
+                        说明文字说明 <span class="text-gray-900 font-medium cursor-pointer hover:underline">文字链接名字</span>
+                        <svg class="inline-block w-3.5 h-3.5 ml-0.5 text-gray-500 mb-0.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6M15 3h6v6M10 14L21 3"/></svg>
+                        明文文字链接名字 文字说明 
+                        <svg class="inline-block w-3.5 h-3.5 mx-0.5 text-gray-500 mb-0.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6M15 3h6v6M10 14L21 3"/></svg>
+                        字说明文字说明文字说明文字说明文字说明文字说明文字说明文字说明文字说明
+                        <span class="text-gray-900 font-medium ml-1 cursor-pointer hover:underline">文字链接名字</span>
+                        <svg class="inline-block w-3.5 h-3.5 ml-0.5 text-gray-500 mb-0.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6M15 3h6v6M10 14L21 3"/></svg>
+                        字说明文字说明文字说明文字说明文字说明文字说明文字说明文字说明文字说明文字说明文字说明文字说明文字说明文字说明文字说明文字说明文字说明文字说明文字说明文字说明文字说明文字说明文字说明文字说明文字说明文字说明文字说明
+                    </div>
+                </section>
+
+                <!-- 6. 底部操作按钮 -->
+                <section class="pt-4 space-y-3 pb-6">
+                    <button class="w-full bg-[#d70014] text-white text-[16px] font-medium py-3.5 rounded active:bg-red-800 transition">
+                        可配置字段
+                    </button>
+                    <button onclick="openBottomHint()" class="w-full bg-white border border-gray-300 text-gray-900 text-[16px] font-medium py-3.5 rounded active:bg-gray-50 transition">
+                        弹窗按钮
+                    </button>
+                </section>
+
+            </div>
+        </div>
+
+        <!-- 底部 Home Indicator (iOS风格) - 固定在最上层 -->
+        <div class="h-8 w-full flex justify-center items-center z-50 absolute bottom-0 pointer-events-none bg-gradient-to-t from-white via-white to-transparent">
+            <div class="w-32 h-1 bg-gray-900 rounded-full mt-2"></div>
+        </div>
+
+        <!-- 自定义 Toast 提示框 -->
+        <div id="customToast" class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-gray-800 text-white text-sm px-6 py-3 rounded-lg z-[200] hidden opacity-0 transition-opacity duration-300 shadow-lg whitespace-nowrap pointer-events-none">
+            提示内容
+        </div>
+
+        <!-- 底部提示弹窗 (Bottom Hint Modal) -->
+        <div id="bottomHintDialog" class="absolute inset-0 z-[100] hidden">
+            <div class="absolute inset-0 bg-black/40 transition-opacity" onclick="closeBottomHint()"></div>
+            <div id="bottomHintContent" class="absolute bottom-0 left-0 w-full bg-white rounded-t-xl transform translate-y-full transition-transform duration-300 ease-out flex flex-col shadow-[0_-10px_40px_rgba(0,0,0,0.1)]">
+                <div class="px-5 py-4 flex justify-between items-center border-b border-gray-100 shrink-0">
+                    <h2 class="text-[18px] font-medium text-gray-900">提示</h2>
+                    <button onclick="closeBottomHint()" class="text-gray-400 p-1 hover:bg-gray-100 rounded-full transition">
+                        <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="6" x2="6" y2="18"></line><line x1="6" y1="6" x2="18" y2="18"></line></svg>
+                    </button>
+                </div>
+                <div class="px-5 pt-6 pb-8">
+                    <p class="text-[15px] text-gray-700 leading-[1.6] mb-8">
+                        详情文案文案文案文案文案文案文案文案文案文案文案文
+                    </p>
+                    <div class="flex gap-3">
+                        <button onclick="closeBottomHint()" class="flex-1 py-3 text-[16px] font-medium text-gray-800 bg-white border border-gray-300 rounded active:bg-gray-50 transition">取消</button>
+                        <button onclick="confirmBottomHint()" class="flex-1 py-3 text-[16px] font-medium text-white bg-[#d70014] rounded active:bg-red-800 transition">确认</button>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <!-- 外部跳转拦截弹窗 (优化后 UI) -->
+        <div id="externalLinkDialog" class="absolute inset-0 z-[110] flex items-center justify-center hidden">
+            <!-- 遮罩层 -->
+            <div class="absolute inset-0 bg-black/50 transition-opacity" onclick="closeExternalDialog()"></div>
+            <!-- 弹窗本体 -->
+            <div class="relative bg-white w-[300px] rounded-xl flex flex-col p-6 animate-zoom-in shadow-2xl">
+                <div class="flex items-center gap-3 mb-3">
+                    <div class="w-8 h-8 rounded-full bg-red-50 flex items-center justify-center shrink-0">
+                        <svg class="w-4 h-4 text-[#d70014]" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path></svg>
+                    </div>
+                    <h3 class="text-[17px] font-bold text-gray-900">您正在离开汇丰中国</h3>
+                </div>
+                <p class="text-[13px] text-gray-500 leading-relaxed mb-6">请注意,外部网站的政策与我们网站的条款和条件以及隐私政策不同。将在新浏览器窗口或选项卡中打开下一个网站。</p>
+                <div class="flex gap-3">
+                    <button onclick="closeExternalDialog()" class="flex-1 py-2.5 text-[15px] font-medium text-gray-700 bg-gray-100 rounded hover:bg-gray-200 active:bg-gray-200 transition">取消</button>
+                    <button onclick="confirmExternalDialog()" class="flex-1 py-2.5 text-[15px] font-medium text-white bg-[#d70014] rounded hover:bg-red-700 active:bg-red-800 transition">继续前往</button>
+                </div>
+            </div>
+        </div>
+
+        <script>
+            // 自定义 Toast 显示函数,替代 alert
+            function showToast(message) {
+                const toast = document.getElementById('customToast');
+                toast.innerText = message;
+                toast.classList.remove('hidden');
+                
+                // 触发重绘以应用动画
+                void toast.offsetWidth;
+                
+                toast.classList.add('opacity-100');
+                
+                setTimeout(() => {
+                    toast.classList.remove('opacity-100');
+                    setTimeout(() => {
+                        toast.classList.add('hidden');
+                    }, 300); // 等待淡出动画结束
+                }, 2000); // 显示 2 秒
+            }
+
+            // --- 底部提示弹窗 ---
+            function openBottomHint() {
+                const modal = document.getElementById('bottomHintDialog');
+                const content = document.getElementById('bottomHintContent');
+                modal.classList.remove('hidden');
+                setTimeout(() => {
+                    content.classList.remove('translate-y-full');
+                }, 10);
+            }
+            
+            function closeBottomHint() {
+                const content = document.getElementById('bottomHintContent');
+                content.classList.add('translate-y-full');
+                setTimeout(() => {
+                    document.getElementById('bottomHintDialog').classList.add('hidden');
+                }, 300);
+            }
+
+            function confirmBottomHint() {
+                closeBottomHint();
+                setTimeout(() => {
+                    openExternalDialog();
+                }, 300);
+            }
+
+            // --- 外部跳转弹窗 ---
+            function openExternalDialog() {
+                document.getElementById('externalLinkDialog').classList.remove('hidden');
+            }
+            
+            function closeExternalDialog() {
+                document.getElementById('externalLinkDialog').classList.add('hidden');
+            }
+            
+            function confirmExternalDialog() {
+                closeExternalDialog();
+                // 模拟跳转后的提示操作
+                setTimeout(() => {
+                    showToast('已确认,将模拟跳转至外部链接!');
+                }, 200); // 稍微延迟等待弹窗消失动画
+            }
+        </script>
+    </div>
+
+</body>
+</html>

+ 4 - 1
工作空间/产研/权益/汇丰全行/产品原型/pc-demo/src/views/PageZoneConfig.vue

@@ -102,7 +102,10 @@
             <div class="config-field-label">补充说明</div>
             <el-input
               v-model="configData.identityModule[m.key].avgBalanceSupplementNote"
-              maxlength="20"
+              type="textarea"
+              :autosize="{ minRows: 2, maxRows: 6 }"
+              maxlength="500"
+              show-word-limit
               placeholder="请输入"
               class="balance-name-input"
               @input="markModified"

BIN
工作空间/产研/权益/汇丰全行/测试用例/组装页_测试用例.xlsx


+ 436 - 0
工作空间/产研/权益/汇丰全行/需求文档/prd-generator-from-demo/SKILL.md

@@ -0,0 +1,436 @@
+---
+name: prd-generator-from-demo
+description: Generate and incrementally update detailed Chinese PRD documents for any business domain from incomplete requirement notes, frontend or mobile prototypes, admin or backend demos, screenshots, existing API docs, config tables, dictionary tables, mock data, or static JSON. Use when Codex must reverse-engineer and complete a development-ready and testable PRD from prototypes and fragmented materials, or revise an existing PRD after prototypes change, with page display rules, backend/admin configuration rules, API fields, button interactions, validation, edge cases, flow diagrams, and open questions.
+---
+# PRD Generator From Demo
+
+## Objective
+
+Generate a detailed Chinese product requirements document from fragmented inputs for any business domain. The output must be concrete enough for frontend, backend, QA, and product stakeholders to split work, implement, and test.
+
+Do not merely polish an existing PRD. Infer and complete missing page structure, fields, states, interactions, admin rules, API contracts, field mappings, edge cases, and unresolved questions from the provided materials.
+
+This skill is domain-neutral. Do not assume a specific industry, product type, tenant, channel, or business vocabulary unless it appears in the user's materials. Preserve the user's domain terms and infer only from visible prototypes, supplied requirements, code, screenshots, APIs, and data files.
+
+## Input Materials
+
+Accept any combination of the following materials from any project:
+
+-   Incomplete requirement notes, partial PRDs, business remarks, or unclear field and rule descriptions.
+-   Frontend or mobile prototype materials, including HTML demos, app page code, screenshots, prototypes, or runnable projects.
+-   Admin, backend, or management-console demo materials, including HTML files, generated admin projects, React/Vue/HTML/CSS/JS code, screenshots, prototypes, or runnable pages.
+-   Existing API documentation.
+-   Screenshots, prototype images, old requirement documents, test cases, configuration tables, dictionary tables, mock data, static JSON, or page notes.
+
+When reading demos, identify page structure, modules, fields, buttons, states, display rules, interaction behavior, validation, permissions, persistence rules, mobile impact, and edge cases.
+
+If the product is not mobile-first, replace "移动端" in the output with the actual user-facing channel, such as "前台", "Web端", "小程序端", "App端", "H5端", or another channel found in the materials.
+
+## Source Priority
+
+When materials conflict, apply this priority:
+
+1.  Incomplete requirement description
+2.  Existing API documentation
+3.  Admin/backend demo
+4.  Frontend/mobile prototype
+5.  Mock data or static data
+6.  Reasonable inference
+
+Follow these conflict rules:
+
+-   If requirement notes and demos conflict, keep both signals and mark the issue as a "疑似冲突点".
+-   If API docs and page fields differ, prefer the API docs and list the difference under "待确认问题".
+-   If demos contain fields, buttons, or modules that are missing from requirement notes, add them to the PRD.
+-   If information cannot be determined, do not pretend it is certain. Put it under "待确认问题".
+
+## Writing Rules
+
+-   Write the final PRD in Chinese.
+-   Use product manager requirement-document language.
+-   Do not write generic background, goals, project value, or market analysis.
+-   Avoid vague wording such as "根据实际情况", "按需展示", or "相关数据".
+-   Explain every field's source, purpose, display rule, interaction rule, and exception rule.
+-   Explain every button's click behavior, permission control, secondary confirmation, success message, and failure message.
+-   Make rules specific, developable, and testable.
+-   Clearly mark inferred content and explain the basis for inference.
+-   Mark virtual APIs as "【虚拟接口,待技术确认】".
+-   When designing virtual APIs, use Chinese interface names and Chinese field names. Do not use English, pinyin, camelCase, snake_case, or technical placeholder names for virtual API fields.
+-   If an existing API document uses English field names, preserve the original technical field names, but add Chinese field meanings so product, business, and testing readers can understand them.
+-   Do not make the PRD read like a stack of tables. For each module, page, API, rule set, and diagram, first write a short natural-language explanation of what it does, when it applies, and what the key rule is. Then use tables only for dense field-level details, mappings, validation lists, and button inventories.
+-   Write in a human product-document style: use complete sentences, explicit cause-and-effect rules, and short paragraphs before tables. Avoid table-only sections unless the content is purely an inventory.
+
+## Generation Workflow
+
+Use this workflow when creating a PRD for the first time:
+
+1.  Inventory all input materials and identify their type.
+2.  Extract user-facing page modules from top to bottom, using the actual channel name from the materials.
+3.  Extract admin pages, filters, lists, dialogs, fields, buttons, validation, permissions, and persistence rules.
+4.  Extract existing API names and fields. Reuse them exactly when available.
+5.  If dynamic data is required but no API exists, design virtual APIs with Chinese interface names and Chinese field names, and mark them as pending technical confirmation.
+6.  Build frontend-admin field mappings.
+7.  Add business flow, swimlane, state-transition, or sequence diagrams when the requirement contains frontend-admin linkage, API call chains, state transitions, publish/enable/disable flows, multiple roles, or complex user paths.
+8.  Collect suspected conflicts, unclear rules, missing fields, and technical assumptions into "待确认问题".
+
+## Incremental Update Workflow
+
+Use this workflow when the user provides an existing PRD plus changed frontend/mobile, backend/admin, or management-console prototypes.
+
+1.  Read the existing PRD first and preserve its section structure, numbering style, terminology, confirmed decisions, and table formats.
+2.  Inspect the current frontend/mobile prototype and backend/admin prototype. Compare them against the existing PRD and identify only changed, added, deleted, or behaviorally affected items.
+3.  Update only impacted sections. Do not rewrite unrelated modules, do not rename stable fields, and do not reorder stable content unless the prototype structure itself changed.
+4.  For every change, update all directly affected places:
+    -   Frontend/mobile module description, display rules, field table, interaction rules, state rules, and edge cases.
+    -   Backend/admin page description, filter/list/form fields, button rules, validation rules, popup prompts, permissions, and edge cases.
+    -   API field descriptions or virtual APIs.
+    -   Frontend-admin field mapping table.
+    -   Mermaid flow diagrams.
+    -   Pending questions.
+5.  If a prototype removes a field, button, or module, mark the removal clearly and delete or update the corresponding requirement only when the removal is evident from the new prototype. If uncertain, keep the existing requirement and add a pending question.
+6.  If a prototype adds a field but the source is unclear, add the field with the most likely source marked as inferred and create a pending question.
+7.  If behavior changes are visible but the persistence/API impact is unclear, update visible behavior and add a pending technical question.
+8.  Add a short "本次更新说明" section at the top of the output when performing an incremental update. Include changed prototype source, changed modules, updated sections, and pending confirmation items.
+
+Use this table for the incremental update summary:
+
+| 更新项 | 变更来源 | 影响页面/模块 | 已更新章节 | 是否存在待确认 |
+| --- | --- | --- | --- | --- |
+
+When returning an updated PRD, include either the full updated document or a patch-style section replacement, depending on the user's request. If the user does not specify, provide the full updated document when the document is short; provide section-level replacements when the document is long.
+
+## Output Structure
+
+Generate the PRD with the following sections.
+
+### 一、需求范围说明
+
+State the covered pages, modules, admin configuration scope, and API scope. Do not write background or goals.
+
+### 二、功能范围与模块结构
+
+This section must only include the structural information needed before detailed requirements. Do not add a separate feature inventory, summary table, background, goals, or value analysis.
+
+2.1 前台/移动端模块结构
+
+Use the actual user-facing channel name from the materials. Describe the user-facing modules in their actual display or operation order, and explain what each module is responsible for. Do not only list visual areas; include the business meaning of each module.
+
+Examples:
+
+-   顶部展示区
+-   用户信息区
+-   权益列表区
+-   活动轮播区
+-   底部按钮区
+
+2.2 后台/管理端配置结构
+
+List backend/admin/management-console modules by configuration responsibility. Explain which frontend/mobile modules they control, not only where they appear in the admin page.
+
+Examples:
+
+-   菜单入口
+-   查询筛选区
+-   列表区
+-   新增/编辑弹窗
+-   配置项区域
+-   上传区域
+-   排序区域
+-   操作按钮区
+
+2.3 前后台关系概览
+
+Briefly explain only the necessary relationship between frontend/mobile display, backend/admin configuration, API data, and user actions. Keep this section concise because the detailed field mapping table appears later in the PRD.
+
+Use this table when applicable:
+
+| 前台/移动端模块 | 后台/管理端配置 | 依赖接口 | 用户操作影响 | 说明 |
+| --- | --- | --- | --- | --- |
+
+### 三、前台/移动端功能详细说明
+
+Use the actual user-facing channel name from the materials. Write one module at a time. Use this structure for each module:
+
+3.x 模块名称
+
+3.x.1 模块说明
+
+Describe the module position, purpose, and display conditions.
+
+3.x.2 展示规则
+
+Explain when the module is shown or hidden, whether it is controlled by admin configuration, and whether it is controlled by API state.
+
+3.x.3 字段说明
+
+Use this table:
+
+| 字段/元素 | 类型  | 展示位置 | 数据来源 | 来源说明 | 展示规则 | 交互规则 | 异常规则 |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+
+Only use one of these data source values:
+
+-   写死
+-   后台配置
+-   接口获取
+-   前端计算
+-   用户操作产生
+-   系统默认
+
+For data source explanations:
+
+-   写死: describe the fixed copy or fixed rule.
+-   后台配置: name the corresponding admin configuration field.
+-   接口获取: name the API, field name, and Chinese field meaning.
+-   前端计算: describe the formula and dependent fields.
+-   用户操作产生: describe the user action source.
+-   系统默认: describe the default value and effective scenario.
+
+3.x.4 交互规则
+
+Explain clicks, jumps, expand/collapse, popups, copy actions, submit actions, return behavior, refresh behavior, and any other interactions.
+
+3.x.5 状态规则
+
+If the module has state branches, use this table:
+
+| 状态值 | 状态含义 | 展示文案 | 展示样式 | 可操作按钮 | 规则说明 |
+| --- | --- | --- | --- | --- | --- |
+
+3.x.6 异常、空数据和边界规则
+
+Describe empty fields, API errors, API timeouts, image load failures, unknown states, user ineligibility, and other boundaries.
+
+### 四、后台/管理端功能详细说明
+
+Write backend/admin/management-console requirements by page, area, field, button, validation, and boundary.
+
+4.x 后台页面名称
+
+4.x.1 页面入口
+
+Describe menu path, page name, and page purpose.
+
+4.x.2 查询筛选区
+
+Describe filter fields, default values, reset support, fuzzy search support, and relationships between filters.
+
+Use this table:
+
+| 字段名称 | 字段类型 | 是否必填 | 默认值 | 数据来源 | 查询规则 | 校验规则 | 说明  |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+
+4.x.3 列表区
+
+Describe list fields, sorting rules, pagination, empty display, and operation column.
+
+Use this table:
+
+| 列表字段 | 字段类型 | 数据来源 | 展示规则 | 排序规则 | 空值规则 | 说明  |
+| --- | --- | --- | --- | --- | --- | --- |
+
+4.x.4 新增/编辑弹窗或配置表单
+
+Describe field differences for create, edit, and view modes, echo rules, and save rules.
+
+Use this table:
+
+| 字段名称 | 字段类型 | 是否必填 | 默认值 | 数据来源 | 配置用途 | 校验规则 | 前台/移动端影响 |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+
+Common field types include:
+
+-   文本输入框
+-   数字输入框
+-   文本域
+-   单选框
+-   多选框
+-   下拉选择
+-   开关
+-   日期选择
+-   时间选择
+-   图片上传
+-   文件上传
+-   富文本编辑器
+-   颜色选择器
+-   排序输入框
+-   表格配置
+-   字典选择
+-   枚举选择
+
+4.x.5 按钮说明
+
+Explain every admin button. Repeated buttons may be described once under common button rules and referenced in specific modules.
+
+Use this table:
+
+| 按钮名称 | 出现场景 | 操作对象 | 点击后行为 | 权限控制 | 二次确认 | 成功提示 | 失败提示 |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+
+Common buttons include:
+
+-   查询
+-   重置
+-   新增
+-   编辑
+-   删除
+-   查看
+-   保存
+-   取消
+-   上传
+-   更换图片
+-   排序
+-   上移
+-   下移
+-   发布
+-   下线
+-   启用
+-   停用
+-   复制
+-   预览
+
+4.x.6 校验规则
+
+Describe required validation, format validation, length validation, image size, image format, duplicate sorting, duplicate enum values, and time ranges.
+
+Use this table:
+
+| 字段/操作 | 校验规则 | 触发时机 | 不通过提示 | 是否阻断提交 |
+| --- | --- | --- | --- | --- |
+
+4.x.7 后台边界规则
+
+Describe admin exceptions and boundaries, such as:
+
+-   必填项为空
+-   字数超限
+-   图片格式错误
+-   图片大小超限
+-   排序值重复
+-   删除已上线配置
+-   编辑已生效配置
+-   多人同时编辑
+-   保存失败
+-   查询无结果
+-   筛选条件重置
+-   权限不足
+-   枚举值被引用后不可删除
+-   配置正在被移动端使用
+
+### 五、接口与字段说明
+
+If existing APIs are provided, reuse original API names and fields. If no API is provided but the page clearly needs dynamic data, design virtual APIs.
+
+Virtual API rules:
+
+-   API names must be Chinese.
+-   Field names must be Chinese.
+-   Do not use English field names, pinyin field names, camelCase, snake_case, abbreviations, or technical placeholders for virtual APIs.
+-   Do not invent names such as `id`, `type`, `status`, `title`, `imageUrl`, `createdTime`, `isEnabled`, or similar English fields for virtual APIs. Use Chinese names such as "记录编号", "类型", "状态", "标题", "图片地址", "创建时间", and "是否启用".
+-   If the user later provides a real API, replace or map the virtual Chinese interface and Chinese fields to the real technical interface and fields.
+-   Mark as "【虚拟接口,待技术确认】".
+-   Explain purpose, input parameters, output parameters, field meanings, field sources, usage locations, and exception rules.
+-   Do not write only "调用接口获取"; specify which API and which field is used by which module.
+
+Before the API tables, write a short paragraph explaining why the page needs this API, which module calls it, and what information it returns or saves.
+
+Use this structure for each API:
+
+接口名称:
+
+接口类型:
+
+接口用途:
+
+是否虚拟接口:
+
+调用时机:
+
+使用页面/模块:
+
+入参:
+
+| 字段名称 | 是否必填 | 字段类型 | 字段说明 | 示例值 |
+| --- | --- | --- | --- | --- |
+
+出参:
+
+| 字段名称 | 字段类型 | 字段说明 | 使用位置 | 异常规则 |
+| --- | --- | --- | --- | --- |
+
+接口异常规则:
+
+| 异常场景 | 页面表现 | 是否允许重试 | 提示文案 |
+| --- | --- | --- | --- |
+
+### 六、前台与后台字段映射关系
+
+Explain how backend/admin configuration fields affect frontend/mobile display.
+
+Use this table:
+
+| 后台配置字段 | 后台位置 | 前台/移动端展示字段或模块 | 影响规则 | 是否必填 | 空值处理 |
+| --- | --- | --- | --- | --- | --- |
+
+### 七、业务流程图 / 泳道图 / 状态流转图 / 接口调用时序图
+
+Add Mermaid diagrams when any of these are present:
+
+-   Frontend-admin linkage
+-   API call chains
+-   State transitions
+-   Publish, enable, disable, approve, online, or offline flows
+-   Multi-role collaboration
+-   Complex user operation paths
+
+Choose the diagram type based on the requirement:
+
+-   普通业务流程图
+-   泳道图
+-   状态流转图
+-   接口调用时序图
+
+Use Mermaid syntax. Keep node text in Chinese and make flow branches explicit.
+
+### 八、权限规则
+
+Describe permission control for admin entry, buttons, data visibility, editable status, deletable status, and mobile eligibility if present.
+
+Use this table when applicable:
+
+| 权限点 | 适用对象 | 控制范围 | 无权限表现 | 说明  |
+| --- | --- | --- | --- | --- |
+
+### 九、埋点与日志需求
+
+If user behavior, operation audit, publish history, or troubleshooting is relevant, define tracking and logs.
+
+Use this table:
+
+| 事件/日志名称 | 触发时机 | 记录字段 | 使用目的 | 备注  |
+| --- | --- | --- | --- | --- |
+
+### 十、待确认问题
+
+List unresolved items clearly. Include suspected conflicts, missing API fields, missing admin rules, unclear button behavior, unclear permission rules, unclear image requirements, unclear state definitions, and inferred assumptions.
+
+Use this table:
+
+| 序号  | 问题类型 | 问题描述 | 影响范围 | 建议确认对象 | 当前处理方式 |
+| --- | --- | --- | --- | --- | --- |
+
+## Quality Checklist
+
+Before finalizing the PRD, verify:
+
+-   Every visible frontend/mobile field has a data source and display rule.
+-   Every backend/admin field has validation and frontend/mobile impact when applicable.
+-   Every button has click behavior, permission, confirmation, success, and failure rules.
+-   Every dynamic module maps to an API field or admin configuration field.
+-   Every virtual API is marked as pending technical confirmation.
+-   Every virtual API uses Chinese interface names and Chinese field names.
+-   Existing English API fields, if any, have Chinese meanings and usage explanations.
+-   Each major section includes natural-language explanation before tables.
+-   Every conflict or uncertainty appears in "待确认问题".
+-   Mermaid diagrams are included when workflows or state transitions are non-trivial.
+-   The document avoids generic background and vague wording.

+ 4 - 0
工作空间/产研/权益/汇丰全行/需求文档/prd-generator-from-demo/agents/openai.yaml

@@ -0,0 +1,4 @@
+interface:
+  display_name: "PRD Generator From Demo"
+  short_description: "通用原型反推中文PRD并按原型变更增量更新需求文档"
+  default_prompt: "根据我提供的需求描述、前台/移动端原型、后台/管理端Demo、接口说明或截图,生成或增量更新可交付研发和测试的详细需求文档。"

+ 496 - 0
工作空间/产研/权益/汇丰全行/需求文档/权益介绍页.md

@@ -0,0 +1,496 @@
+# 权益介绍页前后台需求文档
+
+版本日期:2026-06-01
+
+## 一、业务流程图
+
+### 1.1 后台配置与发布流程
+
+```mermaid
+flowchart TD
+    A["运营进入页面管理 / 权益介绍页"] --> B["选择客户层级 Tab"]
+    B --> C["配置 Tab 名称、头图、标题、按钮文案、权益列表"]
+    C --> D{"是否开启展示权益图片"}
+    D -- "否" --> E["权益列表无需上传图片"]
+    D -- "是" --> F["每条权益均需上传图片"]
+    E --> G{"点击保存草稿或发布上线"}
+    F --> G
+    G -- "保存草稿" --> H{"草稿校验是否通过"}
+    G -- "发布上线" --> I{"发布校验是否通过"}
+    H -- "否" --> J["提示错误并停留当前配置 Tab"]
+    I -- "否" --> J
+    H -- "是" --> K["保存草稿配置"]
+    I -- "是" --> L["生成或更新线上发布配置"]
+    K --> M["可生成草稿预览链接"]
+    L --> N["可生成正式 H5 / 小程序链接"]
+```
+
+### 1.2 移动端访问与渲染流程
+
+```mermaid
+flowchart TD
+    A["客户打开权益介绍页"] --> B{"链接是否包含 draft=1"}
+    B -- "是" --> C["读取草稿预览配置"]
+    B -- "否" --> D["读取已发布配置"]
+    C --> E{"页面配置是否存在"}
+    D --> E
+    E -- "否" --> F["展示页面不存在或配置异常提示"]
+    E -- "是" --> G["读取客户当前 MSC / 客群标签"]
+    G --> H{"是否 Premier / Elite / GPB"}
+    H -- "否" --> I["展示顶部权益首页入口,默认选中卓越理财 Tab"]
+    H -- "是" --> J["隐藏顶部权益首页入口,默认选中客户真实等级 Tab"]
+    I --> K["渲染当前 Tab 介绍内容"]
+    J --> K
+    K --> L["按客户等级与当前 Tab 判断按钮解锁状态"]
+    L --> M["渲染权益列表"]
+```
+
+### 1.3 按钮点击与跳转流程
+
+```mermaid
+flowchart TD
+    A["用户点击权益介绍页按钮"] --> B{"按钮是否已解锁"}
+    B -- "是" --> C["读取客户真实 MSC 对应权益首页"]
+    C --> D["跳转权益首页"]
+    B -- "否" --> E["拦截跳转"]
+    E --> F{"是否配置达标提示弹窗能力"}
+    F -- "是" --> G["展示半屏达标提示弹窗"]
+    F -- "否" --> H["保持当前页并提示暂未达标"]
+```
+
+> 移动端原型中权益介绍页底部存在“精选活动/活动轮播图/轮播指示点”。该模块为二期内容,不在本期范围内;本期前台不展示,本期后台不配置,本期接口不返回或前端忽略该模块数据。
+
+## 二、后台配置需求
+
+### 2.1 后台入口与页面状态
+
+后台入口:`定制功能 / 汇丰银行 / 页面管理 / 权益介绍页`
+
+页面顶部操作:
+
+| 功能  | 需求说明 | 边界规则 |
+| --- | --- | --- |
+| 获取链接 | 打开“获取页面链接”弹窗 | 未发布时不展示正式链接,仅展示草稿预览链接 |
+| 保存草稿 | 保存三档权益介绍页配置为草稿 | 不影响当前线上版本 |
+| 发布上线 | 将当前配置发布为正式版本 | 发布成功后正式链接读取新配置 |
+| 状态展示 | 展示草稿、正式线上环境、有未发布的修改 | 已发布后编辑任意字段,状态切换为“有未发布的修改” |
+
+页面状态规则:
+
+| 状态  | 触发条件 | 后台展示 | 移动端影响 |
+| --- | --- | --- | --- |
+| 草稿  | 尚未发布或仅保存草稿 | 草稿(未发布) | 仅草稿预览链接可访问 |
+| 已发布 | 发布上线成功且无未发布修改 | 正式线上环境 | 正式链接读取该版本 |
+| 有未发布的修改 | 已发布配置被再次编辑但未发布 | 有未发布的修改 | 正式链接仍读取上一次发布版本;草稿预览读取最新草稿 |
+
+### 2.2 编辑页整体结构与操作
+
+编辑页由五部分组成:
+
+1.  顶部操作栏:页面状态、获取链接、保存草稿、发布上线。
+2.  客户层级配置 Tab:卓越理财、卓越理财·尊尚、环球私人银行。
+3.  Tab 名称配置。
+4.  头部配置。
+5.  按钮配置与权益列表配置。
+
+客户层级 Tab:
+
+| 层级  | 前端标识 | 默认名称 | 说明  |
+| --- | --- | --- | --- |
+| 卓越理财 | `premier` | 卓越理财 | Premier 客户对应等级 |
+| 卓越理财·尊尚 | `elite` | 卓越理财·尊尚 | Premier Elite 客户对应等级 |
+| 环球私人银行 | `global` | 环球私人银行 | GPB / PB 客户对应等级 |
+
+操作规则:
+
+| 操作  | 需求说明 | 校验与边界 |
+| --- | --- | --- |
+| 切换客户层级 Tab | 切换不同等级的配置表单 | 三档配置相互隔离,切换时不得串改其他等级数据 |
+| 保存草稿 | 保存三档完整配置 | 校验“展示权益图片”开启后图片必填;保存成功提示“已保存权益介绍页配置草稿!” |
+| 发布上线 | 发布三档完整配置 | 与保存草稿校验一致;发布成功提示“已发布权益介绍页配置!” |
+| 获取链接 | 生成正式链接和草稿预览链接 | 未发布时仅展示草稿预览链接 |
+
+保存范围:
+
+1.  后台保存或发布时提交 `premier`、`elite`、`global` 三档完整配置。
+2.  不允许仅保存当前后台 Tab,避免其他等级配置被覆盖或丢失。
+3.  任意字段修改后,如当前状态为已发布,需切换为“有未发布的修改”。
+
+### 2.3 获取页面链接
+
+点击“获取链接”后展示链接弹窗,支持选择 Campaign ID、Channel ID,生成带投放参数的链接。
+
+| 链接类型 | 展示条件 | 链接格式 | 用途  |
+| --- | --- | --- | --- |
+| 正式 H5 链接 | 页面状态为已发布 | `https://hsbc.com/home` | 正式投放 |
+| 正式小程序链接 | 页面状态为已发布 | `hsbc-app://home` | 小程序或 App 内打开 |
+| 草稿预览链接 | 页面存在草稿配置 | `https://test.hsbc.com/home?draft=1` | 内部测试预览 |
+
+参数拼接规则:
+
+| 参数  | 来源  | 规则  |
+| --- | --- | --- |
+| `draft` | 是否草稿预览 | 草稿预览链接固定为 `draft=1` |
+| `CampaignId` | Campaign 下拉选择 | 选填;选择后拼接到链接 |
+| `Channelid` | Channel 下拉选择 | 选填;选择后拼接到链接 |
+
+边界规则:
+
+1.  Campaign ID、Channel ID 清空时,不拼接对应参数。
+2.  同时选择 Campaign ID、Channel ID 时,按 `CampaignId=xxx&Channelid=yyy` 拼接。
+3.  草稿预览链接如同时存在投放参数,需保留 `draft=1`。
+4.  复制链接成功后提示“链接已复制到剪贴板”。
+5.  浏览器不支持剪贴板时,允许用户手动复制链接。
+
+### 2.4 Tab 名称配置
+
+| 字段  | 类型  | 必填规则 | 移动端消费规则 |
+| --- | --- | --- | --- |
+| Tab 名称 | 单行文本 | 非必填 | 作为移动端等级 Tab 名称;为空时使用默认名称 |
+
+规则:
+
+1.  后台当前层级 Tab 的标题优先展示已配置的 Tab 名称。
+2.  Tab 名称为空时,后台和移动端均使用默认名称兜底。
+3.  Tab 名称过长时,移动端需单行展示并省略或自适应压缩,不得挤压其他 Tab。
+4.  后台不支持新增、删除或调整三档 Tab 顺序。
+
+### 2.5 头部配置
+
+后台配置:
+
+| 字段  | 类型  | 必填规则 | 规则  |
+| --- | --- | --- | --- |
+| 头图配图 | 图片上传 | 非必填 | 建议尺寸 `686px x 296px`;支持替换上传 |
+| 主标题(粗体) | 单行文本 | 非必填 | 作为当前 Tab 内容主标题 |
+| 副标题(小字) | 单行文本 | 非必填 | 作为当前 Tab 内容副标题 |
+
+移动端展示:
+
+1.  头图按移动端内容宽度铺满,保持视觉裁切,不得变形拉伸。
+2.  头图为空或加载失败时,展示默认占位背景,不显示破图。
+3.  主标题为空时不展示标题节点,副标题上移。
+4.  副标题为空时不展示副标题节点。
+5.  主标题、副标题过长时允许自然换行,但不得遮挡按钮或权益列表。
+
+图片边界:
+
+1.  上传新图片后覆盖旧图片。
+2.  图片超过后端限制大小时,上传失败并提示“图片大小超出限制,请重新上传”。
+3.  图片格式限制以统一上传组件为准,建议支持 JPG、JPEG、PNG。
+
+### 2.6 按钮配置
+
+后台配置:
+
+| 字段  | 类型  | 必填规则 | 移动端消费规则 |
+| --- | --- | --- | --- |
+| 已解锁按钮文案 | 单行文本 | 非必填 | 已解锁状态按钮文案;为空时默认“进入权益专区” |
+| 待解锁按钮文案 | 单行文本 | 非必填 | 锁定状态按钮文案;为空时默认“待解锁” |
+
+按钮解锁规则由客户真实 MSC 与当前查看 Tab 共同决定,后台仅配置文案,不配置解锁关系。
+
+| 客户真实等级 | 查看卓越理财 Tab | 查看尊尚 Tab | 查看私行 Tab |
+| --- | --- | --- | --- |
+| 无等级、潜客、仅持卡、运筹理财 | 锁定  | 锁定  | 锁定  |
+| 卓越理财 | 已解锁 | 锁定  | 锁定  |
+| 卓越理财·尊尚 | 已解锁 | 已解锁 | 锁定  |
+| 环球私人银行 | 已解锁 | 已解锁 | 已解锁 |
+
+交互规则:
+
+1.  已解锁按钮点击后,进入客户真实 MSC 对应的权益首页。
+2.  已解锁按钮跳转目标不取当前查看 Tab;例如尊尚客户查看卓越 Tab,点击后仍进入尊尚客户权益首页。
+3.  锁定按钮点击后,前端拦截跳转。
+4.  如本期接入达标提示弹窗,点击锁定按钮后展示半屏达标提示弹窗;弹窗内容不由权益介绍页后台配置。
+5.  连续点击按钮时需防重复跳转。
+
+### 2.7 权益列表配置
+
+权益列表用于配置当前等级介绍页下方的权益说明,移动端按后台顺序自上而下展示。
+
+后台能力:
+
+| 功能  | 需求说明 | 边界规则 |
+| --- | --- | --- |
+| 添加权益 | 在当前列表末尾新增权益项 | 新增后序号自动追加 |
+| 删除权益 | 删除单条权益 | 删除后序号自动重排 |
+| 权益排序 | 输入目标序号后移动权益项 | 目标序号必须在当前列表范围内 |
+| 展示权益图片 | 控制移动端权益列表是否展示图片 | 开关关闭时移动端展示圆点样式 |
+
+权益字段:
+
+| 字段  | 类型  | 必填规则 | 移动端消费规则 |
+| --- | --- | --- | --- |
+| 展示权益图片 | 复选框 / 开关 | 必填  | 控制当前层级权益列表视觉样式 |
+| 权益图片 | 图片上传 | 条件必填 | 仅当“展示权益图片”开启时必填并展示 |
+| 标题  | 单行文本 | 非必填 | 作为权益标题展示 |
+| 描述  | 单行文本或多行文本 | 非必填 | 作为权益描述展示 |
+
+图片开关规则:
+
+| 开关状态 | 后台规则 | 移动端展示 |
+| --- | --- | --- |
+| 关闭  | 不要求上传权益图片;历史图片可清空或保留但不消费 | 不展示权益图片,统一展示圆点列表样式 |
+| 开启  | 每条权益图片必填,建议尺寸 `100px x 100px` | 展示每条权益图片 |
+
+校验规则:
+
+1.  当某档“展示权益图片”开启时,该档所有权益项必须上传图片。
+2.  任一权益缺图时,保存草稿和发布上线均阻断。
+3.  缺图提示格式:“{Tab名称} 第 {序号} 个权益未上传图片,请补充后再保存。”
+4.  缺图时后台自动切换到对应客户层级 Tab。
+
+移动端展示边界:
+
+1.  标题为空且描述有值时,仅展示描述。
+2.  描述为空且标题有值时,仅展示标题。
+3.  标题和描述均为空时,该权益项不展示,避免出现空行。
+4.  当前 Tab 无权益项时,移动端隐藏权益列表区域,保留头图、标题、副标题和按钮。
+5.  权益图片加载失败时展示默认图标或圆点兜底,不显示破图。
+
+### 2.8 配置数据结构
+
+后台按三档层级存储权益介绍页配置。
+
+```json
+{
+  "premier": {
+    "tabName": "卓越理财",
+    "privilegeImageEnabled": false,
+    "buttons": {
+      "unlocked": "进入权益专区",
+      "locked": "待解锁"
+    },
+    "header": {
+      "imageUrl": "",
+      "mainTitle": "卓越理财",
+      "subTitle": "为您和您的家人提供尊崇专属礼遇和权益"
+    },
+    "privileges": [
+      {
+        "imageUrl": "",
+        "title": "国际教育",
+        "desc": "享专属国际化学校优惠及背景提升项目"
+      }
+    ]
+  },
+  "elite": {},
+  "global": {}
+}
+```
+
+数据规则:
+
+1.  `premier`、`elite`、`global` 为固定键,不允许运营新增或删除。
+2.  `privilegeImageEnabled` 为当前层级列表级开关,不是单条权益字段。
+3.  前台不应依赖后台返回客户等级权重,解锁关系需由前端或服务端统一维护。
+4.  接口返回二期轮播字段时,本期前端忽略。
+
+## 三、移动端展示需求
+
+### 3.1 页面访问
+
+移动端通过固定权益介绍页入口或后台生成链接访问权益介绍页。
+
+| 场景  | 处理规则 |
+| --- | --- |
+| 页面配置不存在 | 展示页面不存在或配置异常提示 |
+| 页面未发布且非草稿预览 | 展示页面不存在或配置异常提示 |
+| 草稿预览链接 | 读取草稿配置,仅用于内部测试 |
+| 正式链接 | 读取最近一次发布配置 |
+| 配置接口失败 | 展示错误提示并支持重试,不展示上一客户缓存数据 |
+
+### 3.2 页面骨架
+
+| 区域  | 规则  |
+| --- | --- |
+| 状态栏 | 使用小程序或 App 容器原生状态栏 |
+| 导航栏 | 标题固定为“权益介绍页”;返回按钮返回上一页 |
+| 顶部固定入口 | 仅无三档等级客户展示 |
+| 等级 Tab | 固定展示三档,名称读取后台配置 |
+| 内容区 | 白底,自上而下渲染头图、标题、副标题、按钮、权益列表 |
+| 安全区 | iOS 底部安全区需留白,避免内容被遮挡 |
+
+页面结构:
+
+1.  页面导航栏:标题“权益介绍页”,左侧返回按钮。
+2.  顶部固定入口:仅无三档等级客户展示。
+3.  等级 Tab:卓越理财、卓越理财·尊尚、环球私人银行。
+4.  当前 Tab 的头图。
+5.  当前 Tab 的主标题、副标题。
+6.  进入权益首页按钮。
+7.  当前 Tab 的权益列表。
+
+### 3.3 客户等级与默认展示
+
+客户等级映射:
+
+| 客群  | 前端标识 | 权重  | 默认展示 |
+| --- | --- | --- | --- |
+| 潜客  | `prospect` | 0   | 卓越理财 Tab,展示顶部入口 |
+| 仅持有信用卡客户 | `credit_only` | 0   | 卓越理财 Tab,展示顶部入口 |
+| 运筹理财 | `advance` | 0   | 卓越理财 Tab,展示顶部入口 |
+| 卓越理财 | `premier` | 1   | 卓越理财 Tab,隐藏顶部入口 |
+| 卓越理财·尊尚 | `elite` | 2   | 卓越理财·尊尚 Tab,隐藏顶部入口 |
+| 环球私人银行 | `global` | 3   | 环球私人银行 Tab,隐藏顶部入口 |
+
+边界规则:
+
+1.  客户等级读取失败或无法识别时,按无等级处理。
+2.  无等级客户默认选中第一个 Tab,即卓越理财。
+3.  切换 Tab 只改变当前查看内容,不改变客户真实等级。
+4.  后台配置顺序不影响移动端展示顺序。
+
+### 3.4 顶部固定入口
+
+展示对象:
+
+| 客户类型 | 是否展示 |
+| --- | --- |
+| 潜客、仅持卡、运筹理财、未知等级 | 展示  |
+| 卓越理财、卓越理财·尊尚、环球私人银行 | 隐藏  |
+
+展示内容:
+
+| 字段  | 文案  | 来源  |
+| --- | --- | --- |
+| 标题  | 权益首页 | 前端固定 |
+| 副标题 | 一键查看您的所有权益 | 前端固定 |
+| 操作文案 | 立即查看 | 前端固定 |
+
+交互规则:
+
+1.  点击后进入客户真实 MSC 对应的权益首页。
+2.  对无三档等级客户,进入对应权益首页兜底版本。
+3.  该入口不支持后台隐藏、改名或换图。
+4.  跳转失败时提示“暂时无法查看,请稍后再试”。
+
+### 3.5 等级 Tab 与内容切换
+
+展示规则:
+
+1.  固定展示三档 Tab:卓越理财、卓越理财·尊尚、环球私人银行。
+2.  Tab 名称读取后台 `tabName`,为空时使用默认名称。
+3.  当前 Tab 需展示高亮文字和下划线。
+
+交互规则:
+
+1.  支持点击 Tab 切换内容。
+2.  如后续支持左右滑动切换,滑动结果需与点击 Tab 完全一致。
+3.  切换后需刷新头图、主标题、副标题、按钮状态、权益列表。
+4.  Tab 名称过长时需单行省略或自适应压缩。
+
+### 3.6 头部视觉区
+
+移动端消费字段:
+
+| 字段  | 来源  | 展示规则 |
+| --- | --- | --- |
+| 头图  | `header.imageUrl` | 宽度铺满,按视觉区域裁切 |
+| 主标题 | `header.mainTitle` | 头图下方展示,支持换行 |
+| 副标题 | `header.subTitle` | 主标题下方展示,支持换行 |
+
+边界规则:
+
+1.  头图为空或加载失败时展示默认占位。
+2.  主标题为空时隐藏标题节点。
+3.  副标题为空时隐藏副标题节点。
+4.  文案过长时自然换行,不遮挡按钮和权益列表。
+
+### 3.7 按钮展示与跳转
+
+按钮状态:
+
+| 客户真实等级 | 卓越理财 Tab | 尊尚 Tab | 私行 Tab |
+| --- | --- | --- | --- |
+| 无等级、潜客、仅持卡、运筹理财 | 锁定  | 锁定  | 锁定  |
+| 卓越理财 | 已解锁 | 锁定  | 锁定  |
+| 卓越理财·尊尚 | 已解锁 | 已解锁 | 锁定  |
+| 环球私人银行 | 已解锁 | 已解锁 | 已解锁 |
+
+展示规则:
+
+1.  已解锁状态展示后台 `buttons.unlocked`,为空时默认“进入权益专区”。
+2.  锁定状态展示后台 `buttons.locked`,为空时默认“待解锁”。
+3.  已解锁和锁定状态需有明显视觉区分。
+
+点击规则:
+
+1.  已解锁按钮点击后,跳转至客户真实 MSC 对应的权益首页。
+2.  当前正在查看的 Tab 不作为跳转目标。
+3.  锁定按钮点击后不跳转,可展示达标提示弹窗。
+4.  连续点击需防重复跳转。
+
+### 3.8 权益列表展示
+
+移动端消费字段:
+
+| 字段  | 来源  | 展示规则 |
+| --- | --- | --- |
+| 是否展示图片 | `privilegeImageEnabled` | 控制列表视觉样式 |
+| 图片  | `privileges[].imageUrl` | 开关开启时展示 |
+| 标题  | `privileges[].title` | 作为权益标题 |
+| 描述  | `privileges[].desc` | 作为权益描述 |
+
+展示规则:
+
+1.  权益列表按后台配置顺序展示。
+2.  `privilegeImageEnabled=false` 时,展示圆点列表样式。
+3.  `privilegeImageEnabled=true` 时,展示每条权益图片。
+4.  图片加载失败时展示默认图标或圆点兜底。
+5.  当前 Tab 无权益项时,隐藏权益列表区域。
+6.  标题和描述均为空的权益项不展示。
+
+### 3.9 异常与兜底
+
+| 场景  | 处理规则 |
+| --- | --- |
+| 客户等级未知 | 按无等级处理 |
+| 单个 Tab 配置缺失 | 使用默认 Tab 名称,内容区展示空态 |
+| 图片加载失败 | 展示占位,不显示破图 |
+| 权益首页跳转失败 | 提示“暂时无法查看,请稍后再试” |
+| 接口返回额外字段 | 前端忽略,不影响页面展示 |
+| 接口返回二期轮播字段 | 本期前端忽略 |
+
+## 四、验收标准
+
+### 4.1 后台验收
+
+| 编号  | 验收项 | 通过标准 |
+| --- | --- | --- |
+| A1  | 页面入口 | 可从页面管理进入“权益介绍页”配置页 |
+| A2  | 三档配置隔离 | 切换卓越、尊尚、私行 Tab 时,各档配置互不串改 |
+| A3  | 保存完整配置 | 保存草稿时提交三档完整配置,保存成功后提示成功 |
+| A4  | 发布上线 | 发布成功后状态为“正式线上环境”,正式链接读取新配置 |
+| A5  | 未发布修改 | 已发布后编辑任意字段,状态变为“有未发布的修改” |
+| A6  | Tab 名称兜底 | Tab 名称为空时,后台和移动端均使用默认名称 |
+| A7  | 头图上传 | 支持上传和替换头图,并展示建议尺寸 |
+| A8  | 按钮文案配置 | 已解锁、待解锁按钮文案可分别配置 |
+| A9  | 权益添加删除 | 可添加、删除权益项,删除后序号自动重排 |
+| A10 | 权益排序 | 输入合法目标序号后,权益项移动到目标位置 |
+| A11 | 图片开关关闭 | 关闭“展示权益图片”后,权益图片非必填 |
+| A12 | 图片开关开启 | 开启“展示权益图片”后,任一权益缺图均阻断保存和发布 |
+| A13 | 缺图提示 | 缺图时提示具体 Tab 与权益序号,并切换到对应 Tab |
+| A14 | 获取链接 | 已发布时展示正式 H5、小程序和草稿预览链接 |
+| A15 | 链接参数 | Campaign ID、Channel ID 能正确拼接到链接 |
+
+### 4.2 移动端验收
+
+| 编号  | 验收项 | 通过标准 |
+| --- | --- | --- |
+| M1  | 无等级客户默认展示 | 潜客、仅持卡、运筹客户展示顶部入口,默认选中卓越理财 Tab |
+| M2  | 高阶客户默认展示 | 卓越、尊尚、私行客户分别默认选中自身等级 Tab,并隐藏顶部入口 |
+| M3  | 未知等级兜底 | 客户等级未知时按无等级展示 |
+| M4  | Tab 切换 | 点击 Tab 后头图、标题、副标题、按钮状态、权益列表同步刷新 |
+| M5  | 按钮解锁 | 按客户等级向下兼容解锁,越级 Tab 按钮锁定 |
+| M6  | 跳转目标 | 已解锁按钮始终进入客户真实 MSC 对应权益首页 |
+| M7  | 锁定按钮 | 锁定按钮不跳转,可展示达标提示 |
+| M8  | 顶部入口 | 无等级客户点击顶部入口进入权益首页兜底版本 |
+| M9  | 头图兜底 | 头图为空或加载失败时不显示破图 |
+| M10 | 权益圆点样式 | 后台关闭展示权益图片时,移动端展示圆点列表 |
+| M11 | 权益图片样式 | 后台开启展示权益图片且图片齐全时,移动端展示图片 |
+| M12 | 空权益项 | 标题和描述均为空的权益项不展示 |
+| M13 | 空权益列表 | 当前 Tab 无权益项时隐藏列表区域 |
+| M14 | 二期轮播排除 | 页面不展示精选活动/活动轮播图 |
+| M15 | 异常提示 | 配置不存在、未发布、接口失败时展示错误或重试提示 |

+ 618 - 0
工作空间/产研/权益/汇丰全行/需求文档/权益首页.md

@@ -0,0 +1,618 @@
+# 权益首页前后台需求文档
+
+版本日期:2026-06-01
+
+## 一、范围说明
+
+### 1.1 本期范围
+
+本文档描述“权益首页”的前台展示与后台配置需求。
+
+参考范围:
+
+| 类型  | 文件或原型 | 说明  |
+| --- | --- | --- |
+| 前台原型 | `工作空间/产研/权益/汇丰全行/产品原型/h5-demo/移动端.html` | 以文件中的“权益首页”页面为准,即 `zone-view` 视图 |
+| 后台原型 | `工作空间/产研/权益/汇丰全行/产品原型/pc-demo` | 以“页面管理 / 权益首页配置”及权益、信用卡权益显示页面配置为准 |
+| 结构参考 | `工作空间/产研/权益/汇丰全行/需求文档/组装页.md` | 文档结构、流程图和验收口径参考 |
+
+本期权益首页包含以下模块:
+
+1.  客户身份模块。
+2.  专属礼遇模块。
+3.  信用卡权益模块。
+4.  活动广告轮播图模块。
+5.  积分商城与常用兑换模块。
+6.  积分规则弹窗。
+7.  后台保存草稿、发布上线、获取链接、Campaign ID 和 Channel ID 参数拼接。
+
+### 1.2 本期明确不包含
+
+移动端原型中,卓越理财和卓越理财尊尚客户身份卡片里出现的“合格(上月日均余额)”字段属于二期范围,本期不展示、不配置、不开发、不验收。
+
+具体处理规则:
+
+| 场景  | 本期处理 |
+| --- | --- |
+| 卓越理财身份区域 | 不展示“合格(上月日均余额)” |
+| 卓越理财尊尚身份区域 | 不展示“合格(上月日均余额)” |
+| 后台配置 | 不提供“显示合格状态”配置项 |
+| 接口字段 | 即使后端返回合格相关字段,本期前端也不消费 |
+| 验收  | 不以合格文案、合格状态、上月日均余额达标为验收项 |
+
+> 当前后台原型 `PageZoneConfig.vue` 已在数据归一化时删除 `showQualifyStatus`、`qualifyStatusText` 等旧字段,正式需求以本期范围为准。
+
+## 二、业务流程图
+
+### 2.1 后台配置与发布流程
+
+```mermaid
+flowchart TD
+    A["运营进入 页面管理 / 权益首页配置"] --> B["加载当前草稿或线上配置"]
+    B --> C["维护客户身份、广告轮播、常用兑换、积分规则配置"]
+    C --> D{"点击保存草稿或发布上线"}
+    D -- "保存草稿" --> E{"草稿校验是否通过"}
+    D -- "发布上线" --> F{"发布校验是否通过"}
+    E -- "否" --> G["提示错误并停留当前页面"]
+    F -- "否" --> G
+    E -- "是" --> H["保存草稿版本"]
+    F -- "是" --> I["生成或更新正式线上版本"]
+    H --> J["页面状态展示为草稿"]
+    I --> K["页面状态展示为正式线上环境"]
+    K --> L["可生成正式链接和草稿预览链接"]
+```
+
+### 2.2 移动端访问与渲染流程
+
+```mermaid
+flowchart TD
+    A["客户进入权益首页"] --> B{"是否草稿预览链接"}
+    B -- "是" --> C["读取草稿配置"]
+    B -- "否" --> D["读取已发布配置"]
+    C --> E{"配置是否存在"}
+    D --> E
+    E -- "否" --> F["展示页面不存在或已下线"]
+    E -- "是" --> G["获取登录客户身份、客户标签、权益资格、积分账户和信用卡信息"]
+    G --> H["按客户 MSC Group 匹配身份模块"]
+    H --> I["过滤专属礼遇、信用卡权益、广告和积分模块"]
+    I --> J["按页面固定顺序渲染可展示模块"]
+```
+
+### 2.3 广告与兑换项跳转流程
+
+```mermaid
+flowchart TD
+    A["用户点击广告或常用兑换项"] --> B{"配置的跳转类型"}
+    B -- "H5链接跳转" --> C["读取 H5 URL"]
+    B -- "固定链接跳转" --> D["读取固定链接字典"]
+    B -- "小程序跳转" --> E["读取 AppID 和页面路径"]
+    C --> F{"是否外部域名"}
+    D --> F
+    F -- "否" --> G["直接跳转"]
+    F -- "是" --> H["展示离开汇丰中国确认弹窗"]
+    H --> I{"用户确认继续前往"}
+    I -- "否" --> J["关闭弹窗,停留当前页"]
+    I -- "是" --> G
+    E --> K{"当前环境是否支持小程序跳转"}
+    K -- "是" --> L["跳转到指定小程序页面"]
+    K -- "否" --> M["展示无法打开或使用 H5 兜底"]
+```
+
+## 三、后台配置需求
+
+### 3.1 后台入口与页面状态
+
+后台入口:`定制功能 / 汇丰银行 / 页面管理 / 权益首页配置`
+
+页面顶部操作区包含:
+
+| 功能  | 需求说明 | 边界规则 |
+| --- | --- | --- |
+| 页面状态 | 展示草稿、正式线上环境、有未发布的修改 | 已发布配置被编辑后,状态变为“有未发布的修改”;正式移动端仍读取上一次发布版本 |
+| 获取链接 | 打开链接弹窗 | 可生成草稿预览链接;仅正式线上环境展示正式 H5 和正式小程序链接 |
+| 保存草稿 | 保存当前配置为草稿 | 校验已填写模块的基础必填项;不影响线上版本 |
+| 发布上线 | 将当前草稿发布为正式版本 | 需通过发布校验;发布后移动端正式入口读取最新配置 |
+
+页面状态规则:
+
+| 状态  | 触发条件 | 后台展示 | 移动端影响 |
+| --- | --- | --- | --- |
+| 草稿  | 尚未发布,或仅保存草稿 | 草稿(未发布) | 仅草稿预览链接可访问 |
+| 正式线上环境 | 发布上线成功且无后续修改 | 正式线上环境 | 正式链接读取该版本 |
+| 有未发布的修改 | 已发布后再次编辑但未发布 | 有未发布的修改 | 正式链接仍读取上一次发布版本;草稿预览读取最新草稿 |
+
+### 3.2 获取页面链接
+
+点击“获取链接”后展示链接弹窗,支持选择 Campaign ID 和 Channel ID。
+
+| 链接类型 | 展示条件 | 链接格式 | 用途  |
+| --- | --- | --- | --- |
+| 正式 H5 链接 | 页面状态为正式线上环境 | `https://hsbc.com/zone` | 正式投放 |
+| 正式小程序或 App 链接 | 页面状态为正式线上环境 | `hsbc-app://zone` | App 或小程序容器内打开 |
+| 草稿预览链接 | 页面存在草稿配置 | `https://test.hsbc.com/zone?draft=1` | 内部测试预览 |
+
+参数规则:
+
+| 参数  | 来源  | 规则  |
+| --- | --- | --- |
+| `CampaignId` | Campaign 下拉选择 | 选填;选择后拼接到链接 |
+| `Channelid` | Channel 下拉选择 | 选填;选择后拼接到链接 |
+| `draft` | 是否草稿预览 | 草稿预览链接固定为 `draft=1` |
+
+边界规则:
+
+1.  Campaign ID、Channel ID 为空时,不拼接对应参数。
+2.  参数拼接需避免重复问号;已有查询参数时使用 `&` 追加。
+3.  点击复制后提示“链接已复制到剪贴板”。
+4.  移动端需透传 Campaign ID、Channel ID 到埋点和后续跳转链路,便于归因。
+
+### 3.3 客户身份模块配置
+
+客户身份模块用于控制移动端顶部身份卡片。后台按四类客户身份维护配置:
+
+| 客户身份 | 后台 key | 移动端展示条件 |
+| --- | --- | --- |
+| 运筹理财 | `advance` | 登录客户 MSC Group 命中 Advance |
+| 卓越理财 | `premier` | 登录客户 MSC Group 命中 Premier |
+| 卓越理财尊尚 | `premierElite` | 登录客户 MSC Group 命中 Premier Elite |
+| 环球私人银行 | `privateBank` | 登录客户 MSC Group 命中 Global Private Bank |
+
+字段规则:
+
+| 字段  | 适用身份 | 类型  | 规则  |
+| --- | --- | --- | --- |
+| 客群背景图 | 全部身份 | 图片上传 | 建议尺寸 `750 x 185 px`;用于移动端身份卡片顶部背景 |
+| 等级说明 | 卓越理财、卓越理财尊尚、环球私人银行 | 富文本 | 用于配置等级名称旁边“?”提示弹窗内容 |
+| 显示账户月内日均余额 | 运筹理财、卓越理财、卓越理财尊尚 | 开关或配置字段 | 开启后展示余额名称、余额数值、截止日期和“?”说明入口 |
+| 账户月内日均余额名称 | 运筹理财、卓越理财、卓越理财尊尚 | 单行文本 | 默认“账户月内日均余额”;最多 20 个中文字符 |
+| 余额说明 | 运筹理财、卓越理财、卓越理财尊尚 | 富文本 | 用于配置余额名称旁边“?”提示弹窗内容 |
+
+图片规则:
+
+| 项目  | 规则  |
+| --- | --- |
+| 文件格式 | JPG、JPEG、PNG |
+| 建议尺寸 | `750 x 185 px` |
+| 上传数量 | 每个身份 1 张 |
+| 替换规则 | 再次上传覆盖原图 |
+| 空值兜底 | 后台未上传或图片加载失败时,移动端使用本地默认身份背景图 |
+
+身份配置边界:
+
+1.  私人银行身份不展示账户月内日均余额,也不展示余额说明配置。
+2.  运筹理财不配置等级说明,移动端不展示等级名称旁边的“?”说明入口。
+3.  卓越理财和卓越理财尊尚的等级说明只解释客户身份等级来源,不包含本期排除的“合格(上月日均余额)”。
+4.  若“显示账户月内日均余额”关闭,则移动端隐藏余额行、截止日期和余额说明“?”入口。
+5.  若余额说明为空但余额开关开启,移动端仍可展示余额行,但点击“?”时展示默认提示“暂无说明”或不展示“?”,以产品最终口径为准。推荐后台在发布时校验余额说明必填。
+6.  后台不提供“身份标识文字”“显示合格状态”“显示 PB 权益等级及编号”等旧字段配置。
+
+### 3.4 活动广告轮播图配置
+
+活动广告轮播图用于配置移动端权益首页中的活动海报。
+
+后台能力:
+
+| 功能  | 需求说明 | 边界规则 |
+| --- | --- | --- |
+| 添加轮播 | 在广告列表末尾新增一条广告 | 新增后默认跳转类型为 H5 链接跳转 |
+| 删除轮播 | 删除当前广告项 | 删除后需保存草稿或发布上线才生效 |
+| 调整顺序 | 输入目标序号并移动 | 序号最小为 1,最大为当前广告数量 |
+| 可见人群标签 | 多选客户标签 | 留空代表全量可见;命中特定标签才展示 |
+
+广告字段:
+
+| 字段  | 类型  | 必填规则 | 移动端消费规则 |
+| --- | --- | --- | --- |
+| 广告图片 | 图片上传 | 发布时必填 | 作为广告海报主图 |
+| 主标题 | 单行文本 | 选填  | 为空时隐藏标题文本 |
+| 副标题 | 单行文本 | 选填  | 为空时隐藏副标题文本 |
+| 可见人群标签 | 多选下拉 | 选填  | 留空为全量可见;非空则按客户标签过滤 |
+| 跳转类型 | 单选  | 必填  | H5 链接跳转、固定链接跳转、小程序跳转 |
+| H5 链接跳转 | URL 输入框 | 跳转类型为 H5 时必填 | 点击广告时打开 H5 链接 |
+| 固定链接跳转 | 下拉选择 | 跳转类型为固定链接时必填 | 从固定链接字典读取承接页 |
+| 小程序 AppID | 单行文本 | 跳转类型为小程序时必填 | 用于打开指定小程序 |
+| 小程序页面路径 | 单行文本 | 跳转类型为小程序时必填 | 支持带参数路径 |
+
+图片规则:
+
+| 项目  | 规则  |
+| --- | --- |
+| 文件格式 | JPG、JPEG、PNG |
+| 建议尺寸 | 后台原型提示 `686 x 296 px` |
+| 上传数量 | 每条广告 1 张 |
+| 加载失败 | 移动端隐藏该广告,不展示破图 |
+
+跳转类型规则:
+
+| 跳转类型 | 后台规则 | 移动端规则 |
+| --- | --- | --- |
+| H5 链接跳转 | `linkH5` 必填 | 点击后按链接安全规则跳转 |
+| 固定链接跳转 | `fixedLink` 必选 | 点击后跳转到固定链接对应页面 |
+| 小程序跳转 | `wechatAppId` 和 `wechatPath` 必填 | 小程序环境内打开目标页面;非小程序环境需有兜底策略 |
+
+发布校验:
+
+1.  存在广告项时,每条广告必须填写完整跳转配置。
+2.  跳转类型为小程序时,AppID 和页面路径必须同时填写。
+3.  跳转类型切换后,后台应清空非当前类型的旧字段,避免移动端误读。
+4.  不配置任何广告时,移动端隐藏活动广告模块。
+
+### 3.5 常用兑换配置
+
+常用兑换用于配置积分商城模块内的快捷兑换入口。
+
+后台能力:
+
+| 功能  | 需求说明 | 边界规则 |
+| --- | --- | --- |
+| 添加兑换项 | 在列表末尾新增兑换项 | 新增后需填写图片、展示文字和跳转链接 |
+| 删除兑换项 | 删除当前兑换项 | 删除后需保存草稿或发布上线才生效 |
+| 调整顺序 | 输入目标序号并移动 | 移动端按后台顺序展示 |
+
+字段规则:
+
+| 字段  | 类型  | 必填规则 | 移动端消费规则 |
+| --- | --- | --- | --- |
+| 兑换图标 | 图片上传 | 发布时必填 | 展示在兑换卡片上方 |
+| 展示文字 | 单行文本 | 必填  | 展示在兑换卡片下方 |
+| 跳转链接 | URL 输入框 | 必填  | 点击兑换项后跳转 |
+
+边界规则:
+
+1.  展示文字建议不超过 8 个中文字符,超长时移动端最多展示 1 行,超出省略。
+2.  兑换图标加载失败时,该兑换项可隐藏或展示默认图标。推荐展示默认图标并记录前端日志。
+3.  常用兑换项为空时,移动端隐藏“常用兑换”区域;积分账户区域仍按积分账户状态展示。
+4.  跳转链接为空时阻断保存或发布。
+
+### 3.6 积分规则弹窗配置
+
+积分规则弹窗用于配置移动端“积分规则”入口拉起的底部弹窗内容。
+
+| 字段  | 类型  | 必填规则 | 移动端消费规则 |
+| --- | --- | --- | --- |
+| 弹窗顶部名称 | 单行文本 | 发布时必填 | 作为底部弹窗标题 |
+| 规则内容 | 富文本编辑器 | 发布时必填 | 作为弹窗正文展示 |
+
+富文本规则:
+
+1.  支持文字、基础样式、链接、图片。
+2.  移动端渲染前需做安全过滤,禁止执行脚本。
+3.  富文本内链接按外部链接识别规则处理。
+4.  内容为空、仅空格或仅空标签时视为空内容。
+
+### 3.7 专属礼遇与信用卡权益后台联动
+
+专属礼遇不在“权益首页配置”页面内手工新增商品,而是从借记卡权益商品管理联动。
+
+借记卡权益进入权益首页需同时满足:
+
+1.  商品状态为已上架。
+2.  审核状态为审核通过。
+3.  “显示页面 / 权益首页”配置为显示。
+4.  当前客户命中商品的展示客群或标签条件。
+5.  当前时间处于商品展示有效期内。
+
+信用卡权益进入权益首页需同时满足:
+
+1.  信用卡权益配置“显示页面 / 权益首页”为显示。
+2.  当前客户满足信用卡模块展示前提。
+3.  如权益配置了卡种、客户等级、资格、次数等条件,移动端按客户实际数据判断可用状态。
+
+排序规则:
+
+| 模块  | 后台排序来源 | 移动端影响 |
+| --- | --- | --- |
+| 专属礼遇 | 借记卡权益列表“调整显示顺序” | 权益首页和权益列表页按该顺序展示 |
+| 信用卡权益 | 信用卡权益列表“调整显示顺序” | 权益首页和权益列表页按该顺序展示 |
+| 常用兑换 | 权益首页配置中的兑换项顺序 | 仅影响权益首页常用兑换区域 |
+| 活动广告 | 权益首页配置中的广告顺序 | 仅影响权益首页广告轮播顺序 |
+
+### 3.8 保存与发布校验
+
+| 校验项 | 保存草稿 | 发布上线 |
+| --- | --- | --- |
+| 客户身份背景图 | 不强制 | 不强制,移动端有默认图兜底 |
+| 余额开关开启时余额名称 | 必填  | 必填  |
+| 余额开关开启时余额说明 | 建议校验 | 推荐必填 |
+| 广告项图片 | 已添加广告时必填 | 已添加广告时必填 |
+| 广告项跳转配置 | 已添加广告时必填 | 已添加广告时必填 |
+| 常用兑换展示文字 | 已添加兑换项时必填 | 已添加兑换项时必填 |
+| 常用兑换跳转链接 | 已添加兑换项时必填 | 已添加兑换项时必填 |
+| 积分规则标题 | 不强制 | 必填  |
+| 积分规则内容 | 不强制 | 必填  |
+
+## 四、移动端展示需求
+
+### 4.1 页面入口与页面骨架
+
+移动端权益介绍页中存在“权益首页”入口,点击后进入权益首页页面。权益首页导航标题固定展示为“权益首页”。
+
+页面骨架:
+
+| 区域  | 规则  |
+| --- | --- |
+| 状态栏 | 使用 App 或小程序容器原生状态栏 |
+| 导航栏 | 标题为“权益首页”,左侧返回上一页 |
+| 内容区 | 背景色为浅灰,模块卡片为白底 |
+| 安全区 | iOS 底部安全区需留白,避免内容被遮挡 |
+
+模块顺序:
+
+1.  客户身份模块。
+2.  专属礼遇模块。
+3.  信用卡权益模块。
+4.  活动广告轮播图模块。
+5.  积分商城与常用兑换模块。
+
+任一模块因配置为空、客户不命中、接口无数据而隐藏时,不占位,不留白,后续模块自动上移。
+
+### 4.2 客户身份模块
+
+客户身份模块根据登录客户实际 MSC Group 自动匹配,不允许用户手动切换。原型中的右侧“状态”切换面板仅用于演示。
+
+展示规则:
+
+| 客户身份 | 展示内容 | 边界规则 |
+| --- | --- | --- |
+| 潜客  | 不展示身份卡片 | 页面顶部不留大空白 |
+| 仅持有信用卡客户 | 不展示身份卡片 | 页面顶部不留大空白 |
+| 运筹理财 | 展示背景图、英文等级名、中文等级名、账户月内日均余额 | 不展示等级说明“?” |
+| 卓越理财 | 展示背景图、英文等级名、中文等级名、等级说明“?”、账户月内日均余额 | 不展示“合格(上月日均余额)” |
+| 卓越理财尊尚 | 展示背景图、英文等级名、中文等级名、等级说明“?”、尊尚编号、账户月内日均余额 | 不展示“合格(上月日均余额)” |
+| 环球私人银行 | 展示背景图、英文等级名、中文等级名、私行业务 ID、等级或层级文本 | 不展示任何账户月内日均余额 |
+
+余额展示规则:
+
+| 场景  | 处理  |
+| --- | --- |
+| 后台开启余额展示且接口返回余额 | 展示余额名称、截止日期、余额金额和币种 |
+| 后台关闭余额展示 | 隐藏余额区域和余额说明“?” |
+| 余额接口返回空值 | 展示“数据更新中,请稍后重试”或隐藏金额,按统一异常口径处理 |
+| 私人银行客户 | 强制隐藏余额区域,即使接口返回余额也不展示 |
+
+文案与格式:
+
+| 内容  | 格式  |
+| --- | --- |
+| 截止日期 | `截止日期 YYYY年M月D日` |
+| 金额  | 千分位格式,追加币种,如 `8,000,000 人民币元` |
+| 编号  | 原样展示客户编号,如 `C1234567890` |
+
+说明弹窗:
+
+1.  点击等级名称旁边的“?”,展示后台配置的等级说明富文本。
+2.  点击余额名称旁边的“?”,展示后台配置的余额说明富文本。
+3.  弹窗样式为底部弹窗或系统统一弹窗,支持点击关闭按钮和遮罩关闭。
+4.  弹窗内容为空时不应展示空弹窗。
+
+编号复制:
+
+1.  卓越理财尊尚客户如返回尊尚编号,则展示复制图标。
+2.  环球私人银行客户如返回私行业务 ID,则展示复制图标。
+3.  点击复制后调用系统剪贴板,成功提示“编号已复制”。
+4.  编号为空时隐藏编号和复制图标。
+
+### 4.3 专属礼遇模块
+
+专属礼遇展示客户可见的借记卡权益商品。
+
+展示规则:
+
+1.  仅展示“权益首页=显示”、已上架、审核通过且客户命中的权益。
+2.  无权限或不命中的权益不渲染,不留空位。
+3.  无任何可展示权益时,隐藏整个“专属礼遇”模块,包括标题和“我的权益”入口。
+4.  点击“我的权益”进入我的权益列表页。
+5.  点击具体权益 Icon 进入对应权益详情页或承接页。
+
+排版规则:
+
+| 项目  | 规则  |
+| --- | --- |
+| 单屏数量 | 一屏最多展示 4 个 Icon |
+| 超过 4 个 | 横向滑动展示 |
+| 指示器 | 超过 1 屏时展示 dots |
+| 图标为空 | 展示默认权益图标 |
+| 名称超长 | 最多 2 行,超出省略 |
+
+### 4.4 信用卡权益模块
+
+信用卡权益模块展示信用卡权益列表及客户可用状态。
+
+模块展示前提:
+
+| 客户状态 | 模块处理 |
+| --- | --- |
+| 无储蓄账户且无信用卡账户 | 整个信用卡权益模块隐藏 |
+| 有储蓄账户但无信用卡 | 展示模块,权益为待解锁,引导快速申卡 |
+| 有信用卡但卡种不满足 | 展示模块,相关权益为待解锁,引导卡片升级 |
+| 有信用卡且满足卡种和资格 | 展示模块,权益按可用次数和资格展示 |
+
+权益状态:
+
+| 状态  | 展示  | 点击处理 |
+| --- | --- | --- |
+| 已解锁 | 正常图标和文案 | 进入信用卡权益详情或承接页 |
+| 待解锁 | 置灰展示 | 进入详情页展示申请、升级或年费缴纳引导 |
+| 有剩余次数 | 展示 `剩余次数/总次数`,如 `0/2` | 进入可使用权益详情 |
+| 无剩余次数 | 展示 `0/总次数` | 详情页提示次数已用尽或按信用卡权益平台规则处理 |
+
+排版规则:
+
+1.  一屏最多展示 4 个权益 Icon。
+2.  超过 1 屏时支持横向滑动并展示 dots。
+3.  “境外消费”等固定权益点击后进入信用卡权益平台对应 Tab 或锚点。
+4.  “更多权益”如存在,由信用卡权益平台统一承接。
+
+### 4.5 活动广告轮播图模块
+
+活动广告按后台配置和客户标签过滤后展示。
+
+展示规则:
+
+| 场景  | 处理  |
+| --- | --- |
+| 客户可见广告数量为 0 | 隐藏整个广告模块 |
+| 客户可见广告数量为 1 | 展示静态广告,不展示 dots,不自动轮播 |
+| 客户可见广告数量大于 1 | 横向轮播展示,按后台顺序排列 |
+| 广告图片加载失败 | 隐藏该广告;若全部失败则隐藏模块 |
+
+文案规则:
+
+1.  主标题为空时隐藏主标题。
+2.  副标题为空时隐藏副标题。
+3.  可见人群标签为空代表全量可见,移动端不展示人群标签文案。
+4.  配置了特定人群标签时,可按产品要求展示标签名称;如无明确要求,移动端仅用于过滤,不外显。
+
+点击规则:
+
+1.  H5 链接按链接安全规则跳转。
+2.  固定链接按后台字典承接。
+3.  小程序跳转需同时具备 AppID 和页面路径。
+4.  跳转失败时提示“暂时无法打开,请稍后重试”。
+
+### 4.6 积分商城与常用兑换模块
+
+积分模块展示客户积分账户和常用兑换入口。
+
+展示前提:
+
+| 场景  | 处理  |
+| --- | --- |
+| 有积分账户 | 展示积分商城模块 |
+| 无积分账户 | 隐藏整个积分商城模块 |
+| 积分接口异常 | 展示“数据更新中,请稍后重试”,常用兑换可按配置继续展示 |
+
+积分账户展示:
+
+1.  默认展示客户总积分。
+2.  点击总积分区域展开积分明细。
+3.  再次点击收起积分明细。
+4.  明细包含汇友荟积分、信用卡积分、最近到期积分等接口返回项。
+5.  到期积分日期格式为 `YYYY年M月D日到期积分`。
+
+常用兑换展示:
+
+| 项目  | 规则  |
+| --- | --- |
+| 展示来源 | 后台常用兑换配置 |
+| 单屏数量 | 原型单屏约 3 个兑换卡片 |
+| 超过一屏 | 横向滑动展示 |
+| 无兑换项 | 隐藏常用兑换区域 |
+| 点击兑换项 | 跳转后台配置链接 |
+
+积分规则:
+
+1.  “积分规则”入口位于常用兑换区域右下方。
+2.  点击后拉起底部弹窗。
+3.  弹窗标题读取后台“弹窗顶部名称”。
+4.  弹窗正文读取后台“规则内容”富文本。
+5.  内容较长时弹窗内部滚动,页面底部安全区不遮挡正文。
+
+### 4.7 链接安全与外部跳转
+
+所有后台配置链接均需执行安全识别。
+
+| 链接类型 | 处理  |
+| --- | --- |
+| 汇丰内部域名 | 直接跳转 |
+| App 内部 Scheme | 直接拉起 |
+| 小程序内部路径 | 小程序环境内打开 |
+| 第三方外部域名 | 先展示离开汇丰中国确认弹窗 |
+| 非法链接 | 后台阻断保存;移动端如仍收到非法链接则提示无法打开 |
+
+离开汇丰中国确认弹窗固定文案:
+
+| 字段  | 文案  |
+| --- | --- |
+| 标题  | 您正在离开汇丰中国 |
+| 描述  | 请注意,外部网站的政策与我们网站的条款和条件以及隐私政策不同。将在新浏览器窗口或选项卡中打开下一个网站。 |
+| 取消按钮 | 取消  |
+| 确认按钮 | 继续前往 |
+
+### 4.8 加载、异常与空状态
+
+加载规则:
+
+1.  首次进入权益首页时展示骨架屏。
+2.  身份信息、权益列表、信用卡权益、积分账户可并行请求。
+3.  单个模块失败时优先做模块级降级,不阻断其他模块展示。
+4.  页面关键配置读取失败时展示页面级错误。
+
+异常规则:
+
+| 异常  | 处理  |
+| --- | --- |
+| 页面配置不存在 | 展示“页面不存在或已下线” |
+| 草稿链接过期或无权限 | 展示“页面不存在或已下线” |
+| 客户身份接口失败 | 隐藏身份模块或展示“数据更新中,请稍后重试” |
+| 权益列表接口失败 | 隐藏对应权益模块并记录日志 |
+| 信用卡权益接口失败 | 隐藏信用卡权益模块或展示模块级错误 |
+| 积分接口失败 | 展示积分模块错误态,不展示错误代码 |
+| 图片加载失败 | 使用默认图或隐藏当前图片项 |
+
+## 五、数据来源与字段口径
+
+| 数据  | 来源  | 用途  |
+| --- | --- | --- |
+| 客户 MSC Group | 客户信息或 CDP 接口 | 判断客户身份模块 |
+| 客户标签 | 人群标签或名单包服务 | 过滤广告和权益 |
+| 借记卡权益商品 | 权益商品管理 | 渲染专属礼遇 |
+| 信用卡权益商品 | 信用卡权益管理 | 渲染信用卡权益 |
+| 信用卡持卡状态和卡种 | 信用卡账户接口 | 判断信用卡权益解锁状态 |
+| 权益可用次数 | 信用卡权益或权益资格接口 | 展示 `剩余次数/总次数` |
+| 积分账户 | 积分中台 | 判断积分模块是否展示 |
+| 积分明细 | 积分中台和信用卡积分接口 | 展示积分抽屉 |
+| 页面配置 | 页面管理 / 权益首页配置 | 背景图、广告、常用兑换、积分规则 |
+
+隐私与安全口径:
+
+1.  环球私人银行客户不展示账户月内日均余额。
+2.  余额、编号、积分等客户敏感数据不得写入前端日志明文。
+3.  外部链接跳转必须经过安全白名单判断。
+4.  富文本渲染必须过滤脚本和危险属性。
+
+## 六、验收标准
+
+### 6.1 后台验收
+
+| 编号  | 验收项 | 通过标准 |
+| --- | --- | --- |
+| A1  | 页面状态 | 草稿、正式线上环境、有未发布的修改状态展示正确 |
+| A2  | 保存草稿 | 点击保存草稿后配置保存成功,不影响正式链接读取版本 |
+| A3  | 发布上线 | 发布成功后正式链接读取最新配置 |
+| A4  | 获取链接 | 正式状态展示正式 H5、正式小程序和草稿预览链接;草稿状态仅展示草稿预览链接 |
+| A5  | 链接参数 | 选择 Campaign ID、Channel ID 后正确拼接参数 |
+| A6  | 客户身份配置 | 四类身份可分别配置背景图;私行不展示余额配置 |
+| A7  | 二期字段排除 | 后台不出现“显示合格状态”配置项 |
+| A8  | 等级说明 | 卓越理财、卓越理财尊尚、私行可配置等级说明富文本 |
+| A9  | 余额说明 | 开启余额展示时可配置余额名称和余额说明 |
+| A10 | 广告配置 | 可新增、删除、排序广告,并配置图片、标题、人群标签和跳转 |
+| A11 | 广告跳转校验 | H5、固定链接、小程序跳转类型均按条件必填校验 |
+| A12 | 常用兑换配置 | 可新增、删除、排序兑换项,并配置图片、文字和链接 |
+| A13 | 积分规则配置 | 可配置弹窗标题和富文本内容 |
+| A14 | 权益联动 | 借记卡权益和信用卡权益配置“权益首页=显示”后可进入移动端展示候选池 |
+
+### 6.2 移动端验收
+
+| 编号  | 验收项 | 通过标准 |
+| --- | --- | --- |
+| M1  | 页面标题 | 进入权益首页后导航标题展示“权益首页” |
+| M2  | 模块顺序 | 按客户身份、专属礼遇、信用卡权益、活动广告、积分商城顺序展示 |
+| M3  | 身份匹配 | 不同 MSC Group 客户展示对应身份卡片 |
+| M4  | 二期字段排除 | 卓越理财和卓越理财尊尚均不展示“合格(上月日均余额)” |
+| M5  | 私行隐私 | 环球私人银行客户不展示任何账户月内日均余额 |
+| M6  | 余额说明 | 点击余额“?”展示后台配置的余额说明 |
+| M7  | 等级说明 | 点击等级“?”展示后台配置的等级说明 |
+| M8  | 编号复制 | 尊尚编号或私行业务 ID 存在时可复制,复制成功有提示 |
+| M9  | 专属礼遇过滤 | 未上架、未审核通过、不命中客户条件的权益不展示 |
+| M10 | 专属礼遇空态 | 无可展示权益时隐藏整个专属礼遇模块 |
+| M11 | 信用卡权益状态 | 按客户持卡、卡种、资格和次数展示已解锁或待解锁 |
+| M12 | 广告过滤 | 按可见人群标签过滤广告;0 张隐藏,1 张静态,多张轮播 |
+| M13 | 广告跳转 | H5、固定链接、小程序跳转均按配置执行 |
+| M14 | 积分账户 | 有积分账户展示积分模块,无积分账户隐藏模块 |
+| M15 | 积分抽屉 | 点击总积分可展开或收起积分明细 |
+| M16 | 常用兑换 | 兑换项按后台顺序展示,点击后跳转配置链接 |
+| M17 | 积分规则 | 点击积分规则拉起底部弹窗,内容来自后台富文本 |
+| M18 | 外部链接 | 第三方外链跳转前展示离开汇丰中国确认弹窗 |
+| M19 | 图片异常 | 图片加载失败不出现破图,使用默认图或隐藏对应项 |
+| M20 | 页面异常 | 配置不存在、链接无效、接口异常时不暴露错误代码 |

+ 38 - 148
工作空间/产研/权益/汇丰全行/需求文档/汇丰借记卡移动端——权益.md

@@ -1,21 +1,13 @@
 **与后台的关联说明:**
 
 > -   移动端根据后台"是否权益平台兑换"、"商品类型"和"是否有详情页"组合判断跳转逻辑
->     
 > -   后台"是否权益平台兑换"分为两类:**是**(商品类型为券码或微信立减金)、**否**(第三方权益:太古地产/龙腾/h5链接/小程序链接)
->     
 > -   后台"外部权益链接"字段(太古地产/龙腾/h5链接/小程序链接)决定外部跳转时的交互流程
->     
 > -   后台"展示规则"(展示时间限制 / 展示客群限制)控制移动端权益列表的可见性
->     
 > -   后台"领取规则"(领取时间限制 / 领取客群限制)控制移动端权益详情页的领取校验;**领取客群统一由后台【发放计划】维护,未发放的权益移动端不展示**
->     
 > -   后台"显示页面"(权益首页/列表页、组装页)决定权益在移动端哪些页面展示
->     
 > -   后台"调整显示顺序"决定权益在移动端权益首页/列表中的展示顺序
->     
 > -   后台"分享设置"决定权益是否支持分享及分享内容(分享名称、分享图片)
->     
 
 ## 1\. 我的权益
 
@@ -28,64 +20,34 @@
 **(1)借记卡权益(新增)**
 
 -   **数据来源:** 后台权益商品列表中需同时满足:
-    
     -   商品状态:已上架
-        
     -   商品类型:不为微信立减金(微信立减金统一在"我的立减金"入口跳转展示)
-        
     -   展示时间限制:未开启 或 当前时间在后台配置的展示开始时间~展示结束时间范围内
-        
     -   展示客群限制:未开启 或 用户命中后台配置的客群标签ID
-        
     -   显示页面:后台配置了"权益首页/列表页 = 显示"
-        
     -   奖励点:如果权益商品开启了领取客群限制,需要判断用户的的该科目是否奖励点>0,如果等于0不展示
-        
 -   **列表字段**
-    
     -   权益列表图标(取后台"权益列表图标"字段)
-        
     -   权益名称(取后台"权益名称"字段)
-        
 -   **列表顺序:** 按照后台"调整显示顺序"排列(后台可通过列表【更多 → 调整显示顺序】调整)。
-    
 -   **列表跳转** 根据后台【是否权益平台兑换】+【商品类型】+【是否有详情页】判断:
-    
     -   **是否权益平台兑换=是(券码):** 跳转到权益详情页
-        
     -   **是否权益平台兑换=否,是否有详情页=没有:** 点击直接从列表跳转第三方链接
-        
         -   根据后台配置的【外部权益链接】类型判断跳转交互:
-            
         -   **h5链接:** 弹窗提示
-            
             -   **标题:** 您正在离开汇丰中国
-                
             -   **描述:** 请注意,外部网站的政策与我们网站的条款和条件以及隐私政策不同。将在新浏览器窗口或选项卡中打开下一个网站。
-                
             -   **操作**
-                
                 -   **取消:** 关闭弹窗
-                    
-                -   **继续前往:** 跳转后台配置的h5链接
-                    
-                    ![|42%](../../../../../.resources/image-1776678703451.png)
+                -   **继续前往:** 跳转后台配置的h5链接![|42%](../../../../../.resources/image-1776678703451.png)
         -   **小程序链接:** 弹窗提示
-            
             -   **标题:** 您正在离开汇丰中国
-                
             -   **描述:** 请注意,外部网站的政策与我们网站的条款和条件以及隐私政策不同。将在新浏览器窗口或选项卡中打开下一个网站。
-                
             -   **操作**
-                
                 -   **取消:** 关闭弹窗
-                    
                 -   **继续前往:** 跳转后台配置的微信小程序(使用小程序appid + 页面地址)
-                    
         -   **太古地产:** 点击后弹出授权提醒
-            
             -   勾选同意并**确认**后,显示离开提示,点击确认时调用太古地产接口,然后跳转至后端返回的太古地产免登地址。
-                
             -   **点击取消:** 关闭授权提醒。
                 
                 <br>
@@ -96,12 +58,8 @@
                 
                 ![|45%](../../../../../.resources/image-1776678755981.png)
 -   **龙腾:** 点击后弹出授权提醒
-    
     -   勾选同意并**确认**后,显示离开提示,点击确认时调用龙腾接口,然后跳转至后端返回的龙腾免登地址。
-        
-    -   **点击取消:** 关闭授权提醒。
-        
-        ![|46%](../../../../../.resources/image-1776678775726.png)
+    -   **点击取消:** 关闭授权提醒。![|46%](../../../../../.resources/image-1776678775726.png)
 
 **(2)信用卡权益(现有)**
 
@@ -116,77 +74,48 @@
 展示顺序:
 
 1.  是否权益平台兑换=是的券码权益(未过期)。
-    
 2.  信用卡权益。
-    
 3.  是否权益平台兑换=是的券码权益(已失效)。
-    
 
 筛选项:
 
 -   全部
-    
 -   可使用:未过期
-    
 -   已失效
-    
 
 ![](../../../../../.resources/image-1776678841917.png)
 
 **(1)券码权益(未过期)**
 
 -   **列表字段**
-    
     -   权益列表图标(取"权益图片"字段)
-        
     -   权益名称(取"权益名称"字段)
-        
     -   可用次数
-        
 -   **列表顺序**
-    
     -   领取时间倒序展示
-        
 -   **跳转链接**
-    
     -   跳转订单详情页
-        
 
 **(2)信用卡权益**
 
 -   **列表字段**
-    
     -   权益列表图标(取后台"权益列表图标"字段)
-        
     -   权益名称(取后台"权益名称"字段)
-        
     -   权益副标题(取后台"权益副标题"字段,为空则不展示)
-        
 -   **列表顺序**
-    
     -   领取时间倒序展示
-        
 -   **跳转链接**
-    
     -   跳转订单详情页
-        
 
 **(3)券码权益(已失效)**
 
 -   **列表字段**
-    
     -   权益列表图标(取后台"权益列表图标"字段)
-        
     -   权益名称(取后台"权益名称"字段)
-        
 -   **列表顺序**
-    
     -   领取时间倒序展示
-        
 -   **跳转链接**
-    
     -   跳转订单详情页
-        
 
 ## 2\. 权益详情
 
@@ -195,41 +124,52 @@
 **(1)详情页内容**
 
 -   **权益主图:** 取后台"权益主图"字段
-    
 -   **权益名称:** 取后台"权益名称"字段,超出换行展示
-    
 -   **权益介绍:** 取后台"权益介绍"字段,非富文本,样式固定。图中卡片中权益名称下方内容
-    
 -   **权益有效期:** 取后台"权益有效期"字段
-    
     -   取发放计划字段:
-        
         -   固定日期:【开始日期】-【结束日期】
-            
         -   相对日期:领取后 x 天内有效
-            
     -   自定义:显示自定义输入的内容
-        
 -   **单客户权益数量(无领取限制则不显示):**x 次(整个周期)、月度 x 次、季度 x 次、年度 x 次
-    
 -   **权益内容:** 取后台"权益内容"字段,富文本展示,图中卡片下方的内容。PDF链接需支持点击打开预览查看,不需要支持下载。
-    
 -   **权益说明:** 取后台"权益说明"字段,富文本展示。PDF链接需支持点击打开预览查看,不需要支持下载。
-    
 -   **按钮:** 根据后台"领取规则"中的领取时间限制判断
-    
     -   **开启了领取时间限制且未到领取开始时间:** 显示【未开始】,按钮无法点击
-        
     -   **开启了领取时间限制且超过领取结束时间:** 显示【已失效】,按钮无法点击
-        
-
-**其他:** 显示【领取权益】
-
-<br>
-
-<br>
-
-![|50%](../../../../../.resources/image-1776678923546.png)![|50%](../../../../../.resources/image-1776678942001.png)
+-   **其他:** 显示【领取权益】
+    
+    <br>
+    
+    <br>
+    
+    <br>
+    
+    <br>
+    
+    <br>
+    
+    <br>
+    
+    <br>
+    
+    <br>
+    
+    <br>
+    
+    <br>
+    
+    <br>
+    
+    <br>
+    
+    <br>
+    
+    <br>
+    
+    <br>
+    
+    ![|50%](../../../../../.resources/image-1776678923546.png)![|50%](../../../../../.resources/image-1776678942001.png)
 
 **(2)领取权益**
 
@@ -242,13 +182,9 @@
 **规则校验失败提示:**
 
 -   **领取客群不满足时:** 展示后台配置的不满足提示
-    
     -   内容:取后台"领取客群限制-不满足提示-提示内容"
-        
     -   按钮文案:取后台"领取客群限制-不满足提示-跳转按钮文案"
-        
     -   按钮跳转:取后台"领取客群限制-不满足提示-跳转按钮链接"
-        
 
 **规则校验成功,处理逻辑分两种情况:**
 
@@ -257,72 +193,42 @@
 领取成功提示:
 
 -   **内容:** 尊敬的客户,您已成功领取权益
-    
 -   **按钮文案:** 取后台配置的"领取成功按钮文案"(默认值:"马上去使用")
-    
 -   **按钮跳转:** 跳转权益订单详情页
-    
 
 **第二种:是否权益平台兑换=否,是否有详情页=有**
 
 根据后台配置的【外部权益链接】类型判断跳转交互:
 
 -   **h5链接:** 弹窗提示
-    
     -   **标题:** 您正在离开汇丰中国
-        
     -   **描述:** 请注意,外部网站的政策与我们网站的条款和条件以及隐私政策不同。将在新浏览器窗口或选项卡中打开下一个网站。
-        
     -   **操作**
-        
         -   **取消:** 关闭弹窗
-            
-        -   **继续前往:** 跳转后台配置的h5链接
-            
-            ![|48%](../../../../../.resources/image-1776679010497.png)
+        -   **继续前往:** 跳转后台配置的h5链接![|48%](../../../../../.resources/image-1776679010497.png)
 -   **小程序链接:** 弹窗提示
-    
     -   **标题:** 您正在离开汇丰中国
-        
     -   **描述:** 请注意,外部网站的政策与我们网站的条款和条件以及隐私政策不同。将在新浏览器窗口或选项卡中打开下一个网站。
-        
     -   **操作**
-        
         -   **取消:** 关闭弹窗
-            
         -   **继续前往:** 跳转后台配置的微信小程序(使用小程序appid + 页面地址)
-            
 -   **太古地产:** 点击后弹出授权提醒
-    
     -   勾选同意并**确认**后,显示离开提示,点击确认时调用太古地产接口,然后跳转至后端返回的太古地产免登地址。
-        
-    -   **点击取消:** 关闭授权提醒。
-        
-        ![](../../../../../.resources/image-1776679026345.png)
+    -   **点击取消:** 关闭授权提醒。![](../../../../../.resources/image-1776679026345.png)
 -   **龙腾:** 点击后弹出授权提醒
-    
     -   勾选同意并**确认**后,显示离开提示,点击确认时调用龙腾接口,然后跳转至后端返回的龙腾免登地址。
-        
-    -   **点击取消:** 关闭授权提醒。
-        
-        ![|45%](../../../../../.resources/image-1776679039096.png)
+    -   **点击取消:** 关闭授权提醒。![|45%](../../../../../.resources/image-1776679039096.png)
 
 ## 3\. 权益订单详情
 
 > 仅【券码】类型(是否权益平台兑换=是,商品类型=券码)领取成功后可进入此页面。
 
 -   兑换卡号:默认为掩码状态,点击右侧复制按钮可复制
-    
 -   兑换密钥:默认为掩码状态,点击右侧复制按钮可复制
-    
 -   操作:
-    
     -   隐藏:点击后兑换卡号和兑换密钥为掩码状态,卡号和密钥默认为掩码
-        
     -   显示:点击后变成明文显示
-        
 -   使用按钮:按钮文案取后台配置的"领取成功按钮文案"(默认值:"马上去使用"),点击跳转使用链接
-    
 
 ![](../../../../../.resources/image-1776679076106.png)
 
@@ -335,48 +241,32 @@
 逻辑:
 
 -   查询到openid→调接口→领取成功
-    
 -   查询不到openid、接口失败异常情况:系统异常
-    
 
 (1)商品展示信息
 
 -   权益图片:取后台"权益列表图标"字段
-    
 -   商品名称:取后台"权益名称"字段
-    
 -   副标题描述:取后台"权益副标题"字段
-    
 -   有效期:取SIP固定日期模式的有效期结束时间
-    
 -   按钮名称:根据3种状态分别展示
-    
     -   未领取:立即领取,点击领取该微信立减金
-        
     -   已领取:已领取,点击进入权益商品详情
-        
     -   已过期:已过期,不可点击
-        
 
 今日到期:已领取状态下,有效期结束日 = 当前日。
 
 (2)进入页面,默认展示客户名下所有 未领取、已领取、已过期的不同面值立减金。
 
 -   未领取:客户有权益点 且 有效期结束时间 < 当前时间;
-    
 -   已领取:实质是客户的立减金订单,有效期结束时间 < 当前时间;
-    
 -   已过期:有效期结束时间 >= 当前时间。
-    
 
 (3)展示顺序按照:未领取->已领取->已过期
 
 -   未领取:按照权益点有效期结束时间,先到期先展示;
-    
 -   已领取:按照权益下单时间,先下单先展示;
-    
 -   已过期:按照权益点有效期结束时间,先到期先展示。
-    
 
 (4)页面支持筛选不同状态的商品;不同筛选状态下,没有商品信息,则展示"暂无立减金"。
 

BIN
工作空间/产研/权益/汇丰全行/需求文档/汇丰需求文档 (1).pdf


+ 514 - 0
工作空间/产研/权益/汇丰全行/需求文档/组装页.md

@@ -0,0 +1,514 @@
+# 组装页前后台需求文档
+
+版本日期:2026-05-31
+
+## 一、业务流程图
+
+### 1.1 后台配置与发布流程
+
+```mermaid
+flowchart TD
+    A["运营进入页面管理 / 组装页"] --> B["查询或新建组装页"]
+    B --> C{"是否已有页面 ID"}
+    C -- "否,新建" --> D["填写组装页名称和基础配置"]
+    C -- "是,编辑" --> E["加载已有草稿或线上配置"]
+    D --> F["添加并配置页面模块"]
+    E --> F
+    F --> G{"点击保存草稿或发布上线"}
+    G -- "保存草稿" --> H{"基础字段与强校验是否通过"}
+    G -- "发布上线" --> I{"发布校验是否通过"}
+    H -- "否" --> J["提示错误并停留当前页面"]
+    I -- "否" --> J
+    H -- "是" --> K["保存草稿版本"]
+    I -- "是" --> L["生成或更新线上发布版本"]
+    K --> M["可生成草稿预览链接"]
+    L --> N["可生成正式 H5 / 小程序链接"]
+```
+
+### 1.2 移动端访问与渲染流程
+
+```mermaid
+flowchart TD
+    A["客户打开组装页链接"] --> B{"链接是否包含 draft=1"}
+    B -- "是" --> C["读取草稿预览配置"]
+    B -- "否" --> D["读取已发布配置"]
+    C --> E{"页面配置是否存在"}
+    D --> E
+    E -- "否" --> F["展示页面不存在或已下线提示"]
+    E -- "是" --> G["读取组装页名称作为导航标题"]
+    G --> H["按模块 sort 顺序渲染"]
+    H --> I{"存在权益商品模块"}
+    I -- "否" --> J["渲染静态模块和按钮"]
+    I -- "是" --> K["获取客户标签 / MSC group/ 权益资格"]
+    K --> L["过滤并展示可见权益商品"]
+    L --> J
+```
+
+### 1.3 按钮点击与外部跳转流程
+
+```mermaid
+flowchart TD
+    A["用户点击按钮"] --> B{"点击动作"}
+    B -- "跳转链接" --> C["读取按钮跳转链接"]
+    B -- "弹窗提示" --> D["展示底部提示弹窗"]
+    D --> E{"用户点击确认"}
+    E -- "否,取消或关闭" --> F["关闭弹窗,留在当前页"]
+    E -- "是" --> G{"确认按钮是否配置跳转链接"}
+    G -- "否" --> F
+    G -- "是" --> C
+    C --> H{"是否第三方外部域名"}
+    H -- "否" --> I["直接跳转"]
+    H -- "是" --> J["展示离开汇丰中国确认弹窗"]
+    J --> K{"用户点击继续前往"}
+    K -- "否" --> F
+    K -- "是" --> I
+```
+
+## 二、后台配置需求
+
+### 2.1 后台入口与页面列表
+
+后台入口:`定制功能 / 汇丰银行 / 页面管理 / 组装页`
+
+| 功能  | 需求说明 | 边界规则 |
+| --- | --- | --- |
+| 查询  | 支持按页面 ID、页面名称查询 | 页面名称支持模糊查询;页面 ID 支持精确或包含查询,以后端实现为准 |
+| 重置  | 清空查询条件并刷新列表 | 重置后展示全部组装页 |
+| 新建组装页 | 进入新建编辑态 | 新建时页面 ID 显示“保存后生成” |
+| 编辑  | 进入组装页编辑态 | 编辑已发布页面时,未发布修改不影响当前线上版本 |
+| 链接  | 打开“获取页面链接”弹窗 | 未保存页面无页面 ID,禁止获取链接并提示“请先保存组装页再获取链接” |
+| 状态展示 | 展示草稿、已上架 | 已上架代表存在正式发布版本;草稿代表仅后台可编辑或预览 |
+| 时间展示 | 展示创建时间、更新时间 | 新建保存后写入创建时间和更新时间;编辑保存后只更新更新时间 |
+
+列表字段:
+
+| 字段  | 说明  |
+| --- | --- |
+| 操作  | 编辑、链接 |
+| 页面 ID | 系统生成的唯一页面标识 |
+| 组装页名称 | 后台配置名称,也作为移动端导航标题 |
+| 发布状态 | 草稿、已上架 |
+| 创建时间 | 页面首次保存时间 |
+| 更新时间 | 最近一次保存草稿或发布上线时间 |
+
+### 2.2 编辑页整体结构与操作
+
+编辑页由四部分组成:
+
+1.  顶部操作栏:返回、页面状态、获取链接、保存草稿、发布上线。
+2.  页面整体基础信息:页面 ID、组装页名称。
+3.  微信分享卡片配置。
+4.  动态模块配置区:图片模块、权益商品模块、图文模块、按钮模块。
+
+页面状态规则:
+
+| 状态  | 触发条件 | 后台展示 | 移动端影响 |
+| --- | --- | --- | --- |
+| 新建未保存 | 点击“新建组装页”后未保存 | 页面 ID 为“保存后生成” | 不可生成链接,移动端不可访问 |
+| 草稿  | 保存草稿且未发布 | 草稿  | 仅草稿预览链接可访问 |
+| 已上架 | 发布上线成功且无未发布修改 | 正式线上环境 | 正式链接读取该版本 |
+| 有未发布的修改 | 已发布页面编辑后未发布 | 有未发布的修改 | 正式链接仍读取上一次发布版本;草稿预览读取最新草稿 |
+
+操作规则:
+
+| 操作  | 需求说明 | 校验与边界 |
+| --- | --- | --- |
+| 返回  | 返回组装页列表 | 如存在未保存修改,应弹出确认:“当前修改未保存,确认返回?” |
+| 保存草稿 | 保存当前配置为草稿版本 | 必须校验基础字段和已添加模块的必填项;保存成功后生成页面 ID |
+| 发布上线 | 将当前配置发布为正式版本 | 在草稿校验基础上,要求至少存在 1 个可展示模块 |
+| 获取链接 | 生成正式链接和草稿预览链接 | 未保存页面禁止生成;未发布页面只展示草稿预览链接 |
+
+组装页名称规则:
+
+| 字段  | 规则  |
+| --- | --- |
+| 是否必填 | 保存草稿、发布上线均必填 |
+| 长度  | 1 至 40 个中文字符,英文、数字、空格按 1 个字符计 |
+| 用途  | 后台列表展示、移动端导航标题、小程序页面标题 |
+| 空值处理 | 为空时阻断保存并在字段下方提示“请输入组装页名称” |
+
+> 当前 Demo 中空名称会自动兜底为“未命名组装页”。正式需求不保留该行为,以必填校验为准。
+
+### 2.3 获取页面链接
+
+点击“获取链接”后展示链接弹窗,支持选择 Campaign ID、Channel ID,生成带投放参数的链接。
+
+| 链接类型 | 展示条件 | 链接格式 | 用途  |
+| --- | --- | --- | --- |
+| 正式 H5 链接 | 页面状态为已上架 | `https://hsbc.com/assembly?id={pageId}` | 正式投放 |
+| 正式小程序链接 | 页面状态为已上架 | `hsbc-app://assembly?id={pageId}` | 小程序或 App 内打开 |
+| 草稿预览链接 | 页面已保存 | `https://test.hsbc.com/assembly?id={pageId}&draft=1` | 内部测试预览 |
+
+参数拼接规则:
+
+| 参数  | 来源  | 规则  |
+| --- | --- | --- |
+| `id` | 页面 ID | 必填  |
+| `draft` | 是否草稿预览 | 草稿预览链接固定为 `draft=1` |
+| `CampaignId` | Campaign 下拉选择 | 选填;选择后拼接到链接 |
+| `Channelid` | Channel 下拉选择 | 选填;选择后拼接到链接 |
+
+边界规则:
+
+1.  未发布页面不展示正式 H5 链接和正式小程序链接。
+2.  Campaign ID、Channel ID 清空时,不拼接对应参数。
+3.  复制链接成功后提示“链接已复制到剪贴板”。
+4.  移动端需透传 Campaign ID、Channel ID 到埋点和后续跳转链路,便于归因。
+
+### 2.4 微信分享卡片配置
+
+微信分享卡片配置位于页面基础信息下方,用于控制小程序环境内的分享能力。
+
+| 字段  | 类型  | 必填规则 | 移动端消费规则 |
+| --- | --- | --- | --- |
+| 自定义微信分享 | 复选框 / 开关 | 非必填 | 开启后允许小程序分享;关闭后禁用小程序原生分享入口 |
+| 分享缩略图 | 图片上传 | 开启自定义分享后必填 | 作为微信聊天卡片缩略图 |
+| 分享标题 | 单行文本 | 开启自定义分享后必填 | 作为微信聊天卡片标题 |
+
+图片规则:
+
+| 项目  | 规则  |
+| --- | --- |
+| 文件格式 | JPG、JPEG、PNG |
+| 建议尺寸 | 100px x 100px |
+| 上传数量 | 仅 1 张 |
+| 替换  | 再次上传覆盖原图 |
+| 发布校验 | 开启自定义分享且未上传缩略图时,阻断保存或发布 |
+
+移动端规则:
+
+1.  非小程序环境打开组装页时,不展示微信原生分享控制逻辑。
+2.  小程序环境且自定义分享关闭时,前端调用小程序能力禁用分享菜单。
+3.  小程序环境且自定义分享开启时,前端向小程序分享 SDK 注入分享标题、分享缩略图和当前页面链接。
+4.  分享出去的链接必须携带当前页面 ID;如原链接含 Campaign ID、Channel ID,分享链接需保留参数。
+
+### 2.5 动态模块通用规则
+
+组装页支持以下模块:
+
+| 模块  | 类型  | 是否可重复 | 是否可复制 | 是否可删除 | 是否可排序 |
+| --- | --- | --- | --- | --- | --- |
+| 图片模块 | `image` | 是   | 是   | 是   | 是   |
+| 权益商品模块 | `privilege` | 否,每页最多 1 个 | 否   | 是   | 是   |
+| 图文模块 | `richtext` | 是   | 是   | 是   | 是   |
+| 按钮模块 | `buttonGroup` | 是   | 是   | 是   | 是   |
+
+添加规则:
+
+1.  新建组装页时默认不含任何业务模块。
+2.  页面底部固定展示添加模块按钮:图片模块、权益商品模块、图文模块、按钮模块。
+3.  页面已存在权益商品模块时,添加区隐藏“权益商品模块”按钮。
+4.  点击添加模块后,新模块追加到当前模块列表末尾。
+
+排序规则:
+
+| 场景  | 规则  |
+| --- | --- |
+| 模块排序 | 点击模块右上角“排序”,输入目标序号,确认后移动到目标位置 |
+| 序号范围 | 最小为 1,最大为当前模块数量 |
+| 无效输入 | 输入为空、非数字、超出范围时不执行移动,并提示“请输入有效的顺序位置” |
+| 同位置移动 | 目标位置等于当前位置时关闭气泡,不改变顺序 |
+
+复制规则:
+
+1.  图片、图文、按钮模块点击复制后,复制当前模块的全部配置内容。
+2.  复制出的模块生成新的模块 ID,默认插入到原模块下方。
+3.  权益商品模块不可复制,点击复制时提示“权益商品模块每页仅限配置一个,无法复制”。
+
+删除规则:
+
+1.  点击模块右上角“删除”后弹出二次确认:“确定删除该模块吗?”
+2.  确认后删除整个模块及其内部配置。
+3.  删除后不立即保存到后端,需点击保存草稿或发布上线后生效。
+
+发布校验规则:
+
+| 校验项 | 保存草稿 | 发布上线 |
+| --- | --- | --- |
+| 组装页名称 | 必填  | 必填  |
+| 至少 1 个展示模块 | 不强制 | 必填  |
+| 已添加图片模块上传图片 | 必填  | 必填  |
+| 已添加图文模块内容 | 必填  | 必填  |
+| 已添加按钮模块按钮文案 | 必填  | 必填  |
+| 按钮动作为跳转链接时填写链接 | 必填  | 必填  |
+| 按钮动作为弹窗提示时填写弹窗标题、描述、确认按钮文案 | 必填  | 必填  |
+| 微信分享开启时填写缩略图和标题 | 必填  | 必填  |
+
+### 2.6 图片模块
+
+后台配置:
+
+| 字段  | 类型  | 规则  |
+| --- | --- | --- |
+| 图片  | 图片上传 | 必填;仅支持 JPG、JPEG、PNG;建议宽度 750px;高度不限 |
+
+移动端展示:
+
+1.  图片按模块顺序展示。
+2.  图片宽度为页面通栏 `100%`,左右无边距。
+3.  高度不固定,按图片原始宽高比等比缩放。
+4.  图片不支持点击跳转。
+5.  图片加载失败时,该图片模块不展示,并记录前端错误日志。
+
+边界:
+
+1.  添加图片模块但未上传图片时,保存草稿和发布上线均阻断。
+2.  上传新图片后覆盖旧图片。
+3.  图片超过后端限制大小时,上传失败并提示“图片大小超出限制,请重新上传”。
+
+### 2.7 图文模块
+
+后台配置:
+
+| 字段  | 类型  | 规则  |
+| --- | --- | --- |
+| 图文内容 | 富文本编辑器 | 必填;支持文字、图片、链接、基础标题、列表、PDF 附件、表格 |
+
+富文本能力:
+
+| 能力  | 后台配置 | 移动端展示 |
+| --- | --- | --- |
+| 文字样式 | 支持加粗、斜体、下划线、标题、列表 | 按富文本样式渲染 |
+| 图片  | 支持正文内插入图片 | 宽度自适应,不撑破屏幕 |
+| 超链接 | 支持给文字配置 URL | 点击后走链接跳转规则 |
+| PDF 附件 | 支持上传 PDF 并插入附件标识 | 点击后拉起浏览器或系统 PDF 预览 |
+| 表格  | 支持基础表格 | 表格宽度超过屏幕时,外层横向滚动 |
+
+安全与边界:
+
+1.  移动端渲染前需对富文本进行安全过滤,禁止执行脚本。
+2.  富文本为空、仅空格、仅空标签时视为空内容。
+3.  富文本内链接也需执行外部域名识别;第三方外链必须展示“离开汇丰中国”确认弹窗。
+4.  富文本内图片加载失败时展示破图兜底或隐藏失败图片,不影响其他内容展示。
+
+### 2.8 权益商品模块
+
+权益商品模块用于展示与当前组装页关联的权益商品。
+
+后台配置:
+
+| 字段  | 类型  | 规则  |
+| --- | --- | --- |
+| 可配置大标题 | 单行文本 | 选填;为空时移动端隐藏模块标题 |
+| 权益商品列表 | 自动回显列表 | 来源于权益商品管理中选择“组装页=显示”且包含当前组装页的商品 |
+| 商品排序 | 行级排序 | 支持调整当前组装页内权益商品展示顺序 |
+
+商品排序仅作用于当前组装页,不影响权益首页/列表页排序,也不影响同一权益商品在其他组装页中的展示顺序。
+
+唯一性规则:
+
+1.  单个组装页最多添加 1 个权益商品模块。
+2.  已添加权益商品模块后,添加模块按钮区不再展示“权益商品模块”。
+3.  权益商品模块不支持复制。
+
+与权益商品管理的关系:
+
+在“借记卡权益 / 添加权益 / 编辑权益 / 更多设置 / 显示页面”中,支持配置:
+
+| 字段  | 规则  |
+| --- | --- |
+| 权益首页/列表页 | 选择显示或不显示 |
+| 组装页 | 选择显示或不显示 |
+| 组装页列表 | 当“组装页=显示”时,必须选择一个或多个组装页 |
+
+权益商品进入组装页展示列表需同时满足:
+
+1.  权益商品状态为已上架。
+2.  权益商品审核状态为审核通过。
+3.  权益商品配置了“组装页=显示”。
+4.  权益商品选择的组装页包含当前页面 ID。
+5.  如配置了展示时间限制,当前时间在展示时间范围内。
+6.  如配置了展示客群限制,当前客户命中配置客群。
+7.  如配置了领取客群或发放计划限制,移动端按领取资格决定点击后的领取结果;不满足领取资格的商品是否展示,按权益商品的展示规则决定。
+
+客户数据来源:
+
+| 数据  | 字段建议 | 说明  |
+| --- | --- | --- |
+| 客户 MSC Group List | `mscCodeList` | 用于判断客户所属 MSC 类型 |
+| 客户标签列表 | `tagIds` | 用于判断展示客群限制 |
+| 权益资格 | `eligibleProductIds` 或权益资格接口返回 | 用于判断客户是否可领取或可跳转 |
+
+移动端展示:
+
+1.  模块大标题为空时,只展示权益商品列表。
+2.  无可展示商品时,整个权益商品模块隐藏,包括大标题。
+3.  商品项展示圆形图标、权益名称、权益简介和右箭头。
+4.  商品图标为空时展示默认权益图标。
+5.  商品名称超长时最多展示 1 行,超出省略。
+6.  商品简介超长时最多展示 2 行,超出省略。
+
+点击交互:
+
+1.  点击商品项后,移动端先校验登录态。
+2.  未登录时进入 SSO 登录,登录完成后回到当前商品跳转链路。
+3.  银行自有或荣数商品走权益平台详情或领取页。
+4.  第三方权益如果配置“没有详情页”,从列表直接跳转外部权益链接。
+5.  第三方权益如果配置“有详情页”,先进入权益详情页,再由详情页承接领取或外部跳转。
+6.  跳转第三方 H5 前必须展示“离开汇丰中国”确认弹窗。
+
+> 当前 Demo 的权益商品模块内置了模拟 `items`。正式需求以“权益商品管理”联动回显为准,模块内不手工新增商品内容,只维护标题和当前页商品排序。
+
+### 2.9 按钮模块
+
+按钮模块用于配置页面操作入口。一个按钮模块内可添加多个按钮,移动端按后台按钮顺序纵向展示。
+
+按钮字段:
+
+| 字段  | 类型  | 必填  | 规则  |
+| --- | --- | --- | --- |
+| 按钮文案 | 单行文本 | 是   | 1 至 10 个中文字符 |
+| 点击动作 | 下拉选择 | 是   | 跳转链接、弹窗提示 |
+| 按钮样式 | 下拉选择 | 是   | 突出显示(红色)、次要操作(白色) |
+| 跳转链接类型 | 单选  | 条件必填 | 点击动作=跳转链接时展示并必填,支持 H5 链接跳转、固定链接跳转、小程序跳转 |
+| 目标链接 | 下拉选择 | 条件必填 | 跳转链接类型=固定链接跳转时展示并必填,选项由后台维护,当前 demo 包含“太古地产”“龙腾” |
+| 配置链接 | URL 输入框 | 条件必填 | 跳转链接类型=H5 链接跳转时展示并必填 |
+| 小程序 AppID | 单行文本 | 条件必填 | 跳转链接类型=小程序跳转时展示并必填 |
+| 小程序页面路径 | 单行文本 | 条件必填 | 跳转链接类型=小程序跳转时展示并必填 |
+| 弹窗标题 | 单行文本 | 条件必填 | 点击动作=弹窗提示时必填,最多 20 个中文字符 |
+| 弹窗描述 | 富文本编辑器 | 条件必填 | 点击动作=弹窗提示时必填 |
+| 左侧取消按钮文案 | 单行文本 | 条件必填 | 点击动作=弹窗提示时展示,默认“取消” |
+| 右侧确认按钮展示 | 勾选框 | 条件必填 | 点击动作=弹窗提示时展示,默认展示 |
+| 右侧确认按钮文案 | 单行文本 | 条件必填 | 右侧确认按钮展示=是时必填,最多 6 个中文字符,默认“确认” |
+| 确认按钮跳转链接类型 | 单选  | 条件必填 | 右侧确认按钮展示=是时展示并必填,支持 H5 链接跳转、固定链接跳转、小程序跳转 |
+| 确认按钮目标链接 | 下拉选择 | 条件必填 | 确认按钮跳转链接类型=固定链接跳转时展示并必填,选项由后台维护 |
+| 确认按钮配置链接 | URL 输入框 | 条件必填 | 确认按钮跳转链接类型=H5 链接跳转时展示并必填 |
+| 确认按钮小程序 AppID | 单行文本 | 条件必填 | 确认按钮跳转链接类型=小程序跳转时展示并必填 |
+| 确认按钮小程序页面路径 | 单行文本 | 条件必填 | 确认按钮跳转链接类型=小程序跳转时展示并必填 |
+
+按钮组内部操作:
+
+| 操作  | 规则  |
+| --- | --- |
+| 添加按钮 | 点击“添加按钮”后在按钮列表末尾新增按钮,默认文案为“新按钮”,默认样式为次要操作,默认动作为跳转链接 |
+| 内部排序 | 输入目标序号后移动按钮 |
+| 内部删除 | 点击删除图标后删除当前按钮;删除后如按钮列表为空,移动端不展示该按钮模块 |
+
+移动端展示:
+
+1.  按钮在页面内容流中展示,不固定在屏幕底部。
+2.  按钮宽度为内容区域 `100%`,按钮之间保持固定间距。
+3.  突出显示按钮为汇丰红底白字。
+4.  次要操作按钮为白底深色字,带浅灰描边。
+5.  同一按钮模块配置多个按钮时,按后台顺序纵向排列,后台不限制按钮数量。
+
+跳转链接规则:
+
+1.  点击动作=跳转链接时,必须完整填写当前跳转链接类型对应字段,否则阻断保存并提示“保存失败:按钮模块中存在未填写完整的跳转链接配置!”。
+2.  H5 链接跳转保存 `linkType=h5`、`linkH5`,并同步兼容字段 `link=linkH5`。
+3.  固定链接跳转保存 `linkType=fixed`、`fixedLink`,并同步兼容字段 `link=fixedLink`;切换到固定链接时如未选择目标链接,默认回填“太古地产”。
+4.  小程序跳转保存 `linkType=miniProgram`、`miniAppId`、`miniAppPath`,兼容字段 `link` 置空。
+5.  切换跳转链接类型时,清空未选中类型对应字段,避免保存无效冗余配置。
+6.  内部汇丰域名、App 内部路径或固定内部目标直接跳转。
+7.  第三方外部域名跳转前展示“离开汇丰中国”确认弹窗。
+8.  URL 格式非法时阻断保存并提示“请输入正确的跳转链接”。
+
+弹窗提示规则:
+
+1.  点击按钮后展示底部弹窗。
+2.  弹窗标题、描述、左侧取消按钮文案、右侧确认按钮展示状态和右侧确认按钮文案读取后台配置。
+3.  弹窗右上角固定展示关闭按钮。
+4.  弹窗底部固定展示左侧取消按钮;右侧确认按钮根据“展示”开关决定是否展示。
+5.  右侧确认按钮展示=是时,必须完整填写确认按钮跳转链接类型对应字段,否则阻断保存并提示“保存失败:按钮模块中存在未填写完整的跳转链接配置!”。
+6.  确认按钮跳转链接配置同样支持 H5 链接跳转、固定链接跳转、小程序跳转;字段保存规则与按钮跳转一致,对应字段为 `confirmLinkType`、`confirmFixedLink`、`confirmLinkH5`、`confirmMiniAppId`、`confirmMiniAppPath`,并同步兼容字段 `confirmLink`。
+7.  右侧确认按钮展示=否时,移动端不展示确认按钮,也不校验确认按钮跳转配置。
+8.  点击取消、关闭、遮罩层时关闭弹窗,不执行跳转。
+9.  点击确认后,如确认为第三方外部 H5 域名,先关闭底部弹窗,再展示“离开汇丰中国”确认弹窗。
+
+外部跳转确认弹窗固定文案:
+
+| 字段  | 文案  |
+| --- | --- |
+| 标题  | 您正在离开汇丰中国 |
+| 描述  | 请注意,外部网站的政策与我们网站的条款和条件以及隐私政策不同。将在新浏览器窗口或选项卡中打开下一个网站。 |
+| 取消按钮 | 取消  |
+| 确认按钮 | 继续前往 |
+
+## 三、移动端展示需求
+
+### 3.1 页面访问
+
+移动端通过页面 ID 访问组装页。
+
+| 场景  | 处理规则 |
+| --- | --- |
+| 页面 ID 为空 | 展示错误页:“页面参数错误” |
+| 页面不存在 | 展示错误页:“页面不存在或已下线” |
+| 页面未发布且非草稿预览 | 展示错误页:“页面不存在或已下线” |
+| 草稿预览链接 | 仅内部测试环境可访问,读取草稿配置 |
+| 正式链接 | 读取最近一次发布配置 |
+
+### 3.2 页面骨架
+
+| 区域  | 规则  |
+| --- | --- |
+| 状态栏 | 使用小程序或 App 容器原生状态栏 |
+| 导航栏 | 标题读取组装页名称 |
+| 返回按钮 | 点击返回上一页;无上一页时返回权益首页或关闭当前 WebView |
+| 内容区 | 白底,自上而下按模块顺序渲染 |
+| 安全区 | iOS 底部安全区需留白,避免按钮或内容被遮挡 |
+
+### 3.3 模块渲染顺序
+
+1.  移动端严格按后台保存的模块顺序渲染。
+2.  后台未配置任何模块时,正式页面不可发布;草稿预览展示空白内容区。
+3.  某个模块因数据为空或客户不命中而隐藏时,不占位,不影响后续模块展示。
+4.  同类型模块可以出现多次,权益商品模块除外。
+
+### 3.4 微信小程序分享
+
+| 条件  | 结果  |
+| --- | --- |
+| 非小程序环境 | 不处理微信小程序原生分享 |
+| 小程序环境且自定义分享关闭 | 禁用右上角分享能力 |
+| 小程序环境且自定义分享开启 | 分享标题、缩略图、链接使用后台配置 |
+
+分享链接规则:
+
+1.  分享链接使用正式页面链接,不使用草稿预览链接。
+2.  原访问链接带 Campaign ID、Channel ID 时,分享链接保留参数。
+3.  分享缩略图为空或分享标题为空时,后台不允许发布,因此移动端不做二次兜底。
+
+### 3.5 外部链接识别
+
+后端根据汇丰内部域名白名单识别链接是否为外部链接。白名单内链接直接跳转,白名单外链接展示离开汇丰中国确认弹窗。
+
+白名单由后端维护,范围包含:
+
+| 类型  | 示例  |
+| --- | --- |
+| 汇丰 H5 域名 | `hsbc.com`、`hsbc.com.cn` 及项目实际域名 |
+| 小程序内部路径 | `/pages/`、`hsbc-app://` |
+| 测试域名 | `test.hsbc.com`,仅测试环境生效 |
+
+## 四、验收标准
+
+### 4.1 后台验收
+
+| 编号  | 验收项 | 通过标准 |
+| --- | --- | --- |
+| A1  | 新建组装页 | 输入组装页名称并保存草稿后生成页面 ID,列表出现新记录 |
+| A2  | 组装页名称必填 | 名称为空时保存草稿和发布上线均失败 |
+| A3  | 添加模块 | 图片、图文、按钮模块可多次添加;权益商品模块最多添加 1 次 |
+| A4  | 模块排序 | 输入合法序号后模块移动到目标位置 |
+| A5  | 模块复制 | 图片、图文、按钮模块可复制,权益商品模块不可复制 |
+| A6  | 模块删除 | 删除前二次确认,确认后模块从编辑区移除 |
+| A7  | 分享配置校验 | 开启自定义分享但缺少缩略图或标题时保存失败 |
+| A8  | 按钮链接校验 | 按钮动作为跳转链接,或弹窗右侧确认按钮开启但对应跳转配置未填写完整时保存失败 |
+| A9  | 草稿和正式链接 | 草稿页面只展示预览链接,已上架页面展示正式链接和预览链接 |
+| A10 | 权益商品联动 | 商品配置组装页显示后,在对应组装页权益商品模块中回显 |
+
+### 4.2 移动端验收
+
+| 编号  | 验收项 | 通过标准 |
+| --- | --- | --- |
+| M1  | 标题回显 | 导航标题等于后台组装页名称 |
+| M2  | 模块顺序 | 移动端模块顺序与后台配置一致 |
+| M3  | 图片展示 | 图片通栏展示,按原始比例等比缩放 |
+| M4  | 富文本展示 | 图片、链接、PDF、表格均可正常展示或预览 |
+| M5  | 权益商品过滤 | 未上架、未审核通过、不属于当前页面、不命中客户条件的商品不展示 |
+| M6  | 权益商品空列表 | 无可见商品时隐藏整个权益商品模块 |
+| M7  | 按钮跳转 | H5、固定链接、小程序跳转按后台配置执行;内部链接直接跳转,外部链接先展示离开汇丰确认弹窗 |
+| M8  | 弹窗按钮 | 弹窗取消关闭不跳转;确认按钮按后台展示开关控制,展示时按配置的跳转规则执行 |
+| M9  | 微信分享 | 开关关闭时小程序禁用分享;开启时分享卡片使用后台标题和缩略图 |
+| M10 | 异常页面 | 页面不存在、未发布、ID 为空时展示错误提示 |

+ 701 - 0
工作空间/产研/权益/汇丰全行/需求文档/组装页2.md

@@ -0,0 +1,701 @@
+# 汇丰权益组装页需求文档
+
+## 一、需求范围说明
+
+本文档覆盖“页面管理-组装页”的后台配置能力,以及组装页在移动端运行环境中的展示、分享、权益动态筛选、按钮跳转和弹窗交互规则。后台配置的是跳转目标地址类型,包括 H5 地址或小程序 AppID/页面路径;客户实际使用环境为 App 内 H5 容器或微信小程序内页面。
+
+需求范围包括:
+
+-   移动端组装页:页面标题、微信分享、图片模块、图文模块、权益商品模块、按钮模块、底部弹窗、第三方跳转拦截提示。移动端运行环境包括 App 内 H5 和微信小程序内页面。
+-   后台管理端:组装页列表、查询、分页、新建、编辑、保存草稿、发布上线、获取链接、模块新增/复制/删除/排序、微信分享卡片配置、各模块字段配置。
+-   关联配置:借记卡/信用卡权益商品的“显示页面-组装页”选择,决定权益商品是否可在指定组装页中被动态展示。
+-   接口范围:当前未提供正式接口说明,本文根据 PDF、PC Demo 与 H5 Demo 设计虚拟接口,均标记为【虚拟接口,待技术确认】。
+
+## 二、功能范围与模块结构
+
+### 2.1 移动端模块结构
+
+组装页是可灵活配置的营销活动或线下沙龙引导落地页。页面内容由后台按模块顺序拼装,移动端在 App 内 H5 或微信小程序内按配置顺序自上而下展示。后台的链接配置项用于描述目标类型,选择 H5 时配置 H5 地址,选择小程序时配置 AppID 和页面路径;移动端再根据当前运行环境和端能力执行打开或跳转。
+
+-   顶部系统状态栏与导航栏:展示返回入口和页面标题。页面标题读取后台“组装页名称”,用于 Page Title 与导航栏标题回显。
+-   微信分享能力:仅小程序环境生效。后台开启自定义微信分享后,前端注入分享标题、缩略图与当前页面链接;关闭时禁用分享菜单。
+-   图片模块:作为页面头图或通栏广告图展示,移动端不支持点击。
+-   图文模块:展示活动说明、正文、文字链接与外链图标。正文由后台富文本配置生成。后台可添加多个图文模块,移动端按排序多次出现时仍属于同一个功能模块,本文只描述一次完整规则。
+-   权益商品模块:展示可配置大标题和当前客户有权限看到的权益商品列表。具体商品来自全局权益商品配置,并结合客户标签、发放资格和组装页展示配置动态筛选。
+-   按钮模块:展示一个或多个操作按钮,支持红色主按钮和白色次按钮;点击动作支持直接跳转或先弹出底部提示弹窗。
+-   底部提示弹窗:由按钮模块配置触发,展示弹窗标题、描述、取消按钮、确认按钮及确认按钮跳转配置。
+-   第三方跳转拦截弹窗:当跳转目标识别为第三方页面时,在真正跳转前提示“您正在离开汇丰中国”,客户确认后才跳转。
+
+### 2.2 后台/管理端配置结构
+
+后台入口为“汇丰银行 / 页面管理 / 组装页”。后台通过列表和编辑页管理多个组装页。
+
+-   列表查询区:支持按页面 ID、页面名称筛选组装页。
+-   列表区:展示操作、页面 ID、组装页名称、发布状态、创建时间、更新时间,并提供分页。发布状态包括“草稿”“待发布”“正式”。
+-   新建/编辑页基础信息区:配置组装页名称,页面 ID 由系统保存后自动生成。
+-   微信分享卡片配置区:控制是否启用自定义微信分享,并配置分享缩略图和分享标题。
+-   模块配置区:支持图片模块、权益商品模块、图文模块、按钮模块的组合配置。
+-   模块操作区:支持模块排序、复制、删除;权益商品模块每页仅允许一个,不支持复制。
+-   按钮配置区:支持配置按钮文案、点击动作、按钮样式、跳转目标、弹窗内容和弹窗确认按钮跳转。后台配置的跳转目标可以是 H5 地址、小程序 AppID/页面路径,或固定目标“太古地产”“龙腾”。
+-   获取链接弹窗:支持生成正式环境 H5 链接、小程序链接和草稿预览链接,并可选择 Campaign ID、Channel ID 拼接到链接参数。草稿状态仅生成草稿预览链接;待发布和正式状态可生成正式环境链接与草稿预览链接。
+
+### 2.3 前后台关系概览
+
+组装页本身由后台模块配置驱动,权益商品列表则由权益商品管理、客户标签和发放状态共同决定。后台保存草稿后可以获取预览链接;发布上线后才展示正式链接。
+
+| 移动端模块 | 后台/管理端配置 | 依赖接口 | 用户操作影响 | 说明  |
+| --- | --- | --- | --- | --- |
+| 页面标题 | 组装页名称 | 查询组装页详情【虚拟接口,待技术确认】 | 无   | 同时用于后台列表检索和移动端导航栏标题 |
+| 微信分享 | 自定义微信分享、分享缩略图、分享标题 | 查询组装页详情【虚拟接口,待技术确认】 | 小程序用户分享页面 | 分享链接需保留页面 ID、Campaign ID、Channel ID |
+| 图片模块 | 图片模块上传图 | 查询组装页详情【虚拟接口,待技术确认】 | 无   | 移动端按图片比例自适应展示,不支持点击 |
+| 图文模块 | 富文本编辑器内容 | 查询组装页详情【虚拟接口,待技术确认】 | 点击正文内文字链接 | 富文本中的链接通过内置浏览器打开;第三方链接需弹出离开汇丰提示 |
+| 权益商品模块 | 权益商品模块大标题;权益商品“显示页面-组装页” | 查询组装页可见权益【虚拟接口,待技术确认】 | 点击权益商品进入承接页 | 按客户标签和发放资格动态筛选,未匹配则模块隐藏 |
+| 按钮模块 | 按钮文案、样式、动作、跳转目标、弹窗 | 查询组装页详情【虚拟接口,待技术确认】 | 点击按钮、弹窗确认/取消 | 后台配置 H5 地址或小程序参数;移动端在 App 内或小程序内执行跳转 |
+| 获取链接 | Campaign ID、Channel ID 选择 | 查询 Campaign 列表、查询 Channel 列表【虚拟接口,待技术确认】 | 后台复制链接用于投放 | 草稿仅展示预览链接;正式/已修改状态展示正式链接和预览链接 |
+
+## 三、移动端功能详细说明
+
+### 3.1 页面头部导航栏与标题
+
+3.1.1 模块说明
+
+页面头部位于组装页顶部,包含返回按钮和标题。标题用于告诉客户当前页面主题,必须读取后台配置的“组装页名称”。
+
+3.1.2 展示规则
+
+客户打开组装页后,前端根据页面 ID 查询组装页详情。若接口返回页面名称,则导航栏展示该名称;若页面名称为空或接口异常,展示兜底标题“组装页”,并记录异常日志。
+
+3.1.3 字段说明
+
+| 字段/元素 | 类型  | 展示位置 | 数据来源 | 来源说明 | 展示规则 | 交互规则 | 异常规则 |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+| 返回按钮 | 图标按钮 | 导航栏左侧 | 系统默认 | App 内 H5 或小程序容器固定导航能力 | 始终展示 | 点击返回上一页;无上一页时返回权益首页或关闭 WebView,具体承接待技术确认 | 返回失败时停留当前页 |
+| 页面标题 | 文本  | 导航栏居中 | 后台配置 | 后台“组装页名称”字段 | 单行展示,超长省略 | 不可点击 | 为空时展示“组装页”并记录日志 |
+
+3.1.4 交互规则
+
+点击返回按钮时,优先执行端内返回;若当前页面为外部投放直接打开且无上一页,则应关闭当前 WebView 或跳转权益首页,具体由端能力确认。
+
+3.1.5 状态规则
+
+本模块无业务状态,仅区分正常、标题为空、接口失败三类展示情况。
+
+3.1.6 异常、空数据和边界规则
+
+页面 ID 缺失时,页面不加载组装页内容,展示错误提示“页面不存在或已失效”。页面未发布但非草稿预览链接访问时,展示“页面暂不可访问”。
+
+### 3.2 微信小程序分享
+
+3.2.1 模块说明
+
+微信分享能力只在小程序环境生效,用于将当前组装页分享给其他客户或群聊。
+
+3.2.2 展示规则
+
+客户在 App 内 H5 环境打开组装页时,不调用微信原生分享控制逻辑。客户在微信小程序内打开组装页时,若后台关闭“自定义微信分享”,前端调用小程序能力禁用分享菜单;若开启,则注入分享标题、分享缩略图和当前页面链接。
+
+3.2.3 字段说明
+
+| 字段/元素 | 类型  | 展示位置 | 数据来源 | 来源说明 | 展示规则 | 交互规则 | 异常规则 |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+| 自定义微信分享开关 | 布尔值 | 不直接展示 | 后台配置 | 后台“自定义微信分享”复选框 | 开启时允许分享,关闭时禁用分享菜单 | 用户点击小程序分享入口时生效 | 取值异常按关闭处理 |
+| 分享标题 | 文本  | 微信分享卡片 | 后台配置 | 后台“分享标题”字段 | 开启自定义分享后必填并注入分享 SDK | 用户分享时展示 | 为空时禁用自定义分享并记录日志 |
+| 分享缩略图 | 图片  | 微信分享卡片 | 后台配置 | 后台“分享缩略图”字段,建议 100x100 | 开启自定义分享后必填 | 用户分享时展示 | 图片加载失败时使用小程序默认分享图,待技术确认 |
+| 分享链接 | 链接  | 微信分享卡片 | 前端计算 | 当前页面 URL + 页面 ID + 原 Campaign ID/Channel ID 参数 | 分享链接必须携带页面 ID;如原链接含 Campaign ID、Channel ID,需保留 | 被分享用户打开后按链接参数进入同一页面 | 参数拼接失败时至少保留页面 ID |
+
+3.2.4 交互规则
+
+用户在小程序内点击分享时,前端将当前页面 ID、Campaign ID、Channel ID 作为分享链接参数传出。被分享用户打开链接后,页面按页面 ID 查询配置,Campaign ID 与 Channel ID 用于后续投放归因和埋点。
+
+3.2.5 状态规则
+
+| 状态值 | 状态含义 | 展示文案 | 展示样式 | 可操作按钮 | 规则说明 |
+| --- | --- | --- | --- | --- | --- |
+| 关闭  | 后台未启用自定义分享 | 无   | 禁用分享菜单 | 无   | 小程序环境下禁用分享能力 |
+| 开启且配置完整 | 后台已启用且标题、缩略图完整 | 分享标题 | 微信分享卡片 | 分享  | 注入自定义标题、缩略图和页面链接 |
+| 开启但配置缺失 | 后台已启用但必填信息缺失 | 无   | 按关闭处理 | 无   | 需记录配置异常 |
+
+3.2.6 异常、空数据和边界规则
+
+小程序 SDK 初始化失败时,不影响页面浏览,但分享入口不可用。分享参数中 Campaign ID、Channel ID 为空时,不拼接对应参数。
+
+### 3.3 图片模块
+
+3.3.1 模块说明
+
+图片模块用于展示页面主视觉、广告图或分隔视觉。H5 Demo 中该模块位于页面顶部,作为通栏头图展示。
+
+3.3.2 展示规则
+
+后台可添加多个图片模块,每个图片模块在移动端按后台排序位置展示。图片宽度按屏幕 100% 展示,高度按图片原始比例自适应,不拉伸变形。
+
+3.3.3 字段说明
+
+| 字段/元素 | 类型  | 展示位置 | 数据来源 | 来源说明 | 展示规则 | 交互规则 | 异常规则 |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+| 图片  | 图片  | 模块配置顺序对应位置 | 后台配置 | 后台“图片模块-上传图片”字段,建议宽度 750px | 100% 宽度展示,高度按比例自适应 | 移动端不支持点击 | 图片为空时该模块不应发布;图片加载失败时展示占位并记录日志 |
+
+3.3.4 交互规则
+
+图片模块仅作静态视觉展示,不支持点击跳转、放大预览或长按操作。
+
+3.3.5 状态规则
+
+本模块无业务状态。
+
+3.3.6 异常、空数据和边界规则
+
+后台保存时必须校验图片已上传;若历史数据中图片为空,前端隐藏该图片模块并上报配置异常。图片格式、大小限制未在 Demo 中体现,需技术和设计补充确认。
+
+### 3.4 图文模块
+
+3.4.1 模块说明
+
+图文模块用于展示活动说明、沙龙介绍、规则说明等正文内容。后台通过富文本编辑器维护,移动端按富文本内容渲染。H5 Demo 中出现了两个图文区域,但它们都来源于后台同一种“图文模块”;如果后台配置多个图文模块,移动端只按排序重复渲染同一功能模块,不拆成多个不同需求点。
+
+3.4.2 展示规则
+
+图文模块按后台排序展示。每个图文模块都使用同一套展示、交互和异常规则;后台配置几次,移动端就按顺序渲染几段图文内容。富文本支持加粗、斜体、下划线、有序列表、无序列表、一级至三级标题、链接、图片和清除格式。PDF 原始需求强调字体由前端锁定为汇丰标准字体,富文本排版不得破坏移动端阅读。
+
+3.4.3 字段说明
+
+| 字段/元素 | 类型  | 展示位置 | 数据来源 | 来源说明 | 展示规则 | 交互规则 | 异常规则 |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+| 富文本内容 | 富文本 | 图文模块区域 | 后台配置 | 后台“图文模块-富文本编辑器内容” | 按 HTML 内容渲染,移动端需适配宽度 | 正文内链接可点击 | 内容为空时可保存但不建议发布;若 HTML 解析失败,展示纯文本兜底 |
+| 文字链接 | 文本链接 | 富文本正文内 | 后台配置 | 富文本中插入的链接 | 链接文字按加粗或链接样式展示,右侧可渲染外链图标 | 点击后打开配置链接;第三方链接先弹出离开汇丰提示 | 链接为空或格式非法时点击无响应并记录日志 |
+| 外链图标 | 图标  | 文字链接右侧 | 系统默认 | H5 Demo 中斜箭头外链图标 | 与文字链接同行展示 | 点击图标等同点击文字链接 | 图标加载失败不影响文字链接 |
+
+3.4.4 交互规则
+
+用户点击正文内链接时,前端判断链接目标。后台富文本中维护的是链接地址,移动端根据当前运行环境执行打开:App 内 H5 环境优先在 App WebView 或端内浏览器打开;小程序环境按小程序 WebView 能力或端约定打开。第三方链接需先展示“您正在离开汇丰中国”确认弹窗,用户点击“继续前往”后再打开目标链接。
+
+3.4.5 状态规则
+
+本模块无业务状态。
+
+3.4.6 异常、空数据和边界规则
+
+富文本内图片宽度不得超出屏幕。富文本中含不可识别标签时,前端应过滤高风险脚本,仅保留安全展示内容。具体白名单规则待技术确认。
+
+### 3.5 权益商品模块
+
+3.5.1 模块说明
+
+权益商品模块用于在组装页中展示客户可见的权益商品。该模块是组装页的核心动态区域,支持千人千面展示。
+
+3.5.2 展示规则
+
+每个组装页最多配置一个权益商品模块。后台可配置模块大标题,若大标题为空,移动端隐藏标题但仍可展示商品列表。商品列表不在组装页内手工录入,而是从全局权益商品列表中筛选出“显示页面-组装页”包含当前组装页、且客户满足权限/发放条件的商品。
+
+若当前客户没有任何匹配商品,则整个权益商品模块隐藏,不展示空态文案。
+
+3.5.3 字段说明
+
+| 字段/元素 | 类型  | 展示位置 | 数据来源 | 来源说明 | 展示规则 | 交互规则 | 异常规则 |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+| 模块大标题 | 文本  | 权益商品模块顶部 | 后台配置 | 组装页“权益商品模块-可配置大标题” | 为空时隐藏标题 | 不可点击 | 超长按一行或多行展示规则待设计确认 |
+| 权益图标 | 图片/图标 | 每个权益商品左侧 | 接口获取 | 查询组装页可见权益接口返回“权益图标” | 圆形区域展示 | 点击商品行任意区域触发跳转 | 图片为空时展示系统默认图标 |
+| 权益名称 | 文本  | 每个权益商品主标题 | 接口获取 | 查询组装页可见权益接口返回“权益名称” | 单行展示,超长省略 | 点击商品行进入承接页 | 为空时隐藏该商品并记录异常 |
+| 权益简介 | 文本  | 权益名称下方 | 接口获取 | 查询组装页可见权益接口返回“权益简介” | 单行或两行展示,超长省略 | 点击商品行进入承接页 | 为空时仅展示权益名称 |
+| 右侧箭头 | 图标  | 商品行右侧 | 系统默认 | H5 Demo 固定展示 | 表示可点击进入 | 点击等同商品行点击 | 无   |
+
+3.5.4 交互规则
+
+用户点击权益商品后,前端执行 SSO 登录或端内登录态校验,再打开该权益商品对应承接目标。后台权益商品可配置 H5 地址或小程序参数;移动端根据当前运行环境执行打开。承接页规则与权益商品配置有关:有详情页的商品进入详情页;无详情页的商品可直接从组装页跳转到外部列表页、第三方详情页、H5 地址或小程序页面。
+
+3.5.5 状态规则
+
+| 状态值 | 状态含义 | 展示文案 | 展示样式 | 可操作按钮 | 规则说明 |
+| --- | --- | --- | --- | --- | --- |
+| 有可见商品 | 客户标签、发放资格、展示页面均匹配 | 后台配置的大标题和商品列表 | 标题 + 列表行 | 商品行 | 正常展示 |
+| 无可见商品 | 客户无权限或未发放任何关联商品 | 无   | 模块整体隐藏 | 无   | 不展示空态 |
+| 权益未上架 | 商品未处于可展示状态 | 无   | 不展示该商品 | 无   | 根据权益商品状态过滤 |
+| 组装页未关联 | 商品未选择当前组装页 | 无   | 不展示该商品 | 无   | 根据权益商品“组装页”配置过滤 |
+
+3.5.6 异常、空数据和边界规则
+
+查询客户标签或可见权益失败时,权益商品模块隐藏,并记录接口异常日志,不影响其他模块展示。若单个权益商品字段异常,仅剔除异常商品,不阻断页面整体展示。
+
+### 3.6 按钮模块
+
+3.6.1 模块说明
+
+按钮模块用于承载活动报名、了解更多、外部服务跳转等操作。一个按钮模块内可配置多个按钮,H5 Demo 展示为底部两个按钮。
+
+3.6.2 展示规则
+
+按钮模块按后台排序展示。按钮样式支持“突出显示(红色)”和“次要操作(白色)”。按钮文案必填。按钮点击动作支持“跳转链接”和“弹窗提示”。
+
+3.6.3 字段说明
+
+| 字段/元素 | 类型  | 展示位置 | 数据来源 | 来源说明 | 展示规则 | 交互规则 | 异常规则 |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+| 按钮文案 | 文本  | 按钮内部 | 后台配置 | 按钮模块“按钮文案” | 必填;按配置展示 | 点击按钮触发动作 | 为空时后台阻断保存 |
+| 按钮样式 | 枚举  | 按钮视觉 | 后台配置 | “突出显示(红色)”或“次要操作(白色)” | 红色按钮为主操作,白色按钮为次操作 | 不影响动作 | 异常值按次要操作展示 |
+| 点击动作 | 枚举  | 不直接展示 | 后台配置 | “跳转链接”或“弹窗提示” | 按动作类型执行 | 点击按钮触发 | 未配置时后台阻断保存 |
+| 跳转目标配置 | 链接/枚举 | 不直接展示 | 后台配置 | H5地址、小程序 AppID/页面路径、太古地产、龙腾 | 动作为跳转链接时必填或选择固定目标 | 点击后由 App 或小程序环境执行打开;第三方跳转先拦截确认 | 缺失时后台阻断保存 |
+
+3.6.4 交互规则
+
+当按钮动作为“跳转链接”时,用户点击按钮后按后台配置的目标执行跳转。后台选择 H5 时配置 H5 地址,移动端在 App 内 H5 环境优先使用 App WebView 或端内浏览器打开,在小程序环境按小程序 WebView 或端约定打开;后台选择小程序时配置 AppID 和页面路径,移动端按当前端能力拉起对应小程序页面;太古地产、龙腾为固定跳转项,实际 URL 或端能力待技术确认。若识别为第三方页面,先弹出离开汇丰确认弹窗。
+
+当按钮动作为“弹窗提示”时,用户点击按钮后从页面底部拉起半屏弹窗。点击弹窗右上角关闭图标或左侧取消按钮时,仅关闭弹窗。若右侧确认按钮展示且配置了跳转,点击确认后执行确认按钮跳转;若右侧确认按钮关闭展示,则弹窗不展示右侧确认按钮,用户只能取消或关闭。
+
+3.6.5 状态规则
+
+| 状态值 | 状态含义 | 展示文案 | 展示样式 | 可操作按钮 | 规则说明 |
+| --- | --- | --- | --- | --- | --- |
+| 直接跳转 | 点击动作=跳转链接 | 按钮文案 | 红色或白色 | 当前按钮 | 点击后执行链接跳转 |
+| 弹窗提示-有确认 | 点击动作=弹窗提示且确认按钮展示 | 按钮文案;弹窗标题/描述/取消/确认 | 底部弹窗 | 取消、确认、关闭 | 确认后按确认按钮链接跳转 |
+| 弹窗提示-无确认 | 点击动作=弹窗提示且确认按钮不展示 | 按钮文案;弹窗标题/描述/取消 | 底部弹窗 | 取消、关闭 | 不触发跳转 |
+
+3.6.6 异常、空数据和边界规则
+
+按钮模块内按钮数量为 0 时,后台阻断保存。H5 地址为空、小程序 AppID 为空、小程序页面路径为空、弹窗标题为空、弹窗描述为空、取消按钮文案为空、确认按钮展示但确认跳转目标缺失时,后台均阻断保存。
+
+### 3.7 第三方跳转拦截弹窗
+
+3.7.1 模块说明
+
+第三方跳转拦截弹窗用于在客户离开汇丰中国页面前进行风险提示。
+
+3.7.2 展示规则
+
+当按钮跳转、弹窗确认跳转或富文本链接被识别为第三方页面时,展示居中弹窗。弹窗标题固定为“您正在离开汇丰中国”,说明文案固定提示外部网站政策与汇丰网站条款、隐私政策不同。
+
+3.7.3 字段说明
+
+| 字段/元素 | 类型  | 展示位置 | 数据来源 | 来源说明 | 展示规则 | 交互规则 | 异常规则 |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+| 弹窗标题 | 文本  | 拦截弹窗顶部 | 写死  | “您正在离开汇丰中国” | 固定展示 | 不可点击 | 无   |
+| 提示说明 | 文本  | 弹窗正文 | 写死  | 外部网站政策提示 | 固定展示 | 不可点击 | 无   |
+| 取消按钮 | 按钮  | 弹窗底部左侧 | 写死  | “取消” | 固定展示 | 点击关闭弹窗并停留当前页 | 无   |
+| 继续前往按钮 | 按钮  | 弹窗底部右侧 | 写死  | “继续前往” | 固定展示 | 点击后打开第三方链接 | 跳转失败时提示“跳转失败,请稍后重试” |
+
+3.7.4 交互规则
+
+用户点击取消或遮罩区域时,关闭拦截弹窗并停留当前页。用户点击继续前往后,关闭弹窗并打开原目标链接。
+
+3.7.5 状态规则
+
+本模块仅在第三方跳转前触发,不独立存在业务状态。
+
+3.7.6 异常、空数据和边界规则
+
+第三方识别规则未在材料中明确,当前按“非汇丰域名、太古地产、龙腾”等外部目标推定为第三方,需技术和合规确认。
+
+## 四、后台/管理端功能详细说明
+
+### 4.1 页面管理-组装页
+
+4.1.1 页面入口
+
+菜单路径为“汇丰银行 / 页面管理 / 组装页”。页面用于管理营销活动、沙龙引导等可配置落地页。管理人员可在列表中查询历史配置,进入新建或编辑页面后,通过模块组合生成 H5/小程序端页面。
+
+4.1.2 查询筛选区
+
+查询区用于快速定位已有组装页。Demo 中页面 ID 和页面名称均为输入框,查询逻辑为包含匹配;PDF 描述为精准查询,二者存在疑似冲突,已列入待确认问题。
+
+| 字段名称 | 字段类型 | 是否必填 | 默认值 | 数据来源 | 查询规则 | 校验规则 | 说明  |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+| 页面ID | 文本输入框 | 否   | 空   | 用户操作产生 | 按页面 ID 查询;Demo 为包含匹配 | 不限制为空 | 用于查找指定页面 |
+| 页面名称 | 文本输入框 | 否   | 空   | 用户操作产生 | 按组装页名称查询;Demo 为包含匹配 | 不限制为空 | 用于按名称查找页面 |
+
+4.1.3 列表区
+
+列表按页面 ID 倒序展示组装页。分页支持 10、20、50 条每页,并显示 Total 数量。
+
+| 列表字段 | 字段类型 | 数据来源 | 展示规则 | 排序规则 | 空值规则 | 说明  |
+| --- | --- | --- | --- | --- | --- | --- |
+| 操作  | 按钮组 | 系统默认 | 固定展示“编辑”“链接” | 不参与排序 | 无   | 用于进入编辑页或获取页面链接 |
+| 页面ID | 文本  | 接口获取 | 居中展示 | 默认按 ID 倒序 | 为空时显示“-” | 保存后系统生成 |
+| 组装页名称 | 文本  | 接口获取 | 超长显示 tooltip | 默认按 ID 倒序 | 为空时显示“-” | 同步影响 H5/小程序端标题 |
+| 发布状态 | 枚举标签 | 接口获取 | published 展示“正式”,其他展示“草稿” | 默认按 ID 倒序 | 异常值按草稿展示 | 编辑页中 modified 状态按“有未保存修改/草稿”处理 |
+| 创建时间 | 日期时间 | 接口获取 | yyyy-MM-dd HH:mm:ss | 默认按 ID 倒序 | 为空显示“-” | 新建保存时生成 |
+| 更新时间 | 日期时间 | 接口获取 | yyyy-MM-dd HH:mm:ss | 默认按 ID 倒序 | 为空显示“-” | 每次保存时更新 |
+
+4.1.4 新增/编辑弹窗或配置表单
+
+后台编辑页不是弹窗,而是列表页内切换到编辑视图。新建时页面 ID 显示“保存后生成”;编辑时回显已有配置。
+
+| 字段名称 | 字段类型 | 是否必填 | 默认值 | 数据来源 | 配置用途 | 校验规则 | H5/小程序端影响 |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+| 页面ID | 系统只读文本 | 否   | 保存后生成 | 系统默认 | 唯一标识组装页 | 不允许手工编辑 | 作为页面访问和分享链接的页面 ID |
+| 组装页名称 | 文本输入框 | 是   | 空   | 用户操作产生 | 后台管理名称和移动端标题 | 为空阻断保存,提示“保存失败:基本信息-组装页名称未填写” | 展示为移动端导航栏标题 |
+| 自定义微信分享 | 复选框 | 否   | 关闭  | 用户操作产生 | 控制是否启用小程序分享 | 关闭时无需校验缩略图和标题 | 开启后小程序可分享 |
+| 分享缩略图 | 图片上传 | 开启分享时必填 | 空   | 用户操作产生 | 微信分享卡片缩略图 | 开启分享且为空阻断保存 | 展示在微信分享卡片 |
+| 分享标题 | 文本输入框 | 开启分享时必填 | 空   | 用户操作产生 | 微信分享卡片标题 | 开启分享且为空阻断保存 | 展示在微信分享卡片 |
+| 图片模块图片 | 图片上传 | 是   | 空   | 用户操作产生 | 配置通栏图片 | 图片模块存在时,未上传阻断保存 | 展示为页面图片模块 |
+| 权益商品模块大标题 | 文本输入框 | 否   | 空   | 用户操作产生 | 配置权益商品区标题 | 可为空 | 为空时 H5/小程序端隐藏标题 |
+| 权益商品列表 | 系统回显列表 | 否   | 空   | 接口获取 | 预览当前关联商品 | 组装页内不手工新增商品 | 由权益商品配置和客户身份决定展示 |
+| 图文模块内容 | 富文本编辑器 | 否,PDF 标注必填待确认 | `<p></p>` | 用户操作产生 | 配置活动说明正文 | Demo 未强制校验;是否必填待确认 | 展示为图文内容 |
+| 按钮文案 | 文本输入框 | 是   | 空   | 用户操作产生 | 配置按钮展示文字 | 为空阻断保存 | 展示为按钮文字 |
+| 点击动作 | 下拉选择 | 是   | 跳转链接 | 用户操作产生 | 决定按钮行为 | 必须为跳转链接或弹窗提示 | 控制点击后跳转或弹窗 |
+| 按钮样式 | 下拉选择 | 是   | 次要操作;新增按钮模块默认首个按钮为突出显示 | 用户操作产生 | 配置按钮视觉层级 | 异常值按次要操作处理 | 展示红色或白色按钮 |
+| 链接类型 | 单选  | 动作为跳转时必填 | H5链接跳转 | 用户操作产生 | 配置按钮跳转方式 | H5、小程序需补充必填字段;太古地产/龙腾为固定项 | 决定跳转方式 |
+| H5链接 | 文本输入框 | 链接类型为 H5 时必填 | 空   | 用户操作产生 | 配置目标 H5 URL | 为空阻断保存 | 点击后打开 H5 |
+| 小程序 AppID | 文本输入框 | 链接类型为小程序时必填 | 空   | 用户操作产生 | 配置目标小程序 | 为空阻断保存 | 点击后打开小程序 |
+| 小程序页面路径 | 文本输入框 | 链接类型为小程序时必填 | 空   | 用户操作产生 | 配置目标小程序页面 | 为空阻断保存 | 点击后打开小程序指定页面 |
+| 弹窗标题 | 文本输入框 | 动作为弹窗提示时必填 | 空   | 用户操作产生 | 配置底部弹窗标题 | 为空阻断保存 | 展示为底部弹窗标题 |
+| 弹窗描述 | 富文本编辑器 | 动作为弹窗提示时必填 | 空   | 用户操作产生 | 配置底部弹窗正文 | 空富文本阻断保存 | 展示为底部弹窗说明 |
+| 左侧取消按钮配置 | 文本输入框 | 动作为弹窗提示时必填 | 取消  | 用户操作产生 | 配置取消按钮文案 | 为空阻断保存 | 点击关闭弹窗 |
+| 右侧确认按钮展示 | 复选框 | 否   | 展示  | 用户操作产生 | 控制确认按钮是否展示 | 关闭时不校验确认按钮文案和跳转 | 展示或隐藏确认按钮 |
+| 右侧确认按钮配置 | 文本输入框 | 右侧确认按钮展示时必填 | 确认  | 用户操作产生 | 配置确认按钮文案 | 为空阻断保存 | 点击确认后跳转 |
+| 确认按钮跳转链接配置 | 单选 + 输入 | 右侧确认按钮展示时必填 | H5链接跳转 | 用户操作产生 | 配置弹窗确认后的跳转 | 同按钮跳转校验 | 点击确认后执行 |
+
+4.1.5 按钮说明
+
+| 按钮名称 | 出现场景 | 操作对象 | 点击后行为 | 权限控制 | 二次确认 | 成功提示 | 失败提示 |
+| --- | --- | --- | --- | --- | --- | --- | --- |
+| 查询  | 列表查询区 | 查询条件 | 按页面 ID、页面名称刷新列表 | 需有组装页查看权限 | 无   | 无   | 接口失败提示“查询失败,请稍后重试” |
+| 重置  | 列表查询区 | 查询条件 | 清空页面 ID、页面名称并刷新列表 | 需有组装页查看权限 | 无   | 无   | 无   |
+| 新建组装页 | 列表操作区 | 新组装页 | 进入编辑视图,初始化空配置 | 需有组装页新建权限 | 无   | 无   | 无   |
+| 编辑  | 列表操作列 | 当前行组装页 | 进入编辑视图并回显配置 | 需有组装页编辑权限 | 若有未保存修改离开其他页面需确认 | 无   | 详情获取失败提示“页面不存在或已删除” |
+| 链接/获取链接 | 列表操作列、编辑页顶部 | 当前组装页 | 打开获取页面链接弹窗 | 需有组装页查看权限 | 无   | 复制时提示“链接已复制到剪贴板” | 未保存页面提示“请先保存组装页再获取链接!” |
+| 返回  | 编辑页顶部 | 当前编辑页 | 返回列表;有未保存修改时弹出确认 | 需有查看权限 | 有未保存修改时确认“确定离开/继续编辑” | 无   | 无   |
+| 保存草稿 | 编辑页顶部 | 当前组装页配置 | 执行校验,通过后保存为草稿或已修改 | 需有组装页保存权限 | 无   | “已保存组装页配置草稿!” | 按具体校验项提示“保存失败:...” |
+| 发布上线 | 编辑页顶部 | 当前组装页配置 | 仅在已保存且状态为草稿/已修改时可发布 | 需有组装页发布权限 | Demo 未展示二次确认,建议补充 | “已发布组装页配置!” | 有未保存修改提示“请先保存草稿后再发布上线” |
+| 排序  | 模块/权益商品/按钮右上角 | 当前模块、商品或按钮 | 输入目标序号并移动到对应位置 | 需有编辑权限 | 无   | 无   | 序号越界时不移动 |
+| 复制  | 模块右上角 | 当前模块 | 克隆当前模块及内部数据并插入到当前模块后 | 需有编辑权限 | 无   | 无   | 权益商品模块提示“权益商品模块每页仅限配置一个,无法复制!” |
+| 删除  | 模块/按钮右上角 | 当前模块或按钮 | 删除当前对象 | 需有编辑权限 | 模块删除确认“确定删除该模块吗?” | 无   | 取消后不删除 |
+| 添加按钮 | 按钮模块标题区 | 当前按钮模块 | 在按钮模块内新增按钮 | 需有编辑权限 | 无   | 无   | 无   |
+| 复制链接 | 获取链接弹窗 | 生成链接 | 复制当前链接到剪贴板 | 需有查看权限 | 无   | “链接已复制到剪贴板” | 浏览器剪贴板权限失败时提示“复制失败,请手动复制” |
+
+4.1.6 校验规则
+
+| 字段/操作 | 校验规则 | 触发时机 | 不通过提示 | 是否阻断提交 |
+| --- | --- | --- | --- | --- |
+| 组装页名称 | 必填  | 保存草稿、发布上线 | 保存失败:基本信息-组装页名称未填写 | 是   |
+| 分享缩略图 | 开启自定义微信分享时必填 | 保存草稿、发布上线 | 保存失败:微信分享卡片配置-分享缩略图未上传 | 是   |
+| 分享标题 | 开启自定义微信分享时必填 | 保存草稿、发布上线 | 保存失败:微信分享卡片配置-分享标题未填写 | 是   |
+| 图片模块图片 | 每个图片模块必须上传图片 | 保存草稿、发布上线 | 保存失败:图片模块-第 N 个-图片未上传 | 是   |
+| 按钮模块按钮数量 | 每个按钮模块至少一个按钮 | 保存草稿、发布上线 | 保存失败:按钮模块-第 N 个模块-至少配置一个按钮 | 是   |
+| 按钮文案 | 必填  | 保存草稿、发布上线 | 保存失败:按钮模块-第 N 个模块-第 M 个按钮-按钮文案未填写 | 是   |
+| H5链接 | 链接类型为 H5 时必填 | 保存草稿、发布上线 | 保存失败:...跳转链接配置-配置链接未填写 | 是   |
+| 小程序 AppID | 链接类型为小程序时必填 | 保存草稿、发布上线 | 保存失败:...跳转链接配置-AppID未填写 | 是   |
+| 小程序页面路径 | 链接类型为小程序时必填 | 保存草稿、发布上线 | 保存失败:...跳转链接配置-页面路径未填写 | 是   |
+| 弹窗标题 | 动作为弹窗提示时必填 | 保存草稿、发布上线 | 保存失败:...弹窗内容配置-弹窗标题未填写 | 是   |
+| 弹窗描述 | 动作为弹窗提示时必填,去除 HTML 标签后不能为空 | 保存草稿、发布上线 | 保存失败:...弹窗内容配置-弹窗描述未填写 | 是   |
+| 左侧取消按钮配置 | 动作为弹窗提示时必填 | 保存草稿、发布上线 | 保存失败:...弹窗内容配置-左侧取消按钮配置未填写 | 是   |
+| 右侧确认按钮配置 | 右侧确认按钮展示时必填 | 保存草稿、发布上线 | 保存失败:...弹窗内容配置-右侧确认按钮配置未填写 | 是   |
+| 确认按钮跳转链接 | 右侧确认按钮展示时必填,规则同普通跳转 | 保存草稿、发布上线 | 保存失败:...确认按钮跳转链接配置-具体缺失项 | 是   |
+| 发布上线 | 必须先保存草稿且无未保存修改 | 点击发布上线 | 请先保存草稿后再发布上线 | 是   |
+
+4.1.7 后台边界规则
+
+-   新建页面未保存时点击“获取链接”,提示“请先保存组装页再获取链接!”。
+-   编辑页有未保存修改时点击返回或离开路由,弹出“当前有未保存修改,离开后修改内容将丢失,确定离开吗?”。
+-   编辑页有未保存修改时点击“获取链接”,弹窗仍可打开,但提示“当前链接基于上一次保存内容,最新修改需保存后生效”。
+-   草稿状态仅展示草稿预览链接;正式或已修改状态展示正式环境链接和草稿预览链接。
+-   权益商品模块每页仅限一个;添加后底部“权益商品模块”新增按钮隐藏。
+-   权益商品模块不支持复制。
+-   模块排序、按钮排序、权益商品排序输入目标序号范围为 1 至当前列表长度,越界不移动。
+-   删除模块需二次确认;删除按钮 Demo 未展示二次确认,建议补充确认规则。
+
+## 五、接口与字段说明
+
+当前材料未提供真实接口说明。以下接口根据 PC Demo mock、PDF 与 H5 Demo 反推,均为【虚拟接口,待技术确认】。虚拟接口名称和字段使用中文,后续如提供真实接口,应建立字段映射并替换为真实技术字段。
+
+### 5.1 查询组装页列表
+
+接口名称:查询组装页列表  
+接口类型:查询  
+接口用途:后台组装页列表页按页面 ID、页面名称查询配置记录,并展示分页列表。
+
+是否虚拟接口:【虚拟接口,待技术确认】  
+调用时机:后台进入组装页列表、点击查询、点击重置、保存/删除后刷新列表。  
+使用页面/模块:后台“页面管理-组装页”列表。
+
+入参:
+
+| 字段名称 | 是否必填 | 字段类型 | 字段说明 | 示例值 |
+| --- | --- | --- | --- | --- |
+| 页面编号 | 否   | 文本  | 后台列表筛选条件,对应页面 ID | 1   |
+| 页面名称 | 否   | 文本  | 后台列表筛选条件,对应组装页名称 | 双十一迎新专属活动页 |
+
+出参:
+
+| 字段名称 | 字段类型 | 字段说明 | 使用位置 | 异常规则 |
+| --- | --- | --- | --- | --- |
+| 组装页列表 | 列表  | 符合条件的组装页记录 | 后台列表 | 为空时列表展示空态 |
+| 页面编号 | 文本  | 组装页唯一标识 | 列表、编辑、链接生成 | 为空时该条记录不可生成链接 |
+| 组装页名称 | 文本  | 后台管理名称和移动端标题 | 列表、编辑、移动端标题 | 为空时展示“-” |
+| 发布状态 | 枚举  | 草稿、正式、已修改 | 列表状态标签、链接弹窗 | 异常值按草稿处理 |
+| 创建时间 | 日期时间 | 创建记录时间 | 列表  | 为空显示“-” |
+| 更新时间 | 日期时间 | 最近保存时间 | 列表  | 为空显示“-” |
+
+接口异常规则:
+
+| 异常场景 | 页面表现 | 是否允许重试 | 提示文案 |
+| --- | --- | --- | --- |
+| 接口超时 | 保留原列表或展示空列表 | 是   | 查询失败,请稍后重试 |
+| 无查询结果 | 列表为空态 | 是   | 暂无数据 |
+| 无权限 | 返回上级或展示无权限页 | 否   | 当前账号无权查看组装页 |
+
+### 5.2 查询组装页详情
+
+接口名称:查询组装页详情  
+接口类型:查询  
+接口用途:后台编辑页回显配置;H5/小程序端加载页面标题、分享配置和各模块内容。
+
+是否虚拟接口:【虚拟接口,待技术确认】  
+调用时机:后台点击编辑;H5/小程序端打开组装页。  
+使用页面/模块:后台编辑页、H5/小程序端组装页。
+
+入参:
+
+| 字段名称 | 是否必填 | 字段类型 | 字段说明 | 示例值 |
+| --- | --- | --- | --- | --- |
+| 页面编号 | 是   | 文本  | 组装页唯一标识 | 1   |
+| 是否草稿预览 | 否   | 布尔  | 为 true 时读取草稿预览内容 | true |
+
+出参:
+
+| 字段名称 | 字段类型 | 字段说明 | 使用位置 | 异常规则 |
+| --- | --- | --- | --- | --- |
+| 页面编号 | 文本  | 组装页唯一标识 | 页面标题、链接参数 | 为空时页面不可访问 |
+| 组装页名称 | 文本  | 移动端标题和后台名称 | 导航栏、后台基础信息 | 为空时移动端兜底“组装页” |
+| 发布状态 | 枚举  | 草稿、正式、已修改 | 后台标签、访问控制 | 非预览访问草稿时不展示页面 |
+| 分享配置 | 对象  | 是否启用分享、标题、缩略图 | 微信分享 | 配置缺失按关闭处理 |
+| 模块列表 | 列表  | 图片、权益商品、图文、按钮模块及排序 | H5/小程序端页面内容 | 为空时展示空页面或页面失效提示,待确认 |
+
+接口异常规则:
+
+| 异常场景 | 页面表现 | 是否允许重试 | 提示文案 |
+| --- | --- | --- | --- |
+| 页面不存在 | H5 展示失效页;后台提示错误 | 是   | 页面不存在或已失效 |
+| 页面未发布且非预览 | H5 展示不可访问 | 否   | 页面暂不可访问 |
+| 接口超时 | H5 展示加载失败 | 是   | 加载失败,请稍后重试 |
+
+### 5.3 保存组装页配置
+
+接口名称:保存组装页配置  
+接口类型:保存  
+接口用途:后台保存草稿、保存已发布页面的修改或发布上线。
+
+是否虚拟接口:【虚拟接口,待技术确认】  
+调用时机:点击“保存草稿”或“发布上线”。  
+使用页面/模块:后台组装页编辑页。
+
+入参:
+
+| 字段名称 | 是否必填 | 字段类型 | 字段说明 | 示例值 |
+| --- | --- | --- | --- | --- |
+| 页面编号 | 否   | 文本  | 新建时为空,编辑时必填 | 1   |
+| 组装页名称 | 是   | 文本  | 后台名称和移动端标题 | 双十一迎新专属活动页 |
+| 保存类型 | 是   | 枚举  | 草稿、发布 | 草稿  |
+| 发布状态 | 是   | 枚举  | 保存后的目标状态 | 草稿  |
+| 分享配置 | 否   | 对象  | 微信分享配置 | 开启、标题、缩略图 |
+| 模块列表 | 是   | 列表  | 按顺序保存所有模块 | 图片模块、图文模块 |
+
+出参:
+
+| 字段名称 | 字段类型 | 字段说明 | 使用位置 | 异常规则 |
+| --- | --- | --- | --- | --- |
+| 页面编号 | 文本  | 新建保存后生成的页面 ID | 编辑页、链接生成 | 为空时保存视为失败 |
+| 保存结果 | 文本  | 保存成功或失败信息 | 后台提示 | 失败时展示接口返回文案 |
+
+接口异常规则:
+
+| 异常场景 | 页面表现 | 是否允许重试 | 提示文案 |
+| --- | --- | --- | --- |
+| 必填缺失 | 阻断提交 | 是   | 保存失败:具体字段未填写 |
+| 多人同时编辑冲突 | 阻断提交或提示覆盖风险 | 是   | 当前配置已被更新,请刷新后重试 |
+| 发布失败 | 停留编辑页 | 是   | 发布失败,请稍后重试 |
+
+### 5.4 查询组装页可见权益
+
+接口名称:查询组装页可见权益  
+接口类型:查询  
+接口用途:H5/小程序端根据当前客户身份、发放状态和权益商品展示页面配置,返回当前组装页可展示的权益商品。
+
+是否虚拟接口:【虚拟接口,待技术确认】  
+调用时机:H5/小程序端打开组装页且页面包含权益商品模块时。  
+使用页面/模块:H5/小程序端权益商品模块。
+
+入参:
+
+| 字段名称 | 是否必填 | 字段类型 | 字段说明 | 示例值 |
+| --- | --- | --- | --- | --- |
+| 页面编号 | 是   | 文本  | 当前组装页 ID | 1   |
+| 客户编号 | 是   | 文本  | 当前登录客户标识,由登录态或 SSO 获得 | CUST001 |
+| Campaign编号 | 否   | 文本  | 投放活动编号 | CAMP202511 |
+| Channel编号 | 否   | 文本  | 渠道编号 | CH\_APP |
+
+出参:
+
+| 字段名称 | 字段类型 | 字段说明 | 使用位置 | 异常规则 |
+| --- | --- | --- | --- | --- |
+| 权益列表 | 列表  | 当前客户可见权益商品 | 权益商品模块 | 为空时隐藏整个模块 |
+| 权益编号 | 文本  | 权益商品唯一标识 | 点击跳转、埋点 | 为空时剔除该商品 |
+| 权益名称 | 文本  | 商品名称 | 商品列表主标题 | 为空时剔除该商品 |
+| 权益简介 | 文本  | 商品简要描述 | 商品列表副标题 | 为空时仅展示名称 |
+| 权益图标 | 图片链接 | 商品图标 | 商品列表左侧 | 为空时展示默认图标 |
+| 承接页类型 | 枚举  | 详情页、H5链接、小程序、第三方固定链接 | 点击商品 | 异常值不允许跳转 |
+| 承接页地址 | 链接/对象 | 目标页面地址或小程序参数 | 点击商品 | 为空时点击提示“暂不可访问” |
+
+接口异常规则:
+
+| 异常场景 | 页面表现 | 是否允许重试 | 提示文案 |
+| --- | --- | --- | --- |
+| 客户未登录 | 触发 SSO 或登录 | 是   | 无或端内登录提示 |
+| 无可见权益 | 隐藏权益商品模块 | 是   | 无   |
+| 接口失败 | 隐藏权益商品模块并记录日志 | 是   | 不在页面展示错误 |
+
+### 5.5 查询 Campaign 与 Channel 下拉选项
+
+接口名称:查询链接参数选项  
+接口类型:查询  
+接口用途:后台获取页面链接弹窗中选择 Campaign ID 和 Channel ID,并拼接到生成链接。
+
+是否虚拟接口:【虚拟接口,待技术确认】  
+调用时机:后台打开“获取页面链接”弹窗。  
+使用页面/模块:获取页面链接弹窗。
+
+入参:
+
+| 字段名称 | 是否必填 | 字段类型 | 字段说明 | 示例值 |
+| --- | --- | --- | --- | --- |
+| 选项类型 | 否   | 枚举  | Campaign、Channel;也可由两个接口分别返回 | Campaign |
+
+出参:
+
+| 字段名称 | 字段类型 | 字段说明 | 使用位置 | 异常规则 |  
+| --- | --- | --- | --- |  
+| Campaign选项列表 | 列表 | 可选 Campaign ID 与名称 | Campaign ID 下拉框 | 获取失败时下拉为空 |  
+| Channel选项列表 | 列表 | 可选 Channel ID 与名称 | Channel ID 下拉框 | 获取失败时下拉为空 |  
+| 编号 | 文本 | 选项 ID | URL 参数值 | 为空不展示该选项 |  
+| 名称 | 文本 | 选项显示名称 | 下拉 label | 为空展示编号 |
+
+接口异常规则:
+
+| 异常场景 | 页面表现 | 是否允许重试 | 提示文案 |
+| --- | --- | --- | --- |
+| 选项获取失败 | 下拉框为空,仍可复制不带参数的链接 | 是   | 参数选项获取失败 |
+| 无选项 | 下拉框为空 | 是   | 无   |
+
+## 六、前台与后台字段映射关系
+
+| 后台配置字段 | 后台位置 | H5/小程序端展示字段或模块 | 影响规则 | 是否必填 | 空值处理 |
+| --- | --- | --- | --- | --- | --- |
+| 组装页名称 | 基本信息 | 导航栏标题、Page Title | 保存后移动端读取并回显 | 是   | 后台阻断保存;历史空值移动端兜底“组装页” |
+| 自定义微信分享 | 微信分享卡片配置 | 小程序分享菜单 | 开启后注入自定义分享配置,关闭后禁用分享 | 否   | 默认关闭 |
+| 分享缩略图 | 微信分享卡片配置 | 微信分享卡片图片 | 开启自定义分享时展示 | 条件必填 | 后台阻断保存 |
+| 分享标题 | 微信分享卡片配置 | 微信分享卡片标题 | 开启自定义分享时展示 | 条件必填 | 后台阻断保存 |
+| 图片模块图片 | 图片模块 | 页面通栏图片 | 按模块排序展示 | 是   | 后台阻断保存 |
+| 权益商品模块大标题 | 权益商品模块 | 权益商品区标题 | 为空隐藏标题,不影响列表 | 否   | 隐藏标题 |
+| 权益商品“显示页面-组装页” | 权益商品新增/编辑页 | 权益商品模块列表 | 只有选择当前组装页且客户有权限时才展示 | 条件必填 | 未选择则不在组装页展示 |
+| 权益名称 | 权益商品配置 | 权益商品列表名称 | 商品行主标题 | 是   | 异常商品剔除 |
+| 权益图标 | 权益商品配置 | 权益商品列表图标 | 商品行左侧圆形图标 | 否   | 展示默认图标 |
+| 权益简介/副标题 | 权益商品配置 | 权益商品列表简介 | 商品行副标题 | 否   | 仅展示名称 |
+| 图文模块内容 | 图文模块 | 活动说明正文 | 按富文本渲染 | 待确认 | 空内容不展示正文或展示空白模块,待确认 |
+| 按钮文案 | 按钮模块 | 按钮文字 | 按排序展示 | 是   | 后台阻断保存 |
+| 按钮样式 | 按钮模块 | 按钮颜色与层级 | primary 展示红色,secondary 展示白色 | 是   | 异常值按 secondary |
+| 点击动作 | 按钮模块 | 按钮点击行为 | link 直接跳转,dialog 先弹底部弹窗 | 是   | 后台阻断保存 |
+| H5链接 | 按钮/弹窗跳转配置 | 跳转目标 | 点击后打开 H5 | 条件必填 | 后台阻断保存 |
+| 小程序 AppID/页面路径 | 按钮/弹窗跳转配置 | 跳转目标 | 点击后打开指定小程序页面 | 条件必填 | 后台阻断保存 |
+| 太古地产/龙腾 | 按钮/弹窗跳转配置 | 固定跳转目标 | 点击后打开固定服务 | 条件必填 | 具体地址待技术确认 |
+| 弹窗标题 | 弹窗内容配置 | 底部弹窗标题 | 动作为弹窗提示时展示 | 条件必填 | 后台阻断保存 |
+| 弹窗描述 | 弹窗内容配置 | 底部弹窗正文 | 动作为弹窗提示时展示 | 条件必填 | 后台阻断保存 |
+| 左侧取消按钮配置 | 弹窗内容配置 | 底部弹窗取消按钮 | 点击关闭弹窗 | 条件必填 | 后台阻断保存 |
+| 右侧确认按钮展示 | 弹窗内容配置 | 底部弹窗确认按钮 | 开启时展示确认按钮和跳转配置,关闭时隐藏 | 否   | 默认展示 |
+| 右侧确认按钮配置 | 弹窗内容配置 | 底部弹窗确认按钮文案 | 开启确认按钮时展示 | 条件必填 | 后台阻断保存 |
+
+## 七、业务流程图 / 泳道图 / 状态流转图 / 接口调用时序图
+
+### 7.1 组装页发布与访问流程
+
+```mermaid
+flowchart TD
+  A["运营进入页面管理-组装页"] --> B["新建或编辑组装页"]
+  B --> C["配置基础信息、分享卡片和页面模块"]
+  C --> D{"保存校验是否通过"}
+  D -- "否" --> E["提示具体缺失字段,停留编辑页"]
+  D -- "是" --> F["保存草稿或已修改配置"]
+  F --> G{"是否发布上线"}
+  G -- "否" --> H["可生成草稿预览链接"]
+  G -- "是" --> I{"是否存在未保存修改"}
+  I -- "是" --> J["提示请先保存草稿后再发布上线"]
+  I -- "否" --> K["发布为正式页面"]
+  K --> L["生成正式 H5 链接、小程序链接和草稿预览链接"]
+  L --> M["客户通过链接打开组装页"]
+```
+
+### 7.2 H5/小程序端加载时序
+
+```mermaid
+sequenceDiagram
+  participant U as 客户
+  participant P as H5/小程序端
+  participant A as 组装页配置服务
+  participant E as 权益可见性服务
+  participant S as SSO服务
+
+  U->>P: 打开组装页链接
+  P->>A: 查询组装页详情(页面编号, 是否草稿预览)
+  A-->>P: 返回标题、分享配置、模块列表
+  P->>P: 渲染图片、图文、按钮模块
+  P->>E: 查询组装页可见权益(页面编号, 客户编号)
+  E-->>P: 返回客户可见权益列表
+  P->>P: 有权益则渲染权益商品模块,无权益则隐藏模块
+  U->>P: 点击权益商品或按钮
+  P->>S: 校验登录态或执行SSO
+  S-->>P: 返回登录结果
+  P->>P: 内部链接直接跳转,第三方链接先展示离开汇丰提示
+```
+
+### 7.3 组装页状态流转
+
+```mermaid
+stateDiagram-v2
+  [*] --> 草稿: 新建后保存草稿
+  草稿 --> 草稿: 编辑后保存草稿
+  草稿 --> 正式: 发布上线
+  正式 --> 已修改: 已发布页面编辑后保存草稿
+  已修改 --> 正式: 发布上线
+  已修改 --> 已修改: 继续编辑并保存
+```
+
+## 八、权限规则
+
+| 权限点 | 适用对象 | 控制范围 | 无权限表现 | 说明  |
+| --- | --- | --- | --- | --- |
+| 组装页查看权限 | 后台运营/产品人员 | 菜单入口、列表、详情、链接弹窗 | 菜单不可见或进入后提示无权限 | 至少可查看列表和复制链接 |
+| 组装页新建权限 | 后台运营/产品人员 | 新建组装页按钮 | 按钮隐藏或禁用 | 无权限不得创建页面 |
+| 组装页编辑权限 | 后台运营/产品人员 | 编辑按钮、模块配置、保存草稿 | 编辑入口隐藏或只读 | 保存草稿需单独校验权限 |
+| 组装页发布权限 | 后台运营/产品负责人 | 发布上线按钮 | 按钮隐藏或禁用 | 建议与编辑权限分离 |
+| 链接复制权限 | 后台运营/投放人员 | 获取链接弹窗和复制按钮 | 按钮隐藏或禁用 | 可与查看权限合并 |
+| 权益商品可见权限 | H5/小程序客户 | 权益商品模块 | 未授权商品不展示 | 由客户标签、发放计划、权益商品展示页面共同决定 |
+| 第三方跳转确认 | H5/小程序客户 | 外部链接跳转 | 必须确认后跳转 | 属于合规提示,不应绕过 |
+
+## 九、埋点与日志需求
+
+| 事件/日志名称 | 触发时机 | 记录字段 | 使用目的 | 备注  |
+| --- | --- | --- | --- | --- |
+| 组装页访问事件 | 客户打开组装页 | 页面编号、组装页名称、Campaign编号、Channel编号、客户编号、访问时间、环境 | 统计页面访问和投放归因 | 客户编号需脱敏或使用内部标识 |
+| 微信分享事件 | 小程序用户触发分享 | 页面编号、分享标题、Campaign编号、Channel编号、客户编号、分享时间 | 统计分享行为 | 仅小程序环境记录 |
+| 权益商品曝光事件 | 权益商品模块渲染成功 | 页面编号、客户编号、权益编号列表、曝光时间 | 评估权益展示效果 | 无可见权益时记录空结果日志 |
+| 权益商品点击事件 | 客户点击权益商品 | 页面编号、客户编号、权益编号、承接页类型、Campaign编号、Channel编号 | 分析权益转化 | 跳转失败需记录失败原因 |
+| 按钮点击事件 | 客户点击按钮 | 页面编号、按钮文案、按钮序号、动作类型、链接类型 | 分析按钮转化 | 弹窗提示按钮需继续记录弹窗确认 |
+| 弹窗展示事件 | 客户点击弹窗提示按钮 | 页面编号、按钮序号、弹窗标题 | 分析提示触达 | 无确认按钮也需记录 |
+| 弹窗确认事件 | 客户点击底部弹窗确认按钮 | 页面编号、按钮序号、确认按钮文案、跳转类型 | 分析二次确认转化 | 关闭/取消需单独记录 |
+| 第三方拦截确认事件 | 出现离开汇丰弹窗并点击继续前往 | 页面编号、触发来源、目标类型、目标地址、客户编号 | 合规审计和转化分析 | 目标地址记录需脱敏规则 |
+| 后台保存日志 | 后台保存草稿或发布上线 | 操作人、页面编号、保存类型、变更摘要、操作时间 | 审计和问题追溯 | 建议记录模块变更前后摘要 |
+| 后台复制链接日志 | 后台复制页面链接 | 操作人、页面编号、链接类型、Campaign编号、Channel编号、操作时间 | 投放链路追踪 | 可选  |
+
+## 十、待确认问题
+
+| 序号  | 问题类型 | 问题描述 | 影响范围 | 建议确认对象 | 当前处理方式 |
+| --- | --- | --- | --- | --- | --- |
+| 1   | 疑似冲突点 | PDF 描述列表支持按页面 ID 或名称“精准查询”,PC Demo mock 为 includes 包含匹配。 | 后台查询规则、测试用例 | 产品、后端 | 文档按包含匹配描述,并标记需确认 |
+| 2   | 接口缺失 | 未提供正式接口文档,本文接口均为虚拟接口。 | 前后端开发、联调 | 后端、架构 | 标记【虚拟接口,待技术确认】 |
+| 3   | 展示规则 | 图文模块 PDF 标注“必填”,PC Demo 未在保存校验中强制图文模块内容必填。 | 后台校验、发布规则 | 产品  | 文档标记为待确认,不强行定为必填 |
+| 4   | 跳转规则 | 太古地产、龙腾固定跳转项的真实地址、端能力、是否第三方拦截未提供。 | 按钮跳转、弹窗确认跳转 | 技术、合规 | 暂按固定第三方目标处理 |
+| 5   | 第三方识别 | 哪些域名或链接类型需展示“离开汇丰中国”拦截弹窗未明确。 | 富文本链接、按钮跳转、权益商品跳转 | 合规、技术 | 暂按非汇丰域名和固定外部服务推定 |
+| 6   | 客户身份 | 查询客户标签、客户权益发放资格、SSO 登录态的真实接口和字段未提供。 | 权益商品模块千人千面展示 | 后端、客户系统 | 设计“查询组装页可见权益”虚拟接口 |
+| 7   | 权益排序 | 组装页权益商品模块内展示的商品排序来源不明确:Demo 可在模块内排序已有 items,但商品实际来源为权益商品列表。 | H5 权益列表排序 | 产品、后端 | 当前推定按权益商品配置或接口返回顺序展示 |
+| 8   | 图片限制 | 图片模块和分享缩略图仅给出建议尺寸,未明确格式、大小、比例、压缩规则。 | 后台上传校验、移动端展示 | 设计、技术 | 文档仅写建议尺寸,格式大小待确认 |
+| 9   | 草稿访问 | 草稿预览链接是否需要登录后台权限、是否可外部访问未明确。 | 预览安全、测试流程 | 产品、技术、安全 | 当前仅说明草稿预览用于内部测试 |
+| 10  | 发布确认 | PC Demo 发布上线未展示二次确认,但发布属于线上生效动作,是否需要确认弹窗未明确。 | 后台发布流程 | 产品  | 当前记录 Demo 行为,并建议补充确认 |
+| 11  | 删除能力 | PC Demo 中存在删除接口和方法,但列表操作列未展示删除按钮。是否需要组装页删除能力未明确。 | 后台列表操作、权限 | 产品  | 文档未作为列表显性按钮要求,仅在边界规则中保留 |
+| 12  | 移动端空页面 | 若组装页仅有权益商品模块且客户无可见权益,页面是否展示空白、失效页或其他兜底文案未明确。 | H5/小程序端体验 | 产品、设计 | 当前按“隐藏权益模块,其他模块正常展示”处理 |