Browse Source

pc-v3: 权益商品字段重构、审核与发放计划完善、客群任务新增

- 权益商品:商品来源改为是否权益平台兑换+商品类型,新增SKU编号/库存数等字段
- 审核模块:审核列表/详情完善,审核状态联动与按钮显隐
- 发放计划:列表/编辑/查看/复制功能完善
- 客群任务:新增发放任务列表与详情页面
- Mock数据:补充权益商品、审核、发放计划等接口数据
- 路由/菜单:新增客群任务、审核等菜单入口

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Fade 1 month ago
parent
commit
a86e8a96f9

+ 1 - 0
.gitignore

@@ -2,3 +2,4 @@ node_modules/
 dist/
 .DS_Store
 *.local
+.vercel

+ 454 - 318
guide/汇丰借记卡权益-操作手册-20260427.md

@@ -1,38 +1,219 @@
 # 汇丰借记卡权益 操作手册
 
-> 文档版本:V1.0  
-> 编写日期:2026-04-27  
-> 适用对象:汇丰银行运营人员、审核人员  
+> 文档版本:V1.0\
+> \
+> 编写日期:2026-04-27\
+> \
+> 适用对象:汇丰银行运营人员、审核人员\
+> \
 > 适用系统:Liso 后台 - 定制功能 - 汇丰银行
 
-* * *
+***
 
 ## 目录
 
-1.  [系统概述](#%E4%B8%80%E7%B3%BB%E7%BB%9F%E6%A6%82%E8%BF%B0)
-    
-2.  [后台操作说明](#%E4%BA%8C%E5%90%8E%E5%8F%B0%E6%93%8D%E4%BD%9C%E8%AF%B4%E6%98%8E)
-    
-    -   2.1 [添加权益商品](#21-%E6%B7%BB%E5%8A%A0%E6%9D%83%E7%9B%8A%E5%95%86%E5%93%81)
-        
-    -   2.2 [编辑权益商品](#22-%E7%BC%96%E8%BE%91%E6%9D%83%E7%9B%8A%E5%95%86%E5%93%81)
-        
-    -   2.3 [查看权益商品](#23-%E6%9F%A5%E7%9C%8B%E6%9D%83%E7%9B%8A%E5%95%86%E5%93%81)
-        
-    -   2.4 [审核权益商品](#24-%E5%AE%A1%E6%A0%B8%E6%9D%83%E7%9B%8A%E5%95%86%E5%93%81)
-        
-    -   2.5 [下架权益商品](#25-%E4%B8%8B%E6%9E%B6%E6%9D%83%E7%9B%8A%E5%95%86%E5%93%81)
-        
-    -   2.6 [修改库存](#26-%E4%BF%AE%E6%94%B9%E5%BA%93%E5%AD%98)
-        
-    -   2.7 [权益列表筛选与查询](#27-%E6%9D%83%E7%9B%8A%E5%88%97%E8%A1%A8%E7%AD%9B%E9%80%89%E4%B8%8E%E6%9F%A5%E8%AF%A2)
-        
-3.  [移动端展示效果](#%E4%B8%89%E7%A7%BB%E5%8A%A8%E7%AB%AF%E5%B1%95%E7%A4%BA%E6%95%88%E6%9E%9C)
-    
-4.  [常见问题(FAQ)](#%E5%9B%9B%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98faq)
-    
-
-* * *
+1. [系统概述](#%E4%B8%80%E7%B3%BB%E7%BB%9F%E6%A6%82%E8%BF%B0)
+2. [后台操作说明](#%E4%BA%8C%E5%90%8E%E5%8F%B0%E6%93%8D%E4%BD%9C%E8%AF%B4%E6%98%8E)
+   - 2.1 [添加权益商品](#21-%E6%B7%BB%E5%8A%A0%E6%9D%83%E7%9B%8A%E5%95%86%E5%93%81)
+   - 2.2 [编辑权益商品](#22-%E7%BC%96%E8%BE%91%E6%9D%83%E7%9B%8A%E5%95%86%E5%93%81)
+   - 2.3 [查看权益商品](#23-%E6%9F%A5%E7%9C%8B%E6%9D%83%E7%9B%8A%E5%95%86%E5%93%81)
+   - 2.4 [审核权益商品](#24-%E5%AE%A1%E6%A0%B8%E6%9D%83%E7%9B%8A%E5%95%86%E5%93%81)
+   - 2.5 [下架权益商品](#25-%E4%B8%8B%E6%9E%B6%E6%9D%83%E7%9B%8A%E5%95%86%E5%93%81)
+   - 2.6 [修改库存](#26-%E4%BF%AE%E6%94%B9%E5%BA%93%E5%AD%98)
+   - 2.7 [权益列表筛选与查询](#27-%E6%9D%83%E7%9B%8A%E5%88%97%E8%A1%A8%E7%AD%9B%E9%80%89%E4%B8%8E%E6%9F%A5%E8%AF%A2)
+3. [移动端展示效果](#%E4%B8%89%E7%A7%BB%E5%8A%A8%E7%AB%AF%E5%B1%95%E7%A4%BA%E6%95%88%E6%9E%9C)
+4. [常见问题(FAQ)](#%E5%9B%9B%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98faq)
+
+***
+
+```tldraw id="c1ba9898-32f8-4c82-bc38-ae1a73128ba1" height="520"
+{
+  "store": {
+    "binding:Wv_P4aiX8HCHTpbi5rhTd": {
+      "meta": {},
+      "id": "binding:Wv_P4aiX8HCHTpbi5rhTd",
+      "type": "arrow",
+      "fromId": "shape:284-W03iPdkMlHuEYsjAT",
+      "toId": "shape:40zlOZKFmKzxLDl8OfDzE",
+      "props": {
+        "isPrecise": true,
+        "isExact": false,
+        "normalizedAnchor": {
+          "x": 0.5,
+          "y": 0.5
+        },
+        "snap": "center",
+        "terminal": "end"
+      },
+      "typeName": "binding"
+    },
+    "shape:40zlOZKFmKzxLDl8OfDzE": {
+      "x": -49,
+      "y": 1000.5,
+      "rotation": 0,
+      "isLocked": false,
+      "opacity": 1,
+      "meta": {},
+      "id": "shape:40zlOZKFmKzxLDl8OfDzE",
+      "type": "geo",
+      "props": {
+        "w": 99,
+        "h": 48,
+        "geo": "rectangle",
+        "dash": "draw",
+        "growY": 0,
+        "url": "",
+        "scale": 1,
+        "color": "black",
+        "labelColor": "black",
+        "fill": "none",
+        "size": "m",
+        "font": "draw",
+        "align": "middle",
+        "verticalAlign": "middle",
+        "richText": {
+          "type": "doc",
+          "content": [
+            {
+              "type": "paragraph"
+            }
+          ]
+        }
+      },
+      "parentId": "page:page",
+      "index": "a2hIrkaV",
+      "typeName": "shape"
+    },
+    "shape:MYLJj4c2ldfWYDFoAG2pS": {
+      "x": -45,
+      "y": 895.5,
+      "rotation": 0,
+      "isLocked": false,
+      "opacity": 1,
+      "meta": {},
+      "id": "shape:MYLJj4c2ldfWYDFoAG2pS",
+      "type": "geo",
+      "props": {
+        "w": 89,
+        "h": 50,
+        "geo": "rectangle",
+        "dash": "draw",
+        "growY": 0,
+        "url": "",
+        "scale": 1,
+        "color": "black",
+        "labelColor": "black",
+        "fill": "none",
+        "size": "m",
+        "font": "draw",
+        "align": "middle",
+        "verticalAlign": "middle",
+        "richText": {
+          "type": "doc",
+          "content": [
+            {
+              "type": "paragraph"
+            }
+          ]
+        }
+      },
+      "parentId": "page:page",
+      "index": "a1W7b5fV",
+      "typeName": "shape"
+    },
+    "page:page": {
+      "meta": {},
+      "id": "page:page",
+      "name": "Page 1",
+      "index": "a1",
+      "typeName": "page"
+    },
+    "document:document": {
+      "gridSize": 10,
+      "name": "",
+      "meta": {},
+      "id": "document:document",
+      "typeName": "document"
+    },
+    "shape:284-W03iPdkMlHuEYsjAT": {
+      "x": 0,
+      "y": 947.5,
+      "rotation": 0,
+      "isLocked": false,
+      "opacity": 1,
+      "meta": {},
+      "id": "shape:284-W03iPdkMlHuEYsjAT",
+      "type": "arrow",
+      "props": {
+        "kind": "arc",
+        "elbowMidPoint": 0.5,
+        "dash": "draw",
+        "size": "m",
+        "fill": "none",
+        "color": "black",
+        "labelColor": "black",
+        "bend": 0,
+        "start": {
+          "x": 0,
+          "y": 0
+        },
+        "end": {
+          "x": 0,
+          "y": 47
+        },
+        "arrowheadStart": "none",
+        "arrowheadEnd": "arrow",
+        "richText": {
+          "type": "doc",
+          "content": [
+            {
+              "type": "paragraph"
+            }
+          ]
+        },
+        "labelPosition": 0.5,
+        "font": "draw",
+        "scale": 1
+      },
+      "parentId": "page:page",
+      "index": "a37oH73V",
+      "typeName": "shape"
+    }
+  },
+  "schema": {
+    "schemaVersion": 2,
+    "sequences": {
+      "com.tldraw.store": 5,
+      "com.tldraw.asset": 1,
+      "com.tldraw.camera": 1,
+      "com.tldraw.document": 2,
+      "com.tldraw.instance": 26,
+      "com.tldraw.instance_page_state": 5,
+      "com.tldraw.page": 1,
+      "com.tldraw.instance_presence": 6,
+      "com.tldraw.pointer": 1,
+      "com.tldraw.shape": 4,
+      "com.tldraw.asset.bookmark": 2,
+      "com.tldraw.asset.image": 6,
+      "com.tldraw.asset.video": 5,
+      "com.tldraw.shape.arrow": 8,
+      "com.tldraw.shape.bookmark": 2,
+      "com.tldraw.shape.draw": 4,
+      "com.tldraw.shape.embed": 4,
+      "com.tldraw.shape.frame": 1,
+      "com.tldraw.shape.geo": 11,
+      "com.tldraw.shape.group": 0,
+      "com.tldraw.shape.highlight": 3,
+      "com.tldraw.shape.image": 5,
+      "com.tldraw.shape.line": 5,
+      "com.tldraw.shape.note": 10,
+      "com.tldraw.shape.text": 4,
+      "com.tldraw.shape.video": 4,
+      "com.tldraw.binding.arrow": 1
+    }
+  }
+}
+```
 
 ## 一、系统概述
 
@@ -44,28 +225,28 @@
 
 本系统支持的权益按**商品来源**分为两大类:
 
-| 类型  | 说明  | 跳转方式 |
-| --- | --- | --- |
-| **银行自有** | 商城内的自营权益商品(含券码类商品) | 跳转至权益详情页或订单详情页 |
-| **外部** | 第三方合作商家权益(太古地产、龙腾、自定义链接) | 跳转至第三方页面 |
+| 类型       | 说明                       | 跳转方式           |
+| -------- | ------------------------ | -------------- |
+| **银行自有** | 商城内的自营权益商品(含券码类商品)       | 跳转至权益详情页或订单详情页 |
+| **外部**   | 第三方合作商家权益(太古地产、龙腾、自定义链接) | 跳转至第三方页面       |
 
 ### 1.3 权益商品状态流转
 
-```
+```text
 待审核 ──审核通过──> 已上架 ──下架──> 已下架
    └──审核拒绝──> 审核拒绝
 ```
 
-| 状态  | 含义  | 可执行操作 |
-| --- | --- | --- |
-| 待审核 | 已提交,等待审核人审核 | 查看、编辑、审核 |
-| 审核通过 | 审核通过(同"已上架") | 查看、下架 |
-| 审核拒绝 | 审核未通过 | 查看、编辑 |
-| 已上架 | 已上架,前台可见 | 查看、下架、改库存 |
-| 已下架 | 已下架,前台不可见 | 查看、编辑 |
+| 状态   | 含义           | 可执行操作     |
+| ---- | ------------ | --------- |
+| 待审核  | 已提交,等待审核人审核  | 查看、编辑、审核  |
+| 审核通过 | 审核通过(同"已上架") | 查看、下架     |
+| 审核拒绝 | 审核未通过        | 查看、编辑     |
+| 已上架  | 已上架,前台可见     | 查看、下架、改库存 |
+| 已下架  | 已下架,前台不可见    | 查看、编辑     |
 
-* * *
+***
 
 ## 二、后台操作说明
 
@@ -75,7 +256,7 @@
 
 ![菜单入口](../.resources/image-1776675434545.png)
 
-* * *
+***
 
 ### 2.1 添加权益商品
 
@@ -89,14 +270,12 @@
 
 在添加页面顶部,先选择**商品来源**:
 
--   ☑ **银行自有**(默认)
-    
--   ☐ **外部**
-    
+- ☑ **银行自有**(默认)
+- ☐ **外部**
 
 > ⚠️ 商品来源选定后将动态展示对应的字段;提交保存后**不可修改**。
 
-* * *
+***
 
 2.1.1 添加"银行自有"权益
 
@@ -104,31 +283,31 @@
 
 **步骤一:填写商品信息**
 
-| 字段  | 必填  | 填写说明 |
-| --- | --- | --- |
-| **SKU 编号** | 是   | 输入 SKU 编号后,系统自动检索商城内"机构定价含汇丰银行"且为 SIP 渠道的银行自有商品,按"商品名称-SKU 编号"展示。  <br>选择后将自动回填:商品名称→权益名称、商品图片→权益列表图标、商户价格信息 |
-| **权益名称** | 是   | 最长 40 字符 |
-| **权益副标题** | 否   | 最长 40 字符 |
-| **权益列表图标** | 是   | 上传 1 张,用于权益列表的小图 |
-| **权益主图** | 是   | 上传 1 张,用于权益详情页的大图 |
-| **库存数** | 是   | 整数,0 ~ 100000 |
-| **权益概述** | 是   | 富文本,最长 500 字符(详情页中部展示) |
-| **权益详情** | 是   | 富文本,最长 1000 字符(详情页底部使用说明) |
-| **下单成功短信** | 否   | 默认关闭。开启后选择"短信模板",下单成功时自动发送短信。  <br>支持占位符:商品名称 `${productName}`、结束日期 `${expireDate}`、卡号 `${exchangeNum}`、卡密 `${exchangePwd}`、券码路径 `${qrCodeDownPaths}` |
-| **领取成功按钮文案** | 是   | 默认值"马上去使用",可自定义 |
-| **权益列表顺序** | 否   | 数值越小越靠前 |
+| 字段           | 必填 | 填写说明                                                                                                                                             |
+| ------------ | -- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
+| **SKU 编号**   | 是  | 输入 SKU 编号后,系统自动检索商城内"机构定价含汇丰银行"且为 SIP 渠道的银行自有商品,按"商品名称-SKU 编号"展示。 选择后将自动回填:商品名称→权益名称、商品图片→权益列表图标、商户价格信息                                          |
+| **权益名称**     | 是  | 最长 40 字符                                                                                                                                         |
+| **权益副标题**    | 否  | 最长 40 字符                                                                                                                                         |
+| **权益列表图标**   | 是  | 上传 1 张,用于权益列表的小图                                                                                                                                 |
+| **权益主图**     | 是  | 上传 1 张,用于权益详情页的大图                                                                                                                                |
+| **库存数**      | 是  | 整数,0 ~ 100000                                                                                                                                    |
+| **权益概述**     | 是  | 富文本,最长 500 字符(详情页中部展示)                                                                                                                           |
+| **权益详情**     | 是  | 富文本,最长 1000 字符(详情页底部使用说明)                                                                                                                        |
+| **下单成功短信**   | 否  | 默认关闭。开启后选择"短信模板",下单成功时自动发送短信。 支持占位符:商品名称 `${productName}`、结束日期 `${expireDate}`、卡号 `${exchangeNum}`、卡密 `${exchangePwd}`、券码路径 `${qrCodeDownPaths}` |
+| **领取成功按钮文案** | 是  | 默认值"马上去使用",可自定义                                                                                                                                  |
+| **权益列表顺序**   | 否  | 数值越小越靠前                                                                                                                                          |
 
 **价格信息**(选择 SKU 后自动展示):
 
 ![价格信息区域](../.resources/image-1776678323140.png)
 
-| 字段  | 必填  | 说明  |
-| --- | --- | --- |
-| 商户结算价 | \-  | 自动回填,只读 |
-| 商户结算方式 | \-  | 自动回填(发货结算/使用结算),只读 |
-| **科目号** | 是   | 选择对应科目号 |
+| 字段      | 必填 | 说明                 |
+| ------- | -- | ------------------ |
+| 商户结算价   | -  | 自动回填,只读            |
+| 商户结算方式  | -  | 自动回填(发货结算/使用结算),只读 |
+| **科目号** | 是  | 选择对应科目号            |
 
-* * *
+***
 
 2.1.2 添加"外部"权益
 
@@ -136,21 +315,21 @@
 
 外部权益需先选择 **外部商品链接** 和 **链接入口** 两项关键字段:
 
-| 字段  | 必填  | 说明  |
-| --- | --- | --- |
-| **外部商品链接** | 是   | 三选一:`太古地产` / `龙腾` / `自定义`  <br>选择"自定义"时,需填写自定义链接(最长 400 字符) |
-| **链接入口** | 是   | 二选一:`权益列表页` / `权益详情页`  <br>决定用户在 App 哪一层级跳出至外部 |
+| 字段         | 必填 | 说明                                                     |
+| ---------- | -- | ------------------------------------------------------ |
+| **外部商品链接** | 是  | 三选一:`太古地产` / `龙腾` / `自定义` 选择"自定义"时,需填写自定义链接(最长 400 字符) |
+| **链接入口**   | 是  | 二选一:`权益列表页` / `权益详情页` 决定用户在 App 哪一层级跳出至外部              |
 
 **(A)链接入口 = 权益列表页** 时填写以下字段:
 
 ![外部 - 链接入口=权益列表页](../.resources/image-1776677854190.png)
 
-| 字段  | 必填  | 说明  |
-| --- | --- | --- |
-| 权益名称 | 是   | 最长 40 字符 |
-| 权益副标题 | 否   | 最长 40 字符 |
-| 权益列表图标 | 是   | 上传 1 张 |
-| 列表顺序 | 否   | 数值越小越靠前 |
+| 字段     | 必填 | 说明       |
+| ------ | -- | -------- |
+| 权益名称   | 是  | 最长 40 字符 |
+| 权益副标题  | 否  | 最长 40 字符 |
+| 权益列表图标 | 是  | 上传 1 张   |
+| 列表顺序   | 否  | 数值越小越靠前  |
 
 > 用户在 App 权益列表点击图标时**直接跳转外部**,不进入详情页。
 
@@ -158,19 +337,19 @@
 
 ![外部 - 链接入口=权益详情页](../.resources/image-1776677883654.png)
 
-| 字段  | 必填  | 说明  |
-| --- | --- | --- |
-| 权益名称 | 是   | 最长 40 字符 |
-| 权益副标题 | 否   | 最长 40 字符 |
-| 权益列表图标 | 是   | 上传 1 张 |
-| 权益主图 | 是   | 上传 1 张 |
-| 权益概述 | 是   | 富文本,最长 500 字符 |
-| 权益详情 | 是   | 富文本,最长 1000 字符 |
-| 列表顺序 | 否   | 数值越小越靠前 |
+| 字段     | 必填 | 说明             |
+| ------ | -- | -------------- |
+| 权益名称   | 是  | 最长 40 字符       |
+| 权益副标题  | 否  | 最长 40 字符       |
+| 权益列表图标 | 是  | 上传 1 张         |
+| 权益主图   | 是  | 上传 1 张         |
+| 权益概述   | 是  | 富文本,最长 500 字符  |
+| 权益详情   | 是  | 富文本,最长 1000 字符 |
+| 列表顺序   | 否  | 数值越小越靠前        |
 
 > 用户先进入权益详情页,点击【领取权益】后再跳转外部。
 
-* * *
+***
 
 2.1.3 第二步:设置规则
 
@@ -178,27 +357,27 @@
 
 **展示规则**(控制权益是否在 App 列表中可见):
 
-| 字段  | 类型  | 说明  |
-| --- | --- | --- |
-| **展示时间限制** | 开关  | 默认关闭。开启后配置开始/结束时间(精确到秒),超出区间则不展示 |
-| **展示客群限制** | 开关  | 默认关闭。开启后选择客群标签 ID(支持多选),命中标签的用户才可见 |
+| 字段         | 类型 | 说明                                 |
+| ---------- | -- | ---------------------------------- |
+| **展示时间限制** | 开关 | 默认关闭。开启后配置开始/结束时间(精确到秒),超出区间则不展示   |
+| **展示客群限制** | 开关 | 默认关闭。开启后选择客群标签 ID(支持多选),命中标签的用户才可见 |
 
 **领取规则**(控制用户能否领取):
 
-| 字段  | 类型  | 说明  |
-| --- | --- | --- |
-| **领取时间限制** | 开关  | 默认关闭。开启后配置开始/结束时间(精确到秒)  <br>未到开始时间:按钮显示【未开始】  <br>超过结束时间:按钮显示【已失效】 |
-| **领取客群限制** | 开关  | 默认关闭。开启后需配置:  <br>• **标签**:标签 ID(必填,最长 50 字符)  <br>• **不满足提示内容**:必填,最长 200 字符  <br>• **跳转按钮文案**:必填,最长 10 字符  <br>• **跳转按钮链接**:必填,最长 200 字符 |
+| 字段         | 类型 | 说明                                                                                                                     |
+| ---------- | -- | ---------------------------------------------------------------------------------------------------------------------- |
+| **领取时间限制** | 开关 | 默认关闭。开启后配置开始/结束时间(精确到秒) 未到开始时间:按钮显示【未开始】 超过结束时间:按钮显示【已失效】                                                              |
+| **领取客群限制** | 开关 | 默认关闭。开启后需配置: • **标签**:标签 ID(必填,最长 50 字符) • **不满足提示内容**:必填,最长 200 字符 • **跳转按钮文案**:必填,最长 10 字符 • **跳转按钮链接**:必填,最长 200 字符 |
 
 2.1.4 操作按钮
 
-| 按钮  | 行为  |
-| --- | --- |
-| **上一步 / 下一步** | 在两个步骤间导航 |
-| **取消** | 放弃操作,返回权益列表页 |
-| **提交** | 校验所有必填项,通过后创建记录,状态变为【待审核】 |
+| 按钮            | 行为                        |
+| ------------- | ------------------------- |
+| **上一步 / 下一步** | 在两个步骤间导航                  |
+| **取消**        | 放弃操作,返回权益列表页              |
+| **提交**        | 校验所有必填项,通过后创建记录,状态变为【待审核】 |
 
-* * *
+***
 
 ### 2.2 编辑权益商品
 
@@ -208,40 +387,28 @@
 
 **注意事项**:
 
--   ⚠️ **【商品来源】不可编辑**,其他字段均可编辑
-    
--   保存后状态重置为【待审核】,需重新审核
-    
-
-| 按钮  | 行为  |
-| --- | --- |
-| 取消  | 放弃操作,返回列表页 |
-| 保存  | 校验必填项,通过后更新记录,状态变为【待审核】 |
-
-<br>
-
-<br>
-
-<br>
+- ⚠️ **【商品来源】不可编辑**,其他字段均可编辑
+- 保存后状态重置为【待审核】,需重新审核
 
-<br>
+| 按钮 | 行为                      |
+| -- | ----------------------- |
+| 取消 | 放弃操作,返回列表页              |
+| 保存 | 校验必填项,通过后更新记录,状态变为【待审核】 |
 
 ![编辑权益 1](../.resources/image-1776678460565.png)![编辑权益 2](../.resources/image-1776678477468.png)
 
-* * *
+***
 
 ### 2.3 查看权益商品
 
 **操作入口**:权益列表 → 列表行【操作】列 → 【查看】
 
--   字段同【编辑】,但所有输入框、选择框**禁用**
-    
--   **不展示**【取消】和【提交】按钮
-    
+- 字段同【编辑】,但所有输入框、选择框**禁用**
+- **不展示**【取消】和【提交】按钮
 
 ![查看权益](../.resources/image-1776678401993.png)
 
-* * *
+***
 
 ### 2.4 审核权益商品
 
@@ -249,21 +416,19 @@
 
 **操作流程**:
 
-1.  列表点击【审核】,进入审核页面(字段同【查看】)
-    
-2.  页面底部展示两个操作按钮:
-    
+1. 列表点击【审核】,进入审核页面(字段同【查看】)
+2. 页面底部展示两个操作按钮:
 
-| 按钮  | 行为  |
-| --- | --- |
+| 按钮       | 行为                  |
+| -------- | ------------------- |
 | **审核拒绝** | 弹窗二次确认 → 状态变为【审核拒绝】 |
-| **审核通过** | 弹窗二次确认 → 状态变为【已上架】 |
+| **审核通过** | 弹窗二次确认 → 状态变为【已上架】  |
 
 ![审核操作](../.resources/image-1776678587748.png)
 
 > 💡 **审核通过后即直接【已上架】**,前台立即可见,无需额外上架操作。
 
-* * *
+***
 
 ### 2.5 下架权益商品
 
@@ -271,17 +436,15 @@
 
 **操作流程**:
 
-1.  列表点击【下架】,弹出确认提示:**"确定要下架权益 'XXX' 吗?"**
-    
-2.  选择操作:
-    
+1. 列表点击【下架】,弹出确认提示:**"确定要下架权益 'XXX' 吗?"**
+2. 选择操作:
 
-| 按钮  | 行为  |
-| --- | --- |
-| 确定  | 状态变为【已下架】,前台不再展示且无法兑换下单 |
-| 取消  | 关闭弹窗,状态不变 |
+| 按钮 | 行为                      |
+| -- | ----------------------- |
+| 确定 | 状态变为【已下架】,前台不再展示且无法兑换下单 |
+| 取消 | 关闭弹窗,状态不变               |
 
-* * *
+***
 
 ### 2.6 修改库存
 
@@ -289,29 +452,25 @@
 
 **操作流程**:
 
-1.  列表点击【改库存】,弹出"改库存"对话框
-    
-2.  弹窗内容:
-    
-
-| 字段  | 说明  |
-| --- | --- |
-| 权益名称 | 只读  |
-| 当前库存 | 只读  |
-| **调整类型** | 单选:`增加库存` / `减少库存` |
-| **调整库存数** | 整数  |
+1. 列表点击【改库存】,弹出"改库存"对话框
+2. 弹窗内容:
+
+| 字段         | 说明                             |
+| ---------- | ------------------------------ |
+| 权益名称       | 只读                             |
+| 当前库存       | 只读                             |
+| **调整类型**   | 单选:`增加库存` / `减少库存`             |
+| **调整库存数**  | 整数                             |
 | **调整后库存数** | 自动计算:增加 = 当前 + 调整;减少 = 当前 - 调整 |
 
 **校验规则**:
 
--   增加库存时,**调整后库存数不能大于 100000**,否则提示"调整后库存不能大于 10000"
-    
--   减少库存时,**调整后库存数不能小于 0**,否则提示"调整库存不能小于 0"
-    
+- 增加库存时,**调整后库存数不能大于 100000**,否则提示"调整后库存不能大于 10000"
+- 减少库存时,**调整后库存数不能小于 0**,否则提示"调整库存不能小于 0"
 
 ![改库存弹窗](../.resources/image-1776678623793.png)
 
-* * *
+***
 
 ### 2.7 权益列表筛选与查询
 
@@ -319,49 +478,44 @@
 
 2.7.1 筛选条件
 
-| 字段  | 类型  | 说明  |
-| --- | --- | --- |
-| 权益名称 | 文本输入 | 模糊搜索 |
-| 商品 ID | 文本输入 | 精确匹配 |
+| 字段     | 类型   | 说明   |
+| ------ | ---- | ---- |
+| 权益名称   | 文本输入 | 模糊搜索 |
+| 商品 ID  | 文本输入 | 精确匹配 |
 | SKU 编号 | 文本输入 | 精确匹配 |
-| 科目号 | 文本输入 | 精确匹配 |
+| 科目号    | 文本输入 | 精确匹配 |
 
 **操作按钮**:
 
--   【查询】:根据筛选条件查询权益列表
-    
--   【重置】:清空所有筛选条件
-    
--   【添加权益商品】:打开添加页面
-    
+- 【查询】:根据筛选条件查询权益列表
+- 【重置】:清空所有筛选条件
+- 【添加权益商品】:打开添加页面
 
 2.7.2 列表字段
 
-| 字段  | 说明  |
-| --- | --- |
-| 操作  | 查看 / 编辑 / 审核 / 下架 / 改库存(按状态显示) |
-| 权益名称 | 权益名称 |
-| 审核状态 | 待审核 / 审核通过 / 审核拒绝 / 已上架 / 已下架 |
-| 库存数 | 当前库存数量 |
-| 商品来源 | 银行自有 / 外部 |
-| 外部商品链接 | 太古地产 / 龙腾 / 自定义;银行自有显示"-" |
-| 链接入口 | 权益列表页 / 权益详情页;银行自有显示"-" |
-| 商品 ID | 商品 ID |
-| SKU 编号 | 关联的 SKU 编号 |
-| 商户名称 | 商品商户名称 |
-| 商户结算价 | 商户结算价 |
-| 商户结算方式 | 发货结算 / 使用结算 |
-| 审核人 | 执行审核的操作人 |
-| 审核时间 | 审核操作的时间 |
+| 字段     | 说明                             |
+| ------ | ------------------------------ |
+| 操作     | 查看 / 编辑 / 审核 / 下架 / 改库存(按状态显示) |
+| 权益名称   | 权益名称                           |
+| 审核状态   | 待审核 / 审核通过 / 审核拒绝 / 已上架 / 已下架  |
+| 库存数    | 当前库存数量                         |
+| 商品来源   | 银行自有 / 外部                      |
+| 外部商品链接 | 太古地产 / 龙腾 / 自定义;银行自有显示"-"      |
+| 链接入口   | 权益列表页 / 权益详情页;银行自有显示"-"        |
+| 商品 ID  | 商品 ID                          |
+| SKU 编号 | 关联的 SKU 编号                     |
+| 商户名称   | 商品商户名称                         |
+| 商户结算价  | 商户结算价                          |
+| 商户结算方式 | 发货结算 / 使用结算                    |
+| 审核人    | 执行审核的操作人                       |
+| 审核时间   | 审核操作的时间                        |
 
 2.7.3 分页
 
--   每页默认显示 **20 条**
-    
--   支持:首页、上一页、下一页、末页、跳转至指定页
-    
+- 每页默认显示 **20 条**
+- 支持:首页、上一页、下一页、末页、跳转至指定页
 
-* * *
+***
 
 ## 三、移动端展示效果
 
@@ -369,7 +523,7 @@
 
 ### 3.1 权益主页(积木侧搭建)
 
-借记卡权益通过\*\*积木组件"百变导航"\*\*在权益主页配置入口展示。
+借记卡权益通过**积木组件"百变导航"**在权益主页配置入口展示。
 
 ### 3.2 我的权益 - 权益列表
 
@@ -377,7 +531,7 @@
 
 3.2.1 展示顺序
 
-```
+```text
 借记卡权益(新增) → 信用卡权益(现有) → 微信立减金(置底)
 ```
 
@@ -385,57 +539,47 @@
 
 **展示条件**(必须同时满足):
 
--   ✅ 商品状态:已上架
-    
--   ✅ 商品类型:不为微信立减金
-    
--   ✅ 展示时间限制:未开启 或 当前时间在配置区间内
-    
--   ✅ 展示客群限制:未开启 或 用户命中配置的客群标签
-    
+- ✅ 商品状态:已上架
+- ✅ 商品类型:不为微信立减金
+- ✅ 展示时间限制:未开启 或 当前时间在配置区间内
+- ✅ 展示客群限制:未开启 或 用户命中配置的客群标签
 
 **列表字段**:权益列表图标 + 权益名称
 
 **排序规则**:
 
-1.  按"权益列表顺序"从小到大
-    
-2.  同一顺序,按审核通过时间从后往前
-    
+1. 按"权益列表顺序"从小到大
+2. 同一顺序,按审核通过时间从后往前
 
 **点击跳转规则**:
 
-| 商品来源 | 链接入口 | 跳转行为 |
-| --- | --- | --- |
-| 银行自有 | \-  | 跳转**权益详情页** |
-| 外部  | 权益列表页 | 直接跳转**第三方链接** |
-| 外部  | 权益详情页 | 跳转**权益详情页**,详情页内点击领取再跳第三方 |
+| 商品来源 | 链接入口  | 跳转行为                      |
+| ---- | ----- | ------------------------- |
+| 银行自有 | -     | 跳转**权益详情页**               |
+| 外部   | 权益列表页 | 直接跳转**第三方链接**             |
+| 外部   | 权益详情页 | 跳转**权益详情页**,详情页内点击领取再跳第三方 |
 
 **外部跳转的弹窗交互**:
 
-| 外部商品链接 | 交互流程 |
-| --- | --- |
-| **自定义** | 弹窗"您正在离开汇丰中国" → 点击【继续前往】跳转自定义链接 |
+| 外部商品链接   | 交互流程                                          |
+| -------- | --------------------------------------------- |
+| **自定义**  | 弹窗"您正在离开汇丰中国" → 点击【继续前往】跳转自定义链接               |
 | **太古地产** | 弹出授权提醒 → 勾选同意并确认 → 显示离开提示 → 调用太古地产接口 → 跳转免登地址 |
-| **龙腾** | 弹出授权提醒 → 勾选同意并确认 → 显示离开提示 → 调用龙腾接口 → 跳转免登地址 |
+| **龙腾**   | 弹出授权提醒 → 勾选同意并确认 → 显示离开提示 → 调用龙腾接口 → 跳转免登地址   |
 
-> **自定义弹窗文案**:
-> 
-> -   标题:您正在离开汇丰中国
->     
-> -   描述:请注意,外部网站的政策与我们网站的条款和条件以及隐私政策不同。将在新浏览器窗口或选项卡中打开下一个网站。
->     
-> -   按钮:取消 / 继续前往
->     
+> **自定义弹窗文案**:\
+> 标题:您正在离开汇丰中国\
+> 描述:请注意,外部网站的政策与我们网站的条款和条件以及隐私政策不同。将在新浏览器窗口或选项卡中打开下一个网站。\
+> 按钮:取消 / 继续前往
 
 **外部跳转弹窗示意:**
 
-| 类型  | 截图  |
-| --- | --- |
-| 自定义离开提示 | ![自定义离开提示](../.resources/image-1776678703451.png) |
-| 太古地产授权(步骤一) | ![太古授权](../.resources/image-1776678728870.png) |
-| 太古地产离开提示(步骤二) | ![太古离开提示](../.resources/image-1776678755981.png) |
-| 龙腾授权 | ![龙腾授权](../.resources/image-1776678775726.png) |
+| 类型            | 截图 |
+| ------------- | -- |
+| 自定义离开提示       |    |
+| 太古地产授权(步骤一)   |    |
+| 太古地产离开提示(步骤二) |    |
+| 龙腾授权          |    |
 
 ### 3.3 我的权益 - 我的(已领权益)
 
@@ -443,15 +587,15 @@
 
 **展示顺序**:
 
-```
+```text
 券码权益(未过期)→ 信用卡权益 → 券码权益(已失效)
 ```
 
-| 分类  | 展示字段 | 排序规则 | 点击跳转 |
-| --- | --- | --- | --- |
-| **券码(未过期)** | 图标、名称、副标题 | 券码有效期,先到期先展示 | 订单详情页 |
-| **信用卡权益** | 接口返回 | 按接口返回 | 按接口返回 |
-| **券码(已失效)** | 图标、名称 | 最近到期先展示,仅查近一年 | 订单详情页 |
+| 分类          | 展示字段      | 排序规则          | 点击跳转  |
+| ----------- | --------- | ------------- | ----- |
+| **券码(未过期)** | 图标、名称、副标题 | 券码有效期,先到期先展示  | 订单详情页 |
+| **信用卡权益**   | 接口返回      | 按接口返回         | 按接口返回 |
+| **券码(已失效)** | 图标、名称     | 最近到期先展示,仅查近一年 | 订单详情页 |
 
 ### 3.4 权益详情页
 
@@ -459,33 +603,28 @@
 
 **展示内容**:
 
--   权益主图
-    
--   权益名称(超出换行)
-    
--   权益概述(富文本)
-    
--   权益详情(富文本)
-    
--   领取按钮(按状态显示文案)
-    
+- 权益主图
+- 权益名称(超出换行)
+- 权益概述(富文本)
+- 权益详情(富文本)
+- 领取按钮(按状态显示文案)
 
 **按钮状态规则**:
 
-| 状态  | 按钮文案 | 是否可点击 |
-| --- | --- | --- |
-| 开启领取时间限制且未到开始时间 | 未开始 | ❌   |
-| 开启领取时间限制且超过结束时间 | 已失效 | ❌   |
-| 库存为 0 | 已领完 | ❌   |
-| 其他正常情况 | 领取权益 | ✅   |
+| 状态              | 按钮文案 | 是否可点击 |
+| --------------- | ---- | ----- |
+| 开启领取时间限制且未到开始时间 | 未开始  | ❌     |
+| 开启领取时间限制且超过结束时间 | 已失效  | ❌     |
+| 库存为 0           | 已领完  | ❌     |
+| 其他正常情况          | 领取权益 | ✅     |
 
 | 详情页示意 1 | 详情页示意 2 |
-| --- | --- |
-| ![权益详情页 1](../.resources/image-1776678923546.png) | ![权益详情页 2](../.resources/image-1776678942001.png) |
+| ------- | ------- |
+|         |         |
 
 **点击【领取权益】校验顺序**:
 
-```
+```text
 1. 校验领取客群规则 → 不满足:展示后台配置的不满足提示
 2. 校验商品库存       → 不足:提示"该权益已领完"
 3. 校验通过 → 处理领取逻辑
@@ -493,24 +632,22 @@
 
 **领取成功的两种处理**:
 
--   **银行自有**:弹"尊敬的客户,您已成功领取权益" → 点击按钮跳转**权益订单详情页**
-    
--   **外部 + 详情页入口**:根据外部链接类型走自定义/太古/龙腾跳转流程
-    
+- **银行自有**:弹"尊敬的客户,您已成功领取权益" → 点击按钮跳转**权益订单详情页**
+- **外部 + 详情页入口**:根据外部链接类型走自定义/太古/龙腾跳转流程
 
 **银行自有领取成功提示示意:**
 
 | 提示弹窗 | 跳转后效果 |
-| --- | --- |
-| ![领取成功 1](../.resources/image-1776678975193.png) | ![领取成功 2](../.resources/image-1776678985797.png) |
+| ---- | ----- |
+|      |       |
 
 **外部跳转交互(详情页入口):**
 
-| 类型  | 截图  |
-| --- | --- |
-| 自定义离开提示 | ![详情页-自定义](../.resources/image-1776679010497.png) |
-| 太古地产授权 | ![详情页-太古](../.resources/image-1776679026345.png) |
-| 龙腾授权 | ![详情页-龙腾](../.resources/image-1776679039096.png) |
+| 类型      | 截图 |
+| ------- | -- |
+| 自定义离开提示 |    |
+| 太古地产授权  |    |
+| 龙腾授权    |    |
 
 ### 3.5 权益订单详情(仅券码类)
 
@@ -520,12 +657,12 @@
 
 **展示内容**:
 
-| 字段  | 说明  |
-| --- | --- |
-| 兑换卡号 | 默认掩码,点击【显示】查看明文,点击【复制】复制 |
-| 兑换密钥 | 默认掩码,点击【显示】查看明文,点击【复制】复制 |
-| 隐藏 / 显示 | 切换卡号和密钥的显示状态 |
-| 使用按钮 | 文案取后台"领取成功按钮文案"(默认"马上去使用"),点击跳转使用链接 |
+| 字段      | 说明                                  |
+| ------- | ----------------------------------- |
+| 兑换卡号    | 默认掩码,点击【显示】查看明文,点击【复制】复制            |
+| 兑换密钥    | 默认掩码,点击【显示】查看明文,点击【复制】复制            |
+| 隐藏 / 显示 | 切换卡号和密钥的显示状态                        |
+| 使用按钮    | 文案取后台"领取成功按钮文案"(默认"马上去使用"),点击跳转使用链接 |
 
 ### 3.6 我的立减金
 
@@ -535,27 +672,27 @@
 
 **商品展示信息**:
 
-| 字段  | 取值  |
-| --- | --- |
-| 权益图片 | 后台"权益列表图标" |
-| 商品名称 | 后台"权益名称" |
-| 副标题描述 | 后台"权益副标题" |
-| 有效期 | SIP 固定日期模式的有效期结束时间 |
+| 字段    | 取值                 |
+| ----- | ------------------ |
+| 权益图片  | 后台"权益列表图标"         |
+| 商品名称  | 后台"权益名称"           |
+| 副标题描述 | 后台"权益副标题"          |
+| 有效期   | SIP 固定日期模式的有效期结束时间 |
 
 **按钮三种状态**:
 
-| 状态  | 按钮文案 | 行为  |
-| --- | --- | --- |
-| 未领取 | 立即领取 | 点击领取微信立减金 |
-| 已领取 | 已领取 | 点击进入权益商品详情 |
-| 已过期 | 已过期 | 不可点击 |
+| 状态  | 按钮文案 | 行为         |
+| --- | ---- | ---------- |
+| 未领取 | 立即领取 | 点击领取微信立减金  |
+| 已领取 | 已领取  | 点击进入权益商品详情 |
+| 已过期 | 已过期  | 不可点击       |
 
 **展示顺序**:未领取 → 已领取 → 已过期
 
-| 状态  | 排序规则 |
-| --- | --- |
+| 状态  | 排序规则              |
+| --- | ----------------- |
 | 未领取 | 权益点有效期结束时间,先到期先展示 |
-| 已领取 | 权益下单时间,先下单先展示 |
+| 已领取 | 权益下单时间,先下单先展示     |
 | 已过期 | 权益点有效期结束时间,先到期先展示 |
 
 **筛选**:页面支持按状态筛选,无数据时展示"暂无立减金"。
@@ -564,7 +701,7 @@
 
 **领取流程**:
 
-```
+```text
 1. 调用行内接口 → 用客户号查询 openId
 2. 调用 SIP 订单创建接口(立减金类型必传 openId)
 3. SIP 通过异步通知告诉商城下单成功
@@ -572,72 +709,71 @@
    异常情况:toast 提示"系统异常,请联系客服人员"
 ```
 
-* * *
+***
 
 ## 四、常见问题(FAQ)
 
-**Q1:权益商品提交后还能修改商品来源吗?**  
+**Q1:权益商品提交后还能修改商品来源吗?**\
+\
 A:不能。商品来源(银行自有/外部)一旦提交保存后即不可修改。如需调整,请下架后重新创建。
 
-**Q2:编辑后是否需要重新审核?**  
+**Q2:编辑后是否需要重新审核?**\
+\
 A:是的。编辑保存后状态会重置为【待审核】,需要审核人重新审核通过后才会重新上架。
 
-**Q3:审核通过后多久能在 App 上看到?**  
+**Q3:审核通过后多久能在 App 上看到?**\
+\
 A:审核通过后,状态直接变为【已上架】,前台立即可见(前提是当前时间在"展示时间限制"配置区间内,且用户命中"展示客群限制")。
 
-**Q4:库存为 0 时权益还会展示在列表中吗?**  
+**Q4:库存为 0 时权益还会展示在列表中吗?**\
+\
 A:会展示。但用户点击【领取权益】时会提示"该权益已领完",无法领取。如需彻底隐藏,请执行【下架】操作。
 
-**Q5:外部权益(太古/龙腾)需要后端配合什么?**  
+**Q5:外部权益(太古/龙腾)需要后端配合什么?**\
+\
 A:太古地产和龙腾跳转需要调用对应的免登接口,由后端返回免登地址后再跳转。运营人员只需在后台配置外部商品链接类型即可。
 
-**Q6:自定义外部链接支持什么协议?**  
+**Q6:自定义外部链接支持什么协议?**\
+\
 A:支持标准的 https/http 链接,最长 400 字符。
 
-**Q7:下单成功短信不发送,是否影响订单?**  
+**Q7:下单成功短信不发送,是否影响订单?**\
+\
 A:不影响。"下单成功短信"开关默认关闭,关闭时不会发送短信,订单流程正常。
 
-**Q8:权益列表顺序数值相同,谁先展示?**  
+**Q8:权益列表顺序数值相同,谁先展示?**\
+\
 A:按"审核通过时间"从后往前展示(即最近审核通过的排前面)。
 
-**Q9:领取客群限制和展示客群限制有什么区别?**  
+**Q9:领取客群限制和展示客群限制有什么区别?**\
+\
 A:
 
--   **展示客群限制**:控制权益是否**出现在 App 列表中**,不命中的用户根本看不到
-    
--   **领取客群限制**:权益对所有人可见,但点击领取时校验,不命中的用户会看到不满足提示
-    
+- **展示客群限制**:控制权益是否**出现在 App 列表中**,不命中的用户根本看不到
+- **领取客群限制**:权益对所有人可见,但点击领取时校验,不命中的用户会看到不满足提示
 
-**Q10:改库存有审计记录吗?**  
+**Q10:改库存有审计记录吗?**\
+\
 A:每次改库存操作系统会记录操作人和时间,便于事后追溯。
 
-* * *
+***
 
 ## 附录:客户确认清单
 
 请客户在使用前对以下要点进行确认:
 
--   后台菜单入口路径正确:定制功能 → 汇丰银行
-    
--   权益商品两步骤添加流程符合业务习惯
-    
--   银行自有 vs 外部 两种来源的字段差异符合业务需求
-    
--   外部权益(太古/龙腾/自定义)的跳转交互文案符合品牌规范
-    
--   状态流转规则(待审核 → 已上架 → 已下架)符合内部审批流程
-    
--   库存上限 100000、下限 0 的限制符合实际业务量
-    
--   短信模板占位符(商品名称、卡号、卡密等)字段命名符合现有规范
-    
--   移动端三类权益(借记卡/信用卡/微信立减金)的展示顺序符合产品策略
-    
--   微信立减金领取的接口对接(行内 openId 接口、SIP 订单接口)已确认
-    
-
-* * *
+- 后台菜单入口路径正确:定制功能 → 汇丰银行
+- 权益商品两步骤添加流程符合业务习惯
+- 银行自有 vs 外部 两种来源的字段差异符合业务需求
+- 外部权益(太古/龙腾/自定义)的跳转交互文案符合品牌规范
+- 状态流转规则(待审核 → 已上架 → 已下架)符合内部审批流程
+- 库存上限 100000、下限 0 的限制符合实际业务量
+- 短信模板占位符(商品名称、卡号、卡密等)字段命名符合现有规范
+- 移动端三类权益(借记卡/信用卡/微信立减金)的展示顺序符合产品策略
+- 微信立减金领取的接口对接(行内 openId 接口、SIP 订单接口)已确认
+
+***
 
 **文档结束**
 
-如对本操作手册有任何疑问或修改建议,请联系产品团队。
+如对本操作手册有任何疑问或修改建议,请联系产品团队。

+ 3 - 0
pc-v3/src/components/Layout.vue

@@ -50,6 +50,9 @@
               <el-menu-item index="/customization/hsbc/equity-grant-campaign">
                 发放计划
               </el-menu-item>
+              <el-menu-item index="/customization/hsbc/grant-task">
+                发放任务
+              </el-menu-item>
               <el-menu-item index="/customization/hsbc/campaign-audit">
                 发放计划审核
               </el-menu-item>

+ 13 - 12
pc-v3/src/components/RongshuProductDialog.vue

@@ -23,6 +23,7 @@
 
     <el-table :data="pagedData" border stripe size="small" style="width: 100%">
       <el-table-column prop="name" label="商品名称" min-width="180" show-overflow-tooltip />
+      <el-table-column prop="skuNo" label="SKU编号" width="180" show-overflow-tooltip />
       <el-table-column prop="merchant" label="商户名称" width="160" show-overflow-tooltip />
       <el-table-column label="银行结算价" width="120" align="right">
         <template #default="{ row }">¥{{ row.settlePrice.toFixed(2) }}</template>
@@ -49,18 +50,18 @@
 
 <script>
 const MOCK_PRODUCTS = [
-  { name: '微信立减金 5元(满10减5)', merchant: '微信支付', settlePrice: 5, stock: 2000, mainImage: [{ name: 'wx-5.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A55' }] },
-  { name: '微信立减金 8元(满30减8)', merchant: '微信支付', settlePrice: 8, stock: 1500, mainImage: [{ name: 'wx-8.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A58' }] },
-  { name: '微信立减金 10元(满50减10)', merchant: '微信支付', settlePrice: 10, stock: 1200, mainImage: [{ name: 'wx-10.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A510' }] },
-  { name: '微信立减金 18元(满88减18)', merchant: '微信支付', settlePrice: 18, stock: 1000, mainImage: [{ name: 'wx-18.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A518' }] },
-  { name: '微信立减金 20元(满100减20)', merchant: '微信支付', settlePrice: 20, stock: 800, mainImage: [{ name: 'wx-20.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A520' }] },
-  { name: '微信立减金 30元(满150减30)', merchant: '微信支付', settlePrice: 30, stock: 600, mainImage: [{ name: 'wx-30.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A530' }] },
-  { name: '微信立减金 50元(满200减50)', merchant: '微信支付', settlePrice: 50, stock: 400, mainImage: [{ name: 'wx-50.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A550' }] },
-  { name: '微信立减金 66元(满300减66)', merchant: '微信支付', settlePrice: 66, stock: 300, mainImage: [{ name: 'wx-66.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A566' }] },
-  { name: '微信立减金 88元(满388减88)', merchant: '微信支付', settlePrice: 88, stock: 200, mainImage: [{ name: 'wx-88.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A588' }] },
-  { name: '微信立减金 100元(满500减100)', merchant: '微信支付', settlePrice: 100, stock: 150, mainImage: [{ name: 'wx-100.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A5100' }] },
-  { name: '微信立减金 128元(满600减128)', merchant: '微信支付', settlePrice: 128, stock: 100, mainImage: [{ name: 'wx-128.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A5128' }] },
-  { name: '微信立减金 200元(满800减200)', merchant: '微信支付', settlePrice: 200, stock: 80, mainImage: [{ name: 'wx-200.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A5200' }] }
+  { name: '微信立减金 5元(满10减5)', skuNo: 'V0000003900000801', merchant: '微信支付', settlePrice: 5, stock: 2000, mainImage: [{ name: 'wx-5.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A55' }] },
+  { name: '微信立减金 8元(满30减8)', skuNo: 'V0000003900000802', merchant: '微信支付', settlePrice: 8, stock: 1500, mainImage: [{ name: 'wx-8.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A58' }] },
+  { name: '微信立减金 10元(满50减10)', skuNo: 'V0000003900000803', merchant: '微信支付', settlePrice: 10, stock: 1200, mainImage: [{ name: 'wx-10.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A510' }] },
+  { name: '微信立减金 18元(满88减18)', skuNo: 'V0000003900000804', merchant: '微信支付', settlePrice: 18, stock: 1000, mainImage: [{ name: 'wx-18.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A518' }] },
+  { name: '微信立减金 20元(满100减20)', skuNo: 'V0000003900000805', merchant: '微信支付', settlePrice: 20, stock: 800, mainImage: [{ name: 'wx-20.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A520' }] },
+  { name: '微信立减金 30元(满150减30)', skuNo: 'V0000003900000806', merchant: '微信支付', settlePrice: 30, stock: 600, mainImage: [{ name: 'wx-30.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A530' }] },
+  { name: '微信立减金 50元(满200减50)', skuNo: 'V0000003900000807', merchant: '微信支付', settlePrice: 50, stock: 400, mainImage: [{ name: 'wx-50.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A550' }] },
+  { name: '微信立减金 66元(满300减66)', skuNo: 'V0000003900000808', merchant: '微信支付', settlePrice: 66, stock: 300, mainImage: [{ name: 'wx-66.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A566' }] },
+  { name: '微信立减金 88元(满388减88)', skuNo: 'V0000003900000809', merchant: '微信支付', settlePrice: 88, stock: 200, mainImage: [{ name: 'wx-88.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A588' }] },
+  { name: '微信立减金 100元(满500减100)', skuNo: 'V0000003900000810', merchant: '微信支付', settlePrice: 100, stock: 150, mainImage: [{ name: 'wx-100.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A5100' }] },
+  { name: '微信立减金 128元(满600减128)', skuNo: 'V0000003900000811', merchant: '微信支付', settlePrice: 128, stock: 100, mainImage: [{ name: 'wx-128.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A5128' }] },
+  { name: '微信立减金 200元(满800减200)', skuNo: 'V0000003900000812', merchant: '微信支付', settlePrice: 200, stock: 80, mainImage: [{ name: 'wx-200.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A5200' }] }
 ]
 
 export default {

+ 218 - 12
pc-v3/src/mock/index.js

@@ -378,6 +378,7 @@ const equityList = [
     productId: 'Q100001',
     equityName: '权益A',
     source: '银行自有',
+    isPlatformExchange: '是',
     jumpMethod: '-',
     jumpLink: '-',
     exchangeMethod: '权益平台',
@@ -398,6 +399,7 @@ const equityList = [
     productId: 'Q100002',
     equityName: '权益B',
     source: '第三方',
+    isPlatformExchange: '否',
     jumpMethod: '没有',
     jumpLink: '太古地产',
     exchangeMethod: '第三方(列表跳转)',
@@ -418,6 +420,7 @@ const equityList = [
     productId: 'Q100003',
     equityName: '权益C',
     source: '第三方',
+    isPlatformExchange: '否',
     jumpMethod: '有',
     jumpLink: '龙腾',
     exchangeMethod: '第三方(详情页跳转)',
@@ -438,6 +441,7 @@ const equityList = [
     productId: 'Q100004',
     equityName: '权益D',
     source: '第三方',
+    isPlatformExchange: '否',
     jumpMethod: '有',
     jumpLink: 'h5链接',
     exchangeMethod: '第三方(详情页跳转)',
@@ -458,6 +462,7 @@ const equityList = [
     productId: 'Q100005',
     equityName: '权益E',
     source: '银行自有',
+    isPlatformExchange: '是',
     jumpMethod: '-',
     jumpLink: '-',
     exchangeMethod: '权益平台',
@@ -478,6 +483,7 @@ const equityList = [
     productId: 'Q100006',
     equityName: '权益F(草稿)',
     source: '银行自有',
+    isPlatformExchange: '是',
     jumpMethod: '-',
     jumpLink: '-',
     exchangeMethod: '权益平台',
@@ -493,10 +499,56 @@ const equityList = [
     showOnHome: '不显示',
     showOnAssembly: '不显示',
     assemblyPages: []
+  },
+  {
+    productId: 'Q100007',
+    equityName: '微信立减金 5元(满10减5)',
+    source: '荣数商品',
+    isPlatformExchange: '是',
+    jumpMethod: '-',
+    jumpLink: '-',
+    exchangeMethod: '权益平台',
+    productType: '微信立减金',
+    skuNo: 'V0000003900000801',
+    rongshuProduct: '微信立减金 5元(满10减5)',
+    merchantName: '微信支付',
+    stockCount: 2000,
+    creator: '张三',
+    createTime: '2026-05-20 10:00:00',
+    reviewer: '李四',
+    reviewTime: '2026-05-22 15:30:00',
+    shelfStatus: '已上架',
+    auditStatus: '审核通过',
+    showOnHome: '显示',
+    showOnAssembly: '不显示',
+    assemblyPages: []
+  },
+  {
+    productId: 'Q100008',
+    equityName: '微信立减金 50元(满200减50)',
+    source: '荣数商品',
+    isPlatformExchange: '是',
+    jumpMethod: '-',
+    jumpLink: '-',
+    exchangeMethod: '权益平台',
+    productType: '微信立减金',
+    skuNo: 'V0000003900000807',
+    rongshuProduct: '微信立减金 50元(满200减50)',
+    merchantName: '微信支付',
+    stockCount: 400,
+    creator: '张三',
+    createTime: '2026-05-18 09:30:00',
+    reviewer: '',
+    reviewTime: '',
+    shelfStatus: '未上架',
+    auditStatus: '上架待审核',
+    showOnHome: '显示',
+    showOnAssembly: '显示',
+    assemblyPages: ['组装页1']
   }
 ]
 
-let equityIdCounter = 100006
+let equityIdCounter = 100008
 
 const auditList = [
   {
@@ -509,6 +561,7 @@ const auditList = [
     snapshot: {
       equityName: '权益B',
       source: '第三方',
+      isPlatformExchange: '否',
       jumpMethod: '没有',
       jumpLink: '太古地产',
       productType: '',
@@ -536,6 +589,7 @@ const auditList = [
     snapshot: {
       equityName: '权益D',
       source: '第三方',
+      isPlatformExchange: '否',
       jumpMethod: '有',
       jumpLink: 'h5链接',
       productType: '',
@@ -563,6 +617,7 @@ const auditList = [
     snapshot: {
       equityName: '权益A',
       source: '银行自有',
+      isPlatformExchange: '是',
       jumpMethod: '-',
       jumpLink: '-',
       productType: '券码',
@@ -599,9 +654,10 @@ function snapshotOf(equity) {
   return {
     equityName: equity.equityName,
     source: equity.source,
+    isPlatformExchange: equity.isPlatformExchange || (equity.source === '第三方' ? '否' : '是'),
+    productType: equity.isPlatformExchange === '否' ? '' : (equity.productType || '券码'),
     jumpMethod: equity.jumpMethod,
     jumpLink: equity.jumpLink,
-    productType: equity.productType,
     skuNo: equity.skuNo,
     merchantName: equity.merchantName,
     subTitle: equity.subTitle || ''
@@ -654,10 +710,11 @@ Mock.mock(/\/api\/equity\/save-draft/, 'post', (options) => {
     productId: newId,
     equityName: body.equityName || '未命名权益',
     source: body.source || '银行自有',
+    isPlatformExchange: body.isPlatformExchange || '是',
     jumpMethod: body.jumpMethod || '-',
     jumpLink: body.jumpLink || '-',
     exchangeMethod: body.exchangeMethod || '权益平台',
-    productType: body.productType || '',
+    productType: body.isPlatformExchange === '否' ? '' : (body.productType || '券码'),
     skuNo: body.skuNo || '',
     merchantName: body.merchantName || '',
     creator: body.creator || '李运营',
@@ -697,10 +754,11 @@ Mock.mock(/\/api\/equity\/submit/, 'post', (options) => {
       productId: newId,
       equityName: body.equityName || '未命名权益',
       source: body.source || '银行自有',
+      isPlatformExchange: body.isPlatformExchange || '是',
       jumpMethod: body.jumpMethod || '-',
       jumpLink: body.jumpLink || '-',
       exchangeMethod: body.exchangeMethod || '权益平台',
-      productType: body.productType || '',
+      productType: body.isPlatformExchange === '否' ? '' : (body.productType || '券码'),
       skuNo: body.skuNo || '',
       merchantName: body.merchantName || '',
       creator: submitter,
@@ -915,11 +973,13 @@ const equityGrantCampaignList = [
     startTime: '2026-05-01 00:00:00',
     endTime: '2026-08-31 23:59:59',
     crowdList: [],
+    isAutoGrant: '是',
     grantMode: 'claim',
     equityList: ['Q100001', 'Q100004', 'Q100005'],
     grantCycle: 'total',
     grantQuantity: 1,
     validity: { type: 'relative', fixedRange: [], relativeDays: 30 },
+    auditStatus: '审核通过',
     createTime: '2026-04-20 14:10:00',
     updateTime: '2026-04-20 14:10:00'
   },
@@ -929,11 +989,13 @@ const equityGrantCampaignList = [
     startTime: '2026-04-01 00:00:00',
     endTime: '2026-06-30 23:59:59',
     crowdList: ['A0000120251224'],
+    isAutoGrant: '否',
     grantMode: 'direct',
     equityList: ['Q100001'],
     grantCycle: 'monthly',
     grantQuantity: 2,
     validity: { type: 'fixed', fixedRange: ['2026-04-01', '2026-06-30'], relativeDays: 30 },
+    auditStatus: '新增待审核',
     createTime: '2026-03-25 10:20:30',
     updateTime: '2026-03-25 10:20:30'
   }
@@ -970,6 +1032,7 @@ Mock.mock(/\/api\/equity-grant-campaign\/save/, 'post', (options) => {
       startTime: body.startTime,
       endTime: body.endTime,
       crowdList: body.crowdList || [],
+      isAutoGrant: body.isAutoGrant || '是',
       equityList: body.equityList || [],
       grantCycle: body.grantCycle || 'total',
       grantQuantity: body.grantQuantity || 1,
@@ -985,10 +1048,12 @@ Mock.mock(/\/api\/equity-grant-campaign\/save/, 'post', (options) => {
     startTime: body.startTime,
     endTime: body.endTime,
     crowdList: body.crowdList || [],
+    isAutoGrant: body.isAutoGrant || '是',
     equityList: body.equityList || [],
     grantCycle: body.grantCycle || 'total',
     grantQuantity: body.grantQuantity || 1,
     validity: body.validity || defaultValidity,
+    auditStatus: '新增待审核',
     createTime: now,
     updateTime: now
   })
@@ -1003,6 +1068,99 @@ Mock.mock(/\/api\/equity-grant-campaign\/delete/, 'post', (options) => {
   return { code: 200, data: null, msg: '删除成功' }
 })
 
+// =============================================
+// 发放任务
+// =============================================
+const grantTaskList = [
+  {
+    taskId: 'T20260501001',
+    planName: '夏日畅享权益月',
+    planId: 'P000002',
+    taskType: '自动',
+    taskCycle: '2026-05-01 ~ 2026-05-31',
+    status: '已完成',
+    createTime: '2026-05-01 00:00:00',
+    executeTime: '2026-05-01 00:05:12',
+    executor: '系统'
+  },
+  {
+    taskId: 'T20260401001',
+    planName: '春季会员尊享礼遇',
+    planId: 'P000001',
+    taskType: '手动',
+    taskCycle: '2026-04-01 ~ 2026-04-30',
+    status: '待执行',
+    createTime: '2026-04-01 00:00:00',
+    executeTime: '',
+    executor: ''
+  },
+  {
+    taskId: 'T20260401002',
+    planName: '春季会员尊享礼遇',
+    planId: 'P000001',
+    taskType: '手动',
+    taskCycle: '2026-05-01 ~ 2026-05-31',
+    status: '执行中',
+    createTime: '2026-05-01 00:00:00',
+    executeTime: '2026-05-01 10:30:00',
+    executor: '张三'
+  }
+]
+
+Mock.mock(/\/api\/grant-task\/list/, 'get', (options) => {
+  const url = new URL(options.url, 'http://localhost')
+  const planName = url.searchParams.get('planName') || ''
+  const status = url.searchParams.get('status') || ''
+  let filtered = grantTaskList
+  if (planName) filtered = filtered.filter(t => t.planName.includes(planName))
+  if (status) filtered = filtered.filter(t => t.status === status)
+  return { code: 200, data: filtered, msg: 'ok' }
+})
+
+Mock.mock(/\/api\/grant-task\/detail/, 'get', (options) => {
+  const url = new URL(options.url, 'http://localhost')
+  const taskId = url.searchParams.get('taskId') || ''
+  const task = grantTaskList.find(t => t.taskId === taskId)
+  if (!task) return { code: 404, data: null, msg: '任务不存在' }
+  const plan = equityGrantCampaignList.find(c => c.id === task.planId)
+  const cycleMap = {
+    'total': '整个周期',
+    'monthly': '每月',
+    'quarterly': '每季度',
+    'yearly': '每年'
+  }
+  const planData = {
+    ...task,
+    grantMode: plan ? plan.grantMode : 'claim',
+    isAutoGrant: plan ? plan.isAutoGrant : '是',
+    planStartTime: plan ? plan.startTime : '',
+    planEndTime: plan ? plan.endTime : '',
+    grantQuantityLabel: plan ? `${cycleMap[plan.grantCycle] || plan.grantCycle} ${plan.grantQuantity} 个` : '',
+    validityLabel: plan ? (plan.validity.type === 'fixed' ? (plan.validity.fixedRange.join(' 至 ')) : `自发放起 ${plan.validity.relativeDays} 天内有效`) : '',
+    crowdLabel: plan ? (plan.crowdList.length ? plan.crowdList.map(id => {
+      const crowdNames = { 'A0000120251224': '名单1' }
+      return crowdNames[id] ? `${crowdNames[id]} (${id})` : id
+    }).join('、') : '-') : '-',
+    equityLabel: plan ? (plan.equityList.length ? plan.equityList.map(id => {
+      const e = equityList.find(p => p.productId === id)
+      return e ? `${e.equityName} (${id})` : id
+    }).join('、') : '-') : '-',
+    smsLabel: plan ? '发放成功通用模板' : '-'
+  }
+  return { code: 200, data: planData, msg: 'ok' }
+})
+
+Mock.mock(/\/api\/grant-task\/execute/, 'post', (options) => {
+  const body = JSON.parse(options.body)
+  const idx = grantTaskList.findIndex(t => t.taskId === body.taskId)
+  if (idx < 0) return { code: 404, data: null, msg: '任务不存在' }
+  if (grantTaskList[idx].status !== '待执行') return { code: 400, data: null, msg: '该任务不在待执行状态' }
+  grantTaskList[idx].status = '执行中'
+  grantTaskList[idx].executeTime = nowStr()
+  grantTaskList[idx].executor = '运营人员'
+  return { code: 200, data: null, msg: '执行成功' }
+})
+
 Mock.mock(/\/api\/equity-grant-campaign\/detail/, 'get', (options) => {
   const url = new URL(options.url, 'http://localhost')
   const id = url.searchParams.get('id')
@@ -1016,13 +1174,39 @@ Mock.mock(/\/api\/equity-grant-campaign\/end/, 'post', (options) => {
   const body = JSON.parse(options.body)
   const idx = equityGrantCampaignList.findIndex(c => c.id === body.id)
   if (idx < 0) return { code: 404, data: null, msg: '发放计划不存在' }
+  const cur = equityGrantCampaignList[idx]
+  if (cur.auditStatus !== '审核通过') return { code: 400, data: null, msg: '仅审核通过状态可提交结束审核' }
+  // 创建审核单并更新发放计划状态为结束待审核
+  const auditId = nextCampaignAuditId()
   const now = nowStr()
-  equityGrantCampaignList[idx] = {
-    ...equityGrantCampaignList[idx],
-    endTime: now,
-    updateTime: now
-  }
-  return { code: 200, data: null, msg: '已结束' }
+  equityGrantCampaignList[idx] = { ...cur, auditStatus: '结束待审核', updateTime: now }
+  campaignAuditList.unshift({
+    id: auditId,
+    auditType: 'end',
+    bizModuleName: '发放计划',
+    bizId: cur.id,
+    bizName: cur.name,
+    snapshot: {
+      name: cur.name,
+      startTime: cur.startTime,
+      endTime: cur.endTime,
+      grantMode: cur.grantMode,
+      crowdList: cur.crowdList || [],
+      equityList: cur.equityList || [],
+      grantCycle: cur.grantCycle,
+      grantQuantity: cur.grantQuantity,
+      validity: cur.validity,
+      smsTemplateId: cur.smsTemplateId || '',
+      smsTemplate: cur.smsTemplate || ''
+    },
+    submitterName: body.submitterName || '运营',
+    submitTime: now,
+    auditorName: '',
+    auditTime: '',
+    auditStatus: 'pending',
+    auditComment: ''
+  })
+  return { code: 200, data: { auditId }, msg: '已提交结束审核' }
 })
 
 // =============================================
@@ -1205,10 +1389,10 @@ const campaignAuditList = [
 Mock.mock(/\/api\/campaign-audit\/list/, 'get', (options) => {
   const url = new URL(options.url, 'http://localhost')
   const auditStatus = url.searchParams.get('auditStatus') || ''
-  const bizName = url.searchParams.get('bizName') || ''
+  const bizId = url.searchParams.get('bizId') || ''
   let filtered = campaignAuditList
   if (auditStatus) filtered = filtered.filter(a => a.auditStatus === auditStatus)
-  if (bizName) filtered = filtered.filter(a => a.bizName.includes(bizName))
+  if (bizId) filtered = filtered.filter(a => a.bizId === bizId)
   return { code: 200, data: filtered, msg: 'ok' }
 })
 
@@ -1229,6 +1413,21 @@ Mock.mock(/\/api\/campaign-audit\/approve/, 'post', (options) => {
   if (audit.auditStatus !== 'pending') return { code: 400, data: null, msg: '该审核单已完成' }
   const now = nowStr()
   campaignAuditList[idx] = { ...audit, auditStatus: 'approved', auditorName: body.auditorName || '王五', auditTime: now, auditComment: body.comment || '' }
+  // 同步更新发放计划主表
+  const campaignIdx = equityGrantCampaignList.findIndex(c => c.id === audit.bizId)
+  if (campaignIdx >= 0) {
+    if (audit.auditType === 'new') {
+      equityGrantCampaignList[campaignIdx].auditStatus = '审核通过'
+    } else if (audit.auditType === 'end') {
+      // 结束审核通过:实际结束发放计划
+      equityGrantCampaignList[campaignIdx] = {
+        ...equityGrantCampaignList[campaignIdx],
+        endTime: now,
+        auditStatus: '审核通过',
+        updateTime: now
+      }
+    }
+  }
   return { code: 200, data: null, msg: '审核通过' }
 })
 
@@ -1240,6 +1439,13 @@ Mock.mock(/\/api\/campaign-audit\/reject/, 'post', (options) => {
   if (audit.auditStatus !== 'pending') return { code: 400, data: null, msg: '该审核单已完成' }
   const now = nowStr()
   campaignAuditList[idx] = { ...audit, auditStatus: 'rejected', auditorName: body.auditorName || '王五', auditTime: now, auditComment: body.comment || '' }
+  // 驳回后回退发放计划审核状态为审核通过,允许重新编辑/结束
+  const campaignIdx = equityGrantCampaignList.findIndex(c => c.id === audit.bizId)
+  if (campaignIdx >= 0) equityGrantCampaignList[campaignIdx] = {
+    ...equityGrantCampaignList[campaignIdx],
+    auditStatus: '审核通过',
+    updateTime: now
+  }
   return { code: 200, data: null, msg: '已驳回' }
 })
 

+ 18 - 0
pc-v3/src/router/index.js

@@ -264,6 +264,24 @@ const routes = [
         component: () => import('@/views/EquityGrantCampaignView.vue'),
         meta: { title: '查看发放计划' }
       },
+      {
+        path: 'customization/hsbc/grant-task',
+        name: 'GrantTaskList',
+        component: () => import('@/views/GrantTaskList.vue'),
+        meta: { title: '发放任务' }
+      },
+      {
+        path: 'customization/hsbc/grant-task/view/:taskId',
+        name: 'GrantTaskView',
+        component: () => import('@/views/GrantTaskDetail.vue'),
+        meta: { title: '查看发放任务' }
+      },
+      {
+        path: 'customization/hsbc/grant-task/execute/:taskId',
+        name: 'GrantTaskExecute',
+        component: () => import('@/views/GrantTaskDetail.vue'),
+        meta: { title: '执行发放任务' }
+      },
       {
         path: 'customization/hsbc/campaign-audit',
         name: 'CampaignAuditList',

+ 7 - 1
pc-v3/src/store/ruleGroupStore.js

@@ -16,6 +16,7 @@ const state = reactive({
       logic: 'AND',
       description: '2025/9/30 前开户 + MSC 属于卓越/运筹 + TRB < 50万',
       status: 'online',
+      auditStatus: '审核通过',
       creator: '张运营',
       createdAt: '2026-04-01 09:15:30',
       updater: '王审核',
@@ -54,6 +55,7 @@ const state = reactive({
       logic: 'AND',
       description: 'MSC 属于卓越/尊尚 且 月末余额 ≥ 100 万',
       status: 'online',
+      auditStatus: '审核通过',
       creator: '李产品',
       createdAt: '2026-04-10 16:55:02',
       updater: '李产品',
@@ -80,6 +82,7 @@ const state = reactive({
       logic: 'OR',
       description: 'TRB ≥ 50 万 或 月末余额 ≥ 50 万',
       status: 'draft',
+      auditStatus: '新增待审核',
       creator: '赵市场',
       createdAt: '2026-04-20 11:48:33',
       updater: '赵市场',
@@ -109,11 +112,12 @@ export default {
   get list() {
     return state.list
   },
-  query({ id = '', name = '', type = '' } = {}) {
+  query({ id = '', name = '', type = '', auditStatus = '' } = {}) {
     return state.list.filter((t) => {
       if (id && !t.id.includes(id)) return false
       if (name && !t.name.includes(name)) return false
       if (type && t.type !== type) return false
+      if (auditStatus && t.auditStatus !== auditStatus) return false
       return true
     })
   },
@@ -128,6 +132,7 @@ export default {
       logic: payload.logic || 'AND',
       description: payload.description || '',
       status: 'draft',
+      auditStatus: '新增待审核',
       creator: '当前用户',
       createdAt: now(),
       updater: '当前用户',
@@ -157,6 +162,7 @@ export default {
     const target = state.list.find((t) => t.id === id)
     if (!target) return
     target.status = 'online'
+    target.auditStatus = '审核通过'
     target.updater = '当前用户'
     target.updatedAt = now()
   }

+ 90 - 49
pc-v3/src/views/AddEquityProduct.vue

@@ -30,15 +30,22 @@
           <el-form :model="form" label-width="120px" label-position="left">
             <el-row :gutter="20">
               <el-col :span="8">
-                <el-form-item label="权益来源" required>
-                  <el-radio-group v-model="form.source">
-                    <el-radio label="银行自有"></el-radio>
-                    <el-radio label="荣数商品"></el-radio>
-                    <el-radio label="第三方"></el-radio>
+                <el-form-item label="是否权益平台兑换" required label-width="150px">
+                  <el-radio-group v-model="form.isPlatformExchange" @change="handlePlatformExchangeChange">
+                    <el-radio label="是"></el-radio>
+                    <el-radio label="否"></el-radio>
                   </el-radio-group>
                 </el-form-item>
               </el-col>
-              <el-col :span="8" v-if="form.source === '荣数商品'">
+              <el-col :span="8" v-if="form.isPlatformExchange === '是'">
+                <el-form-item label="商品类型" required>
+                  <el-radio-group v-model="form.productType" @change="handleProductTypeChange">
+                    <el-radio label="券码"></el-radio>
+                    <el-radio label="微信立减金"></el-radio>
+                  </el-radio-group>
+                </el-form-item>
+              </el-col>
+              <el-col :span="8" v-if="form.isPlatformExchange === '是' && form.productType === '微信立减金'">
                 <el-form-item label="选择权益" required>
                   <el-input
                     v-model="form.rongshuProduct"
@@ -51,16 +58,14 @@
                   </el-input>
                 </el-form-item>
               </el-col>
-              <el-col :span="8" v-if="form.source === '银行自有'">
-                <el-form-item label="权益类型" required>
-                  <el-radio-group v-model="form.productType">
-                    <el-radio label="券码"></el-radio>
-                  </el-radio-group>
+              <el-col :span="8" v-if="form.isPlatformExchange === '是' && form.productType === '微信立减金' && form.rongshuSkuNo">
+                <el-form-item label="SKU编号">
+                  <el-input v-model="form.rongshuSkuNo" readonly></el-input>
                 </el-form-item>
               </el-col>
             </el-row>
             <el-row :gutter="20">
-              <el-col :span="8" v-if="form.source === '第三方'">
+              <el-col :span="8" v-if="form.isPlatformExchange === '否'">
                 <el-form-item label="外部权益链接" required>
                   <el-select v-model="form.externalLink" placeholder="请选择外部权益链接">
                     <el-option label="太古地产" value="太古地产"></el-option>
@@ -70,12 +75,12 @@
                   </el-select>
                 </el-form-item>
               </el-col>
-              <el-col :span="8" v-if="form.source === '第三方' && form.externalLink === 'h5链接'" :gutter="20">
+              <el-col :span="8" v-if="form.isPlatformExchange === '否' && form.externalLink === 'h5链接'" :gutter="20">
                 <el-form-item label="h5链接" required>
                   <el-input v-model="form.customLink" placeholder="请输入h5链接"></el-input>
                 </el-form-item>
               </el-col>
-              <el-col :span="8" v-if="form.source === '第三方'">
+              <el-col :span="8" v-if="form.isPlatformExchange === '否'">
                 <el-form-item required label-width="140px">
                   <template #label>
                     <span style="white-space: nowrap;">是否有详情页<el-tooltip content="没有详情页时直接从首页/列表页/组装页直接跳转" placement="top"><el-icon class="tip-icon"><QuestionFilled /></el-icon></el-tooltip></span>
@@ -87,7 +92,7 @@
                 </el-form-item>
               </el-col>
             </el-row>
-            <el-row :gutter="20" v-if="form.source === '第三方' && form.externalLink === '小程序链接'">
+            <el-row :gutter="20" v-if="form.isPlatformExchange === '否' && form.externalLink === '小程序链接'">
               <el-col :span="8">
                 <el-form-item label="小程序appid" required>
                   <el-input v-model="form.miniAppId" placeholder="请输入小程序appid"></el-input>
@@ -100,20 +105,15 @@
               </el-col>
             </el-row>
 
-            <template v-if="form.source === '银行自有' || form.source === '荣数商品'">
+            <template v-if="form.isPlatformExchange === '是'">
               <el-row :gutter="20">
                 <el-col :span="8">
                   <el-form-item label="权益名称" required>
                     <el-input v-model="form.equityName" maxlength="40" placeholder="请输入权益名称"></el-input>
                   </el-form-item>
                 </el-col>
-                <el-col :span="8">
-                  <el-form-item label="权益副标题">
-                    <el-input v-model="form.subTitle" maxlength="40" placeholder="请输入权益副标题"></el-input>
-                  </el-form-item>
-                </el-col>
               </el-row>
-              <el-row :gutter="20" v-if="form.source === '荣数商品'">
+              <el-row :gutter="20" v-if="form.productType === '微信立减金'">
                 <el-col :span="8">
                   <el-form-item label="库存数" required>
                     <el-input-number
@@ -154,18 +154,13 @@
               </el-row>
             </template>
 
-            <template v-else-if="form.source === '第三方'">
+            <template v-else-if="form.isPlatformExchange === '否'">
               <el-row :gutter="20">
                 <el-col :span="8">
                   <el-form-item label="权益名称" required>
                     <el-input v-model="form.equityName" maxlength="40" placeholder="请输入权益名称"></el-input>
                   </el-form-item>
                 </el-col>
-                <el-col :span="8">
-                  <el-form-item label="权益副标题">
-                    <el-input v-model="form.subTitle" maxlength="40" placeholder="请输入权益副标题"></el-input>
-                  </el-form-item>
-                </el-col>
               </el-row>
               <el-row :gutter="20" v-if="form.externalJumpMethod === '没有'">
                 <el-col :span="8">
@@ -268,7 +263,7 @@
             <el-row :gutter="20">
               <el-col :span="12">
                 <el-form-item label="权益有效期" required>
-                  <template v-if="form.source === '银行自有' || form.source === '荣数商品'">
+                  <template v-if="form.isPlatformExchange === '是'">
                     <el-radio-group v-model="form.validityType">
                       <el-radio label="fromGrantPlan">取自发放计划</el-radio>
                       <el-radio label="custom">自定义输入</el-radio>
@@ -304,7 +299,7 @@
                 </el-form-item>
               </el-col>
             </el-row>
-            <template v-if="form.source === '银行自有' || form.source === '荣数商品'">
+            <template v-if="form.isPlatformExchange === '是'">
               <el-row :gutter="20">
                 <el-col :span="24">
                   <el-form-item>
@@ -347,7 +342,7 @@
                   </el-form-item>
                 </el-col>
               </el-row>
-              <el-row :gutter="20" v-if="form.source === '银行自有'">
+              <el-row :gutter="20" v-if="form.productType === '券码'">
                 <el-col :span="8">
                   <el-form-item label="领取成功按钮" required>
                     <el-input v-model="form.successButtonText" placeholder="请输入按钮文案"></el-input>
@@ -613,8 +608,10 @@ export default {
         { id: 'SMS_TPL_003', name: '实物类短信模板', content: '【银行】您购买的${productName}已受理,我们将尽快安排发货,感谢您的支持。' }
       ],
       form: {
+        isPlatformExchange: '是',
         source: '银行自有',
         rongshuProduct: '',
+        rongshuSkuNo: '',
         productType: '券码',
         faceValueThreshold: '',
         faceValueDiscount: '',
@@ -630,7 +627,6 @@ export default {
         equityName: '',
         productId: '',
         merchantName: '',
-        subTitle: '',
         listIcon: [],
         mainImage: [],
         introduction: '',
@@ -663,10 +659,14 @@ export default {
     }
   },
   computed: {
+    mappedSource() {
+      if (this.form.isPlatformExchange === '否') return '第三方'
+      if (this.form.productType === '微信立减金') return '荣数商品'
+      return '银行自有'
+    },
     shouldShowDetailCard() {
-      const s = this.form.source
-      if (s === '银行自有' || s === '荣数商品') return true
-      if (s === '第三方' && this.form.externalJumpMethod === '有') return true
+      if (this.form.isPlatformExchange === '是') return true
+      if (this.form.isPlatformExchange === '否' && this.form.externalJumpMethod === '有') return true
       return false
     }
   },
@@ -677,10 +677,35 @@ export default {
     }
   },
   methods: {
+    handlePlatformExchangeChange(val) {
+      if (val === '是') {
+        this.form.productType = '券码'
+        this.form.externalLink = '太古地产'
+        this.form.externalJumpMethod = '没有'
+        this.form.customLink = ''
+        this.form.miniAppId = ''
+        this.form.miniAppPath = ''
+      } else {
+        this.form.rongshuProduct = ''
+        this.form.rongshuSkuNo = ''
+        this.form.stockCount = null
+        this.form.merchantName = ''
+      }
+    },
+    handleProductTypeChange(val) {
+      if (val === '券码') {
+        this.form.rongshuProduct = ''
+        this.form.rongshuSkuNo = ''
+        this.form.stockCount = null
+        this.form.merchantName = ''
+      }
+    },
     loadCopySource(id) {
       const mockMap = {
         'Q100001': {
           source: '银行自有',
+          isPlatformExchange: '是',
+          productType: '券码',
           externalJumpMethod: '',
           externalLink: '',
           customLink: '',
@@ -688,7 +713,6 @@ export default {
           miniAppPath: '',
           skuNo: 'SKU001',
           equityName: '权益A',
-          subTitle: '副标题示例',
           listIcon: [],
           mainImage: [],
           overview: '<p>权益内容内容</p>',
@@ -713,6 +737,8 @@ export default {
         },
         'Q100002': {
           source: '第三方',
+          isPlatformExchange: '否',
+          productType: '',
           externalJumpMethod: '没有',
           externalLink: '太古地产',
           customLink: '',
@@ -720,7 +746,6 @@ export default {
           miniAppPath: '',
           skuNo: 'SKU002',
           equityName: '权益B',
-          subTitle: '外部列表页副标题',
           listIcon: [],
           mainImage: [],
           overview: '',
@@ -746,6 +771,8 @@ export default {
         },
         'Q100003': {
           source: '第三方',
+          isPlatformExchange: '否',
+          productType: '',
           externalJumpMethod: '有',
           externalLink: '龙腾',
           customLink: '',
@@ -753,7 +780,6 @@ export default {
           miniAppPath: '',
           skuNo: 'SKU003',
           equityName: '权益C',
-          subTitle: '外部详情页副标题',
           listIcon: [],
           mainImage: [],
           overview: '<p>外部详情页权益内容</p>',
@@ -778,12 +804,13 @@ export default {
         },
         'Q100004': {
           source: '第三方',
+          isPlatformExchange: '否',
+          productType: '',
           externalJumpMethod: '有',
           externalLink: 'h5链接',
           customLink: 'https://example.com/custom',
           skuNo: 'SKU004',
           equityName: '权益D',
-          subTitle: '外部自定义链接副标题',
           listIcon: [],
           mainImage: [],
           overview: '<p>自定义链接权益内容</p>',
@@ -812,13 +839,24 @@ export default {
         const core = res.data || {}
         const rich = mockMap[id] || {}
         const merged = { ...rich }
-        const coreFields = ['equityName', 'source', 'productType', 'skuNo', 'merchantName', 'subTitle']
+        const coreFields = ['equityName', 'source', 'isPlatformExchange', 'productType', 'skuNo', 'merchantName']
         coreFields.forEach(k => {
           if (core[k] !== undefined && core[k] !== null && core[k] !== '') {
             merged[k] = core[k]
           }
         })
-        if (core.source === '第三方') {
+        // 根据接口返回的 source 推算 isPlatformExchange 和 productType
+        if (!merged.isPlatformExchange) {
+          if (core.source === '第三方') merged.isPlatformExchange = '否'
+          else merged.isPlatformExchange = '是'
+        }
+        if (merged.isPlatformExchange === '是' && !merged.productType) {
+          merged.productType = core.source === '荣数商品' ? '微信立减金' : '券码'
+        }
+        if (merged.isPlatformExchange === '否') {
+          merged.productType = ''
+        }
+        if (merged.isPlatformExchange === '否') {
           if (core.jumpMethod) merged.externalJumpMethod = core.jumpMethod
           if (core.jumpLink) merged.externalLink = core.jumpLink
         }
@@ -847,17 +885,19 @@ export default {
     },
     buildPayload() {
       const f = this.form
-      const isCustomValidity = f.source === '第三方' || f.validityType === 'custom'
+      const source = this.mappedSource
+      const isNotPlatform = f.isPlatformExchange === '否'
+      const isCustomValidity = isNotPlatform || f.validityType === 'custom'
       return {
         equityName: f.equityName,
-        source: f.source,
-        productType: f.productType || '',
-        skuNo: f.skuNo || '',
+        source: source,
+        isPlatformExchange: f.isPlatformExchange,
+        productType: f.isPlatformExchange === '是' ? f.productType : '',
+        skuNo: (f.isPlatformExchange === '是' && f.productType === '微信立减金') ? (f.rongshuSkuNo || f.skuNo || '') : (f.skuNo || ''),
         merchantName: f.merchantName || '',
-        subTitle: f.subTitle || '',
-        jumpMethod: f.source === '第三方' ? f.externalJumpMethod : '-',
-        jumpLink: f.source === '第三方' ? f.externalLink : '-',
-        exchangeMethod: f.source === '第三方'
+        jumpMethod: isNotPlatform ? f.externalJumpMethod : '-',
+        jumpLink: isNotPlatform ? f.externalLink : '-',
+        exchangeMethod: isNotPlatform
           ? (f.externalJumpMethod === '有' ? '第三方(详情页跳转)' : '第三方(列表跳转)')
           : '权益平台',
         validityType: isCustomValidity ? 'custom' : 'fromGrantPlan',
@@ -930,6 +970,7 @@ export default {
     },
     onRongshuSelect(product) {
       this.form.rongshuProduct = product.name
+      this.form.rongshuSkuNo = product.skuNo
       this.form.equityName = product.name
       this.form.merchantName = product.merchant
       this.form.stockCount = product.stock

+ 41 - 20
pc-v3/src/views/AuditDetail.vue

@@ -23,34 +23,34 @@
           <el-form :model="form" label-width="120px" label-position="left">
             <el-row :gutter="20">
               <el-col :span="8">
-                <el-form-item label="权益来源">
-                  <el-radio-group v-model="form.source" disabled>
-                    <el-radio-button label="银行自有"></el-radio-button>
-                    <el-radio-button label="荣数商品"></el-radio-button>
-                    <el-radio-button label="第三方"></el-radio-button>
+                <el-form-item label="是否权益平台兑换" label-width="150px">
+                  <el-radio-group v-model="form.isPlatformExchange" disabled>
+                    <el-radio-button label="是"></el-radio-button>
+                    <el-radio-button label="否"></el-radio-button>
                   </el-radio-group>
                 </el-form-item>
               </el-col>
-              <el-col :span="8" v-if="form.source === '银行自有'">
-                <el-form-item label="权益类型">
+              <el-col :span="8" v-if="form.isPlatformExchange === '是'">
+                <el-form-item label="商品类型">
                   <el-radio-group v-model="form.productType" disabled>
                     <el-radio-button label="券码"></el-radio-button>
+                    <el-radio-button label="微信立减金"></el-radio-button>
                   </el-radio-group>
                 </el-form-item>
               </el-col>
-              <el-col :span="8" v-if="form.source === '银行自有'">
-                <el-form-item label="商户名称">
-                  <el-input :value="form.merchantName" readonly></el-input>
+              <el-col :span="8" v-if="form.isPlatformExchange === '是' && form.productType === '微信立减金'">
+                <el-form-item label="选择权益">
+                  <el-input :value="form.rongshuProduct" readonly></el-input>
                 </el-form-item>
               </el-col>
             </el-row>
             <el-row :gutter="20">
-              <el-col :span="8" v-if="form.source === '第三方'">
+              <el-col :span="8" v-if="form.isPlatformExchange === '否'">
                 <el-form-item label="外部权益链接">
                   <el-input :value="form.externalLink" readonly></el-input>
                 </el-form-item>
               </el-col>
-              <el-col :span="8" v-if="form.source === '第三方'">
+              <el-col :span="8" v-if="form.isPlatformExchange === '否'">
                 <el-form-item label="是否有详情页">
                   <el-radio-group v-model="form.externalJumpMethod" disabled>
                     <el-radio-button label="没有"></el-radio-button>
@@ -70,7 +70,7 @@
                   <el-input :value="form.subTitle" readonly></el-input>
                 </el-form-item>
               </el-col>
-              <el-col :span="8" v-if="form.source === '银行自有'">
+              <el-col :span="8" v-if="form.isPlatformExchange === '是' && form.productType === '券码'">
                 <el-form-item label="SIP商品编号">
                   <el-input :value="form.skuNo" readonly></el-input>
                 </el-form-item>
@@ -133,7 +133,7 @@
                 </el-form-item>
               </el-col>
             </el-row>
-            <el-row :gutter="20" v-if="form.source === '银行自有'">
+            <el-row :gutter="20" v-if="form.isPlatformExchange === '是' && form.productType === '券码'">
               <el-col :span="8">
                 <el-form-item label="领取成功按钮">
                   <el-input :value="form.successButtonText" readonly></el-input>
@@ -288,6 +288,7 @@ import { ElMessage, ElMessageBox } from 'element-plus'
 
 const detailMockMap = {
   'Q100001': {
+    isPlatformExchange: '是', productType: '券码',
     listIcon: [], mainImage: [],
     introduction: '权益A 介绍内容示例',
     overview: '<p>权益内容内容</p>',
@@ -304,6 +305,7 @@ const detailMockMap = {
     claimGroupEnabled: false
   },
   'Q100002': {
+    isPlatformExchange: '否', productType: '',
     externalJumpMethod: '没有', externalLink: '太古地产',
     listIcon: [], mainImage: [], introduction: '',
     overview: '', details: '',
@@ -316,6 +318,7 @@ const detailMockMap = {
     claimGroupEnabled: true
   },
   'Q100003': {
+    isPlatformExchange: '否', productType: '',
     externalJumpMethod: '有', externalLink: '龙腾',
     listIcon: [], mainImage: [],
     introduction: '权益C 介绍内容示例',
@@ -326,6 +329,7 @@ const detailMockMap = {
     claimGroupEnabled: false
   },
   'Q100004': {
+    isPlatformExchange: '否', productType: '',
     externalJumpMethod: '有', externalLink: 'h5链接',
     listIcon: [], mainImage: [],
     introduction: '权益D 介绍内容示例',
@@ -344,8 +348,10 @@ export default {
       audit: null,
       activeStep: 0,
       form: {
+        isPlatformExchange: '是',
         source: '银行自有',
-        productType: '',
+        productType: '券码',
+        rongshuProduct: '',
         externalJumpMethod: '',
         externalLink: '',
         equityName: '',
@@ -377,10 +383,14 @@ export default {
     }
   },
   computed: {
+    mappedSource() {
+      if (this.form.isPlatformExchange === '否') return '第三方'
+      if (this.form.productType === '微信立减金') return '荣数商品'
+      return '银行自有'
+    },
     shouldShowDetailCard() {
-      const s = this.form.source
-      if (s === '银行自有' || s === '荣数商品') return true
-      if (s === '第三方' && this.form.externalJumpMethod === '有') return true
+      if (this.form.isPlatformExchange === '是') return true
+      if (this.form.isPlatformExchange === '否' && this.form.externalJumpMethod === '有') return true
       return false
     },
     canAudit() {
@@ -409,8 +419,19 @@ export default {
       }
       // 2) 用 audit snapshot 覆盖(变更类型时会包含最新内容)
       Object.assign(this.form, this.audit.snapshot || {})
-      // 3) 推导第三方相关字段
-      if (this.form.source === '第三方') {
+      // 3) 根据接口返回的 source 推算 isPlatformExchange 和 productType
+      if (!this.form.isPlatformExchange || this.form.isPlatformExchange === '') {
+        if (this.form.source === '第三方') this.form.isPlatformExchange = '否'
+        else this.form.isPlatformExchange = '是'
+      }
+      if (this.form.isPlatformExchange === '是' && (!this.form.productType || this.form.productType === '')) {
+        this.form.productType = this.form.source === '荣数商品' ? '微信立减金' : '券码'
+      }
+      if (this.form.isPlatformExchange === '否') {
+        this.form.productType = ''
+      }
+      // 4) 推导第三方相关字段
+      if (this.form.isPlatformExchange === '否') {
         if (this.form.jumpLink && !this.form.externalLink) this.form.externalLink = this.form.jumpLink
         if (this.form.jumpMethod && !this.form.externalJumpMethod) {
           this.form.externalJumpMethod = this.form.jumpMethod

+ 51 - 26
pc-v3/src/views/AuditEquityProduct.vue

@@ -30,34 +30,34 @@
           <el-form :model="form" label-width="120px" label-position="left">
             <el-row :gutter="20">
               <el-col :span="8">
-                <el-form-item label="权益来源">
-                  <el-radio-group v-model="form.source" disabled>
-                    <el-radio-button label="银行自有"></el-radio-button>
-                    <el-radio-button label="荣数商品"></el-radio-button>
-                    <el-radio-button label="第三方"></el-radio-button>
+                <el-form-item label="是否权益平台兑换" label-width="150px">
+                  <el-radio-group v-model="form.isPlatformExchange" disabled>
+                    <el-radio-button label="是"></el-radio-button>
+                    <el-radio-button label="否"></el-radio-button>
                   </el-radio-group>
                 </el-form-item>
               </el-col>
-              <el-col :span="8" v-if="form.source === '荣数商品'">
-                <el-form-item label="选择权益">
-                  <el-input :value="form.rongshuProduct" readonly></el-input>
-                </el-form-item>
-              </el-col>
-              <el-col :span="8" v-if="form.source === '银行自有'">
-                <el-form-item label="权益类型">
+              <el-col :span="8" v-if="form.isPlatformExchange === '是'">
+                <el-form-item label="商品类型">
                   <el-radio-group v-model="form.productType" disabled>
                     <el-radio-button label="券码"></el-radio-button>
+                    <el-radio-button label="微信立减金"></el-radio-button>
                   </el-radio-group>
                 </el-form-item>
               </el-col>
-              <el-col :span="8" v-if="form.source === '银行自有'">
+              <el-col :span="8" v-if="form.isPlatformExchange === '是' && form.productType === '微信立减金'">
+                <el-form-item label="选择权益">
+                  <el-input :value="form.rongshuProduct" readonly></el-input>
+                </el-form-item>
+              </el-col>
+              <el-col :span="8" v-if="form.isPlatformExchange === '是' && form.productType === '券码'">
                 <el-form-item label="商户名称">
                   <el-input :value="form.merchantName" readonly></el-input>
                 </el-form-item>
               </el-col>
             </el-row>
             <el-row :gutter="20">
-              <el-col :span="8" v-if="form.source === '第三方'">
+              <el-col :span="8" v-if="form.isPlatformExchange === '否'">
                 <el-form-item label="外部权益链接">
                   <el-select v-model="form.externalLink" placeholder="请选择外部权益链接" disabled>
                     <el-option label="太古地产" value="太古地产"></el-option>
@@ -67,12 +67,12 @@
                   </el-select>
                 </el-form-item>
               </el-col>
-              <el-col :span="8" v-if="form.source === '第三方' && form.externalLink === 'h5链接'" :gutter="20">
+              <el-col :span="8" v-if="form.isPlatformExchange === '否' && form.externalLink === 'h5链接'" :gutter="20">
                 <el-form-item label="h5链接">
                   <el-input v-model="form.customLink" placeholder="请输入h5链接" readonly></el-input>
                 </el-form-item>
               </el-col>
-              <el-col :span="8" v-if="form.source === '第三方'">
+              <el-col :span="8" v-if="form.isPlatformExchange === '否'">
                 <el-form-item label-width="140px">
                   <template #label>
                     <span style="white-space: nowrap;">是否有详情页<el-tooltip content="没有详情页时直接从首页/列表页/组装页直接跳转" placement="top"><el-icon class="tip-icon"><QuestionFilled /></el-icon></el-tooltip></span>
@@ -84,7 +84,7 @@
                 </el-form-item>
               </el-col>
             </el-row>
-            <el-row :gutter="20" v-if="form.source === '第三方' && form.externalLink === '小程序链接'">
+            <el-row :gutter="20" v-if="form.isPlatformExchange === '否' && form.externalLink === '小程序链接'">
               <el-col :span="8">
                 <el-form-item label="小程序appid">
                   <el-input v-model="form.miniAppId" readonly></el-input>
@@ -97,8 +97,8 @@
               </el-col>
             </el-row>
 
-            <template v-if="form.source === '银行自有' || form.source === '荣数商品'">
-              <el-row :gutter="20" v-if="form.source === '荣数商品'">
+            <template v-if="form.isPlatformExchange === '是'">
+              <el-row :gutter="20" v-if="form.productType === '微信立减金'">
                 <el-col :span="8">
                   <el-form-item label="库存数">
                     <el-input :value="form.stockCount" readonly></el-input>
@@ -106,7 +106,7 @@
                 </el-col>
               </el-row>
               <el-row :gutter="20">
-                <el-col :span="8" v-if="form.source === '银行自有'">
+                <el-col :span="8" v-if="form.productType === '券码'">
                   <el-form-item label="SIP商品编号">
                     <el-input v-model="form.skuNo" readonly></el-input>
                   </el-form-item>
@@ -141,7 +141,7 @@
               </el-row>
             </template>
 
-            <template v-else-if="form.source === '第三方'">
+            <template v-else-if="form.isPlatformExchange === '否'">
               <el-row :gutter="20">
                 <el-col :span="8">
                   <el-form-item label="权益名称">
@@ -242,7 +242,7 @@
                 </el-form-item>
               </el-col>
             </el-row>
-            <template v-if="form.source === '银行自有' || form.source === '荣数商品'">
+            <template v-if="form.isPlatformExchange === '是'">
               <el-row :gutter="20">
                 <el-col :span="24">
                   <el-form-item label="下单成功短信">
@@ -449,6 +449,7 @@ export default {
         { id: 'SMS_TPL_003', name: '实物类短信模板', content: '【银行】您购买的${productName}已受理,我们将尽快安排发货,感谢您的支持。' }
       ],
       form: {
+        isPlatformExchange: '是',
         source: '银行自有',
         rongshuProduct: '',
         productType: '券码',
@@ -500,10 +501,14 @@ export default {
     }
   },
   computed: {
+    mappedSource() {
+      if (this.form.isPlatformExchange === '否') return '第三方'
+      if (this.form.productType === '微信立减金') return '荣数商品'
+      return '银行自有'
+    },
     shouldShowDetailCard() {
-      const s = this.form.source
-      if (s === '银行自有' || s === '荣数商品') return true
-      if (s === '第三方' && this.form.externalJumpMethod === '有') return true
+      if (this.form.isPlatformExchange === '是') return true
+      if (this.form.isPlatformExchange === '否' && this.form.externalJumpMethod === '有') return true
       return false
     }
   },
@@ -517,6 +522,8 @@ export default {
       const mockMap = {
         'Q100001': {
           source: '银行自有',
+          isPlatformExchange: '是',
+          productType: '券码',
           externalJumpMethod: '',
           externalLink: '',
           customLink: '',
@@ -549,6 +556,8 @@ export default {
         },
         'Q100002': {
           source: '第三方',
+          isPlatformExchange: '否',
+          productType: '',
           externalJumpMethod: '没有',
           externalLink: '太古地产',
           customLink: '',
@@ -582,6 +591,8 @@ export default {
         },
         'Q100003': {
           source: '第三方',
+          isPlatformExchange: '否',
+          productType: '',
           externalJumpMethod: '有',
           externalLink: '龙腾',
           customLink: '',
@@ -614,6 +625,8 @@ export default {
         },
         'Q100004': {
           source: '第三方',
+          isPlatformExchange: '否',
+          productType: '',
           externalJumpMethod: '有',
           externalLink: 'h5链接',
           customLink: 'https://custom-link.com',
@@ -644,7 +657,19 @@ export default {
         }
       }
       if (mockMap[id]) {
-        this.form = { ...this.form, ...mockMap[id] }
+        const merged = { ...mockMap[id] }
+        // 根据接口返回的 source 推算 isPlatformExchange 和 productType
+        if (!merged.isPlatformExchange) {
+          if (merged.source === '第三方') merged.isPlatformExchange = '否'
+          else merged.isPlatformExchange = '是'
+        }
+        if (merged.isPlatformExchange === '是' && !merged.productType) {
+          merged.productType = merged.source === '荣数商品' ? '微信立减金' : '券码'
+        }
+        if (merged.isPlatformExchange === '否') {
+          merged.productType = ''
+        }
+        this.form = { ...this.form, ...merged }
       }
     },
     goBack() {

+ 1 - 1
pc-v3/src/views/CampaignAuditDetail.vue

@@ -29,7 +29,7 @@
               {{ snapshot.grantMode === 'direct' ? '直接发放' : '用户领取' }}
             </el-tag>
           </el-descriptions-item>
-          <el-descriptions-item label="权益数量">{{ grantSummary }}</el-descriptions-item>
+          <el-descriptions-item label="单客户权益数量">{{ grantSummary }}</el-descriptions-item>
           <el-descriptions-item label="开始时间">{{ snapshot.startTime || '-' }}</el-descriptions-item>
           <el-descriptions-item label="结束时间">{{ snapshot.endTime || '-' }}</el-descriptions-item>
           <el-descriptions-item label="选择客群" :span="2">

+ 8 - 5
pc-v3/src/views/CampaignAuditList.vue

@@ -9,8 +9,8 @@
       <div class="search-section">
         <div class="search-row">
           <el-form :model="searchForm" label-width="120px" inline>
-            <el-form-item label="发放计划名称:">
-              <el-input v-model="searchForm.bizName" placeholder="关键字" style="width: 200px" />
+            <el-form-item label="发放计划ID:">
+              <el-input v-model="searchForm.bizId" placeholder="精确匹配" style="width: 200px" />
             </el-form-item>
             <div class="button-group" style="margin-left: 20px;">
               <el-button type="primary" @click="loadData">查询</el-button>
@@ -39,6 +39,9 @@
         </el-table-column>
         <el-table-column prop="bizName" label="发放计划名称" min-width="160" show-overflow-tooltip />
         <el-table-column prop="bizId" label="发放计划 ID" width="160" align="center" />
+        <el-table-column label="业务模块" width="120" align="center">
+          <template #default>发放计划</template>
+        </el-table-column>
         <el-table-column label="审核类型" width="120" align="center">
           <template #default="scope">
             <el-tag :type="auditTypeTag(scope.row.auditType)" size="small">
@@ -81,7 +84,7 @@ export default {
   data() {
     return {
       activeTab: 'pending',
-      searchForm: { bizName: '' },
+      searchForm: { bizId: '' },
       tableData: []
     }
   },
@@ -102,13 +105,13 @@ export default {
     loadData() {
       const params = new URLSearchParams()
       params.append('auditStatus', this.activeTab)
-      if (this.searchForm.bizName) params.append('bizName', this.searchForm.bizName)
+      if (this.searchForm.bizId) params.append('bizId', this.searchForm.bizId)
       request.get('/api/campaign-audit/list?' + params.toString()).then(res => {
         this.tableData = res.data || []
       }).catch(() => {})
     },
     handleReset() {
-      this.searchForm = { bizName: '' }
+      this.searchForm = { bizId: '' }
       this.loadData()
     },
     auditTypeLabel(t) {

+ 2 - 1
pc-v3/src/views/CreditCardEquity.vue

@@ -49,7 +49,7 @@
                   </div>
                 </div>
                 <template #reference>
-                  <el-button type="text" size="small">调整显示顺序</el-button>
+                  <el-button v-if="scope.row.shelfStatus === '已上架'" type="text" size="small">调整显示顺序</el-button>
                 </template>
               </el-popover>
               <el-button type="text" size="small" @click="openShowPagesDialog(scope.row)">设置显示页面</el-button>
@@ -60,6 +60,7 @@
               >
                 <div class="more-actions-menu">
                   <div
+                    v-if="scope.row.shelfStatus === '已上架'"
                     class="more-actions-item"
                     @click="openLinkDialogFromMore(scope.row, scope.$index)"
                   >生成链接</div>

+ 100 - 49
pc-v3/src/views/EditEquityProduct.vue

@@ -30,16 +30,22 @@
         <el-form :model="form" label-width="120px" label-position="left">
           <el-row :gutter="20">
             <el-col :span="8">
-              <el-form-item label="权益来源" required>
-                <!-- 编辑时不允许修改权益来源 -->
-                <el-radio-group v-model="form.source" disabled>
-                  <el-radio label="银行自有"></el-radio>
-                  <el-radio label="荣数商品"></el-radio>
-                  <el-radio label="第三方"></el-radio>
+              <el-form-item label="是否权益平台兑换" required label-width="150px">
+                <el-radio-group v-model="form.isPlatformExchange" disabled>
+                  <el-radio label="是"></el-radio>
+                  <el-radio label="否"></el-radio>
                 </el-radio-group>
               </el-form-item>
             </el-col>
-            <el-col :span="8" v-if="form.source === '荣数商品'">
+            <el-col :span="8" v-if="form.isPlatformExchange === '是'">
+              <el-form-item label="商品类型" required>
+                <el-radio-group v-model="form.productType" disabled>
+                  <el-radio label="券码"></el-radio>
+                  <el-radio label="微信立减金"></el-radio>
+                </el-radio-group>
+              </el-form-item>
+            </el-col>
+            <el-col :span="8" v-if="form.isPlatformExchange === '是' && form.productType === '微信立减金'">
               <el-form-item label="选择权益" required>
                 <el-input
                   v-model="form.rongshuProduct"
@@ -52,16 +58,14 @@
                 </el-input>
               </el-form-item>
             </el-col>
-            <el-col :span="8" v-if="form.source === '银行自有'">
-              <el-form-item label="权益类型" required>
-                <el-radio-group v-model="form.productType">
-                  <el-radio label="券码"></el-radio>
-                </el-radio-group>
+            <el-col :span="8" v-if="form.isPlatformExchange === '是' && form.productType === '微信立减金' && form.rongshuSkuNo">
+              <el-form-item label="SKU编号">
+                <el-input v-model="form.rongshuSkuNo" readonly></el-input>
               </el-form-item>
             </el-col>
           </el-row>
           <el-row :gutter="20">
-            <el-col :span="8" v-if="form.source === '第三方'">
+            <el-col :span="8" v-if="form.isPlatformExchange === '否'">
               <el-form-item label="外部权益链接" required>
                 <el-select v-model="form.externalLink" placeholder="请选择外部权益链接">
                   <el-option label="太古地产" value="太古地产"></el-option>
@@ -71,12 +75,12 @@
                 </el-select>
               </el-form-item>
             </el-col>
-            <el-col :span="8" v-if="form.source === '第三方' && form.externalLink === 'h5链接'">
+            <el-col :span="8" v-if="form.isPlatformExchange === '否' && form.externalLink === 'h5链接'">
               <el-form-item label="h5链接" required>
                 <el-input v-model="form.customLink" placeholder="请输入h5链接"></el-input>
               </el-form-item>
             </el-col>
-            <el-col :span="8" v-if="form.source === '第三方'">
+            <el-col :span="8" v-if="form.isPlatformExchange === '否'">
               <el-form-item required label-width="140px">
                 <template #label>
                   <span style="white-space: nowrap;">是否有详情页<el-tooltip content="没有详情页时直接从首页/列表页/组装页直接跳转" placement="top"><el-icon class="tip-icon"><QuestionFilled /></el-icon></el-tooltip></span>
@@ -88,7 +92,7 @@
               </el-form-item>
             </el-col>
           </el-row>
-          <el-row :gutter="20" v-if="form.source === '第三方' && form.externalLink === '小程序链接'">
+          <el-row :gutter="20" v-if="form.isPlatformExchange === '否' && form.externalLink === '小程序链接'">
             <el-col :span="8">
               <el-form-item label="小程序appid" required>
                 <el-input v-model="form.miniAppId" placeholder="请输入小程序appid"></el-input>
@@ -101,20 +105,15 @@
             </el-col>
           </el-row>
 
-          <template v-if="form.source === '银行自有' || form.source === '荣数商品'">
+          <template v-if="form.isPlatformExchange === '是'">
             <el-row :gutter="20">
               <el-col :span="8">
                 <el-form-item label="权益名称" required>
                   <el-input v-model="form.equityName" maxlength="40" placeholder="请输入权益名称"></el-input>
                 </el-form-item>
               </el-col>
-              <el-col :span="8">
-                <el-form-item label="权益副标题">
-                  <el-input v-model="form.subTitle" maxlength="40" placeholder="请输入权益副标题"></el-input>
-                </el-form-item>
-              </el-col>
             </el-row>
-            <el-row :gutter="20" v-if="form.source === '荣数商品'">
+            <el-row :gutter="20" v-if="form.productType === '微信立减金'">
               <el-col :span="8">
                 <el-form-item label="库存数" required>
                   <el-input-number
@@ -155,18 +154,13 @@
             </el-row>
           </template>
 
-          <template v-else-if="form.source === '第三方'">
+          <template v-else-if="form.isPlatformExchange === '否'">
             <el-row :gutter="20">
               <el-col :span="8">
                 <el-form-item label="权益名称" required>
                   <el-input v-model="form.equityName" maxlength="40" placeholder="请输入权益名称"></el-input>
                 </el-form-item>
               </el-col>
-              <el-col :span="8">
-                <el-form-item label="权益副标题">
-                  <el-input v-model="form.subTitle" maxlength="40" placeholder="请输入权益副标题"></el-input>
-                </el-form-item>
-              </el-col>
             </el-row>
             <el-row :gutter="20" v-if="form.externalJumpMethod === '没有'">
               <el-col :span="8">
@@ -269,7 +263,7 @@
           <el-row :gutter="20">
             <el-col :span="12">
               <el-form-item label="权益有效期" required>
-                <template v-if="form.source === '银行自有' || form.source === '荣数商品'">
+                <template v-if="form.isPlatformExchange === '是'">
                   <el-radio-group v-model="form.validityType">
                     <el-radio label="fromGrantPlan">取自发放计划</el-radio>
                     <el-radio label="custom">自定义输入</el-radio>
@@ -305,7 +299,7 @@
               </el-form-item>
             </el-col>
           </el-row>
-          <template v-if="form.source === '银行自有' || form.source === '荣数商品'">
+          <template v-if="form.isPlatformExchange === '是'">
             <el-row :gutter="20">
               <el-col :span="24">
                 <el-form-item>
@@ -350,7 +344,7 @@
                 </el-form-item>
               </el-col>
             </el-row>
-            <el-row :gutter="20" v-if="form.source === '银行自有'">
+            <el-row :gutter="20" v-if="form.productType === '券码'">
               <el-col :span="8">
                 <el-form-item label="领取成功按钮" required>
                   <el-input v-model="form.successButtonText" placeholder="请输入按钮文案"></el-input>
@@ -621,8 +615,10 @@ export default {
         { id: 'SMS_TPL_003', name: '实物类短信模板', content: '【银行】您购买的${productName}已受理,我们将尽快安排发货,感谢您的支持。' }
       ],
       form: {
+        isPlatformExchange: '是',
         source: '银行自有',
         rongshuProduct: '',
+        rongshuSkuNo: '',
         productType: '券码',
         faceValueThreshold: '',
         faceValueDiscount: '',
@@ -639,7 +635,6 @@ export default {
         equityName: '',
         productId: '',
         merchantName: '',
-        subTitle: '',
         listIcon: [],
         mainImage: [],
         introduction: '',
@@ -672,10 +667,14 @@ export default {
     }
   },
   computed: {
+    mappedSource() {
+      if (this.form.isPlatformExchange === '否') return '第三方'
+      if (this.form.productType === '微信立减金') return '荣数商品'
+      return '银行自有'
+    },
     shouldShowDetailCard() {
-      const s = this.form.source
-      if (s === '银行自有' || s === '荣数商品') return true
-      if (s === '第三方' && this.form.externalJumpMethod === '有') return true
+      if (this.form.isPlatformExchange === '是') return true
+      if (this.form.isPlatformExchange === '否' && this.form.externalJumpMethod === '有') return true
       return false
     }
   },
@@ -692,30 +691,43 @@ export default {
           this.currentShelfStatus = res.data.shelfStatus || ''
           this.currentAuditStatus = res.data.auditStatus || ''
           // 用 API 返回的核心字段覆盖(保证编辑/已上架的内容是当前线上版本)
-          const fields = ['equityName', 'source', 'productType', 'skuNo', 'merchantName', 'subTitle']
+          const fields = ['equityName', 'source', 'isPlatformExchange', 'productType', 'skuNo', 'merchantName']
           fields.forEach(k => {
             if (res.data[k] !== undefined && res.data[k] !== null && res.data[k] !== '') {
               this.form[k] = res.data[k]
             }
           })
+          // 根据接口返回的 source 推算 isPlatformExchange 和 productType
+          if (!this.form.isPlatformExchange) {
+            if (res.data.source === '第三方') this.form.isPlatformExchange = '否'
+            else this.form.isPlatformExchange = '是'
+          }
+          if (this.form.isPlatformExchange === '是' && !this.form.productType) {
+            this.form.productType = res.data.source === '荣数商品' ? '微信立减金' : '券码'
+          }
+          if (this.form.isPlatformExchange === '否') {
+            this.form.productType = ''
+          }
           this.form.productId = id
         }
       }).catch(() => {})
     },
     buildPayload() {
       const f = this.form
-      const isCustomValidity = f.source === '第三方' || f.validityType === 'custom'
+      const source = this.mappedSource
+      const isNotPlatform = f.isPlatformExchange === '否'
+      const isCustomValidity = isNotPlatform || f.validityType === 'custom'
       return {
         productId: f.productId || this.$route.params.id,
         equityName: f.equityName,
-        source: f.source,
-        productType: f.productType || '',
-        skuNo: f.skuNo || '',
+        source: source,
+        isPlatformExchange: f.isPlatformExchange,
+        productType: f.isPlatformExchange === '是' ? f.productType : '',
+        skuNo: (f.isPlatformExchange === '是' && f.productType === '微信立减金') ? (f.rongshuSkuNo || f.skuNo || '') : (f.skuNo || ''),
         merchantName: f.merchantName || '',
-        subTitle: f.subTitle || '',
-        jumpMethod: f.source === '第三方' ? f.externalJumpMethod : '-',
-        jumpLink: f.source === '第三方' ? f.externalLink : '-',
-        exchangeMethod: f.source === '第三方'
+                jumpMethod: isNotPlatform ? f.externalJumpMethod : '-',
+        jumpLink: isNotPlatform ? f.externalLink : '-',
+        exchangeMethod: isNotPlatform
           ? (f.externalJumpMethod === '有' ? '第三方(详情页跳转)' : '第三方(列表跳转)')
           : '权益平台',
         validityType: isCustomValidity ? 'custom' : 'fromGrantPlan',
@@ -752,6 +764,8 @@ export default {
       const mockMap = {
         'Q100001': {
           source: '银行自有',
+          isPlatformExchange: '是',
+          productType: '券码',
           externalJumpMethod: '',
           externalLink: '',
           customLink: '',
@@ -759,7 +773,6 @@ export default {
         miniAppPath: '',
           skuNo: 'SKU001',
           equityName: '权益A',
-          subTitle: '副标题示例',
           listIcon: [],
           mainImage: [],
           overview: '<p>权益内容内容</p>',
@@ -784,6 +797,8 @@ export default {
         },
         'Q100002': {
           source: '第三方',
+          isPlatformExchange: '否',
+          productType: '',
           externalJumpMethod: '没有',
           externalLink: '太古地产',
           customLink: '',
@@ -791,7 +806,6 @@ export default {
         miniAppPath: '',
           skuNo: 'SKU002',
           equityName: '权益B',
-          subTitle: '外部列表页副标题',
           listIcon: [],
           mainImage: [],
           overview: '',
@@ -817,6 +831,8 @@ export default {
         },
         'Q100003': {
           source: '第三方',
+          isPlatformExchange: '否',
+          productType: '',
           externalJumpMethod: '有',
           externalLink: '龙腾',
           customLink: '',
@@ -824,7 +840,6 @@ export default {
         miniAppPath: '',
           skuNo: 'SKU003',
           equityName: '权益C',
-          subTitle: '外部详情页副标题',
           listIcon: [],
           mainImage: [],
           overview: '<p>外部详情页权益内容</p>',
@@ -849,12 +864,13 @@ export default {
         },
         'Q100004': {
           source: '第三方',
+          isPlatformExchange: '否',
+          productType: '',
           externalJumpMethod: '有',
           externalLink: 'h5链接',
           customLink: 'https://example.com/custom',
           skuNo: 'SKU004',
           equityName: '权益D',
-          subTitle: '外部自定义链接副标题',
           listIcon: [],
           mainImage: [],
           overview: '<p>自定义链接权益内容</p>',
@@ -880,6 +896,17 @@ export default {
       }
       if (id && mockMap[id]) {
         Object.assign(this.form, mockMap[id])
+        // 根据 mockMap 数据推算 isPlatformExchange 和 productType(以防 mockMap 缺少这些字段)
+        if (!this.form.isPlatformExchange) {
+          if (this.form.source === '第三方') this.form.isPlatformExchange = '否'
+          else this.form.isPlatformExchange = '是'
+        }
+        if (this.form.isPlatformExchange === '是' && !this.form.productType) {
+          this.form.productType = this.form.source === '荣数商品' ? '微信立减金' : '券码'
+        }
+        if (this.form.isPlatformExchange === '否') {
+          this.form.productType = ''
+        }
       }
     },
     nextStep() {
@@ -895,6 +922,29 @@ export default {
     goBack() {
       this.$router.push('/customization/hsbc/equity-products')
     },
+    handlePlatformExchangeChange(val) {
+      if (val === '是') {
+        this.form.productType = '券码'
+        this.form.externalLink = '太古地产'
+        this.form.externalJumpMethod = '没有'
+        this.form.customLink = ''
+        this.form.miniAppId = ''
+        this.form.miniAppPath = ''
+      } else {
+        this.form.rongshuProduct = ''
+        this.form.rongshuSkuNo = ''
+        this.form.stockCount = null
+        this.form.merchantName = ''
+      }
+    },
+    handleProductTypeChange(val) {
+      if (val === '券码') {
+        this.form.rongshuProduct = ''
+        this.form.rongshuSkuNo = ''
+        this.form.stockCount = null
+        this.form.merchantName = ''
+      }
+    },
     handleSmsEnabledChange(val) {
       if (!val) {
         this.form.smsTemplateId = ''
@@ -926,6 +976,7 @@ export default {
     },
     onRongshuSelect(product) {
       this.form.rongshuProduct = product.name
+      this.form.rongshuSkuNo = product.skuNo
       this.form.equityName = product.name
       this.form.merchantName = product.merchant
       this.form.stockCount = product.stock

+ 33 - 11
pc-v3/src/views/EquityGrantCampaign.vue

@@ -26,6 +26,13 @@
                 <el-option label="已结束" value="已结束" />
               </el-select>
             </el-form-item>
+            <el-form-item label="审核状态:">
+              <el-select v-model="searchForm.auditStatus" placeholder="全部" clearable style="width:140px">
+                <el-option label="新增待审核" value="新增待审核" />
+                <el-option label="结束待审核" value="结束待审核" />
+                <el-option label="审核通过" value="审核通过" />
+              </el-select>
+            </el-form-item>
             <div class="button-group">
               <el-button type="primary" @click="handleSearch">查询</el-button>
               <el-button @click="handleReset">重置</el-button>
@@ -45,7 +52,7 @@
           <template #default="scope">
             <el-button type="text" size="small" @click="handleView(scope.row)">查看</el-button>
             <el-button
-              v-if="statusLabel(scope.row) !== '进行中'"
+              v-if="statusLabel(scope.row) !== '进行中' && scope.row.auditStatus === '审核通过'"
               type="text"
               size="small"
               @click="handleEdit(scope.row)"
@@ -56,14 +63,14 @@
               @click="handleCopy(scope.row)"
             >复制</el-button>
             <el-button
-              v-if="statusLabel(scope.row) === '进行中'"
+              v-if="statusLabel(scope.row) === '进行中' && scope.row.auditStatus === '审核通过'"
               type="text"
               size="small"
               style="color:#E6A23C"
               @click="handleEnd(scope.row)"
             >结束</el-button>
             <el-button
-              v-if="statusLabel(scope.row) !== '进行中'"
+              v-if="statusLabel(scope.row) !== '进行中' && scope.row.auditStatus === '审核通过'"
               type="text"
               size="small"
               style="color:#F56C6C"
@@ -80,6 +87,11 @@
             <el-tag :type="statusTag(scope.row)" size="small">{{ statusLabel(scope.row) }}</el-tag>
           </template>
         </el-table-column>
+        <el-table-column label="审核状态" width="120" align="center">
+          <template #default="scope">
+            <el-tag :type="auditStatusTag(scope.row.auditStatus)" size="small">{{ scope.row.auditStatus }}</el-tag>
+          </template>
+        </el-table-column>
         <el-table-column label="获取方式" width="110" align="center">
           <template #default="scope">
             <el-tag :type="scope.row.grantMode === 'direct' ? 'warning' : 'success'" size="small">
@@ -87,7 +99,7 @@
             </el-tag>
           </template>
         </el-table-column>
-        <el-table-column label="权益数量" width="150" align="center">
+        <el-table-column label="单客户权益数量" width="150" align="center">
           <template #default="scope">
             {{ grantSummary(scope.row) }}
           </template>
@@ -97,6 +109,11 @@
             {{ validitySummary(scope.row.validity) }}
           </template>
         </el-table-column>
+        <el-table-column label="是否自动发放" width="110" align="center">
+          <template #default="scope">
+            <el-tag :type="scope.row.isAutoGrant === '是' ? 'success' : 'info'" size="small">{{ scope.row.isAutoGrant }}</el-tag>
+          </template>
+        </el-table-column>
         <el-table-column prop="createTime" label="创建时间" width="170" align="center" />
       </el-table>
     </el-card>
@@ -113,14 +130,16 @@ export default {
   name: 'EquityGrantCampaign',
   data() {
     return {
-      searchForm: { name: '', dateRange: [], status: '' },
+      searchForm: { name: '', dateRange: [], status: '', auditStatus: '' },
       tableData: []
     }
   },
   computed: {
     filteredData() {
-      if (!this.searchForm.status) return this.tableData
-      return this.tableData.filter(r => this.statusLabel(r) === this.searchForm.status)
+      let data = this.tableData
+      if (this.searchForm.status) data = data.filter(r => this.statusLabel(r) === this.searchForm.status)
+      if (this.searchForm.auditStatus) data = data.filter(r => r.auditStatus === this.searchForm.auditStatus)
+      return data
     }
   },
   created() {
@@ -148,7 +167,7 @@ export default {
     },
     handleSearch() { this.fetchList() },
     handleReset() {
-      this.searchForm = { name: '', dateRange: [], status: '' }
+      this.searchForm = { name: '', dateRange: [], status: '', auditStatus: '' }
       this.fetchList()
     },
     handleCreate() {
@@ -165,12 +184,12 @@ export default {
     },
     async handleEnd(row) {
       await ElMessageBox.confirm(
-        `确定结束发放计划「${row.name}」吗?结束后将立即生效,且不再继续发放权益。`,
+        `确定结束发放计划「${row.name}」吗?结束操作需审核通过后才生效。`,
         '结束发放计划',
-        { type: 'warning', confirmButtonText: '确认结束', cancelButtonText: '取消' }
+        { type: 'warning', confirmButtonText: '提交结束审核', cancelButtonText: '取消' }
       )
       await request.post('/api/equity-grant-campaign/end', { id: row.id })
-      ElMessage.success('已结束')
+      ElMessage.success('已提交结束审核')
       this.fetchList()
     },
     async handleDelete(row) {
@@ -210,6 +229,9 @@ export default {
     statusTag(row) {
       const l = this.statusLabel(row)
       return { 未开始: 'info', 进行中: 'success', 已结束: '' }[l] || ''
+    },
+    auditStatusTag(s) {
+      return { '审核通过': 'success', '新增待审核': 'warning', '结束待审核': 'danger' }[s] || ''
     }
   }
 }

+ 9 - 2
pc-v3/src/views/EquityGrantCampaignEdit.vue

@@ -55,6 +55,12 @@
             />
           </el-select>
         </el-form-item>
+        <el-form-item label="是否自动发放" prop="isAutoGrant" required>
+          <el-radio-group v-model="form.isAutoGrant">
+            <el-radio label="是">是</el-radio>
+            <el-radio label="否">否</el-radio>
+          </el-radio-group>
+        </el-form-item>
         <el-form-item label="获取方式" prop="grantMode" required>
           <el-radio-group v-model="form.grantMode" @change="handleGrantModeChange">
             <el-radio label="claim">用户领取</el-radio>
@@ -93,7 +99,7 @@
             />
           </el-select>
         </el-form-item>
-        <el-form-item label="权益数量" required>
+        <el-form-item label="单客户权益数量" required>
           <div class="grant-row">
             <el-select v-model="form.grantCycle" placeholder="类型" style="width:140px">
               <el-option label="整个周期" value="total" />
@@ -175,6 +181,7 @@ function emptyForm() {
     startTime: '',
     endTime: '',
     crowdList: [],
+    isAutoGrant: '是',
     grantMode: 'claim',
     equityList: [],
     grantCycle: 'total',
@@ -322,7 +329,7 @@ export default {
           return
         }
         if (!this.form.grantQuantity || this.form.grantQuantity < 1) {
-          ElMessage.warning('请输入权益数量')
+          ElMessage.warning('请输入单客户权益数量')
           return
         }
         if (!this.isClaimMode && this.form.equityList.length !== 1) {

+ 1 - 1
pc-v3/src/views/EquityGrantCampaignView.vue

@@ -16,7 +16,7 @@
         <el-descriptions-item label="获取方式">
           <el-tag :type="current.grantMode === 'direct' ? 'warning' : 'success'" size="small">{{ grantModeLabel }}</el-tag>
         </el-descriptions-item>
-        <el-descriptions-item label="权益数量">{{ grantSummary }}</el-descriptions-item>
+        <el-descriptions-item label="单客户权益数量">{{ grantSummary }}</el-descriptions-item>
         <el-descriptions-item label="开始时间">{{ current.startTime || '-' }}</el-descriptions-item>
         <el-descriptions-item label="结束时间">{{ current.endTime || '-' }}</el-descriptions-item>
         <el-descriptions-item label="权益有效期" :span="2">{{ validitySummary }}</el-descriptions-item>

+ 27 - 6
pc-v3/src/views/EquityProducts.vue

@@ -91,7 +91,7 @@
                     </div>
                   </div>
                   <template #reference>
-                    <div class="more-actions-item">调整显示顺序</div>
+                    <div v-if="scope.row.shelfStatus === '已上架'" class="more-actions-item">调整显示顺序</div>
                   </template>
                 </el-popover>
                 <div
@@ -99,16 +99,17 @@
                   @click="handleCopyFromMore(scope.row, scope.$index)"
                 >复制</div>
                 <div
+                  v-if="scope.row.shelfStatus === '已上架'"
                   class="more-actions-item"
                   @click="openLinkDialogFromMore(scope.row, scope.$index)"
                 >生成链接</div>
                 <div
-                  v-if="scope.row.source === '银行自有' && scope.row.productType === '券码'"
+                  v-if="scope.row.shelfStatus === '已上架' && scope.row.isPlatformExchange === '是' && scope.row.productType === '券码'"
                   class="more-actions-item"
                   @click="handleImportCouponsFromMore(scope.row, scope.$index)"
                 >导入券码</div>
                 <div
-                  v-if="scope.row.source === '银行自有' && scope.row.productType === '券码'"
+                  v-if="scope.row.shelfStatus === '已上架' && scope.row.isPlatformExchange === '是' && scope.row.productType === '券码'"
                   class="more-actions-item"
                   @click="handleManageCouponsFromMore(scope.row, scope.$index)"
                 >券码管理</div>
@@ -137,9 +138,29 @@
             <el-tag :type="getAuditTagType(scope.row.auditStatus)" size="small">{{ scope.row.auditStatus }}</el-tag>
           </template>
         </el-table-column>
-        <el-table-column prop="source" label="权益来源" width="100"></el-table-column>
-        <el-table-column prop="jumpLink" label="外部权益链接" width="120"></el-table-column>
-        <el-table-column prop="jumpMethod" label="是否有详情页" width="120"></el-table-column>
+        <el-table-column label="是否权益平台兑换" width="150">
+          <template #default="scope">
+            <el-tag :type="scope.row.isPlatformExchange === '是' ? 'success' : 'info'" size="small">{{ scope.row.isPlatformExchange }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column label="商品类型" width="120">
+          <template #default="scope">
+            <span v-if="scope.row.isPlatformExchange === '是'">{{ scope.row.productType }}</span>
+            <span v-else class="empty-text">-</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="外部权益链接" width="120">
+          <template #default="scope">
+            <span v-if="scope.row.isPlatformExchange === '否'">{{ scope.row.jumpLink }}</span>
+            <span v-else class="empty-text">-</span>
+          </template>
+        </el-table-column>
+        <el-table-column label="是否有详情页" width="120">
+          <template #default="scope">
+            <span v-if="scope.row.isPlatformExchange === '否'">{{ scope.row.jumpMethod }}</span>
+            <span v-else class="empty-text">-</span>
+          </template>
+        </el-table-column>
         <el-table-column prop="productId" label="权益编号" width="100"></el-table-column>
         <el-table-column label="显示页面" min-width="220">
           <template #default="scope">

+ 100 - 0
pc-v3/src/views/GrantTaskDetail.vue

@@ -0,0 +1,100 @@
+<template>
+  <div class="grant-task-detail">
+    <el-card>
+      <el-descriptions title="计划信息" :column="2" border>
+        <el-descriptions-item label="发放计划 ID">{{ task.planId }}</el-descriptions-item>
+        <el-descriptions-item label="发放计划名称">{{ task.planName }}</el-descriptions-item>
+        <el-descriptions-item label="获取方式">
+          <el-tag :type="task.grantMode === 'direct' ? 'warning' : 'success'" size="small">
+            {{ task.grantMode === 'direct' ? '直接发放' : '用户领取' }}
+          </el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="是否自动发放">
+          <el-tag :type="task.isAutoGrant === '是' ? 'success' : 'info'" size="small">{{ task.isAutoGrant }}</el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="单客户权益数量">{{ task.grantQuantityLabel }}</el-descriptions-item>
+        <el-descriptions-item label="权益有效期">{{ task.validityLabel }}</el-descriptions-item>
+        <el-descriptions-item label="开始时间">{{ task.planStartTime }}</el-descriptions-item>
+        <el-descriptions-item label="结束时间">{{ task.planEndTime }}</el-descriptions-item>
+        <el-descriptions-item label="选择客群">{{ task.crowdLabel }}</el-descriptions-item>
+        <el-descriptions-item label="选择权益">{{ task.equityLabel }}</el-descriptions-item>
+        <el-descriptions-item label="短信通知">{{ task.smsLabel }}</el-descriptions-item>
+      </el-descriptions>
+    </el-card>
+
+    <el-card style="margin-top: 16px;">
+      <el-descriptions title="任务信息" :column="2" border>
+        <el-descriptions-item label="任务 ID">{{ task.taskId }}</el-descriptions-item>
+        <el-descriptions-item label="任务类型">
+          <el-tag :type="task.taskType === '自动' ? 'success' : 'warning'" size="small">{{ task.taskType }}</el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="任务周期">{{ task.taskCycle }}</el-descriptions-item>
+        <el-descriptions-item label="任务状态">
+          <el-tag :type="statusTag(task.status)" size="small">{{ task.status }}</el-tag>
+        </el-descriptions-item>
+        <el-descriptions-item label="创建时间">{{ task.createTime }}</el-descriptions-item>
+        <el-descriptions-item label="执行时间">{{ task.executeTime || '-' }}</el-descriptions-item>
+        <el-descriptions-item label="执行人">{{ task.executor || '-' }}</el-descriptions-item>
+      </el-descriptions>
+    </el-card>
+
+    <div v-if="isExecute" class="execute-section" style="margin-top: 16px;">
+        <el-button type="primary" @click="handleExecute">确认执行</el-button>
+        <el-button @click="handleBack">取消</el-button>
+    </div>
+
+    <div v-else class="back-actions">
+      <el-button style="margin-top: 16px;" @click="handleBack">返回</el-button>
+    </div>
+  </div>
+</template>
+
+<script>
+import { ElMessage, ElMessageBox } from 'element-plus'
+import request from '@/utils/request'
+
+export default {
+  name: 'GrantTaskDetail',
+  data() {
+    return {
+      task: {}
+    }
+  },
+  computed: {
+    isExecute() {
+      return this.$route.name === 'GrantTaskExecute'
+    },
+    statusTag() {
+      return (s) => {
+        if (s === '已完成') return 'success'
+        if (s === '执行中') return ''
+        return 'info'
+      }
+    }
+  },
+  created() {
+    this.fetchData()
+  },
+  methods: {
+    async fetchData() {
+      const res = await request.get('/api/grant-task/detail', { params: { taskId: this.$route.params.taskId } })
+      this.task = res.data || {}
+    },
+    async handleExecute() {
+      await ElMessageBox.confirm('确认执行该发放任务?', '执行确认', { type: 'warning' })
+      const res = await request.post('/api/grant-task/execute', { taskId: this.task.taskId })
+      ElMessage.success(res.msg || '执行成功')
+      this.$router.push('/customization/hsbc/grant-task')
+    },
+    handleBack() {
+      this.$router.push('/customization/hsbc/grant-task')
+    }
+  }
+}
+</script>
+
+<style scoped>
+.grant-task-detail { padding: 20px; }
+.execute-actions { margin-top: 16px; }
+.back-actions { margin-top: 16px; }
+</style>

+ 125 - 0
pc-v3/src/views/GrantTaskList.vue

@@ -0,0 +1,125 @@
+<template>
+  <div class="grant-task-list">
+    <el-card>
+      <el-tabs v-model="activeTab">
+        <el-tab-pane label="待执行" name="待执行" />
+        <el-tab-pane label="执行中" name="执行中" />
+        <el-tab-pane label="已完成" name="已完成" />
+        <el-tab-pane label="全部" name="all" />
+      </el-tabs>
+      <div class="search-section">
+        <div class="search-row">
+          <el-form :model="searchForm" label-width="100px" inline>
+            <el-form-item label="发放计划ID:">
+              <el-input v-model="searchForm.planId" placeholder="精准匹配" clearable style="width:220px" />
+            </el-form-item>
+            <el-form-item label="计划名称:">
+              <el-input v-model="searchForm.planName" placeholder="关键字" clearable style="width:220px" />
+            </el-form-item>
+            <el-form-item label="任务类型:">
+              <el-select v-model="searchForm.taskType" placeholder="全部" clearable style="width:140px">
+                <el-option label="自动" value="自动" />
+                <el-option label="手动" value="手动" />
+              </el-select>
+            </el-form-item>
+            <div class="button-group">
+              <el-button type="primary" @click="handleSearch">查询</el-button>
+              <el-button @click="handleReset">重置</el-button>
+            </div>
+          </el-form>
+        </div>
+      </div>
+
+      <el-table :data="filteredData" stripe border style="width:100%">
+        <el-table-column label="操作" width="140" fixed="left">
+          <template #default="scope">
+            <el-button type="text" size="small" @click="handleView(scope.row)">查看</el-button>
+            <el-button
+              v-if="scope.row.status === '待执行'"
+              type="text"
+              size="small"
+              style="color:#E6A23C"
+              @click="handleExecute(scope.row)"
+            >执行</el-button>
+          </template>
+        </el-table-column>
+        <el-table-column prop="taskId" label="任务 ID" width="160" align="center" />
+        <el-table-column prop="planName" label="计划名称" min-width="200" show-overflow-tooltip />
+        <el-table-column prop="planId" label="发放计划 ID" width="130" align="center" />
+        <el-table-column label="任务类型" width="100" align="center">
+          <template #default="scope">
+            <el-tag :type="scope.row.taskType === '自动' ? 'success' : 'warning'" size="small">{{ scope.row.taskType }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="taskCycle" label="任务周期" width="160" align="center" />
+        <el-table-column label="任务状态" width="100" align="center">
+          <template #default="scope">
+            <el-tag :type="statusTag(scope.row.status)" size="small">{{ scope.row.status }}</el-tag>
+          </template>
+        </el-table-column>
+        <el-table-column prop="createTime" label="创建时间" width="170" align="center" />
+        <el-table-column prop="executeTime" label="执行时间" width="170" align="center" />
+        <el-table-column prop="executor" label="执行人" width="120" align="center" />
+      </el-table>
+    </el-card>
+  </div>
+</template>
+
+<script>
+import request from '@/utils/request'
+
+export default {
+  name: 'GrantTaskList',
+  data() {
+    return {
+      activeTab: '待执行',
+      searchForm: { planId: '', planName: '', taskType: '' },
+      tableData: []
+    }
+  },
+  computed: {
+    filteredData() {
+      let data = this.tableData
+      if (this.activeTab !== 'all') data = data.filter(t => t.status === this.activeTab)
+      if (this.searchForm.planId) data = data.filter(t => t.planId === this.searchForm.planId)
+      if (this.searchForm.planName) data = data.filter(t => t.planName.includes(this.searchForm.planName))
+      if (this.searchForm.taskType) data = data.filter(t => t.taskType === this.searchForm.taskType)
+      return data
+    }
+  },
+  created() {
+    this.fetchData()
+  },
+  methods: {
+    statusTag(s) {
+      if (s === '已完成') return 'success'
+      if (s === '执行中') return ''
+      return 'info'
+    },
+    async fetchData() {
+      const res = await request.get('/api/grant-task/list')
+      this.tableData = res.data || []
+    },
+    handleView(row) {
+      this.$router.push(`/customization/hsbc/grant-task/view/${row.taskId}`)
+    },
+    handleExecute(row) {
+      this.$router.push(`/customization/hsbc/grant-task/execute/${row.taskId}`)
+    },
+    handleSearch() {
+      this.fetchData()
+    },
+    handleReset() {
+      this.searchForm = { planId: '', planName: '', taskType: '' }
+      this.fetchData()
+    }
+  }
+}
+</script>
+
+<style scoped>
+.grant-task-list { padding: 20px; }
+.search-section { margin-top: 4px; }
+.search-row { display: flex; align-items: center; }
+.button-group { margin-left: 20px; }
+</style>

+ 19 - 2
pc-v3/src/views/RuleGroupList.vue

@@ -21,6 +21,13 @@
                 />
               </el-select>
             </el-form-item>
+            <el-form-item label="审核状态:">
+              <el-select v-model="searchForm.auditStatus" clearable placeholder="全部" style="width: 160px">
+                <el-option label="新增待审核" value="新增待审核" />
+                <el-option label="编辑待审核" value="编辑待审核" />
+                <el-option label="审核通过" value="审核通过" />
+              </el-select>
+            </el-form-item>
             <div class="button-group">
               <el-button type="primary" @click="handleSearch">查询</el-button>
               <el-button @click="handleReset">重置</el-button>
@@ -73,6 +80,11 @@
             </el-tag>
           </template>
         </el-table-column>
+        <el-table-column label="审核状态" width="120" align="center">
+          <template #default="scope">
+            <el-tag :type="auditStatusTag(scope.row.auditStatus)" size="small">{{ scope.row.auditStatus }}</el-tag>
+          </template>
+        </el-table-column>
         <el-table-column prop="creator" label="创建人" width="100" />
         <el-table-column prop="createdAt" label="创建时间" width="170" />
       </el-table>
@@ -100,7 +112,7 @@ export default {
   name: 'RuleGroupList',
   data() {
     return {
-      searchForm: { id: '', name: '', type: '' },
+      searchForm: { id: '', name: '', type: '', auditStatus: '' },
       page: { current: 1, size: 10 },
       groupTypes: GROUP_TYPES
     }
@@ -119,11 +131,16 @@ export default {
       const item = this.groupTypes.find((g) => g.value === type)
       return item ? item.label : type
     },
+    auditStatusTag(s) {
+      if (s === '审核通过') return 'success'
+      if (s === '新增待审核' || s === '编辑待审核') return ''
+      return 'info'
+    },
     handleSearch() {
       this.page.current = 1
     },
     handleReset() {
-      this.searchForm = { id: '', name: '', type: '' }
+      this.searchForm = { id: '', name: '', type: '', auditStatus: '' }
       this.page.current = 1
     },
     handleCreate() {

+ 99 - 29
pc-v3/src/views/ViewEquityProduct.vue

@@ -30,34 +30,39 @@
           <el-form :model="form" label-width="120px" label-position="left">
             <el-row :gutter="20">
               <el-col :span="8">
-                <el-form-item label="权益来源">
-                  <el-radio-group v-model="form.source" disabled>
-                    <el-radio label="银行自有"></el-radio>
-                    <el-radio label="荣数商品"></el-radio>
-                    <el-radio label="第三方"></el-radio>
+                <el-form-item label="是否权益平台兑换" label-width="150px">
+                  <el-radio-group v-model="form.isPlatformExchange" disabled>
+                    <el-radio label="是"></el-radio>
+                    <el-radio label="否"></el-radio>
                   </el-radio-group>
                 </el-form-item>
               </el-col>
-              <el-col :span="8" v-if="form.source === '荣数商品'">
+              <el-col :span="8" v-if="form.isPlatformExchange === '是'">
+                <el-form-item label="商品类型">
+                  <el-radio-group v-model="form.productType" disabled>
+                    <el-radio label="券码"></el-radio>
+                    <el-radio label="微信立减金"></el-radio>
+                  </el-radio-group>
+                </el-form-item>
+              </el-col>
+              <el-col :span="8" v-if="form.isPlatformExchange === '是' && form.productType === '微信立减金'">
                 <el-form-item label="选择权益">
                   <el-input :value="form.rongshuProduct" readonly></el-input>
                 </el-form-item>
               </el-col>
-              <el-col :span="8" v-if="form.source === '银行自有'">
-                <el-form-item label="权益类型">
-                  <el-radio-group v-model="form.productType" disabled>
-                    <el-radio label="券码"></el-radio>
-                  </el-radio-group>
+              <el-col :span="8" v-if="form.isPlatformExchange === '是' && form.productType === '微信立减金' && form.rongshuSkuNo">
+                <el-form-item label="SKU编号">
+                  <el-input :value="form.rongshuSkuNo" readonly></el-input>
                 </el-form-item>
               </el-col>
-              <el-col :span="8" v-if="form.source === '银行自有'">
+              <el-col :span="8" v-if="form.isPlatformExchange === '是' && form.productType === '券码'">
                 <el-form-item label="商户名称">
                   <el-input :value="form.merchantName" readonly></el-input>
                 </el-form-item>
               </el-col>
             </el-row>
             <el-row :gutter="20">
-              <el-col :span="8" v-if="form.source === '第三方'">
+              <el-col :span="8" v-if="form.isPlatformExchange === '否'">
                 <el-form-item label="外部权益链接">
                   <el-select v-model="form.externalLink" placeholder="请选择外部权益链接" disabled>
                     <el-option label="太古地产" value="太古地产"></el-option>
@@ -67,12 +72,12 @@
                   </el-select>
                 </el-form-item>
               </el-col>
-              <el-col :span="8" v-if="form.source === '第三方' && form.externalLink === 'h5链接'" :gutter="20">
+              <el-col :span="8" v-if="form.isPlatformExchange === '否' && form.externalLink === 'h5链接'" :gutter="20">
                 <el-form-item label="h5链接">
                   <el-input v-model="form.customLink" placeholder="请输入h5链接" readonly></el-input>
                 </el-form-item>
               </el-col>
-              <el-col :span="8" v-if="form.source === '第三方'">
+              <el-col :span="8" v-if="form.isPlatformExchange === '否'">
                 <el-form-item label-width="140px">
                   <template #label>
                     <span style="white-space: nowrap;">是否有详情页<el-tooltip content="没有详情页时直接从首页/列表页/组装页直接跳转" placement="top"><el-icon class="tip-icon"><QuestionFilled /></el-icon></el-tooltip></span>
@@ -84,7 +89,7 @@
                 </el-form-item>
               </el-col>
             </el-row>
-            <el-row :gutter="20" v-if="form.source === '第三方' && form.externalLink === '小程序链接'">
+            <el-row :gutter="20" v-if="form.isPlatformExchange === '否' && form.externalLink === '小程序链接'">
               <el-col :span="8">
                 <el-form-item label="小程序appid">
                   <el-input v-model="form.miniAppId" readonly></el-input>
@@ -97,8 +102,8 @@
               </el-col>
             </el-row>
 
-            <template v-if="form.source === '银行自有' || form.source === '荣数商品'">
-              <el-row :gutter="20" v-if="form.source === '荣数商品'">
+            <template v-if="form.isPlatformExchange === '是'">
+              <el-row :gutter="20" v-if="form.productType === '微信立减金'">
                 <el-col :span="8">
                   <el-form-item label="库存数">
                     <el-input :value="form.stockCount" readonly></el-input>
@@ -111,11 +116,6 @@
                     <el-input v-model="form.equityName" readonly></el-input>
                   </el-form-item>
                 </el-col>
-                <el-col :span="8">
-                  <el-form-item label="权益副标题">
-                    <el-input v-model="form.subTitle" readonly></el-input>
-                  </el-form-item>
-                </el-col>
               </el-row>
               <el-row :gutter="20">
                 <el-col :span="8">
@@ -136,7 +136,7 @@
               </el-row>
             </template>
 
-            <template v-else-if="form.source === '第三方'">
+            <template v-else-if="form.isPlatformExchange === '否'">
               <el-row :gutter="20">
                 <el-col :span="8">
                   <el-form-item label="权益名称">
@@ -245,7 +245,7 @@
                 </el-form-item>
               </el-col>
             </el-row>
-            <template v-if="form.source === '银行自有' || form.source === '荣数商品'">
+            <template v-if="form.isPlatformExchange === '是'">
               <el-row :gutter="20">
                 <el-col :span="24">
                   <el-form-item label="下单成功短信">
@@ -271,7 +271,7 @@
                   </el-form-item>
                 </el-col>
               </el-row>
-              <el-row :gutter="20" v-if="form.source === '银行自有'">
+              <el-row :gutter="20" v-if="form.productType === '券码'">
                 <el-col :span="8">
                   <el-form-item label="领取成功按钮">
                     <el-input :value="form.successButtonText" readonly></el-input>
@@ -480,8 +480,10 @@ export default {
         { id: 'SMS_TPL_003', name: '实物类短信模板', content: '【银行】您购买的${productName}已受理,我们将尽快安排发货,感谢您的支持。' }
       ],
       form: {
+        isPlatformExchange: '是',
         source: '银行自有',
         rongshuProduct: '',
+        rongshuSkuNo: '',
         productType: '券码',
         faceValueThreshold: null,
         faceValueDiscount: null,
@@ -532,10 +534,14 @@ export default {
     }
   },
   computed: {
+    mappedSource() {
+      if (this.form.isPlatformExchange === '否') return '第三方'
+      if (this.form.productType === '微信立减金') return '荣数商品'
+      return '银行自有'
+    },
     shouldShowDetailCard() {
-      const s = this.form.source
-      if (s === '银行自有' || s === '荣数商品') return true
-      if (s === '第三方' && this.form.externalJumpMethod === '有') return true
+      if (this.form.isPlatformExchange === '是') return true
+      if (this.form.isPlatformExchange === '否' && this.form.externalJumpMethod === '有') return true
       return false
     },
     canRequestOffshelf() {
@@ -553,6 +559,8 @@ export default {
       const mockMap = {
         'Q100001': {
           source: '银行自有',
+          isPlatformExchange: '是',
+          productType: '券码',
           externalJumpMethod: '',
           externalLink: '',
           customLink: '',
@@ -585,6 +593,8 @@ export default {
         },
         'Q100002': {
           source: '第三方',
+          isPlatformExchange: '否',
+          productType: '',
           externalJumpMethod: '没有',
           externalLink: '太古地产',
           customLink: '',
@@ -618,6 +628,8 @@ export default {
         },
         'Q100003': {
           source: '第三方',
+          isPlatformExchange: '否',
+          productType: '',
           externalJumpMethod: '有',
           externalLink: '龙腾',
           customLink: '',
@@ -650,6 +662,8 @@ export default {
         },
         'Q100004': {
           source: '第三方',
+          isPlatformExchange: '否',
+          productType: '',
           externalJumpMethod: '有',
           externalLink: 'h5链接',
           customLink: 'https://example.com/custom',
@@ -677,6 +691,47 @@ export default {
           claimDenyMessage: '很抱歉,您暂不符合领取条件。',
           claimDenyButtonText: '返回',
           claimDenyButtonLink: '权益首页'
+        },
+        'Q100007': {
+          source: '荣数商品',
+          isPlatformExchange: '是',
+          productType: '微信立减金',
+          externalJumpMethod: '',
+          externalLink: '',
+          customLink: '',
+          miniAppId: '',
+          miniAppPath: '',
+          skuNo: 'V0000003900000801',
+          rongshuProduct: '微信立减金 5元(满10减5)',
+          rongshuSkuNo: 'V0000003900000801',
+          equityName: '微信立减金 5元(满10减5)',
+          merchantName: '微信支付',
+          stockCount: 2000,
+          subTitle: '',
+          listIcon: [],
+          mainImage: [{ name: 'wx-5.png', url: 'https://placehold.co/200x200/07c160/ffffff?text=%C2%A55' }],
+          overview: '<p>微信立减金权益内容</p>',
+          details: '<p>微信立减金权益说明</p>',
+          introduction: '满10减5',
+          smsEnabled: true,
+          smsTemplateId: 'SMS_TPL_002',
+          smsTemplate: '【银行】尊敬的客户,您的${productName}购买成功,券码为${exchangeNum},请于${expireDate}前使用。',
+          successButtonText: '',
+          validityType: 'fromGrantPlan',
+          validityText: '',
+          showTimeEnabled: false,
+          showStartTime: '',
+          showEndTime: '',
+          showGroupEnabled: false,
+          showGroupTagIds: [],
+          claimTimeEnabled: false,
+          claimStartTime: '',
+          claimEndTime: '',
+          claimGroupEnabled: false,
+          claimGroupTagId: '',
+          claimDenyMessage: '很抱歉,您暂不符合领取条件。',
+          claimDenyButtonText: '返回',
+          claimDenyButtonLink: '权益首页'
         }
       }
       if (id && mockMap[id]) {
@@ -684,6 +739,17 @@ export default {
       } else if (id) {
         Object.assign(this.form, mockMap['Q100001'])
       }
+      // 根据接口返回的 source 推算 isPlatformExchange 和 productType
+      if (!this.form.isPlatformExchange) {
+        if (this.form.source === '第三方') this.form.isPlatformExchange = '否'
+        else this.form.isPlatformExchange = '是'
+      }
+      if (this.form.isPlatformExchange === '是' && !this.form.productType) {
+        this.form.productType = this.form.source === '荣数商品' ? '微信立减金' : '券码'
+      }
+      if (this.form.isPlatformExchange === '否') {
+        this.form.productType = ''
+      }
 
       const logsMap = {
         'Q100001': [
@@ -703,6 +769,10 @@ export default {
           { operator: '钱七', operateTime: '2026-02-01 09:48:12', action: '创建' },
           { operator: '李四', operateTime: '2026-02-01 14:11:36', action: '审核' },
           { operator: '赵六', operateTime: '2026-04-05 18:22:47', action: '下架' }
+        ],
+        'Q100007': [
+          { operator: '张三', operateTime: '2026-05-20 10:00:00', action: '创建' },
+          { operator: '李四', operateTime: '2026-05-22 15:30:00', action: '审核' }
         ]
       }
       this.operationLogs = (id && logsMap[id]) ? logsMap[id] : (id ? logsMap['Q100001'] : [])

+ 135 - 54
prd/汇丰银行/汇丰借记卡权益移动端.md → prd/汇丰银行/汇丰借记卡移动端——权益.md

@@ -1,25 +1,29 @@
 **与后台的关联说明:**
 
-> -   移动端根据后台"商品来源"和"跳转触发页"两个字段组合判断跳转逻辑
+> -   移动端根据后台"商品来源"和"是否有详情页"两个字段组合判断跳转逻辑
 >     
-> -   后台"外部商品链接"字段(太古地产/龙腾/自定义)决定外部跳转时的交互流程
+> -   商品来源分为三类:**银行自有**(券码)、**荣数商品**(微信立减金)、**第三方**(太古地产/龙腾/h5链接/小程序链接)
 >     
-> -   后台"展示规则"控制移动端权益列表的可见性
+> -   后台"外部商品链接"字段(太古地产/龙腾/h5链接/小程序链接)决定外部跳转时的交互流程
 >     
-> -   后台"领取规则"控制移动端权益详情页的领取校验
+> -   后台"展示规则"(展示时间限制 / 展示客群限制)控制移动端权益列表的可见性
+>     
+> -   后台"领取规则"(领取时间限制 / 领取客群限制)控制移动端权益详情页的领取校验;**领取客群统一由后台【发放计划】维护,未发放的权益移动端不展示**
+>     
+> -   后台"显示页面"(权益首页/列表页、组装页)决定权益在移动端哪些页面展示
+>     
+> -   后台"调整显示顺序"决定权益在移动端权益首页/列表中的展示顺序
+>     
+> -   后台"分享设置"决定权益是否支持分享及分享内容(分享名称、分享图片)
 >     
 
-## 1\. 权益主页(积木侧搭建)
-
-新增借记卡权益(通过积木组件百变导航配置)
-
-## 2\. 我的权益
+## 1\. 我的权益
 
-### 2.1 权益列表
+### 1.1 权益列表
 
 ![](../../.resources/image-1776678669459.png)
 
-展示顺序:先展示借记卡权益,再展示信用卡权益,最后是微信立减金(置底)
+展示顺序:先展示借记卡权益,再展示信用卡权益,最后是微信立减金入口(置底)
 
 **(1)借记卡权益(新增)**
 
@@ -27,29 +31,33 @@
     
     -   商品状态:已上架
         
-    -   商品类型:不为微信立减金
+    -   商品类型:不为微信立减金(微信立减金统一在"我的立减金"入口跳转展示)
         
     -   展示时间限制:未开启 或 当前时间在后台配置的展示开始时间~展示结束时间范围内
         
     -   展示客群限制:未开启 或 用户命中后台配置的客群标签ID
         
+    -   显示页面:后台配置了"权益首页/列表页 = 显示"
+        
+    -   奖励点:如果权益商品开启了领取客群限制,需要判断用户的的该科目是否奖励点>0,如果等于0不展示
+        
 -   **列表字段**
     
     -   权益列表图标(取后台"权益列表图标"字段)
         
     -   权益名称(取后台"权益名称"字段)
         
--   **列表顺序:** 按照审核通过时间从后往前排序展示
+-   **列表顺序:** 按照后台"调整显示顺序"排列(后台可通过列表【更多 → 调整显示顺序】调整)
     
--   **列表跳转** 根据后台【商品来源】+【跳转触发页】判断:
+-   **列表跳转** 根据后台【商品来源】+【是否有详情页】判断:
     
     -   **商品来源=银行自有:** 跳转到权益详情页
         
-    -   **商品来源=第三方,跳转触发页=权益列表页:** 点击跳转第三方链接
+    -   **商品来源=第三方,是否有详情页=没有:** 点击直接从列表跳转第三方链接
         
         -   根据后台配置的【外部商品链接】类型判断跳转交互:
             
-        -   **自定义:** 弹窗提示
+        -   **h5链接:** 弹窗提示
             
             -   **标题:** 您正在离开汇丰中国
                 
@@ -59,9 +67,21 @@
                 
                 -   **取消:** 关闭弹窗
                     
-                -   **继续前往:** 跳转后台配置的自定义链接
+                -   **继续前往:** 跳转后台配置的h5链接
                     
                     ![](../../.resources/image-1776678703451.png)
+        -   **小程序链接:** 弹窗提示
+            
+            -   **标题:** 您正在离开汇丰中国
+                
+            -   **描述:** 请注意,外部网站的政策与我们网站的条款和条件以及隐私政策不同。将在新浏览器窗口或选项卡中打开下一个网站。
+                
+            -   **操作**
+                
+                -   **取消:** 关闭弹窗
+                    
+                -   **继续前往:** 跳转后台配置的微信小程序(使用小程序appid + 页面地址)
+                    
         -   **太古地产:** 点击后弹出授权提醒
             
             -   勾选同意并**确认**后,显示离开提示,点击确认时调用太古地产接口,然后跳转至后端返回的太古地产免登地址。
@@ -70,32 +90,46 @@
                 
                 <br>
                 
-                <br>
-                
-                <br>
+                ![](../../.resources/image-1776678728870.png)
                 
                 <br>
                 
-                ![](../../.resources/image-1776678728870.png)![](../../.resources/image-1776678755981.png)
-        -   **龙腾:** 点击后弹出授权提醒
-            
-            -   勾选同意并**确认**后,显示离开提示,点击确认时调用龙腾接口,然后跳转至后端返回的龙腾免登地址。
-                
-            -   **点击取消:** 关闭授权提醒。
-                
-                ![](../../.resources/image-1776678775726.png)
+                ![](../../.resources/image-1776678755981.png)
+-   **龙腾:** 点击后弹出授权提醒
+    
+    -   勾选同意并**确认**后,显示离开提示,点击确认时调用龙腾接口,然后跳转至后端返回的龙腾免登地址。
+        
+    -   **点击取消:** 关闭授权提醒。
+        
+        ![](../../.resources/image-1776678775726.png)
 
 **(2)信用卡权益(现有)**
 
-通过营销提供的接口查询:若客户未达标,展示带解锁;若科目已达标,展示剩余可用次数(0次也展示)。
+通过营销提供的接口查询:若客户未达标,展示【待解锁】;若科目已达标,展示剩余可用次数(0次也展示)。
 
 **(3)微信立减金(新增)**
 
 底部固定展示微信立减金入口,点击跳转至微信立减金列表页面。
 
-### 2.2 我的权益
+### 1.2 我的权益
 
-展示顺序:先展示【商品来源为银行自有券码】(未过期),再展示【信用卡权益】,最后展示【商品来源为银行自有券码权益】(已失效)。
+展示顺序:
+
+1.  商品来源为银行自有券码(未过期)。
+    
+2.  信用卡权益。
+    
+3.  商品来源为银行自有券码权益(已失效)。
+    
+
+筛选项:
+
+-   全部
+    
+-   可使用:未过期
+    
+-   已失效
+    
 
 ![](../../.resources/image-1776678841917.png)
 
@@ -103,15 +137,15 @@
 
 -   **列表字段**
     
-    -   权益列表图标(取后台"权益列表图标"字段)
+    -   权益列表图标(取"权益图片"字段)
         
-    -   权益名称(取后台"权益名称"字段)
+    -   权益名称(取"权益名称"字段)
         
-    -   权益副标题(取后台"权益副标题"字段,为空则不展示)
+    -   可用次数
         
 -   **列表顺序**
     
-    -   按照券码有效期,先到期先展示
+    -   领取时间倒序展示
         
 -   **跳转链接**
     
@@ -120,7 +154,22 @@
 
 **(2)信用卡权益**
 
-通过营销提供的接口查询:若客户未达标,展示带解锁;若科目已达标,展示剩余可用次数(0次也展示)。
+-   **列表字段**
+    
+    -   权益列表图标(取后台"权益列表图标"字段)
+        
+    -   权益名称(取后台"权益名称"字段)
+        
+    -   权益副标题(取后台"权益副标题"字段,为空则不展示)
+        
+-   **列表顺序**
+    
+    -   领取时间倒序展示
+        
+-   **跳转链接**
+    
+    -   跳转订单详情页
+        
 
 **(3)券码权益(已失效)**
 
@@ -132,18 +181,16 @@
         
 -   **列表顺序**
     
-    -   按照券码有效期,最近到期先展示
-        
-    -   查询最近一年的到期订单
+    -   领取时间倒序展示
         
 -   **跳转链接**
     
     -   跳转订单详情页
         
 
-## 3\. 权益详情
+## 2\. 权益详情
 
-> 仅商品来源=银行自有,以及商品来源=第三方且跳转触发页=权益详情页的权益会进入此页面。
+> 仅商品来源=银行自有,以及商品来源=第三方且是否有详情页=有的权益会进入此页面。
 
 **(1)详情页内容**
 
@@ -151,9 +198,23 @@
     
 -   **权益名称:** 取后台"权益名称"字段,超出换行展示
     
--   **权益概述:** 取后台"权益概述"字段,富文本展示,图中卡片中权益名称下方内容
+-   **权益介绍:** 取后台"权益介绍"字段,非富文本,样式固定。图中卡片中权益名称下方内容
     
--   **权益详情:** 取后台"权益详情"字段,富文本展示,图中卡片下方的内容
+-   **权益有效期:** 取后台"权益有效期"字段
+    
+    -   取发放计划字段:
+        
+        -   固定日期:【开始日期】-【结束日期】
+            
+        -   相对日期:领取后 x 天内有效
+            
+    -   自定义:显示自定义输入的内容
+        
+-   **权益数量(无领取限制则不显示):**x 次(整个周期)、月度 x 次、季度 x 次、年度 x 次
+    
+-   **权益内容:** 取后台"权益内容"字段,富文本展示,图中卡片下方的内容。PDF链接需支持点击打开预览查看,不需要支持下载。
+    
+-   **权益说明:** 取后台"权益说明"字段,富文本展示。PDF链接需支持点击打开预览查看,不需要支持下载。
     
 -   **按钮:** 根据后台"领取规则"中的领取时间限制判断
     
@@ -187,13 +248,17 @@
         
         <br>
         
-        ![](../../.resources/image-1776678923546.png)![](../../.resources/image-1776678942001.png)
+        <br>
+        
+        ![|50%](../../.resources/image-1776678923546.png)![|50%](../../.resources/image-1776678942001.png)
 
 **(2)领取权益**
 
 点击【领取权益】按以下顺序校验领取规则:
 
-**校验顺序:校验领取客群规则**
+**校验顺序:先校验发放计划 → 再校验领取客群规则**
+
+> 注意:领取客群统一由后台【发放计划】维护。未在发放计划中发放给当前用户的权益,移动端不展示领取入口。用户在权益详情页点击领取时,需校验该用户是否在发放计划的客群范围内。
 
 **规则校验失败提示:**
 
@@ -227,13 +292,28 @@
 
 <br>
 
-![](../../.resources/image-1776678975193.png)![](../../.resources/image-1776678985797.png)
+<br>
 
-**第二种:商品来源=第三方,跳转触发页=权益详情页**
+![|50%](../../.resources/image-1776678975193.png)![|51%](../../.resources/image-1776678985797.png)
+
+**第二种:商品来源=第三方,是否有详情页=有**
 
 根据后台配置的【外部商品链接】类型判断跳转交互:
 
--   **自定义:** 弹窗提示
+-   **h5链接:** 弹窗提示
+    
+    -   **标题:** 您正在离开汇丰中国
+        
+    -   **描述:** 请注意,外部网站的政策与我们网站的条款和条件以及隐私政策不同。将在新浏览器窗口或选项卡中打开下一个网站。
+        
+    -   **操作**
+        
+        -   **取消:** 关闭弹窗
+            
+        -   **继续前往:** 跳转后台配置的h5链接
+            
+            ![|58%](../../.resources/image-1776679010497.png)
+-   **小程序链接:** 弹窗提示
     
     -   **标题:** 您正在离开汇丰中国
         
@@ -243,9 +323,8 @@
         
         -   **取消:** 关闭弹窗
             
-        -   **继续前往:** 跳转后台配置的自定义链接
+        -   **继续前往:** 跳转后台配置的微信小程序(使用小程序appid + 页面地址)
             
-            ![](../../.resources/image-1776679010497.png)
 -   **太古地产:** 点击后弹出授权提醒
     
     -   勾选同意并**确认**后,显示离开提示,点击确认时调用太古地产接口,然后跳转至后端返回的太古地产免登地址。
@@ -259,9 +338,9 @@
         
     -   **点击取消:** 关闭授权提醒。
         
-        ![](../../.resources/image-1776679039096.png)
+        ![|54%](../../.resources/image-1776679039096.png)
 
-## 4\. 权益订单详情
+## 3\. 权益订单详情
 
 > 仅【券码】类型(商品来源=银行自有)领取成功后可进入此页面。
 
@@ -280,9 +359,11 @@
 
 ![](../../.resources/image-1776679076106.png)
 
-## 5\. 我的立减金
+## 4\. 我的立减金
+
+> 微信立减金的后台数据来源为**荣数商品**(商品来源=荣数商品)。后台在添加权益时选择"荣数商品"来源,从荣数商品池中选择具体的立减金商品(如"微信立减金 10元"等),自动回填商品信息。
 
-![](../../.resources/image-1776679101444.png)
+![|53%](../../.resources/image-1776679101444.png)
 
 逻辑:
 

+ 50 - 78
prd/汇丰银行/汇丰银行权益中台-FSD.md

@@ -1,8 +1,8 @@
-# 汇丰银行权益中台FSD
-
 # 一、系统说明
 
-# 二、角色和用户管理
+<br>
+
+# 二、角色管理
 
 ## 流程
 
@@ -10,7 +10,7 @@
     
 2.  点击“新商城外跳联登”,进入【商城】角色管理配置角色
     
-3.  回到【统一门户】系统管理->用户管理->添加用户并分配角色
+3.  回到【统一门户】系统管理->用户管理->分配角色
     
 
 ## 1.角色管理
@@ -42,52 +42,21 @@
 
 ![BlockNote image](../../.resources/image-1779242945672.png)
 
-## 2\. 用户管理
-
-### 2.1 用户列表
-
-![BlockNote image](../../.resources/image-1779242966310.png)
-
-### 2.2 添加用户
-
-> **一期不需要添加用户,我们会批量导入用户进去。**
+### 1.3 分配角色
 
-![BlockNote image](../../.resources/image-1779242979631.png)
-
-点击【添加】可添加用户。
-
--   昵称:必填,可输入用户姓名
-    
--   用户名:必填
-    
--   用户类别:必填,需选择【普通用户】
-    
--   一级和二级分行:相当于组织架构,权益列表根据一级分行进行数据的隔离,二级分行没有作用。如下
-    
-    -   一级分行A(对应A部门)
-        
-    -   一级分行B(对应B部门)
-        
--   手机号:必填,用于登录发送验证码校验添加完成后,会给该用户的手机号发送包含 账号名称和初始密码 的短信。
-    
-
-![BlockNote image](../../.resources/image-1779242994166.png)
-
-### 2.3 分配角色
-
-<br>
+进入【统一门户】-【用户管理】分配角色
 
 <br>
 
 ![BlockNote image](../../.resources/image-1779243010146.png)![BlockNote image](../../.resources/image-1779243019476.png)
 
-## 3\. 用户登录
+## 2\. 用户登录
 
 登录页填写账号、密码即可登录。
 
 ![BlockNote image](../../.resources/image-1779243033492.png)
 
-## 4\. 用户配置计划
+## 3\. 用户配置计划
 
 -   一期:在CUPD中独立配置,我们会批量导入行内账号,可通过账号和密码登录。
     
@@ -107,13 +76,13 @@
 
 ### 1.2 权益分类
 
-按**商品来源**分为三类:
+按**是否权益平台兑换**分为两类:
 
-| 商品来源 | 说明  |
-| --- | --- |
-| **银行自有** | 银行自有商户权益商品,细分仅为"券码"商品 |
-| **荣数商品** | 由荣数侧统一提供的权益商品池(一期仅微信立减金),选择后自动回填名称、主图和库存 |
-| **第三方** | 第三方合作商家权益(太古地产、龙腾、h5链接、小程序链接) |
+| 是否权益平台兑换 | 商品类型 | 说明  |
+| --- | --- | --- |
+| **是** | **券码** | 银行自有商户权益商品 |
+| **是** | **微信立减金** | 由荣数侧统一提供的权益商品池,选择后自动回填名称、主图和库存 |
+| **否** | —   | 第三方合作商家权益(太古地产、龙腾、h5链接、小程序链接) |
 
 ### 1.3 权益商品状态流转
 
@@ -127,10 +96,10 @@
 | 商品状态 | 审核状态 | 业务含义 | 可执行操作 |
 | --- | --- | --- | --- |
 | 未上架 | 草稿  | 新建后未提审 | 查看、编辑、删除 |
-| 未上架 | 上架待审核 | 新建提审,等待审核 | 查看、调整显示顺序、生成链接 |
+| 未上架 | 上架待审核 | 新建提审,等待审核,前台不可见 | 查看、调整显示顺序 |
 | 已上架 | 审核通过 | 正式上架中,前台可见 | 查看、下架、导入券码、券码管理、调整显示顺序、生成链接 |
-| 已上架 | 下架待审核 | 已上架但已发起下架,等待审核 | 查看、导入券码、券码管理、调整显示顺序、生成链接 |
-| 未上架 | 审核通过 | 已下架,前台不可见 | 查看、编辑、删除、导入券码、券码管理、调整显示顺序、生成链接 |
+| 已上架 | 下架待审核 | 已上架但已发起下架,等待审核,前台可见 | 查看、调整显示顺序 |
+| 未上架 | 审核通过 | 已下架,前台不可见 | 查看、编辑、删除、调整显示顺序 |
 
 ### 1.4 操作入口
 
@@ -177,9 +146,10 @@
 | 权益名称 | 权益名称,超过一行时换行显示 |
 | 商品状态 | 使用色块 Tag 展示 可选值:未上架(灰)/ 已上架(绿) |
 | 审核状态 | 使用色块 Tag 展示 可选值:草稿(灰)/ 上架待审核(默认)/ 下架待审核(红)/ 审核通过(绿) |
-| 权益来源 | 银行自有 / 荣数商品 / 第三方 |
-| 外部权益链接 | 第三方权益的链接来源:太古地产 / 龙腾 / h5链接 / 小程序链接;非第三方显示"-" |
-| 是否有详情页 | 仅第三方权益使用,标识跳转触发位:"有" = 用户进入权益详情页后再跳出;"没有" = 用户在首页/列表页/组装页“点击后直接跳出;非第三方显示"-" |
+| 是否权益平台兑换 | 是 / 否,Tag 展示:是(绿)/ 否(灰) |
+| 商品类型 | 仅是否权益平台兑换 = 是时显示,可选值:券码 / 微信立减金;是否权益平台兑换 = 否时显示”-” |
+| 外部权益链接 | 仅是否权益平台兑换 = 否时显示,链接来源:太古地产 / 龙腾 / h5链接 / 小程序链接;是否权益平台兑换 = 是时显示”-” |
+| 是否有详情页 | 仅是否权益平台兑换 = 否时使用,标识跳转触发位:”有” = 用户进入权益详情页后再跳出;”没有” = 用户在首页/列表页/组装页点击后直接跳出;是否权益平台兑换 = 是时显示”-” |
 | 权益编号 | 系统生成,统一 `Q` + 6 位序号格式(如 `Q000001`),全局唯一 |
 | 显示页面 | 使用 Tag 展示当前权益启用的展示位:开启"权益首页/列表页"时显示一个「权益首页/列表页」Tag;开启"组装页"时按所选组装页(组装页 A/B/C/D…)追加 Tag。两项均未开启时显示"-" |
 | 创建人 | 创建该权益的用户昵称 |
@@ -199,8 +169,8 @@
 | 更多 → 调整显示顺序 | 所有状态 | 弹出气泡:"调整到第 N 位",输入框默认值=当前位次,范围 1 ~ 当前列表总条数;提示文案"移动端权益首页和列表页按照该顺序展示";【确定】后列表局部刷新到目标位置 |
 | 更多 → 复制 | 所有状态 | 进入【添加权益】向导,自动回填源权益的基本信息、规则、显示页面等字段;保存时由系统生成新权益编号 |
 | 更多 → 生成链接 | 所有状态 | 弹出"生成借记卡权益链接"对话框,给出可分享的借记卡权益链接 |
-| 更多 → 导入券码 | 权益来源 = `银行自有` 且 权益类型 = `券码` | 新开页面跳转至统一资源管理后台的"新增导入批次"页面 |
-| 更多 → 券码管理 | 权益来源 = `银行自有` 且 权益类型 = `券码` | 新开页面跳转至统一资源管理后台的"码库管理"页面 |
+| 更多 → 导入券码 | 是否权益平台兑换 = `是` 且 商品类型 = `券码` | 新开页面跳转至统一资源管理后台的"新增导入批次"页面 |
+| 更多 → 券码管理 | 是否权益平台兑换 = `是` 且 商品类型 = `券码` | 新开页面跳转至统一资源管理后台的"码库管理"页面 |
 | 更多 → 删除 | 商品状态 = `未上架` 且 审核状态 ∈ { `草稿`, `审核通过` } | 二次确认弹窗("确定删除权益'XXX'吗?"),确认后从列表移除 |
 
 生成借记卡权益链接对话框:
@@ -232,49 +202,51 @@
 
 2.2.1 第一步:填写权益信息
 
-第一步包含两个卡片:**基本信息**(始终显示)与 **详情信息**(按"权益来源 / 是否有详情页"条件显示)。
+第一步包含两个卡片:**基本信息**(始终显示)与 **详情信息**(按"是否权益平台兑换 / 是否有详情页"条件显示)。
 
 (1)基本信息
 
-页面顶部先选择**权益来源**(必填,圆点单选,默认"银行自有"):
+页面顶部先选择**是否权益平台兑换**(必填,圆点单选,默认"是"):
 
--   银行自有(默认)
+-   是(默认)
+    
+-   否
     
--   荣数商品
+
+当是否权益平台兑换 = "是"时,下方展示**商品类型**(必填,圆点单选,默认"券码"):
+
+-   券码(默认)
     
--   第三方
+-   微信立减金
     
 
-不同权益来源展开不同字段:
+不同组合展开不同字段:
 
-**A. 权益来源 = 银行自有**
+**A. 是否权益平台兑换 = 是,商品类型 = 券码**
 
 | 字段  | 必填  | 说明  |
 | --- | --- | --- |
-| 权益类型 | 是   | 圆点单选,目前仅"券码" |
 | 权益名称 | 是   | 最长 40 字符 |
 | 权益副标题 | 否   | 最长 40 字符 |
 | 权益图标 | 是   | 上传 1 张,建议尺寸 80×80px。Tooltip:"展示在权益首页和权益列表页" |
 
 ![BlockNote image](./screenshots/2-2-equity-add-step1.png)
 
-**B. 权益来源 = 荣数商品**
+**B. 是否权益平台兑换 = 是,商品类型 = 微信立减金**
 
 | 字段  | 必填  | 说明  |
 | --- | --- | --- |
-| 选择权益 | 是   | 只读输入框 + 【选择】按钮。弹窗"选择荣数商品"中按商品名称模糊搜索,每页 10 条;选中后自动回填权益名称、商户名称、库存数、权益主图。**荣数商品池均为微信立减金商品**(如"微信立减金 10元(满50减10)"等) |
+| 选择权益 | 是   | 只读输入框 + 【选择】按钮。弹窗"选择微信立减金"中按商品名称模糊搜索,每页 10 条;选中后自动回填权益名称、商户名称、库存数、权益主图 |
 | 权益名称 | 是   | 最长 40 字符,由"选择权益"自动回填,仍可手动编辑 |
 | 权益副标题 | 否   | 最长 40 字符 |
-| 库存数 | 是   | 整数,范围 0 ~ 100000,由"选择权益"自动回填,最大不超过荣数的库存 |
+| 库存数 | 是   | 整数,范围 0 ~ 100000,由"选择权益"自动回填,最大不超过库存上限 |
 | 权益图标 | 是   | 上传 1 张,建议尺寸 80×80px |
 
 <br>
 
-<br>
-
 ![BlockNote image](./screenshots/2-2-equity-add-source-rongshu.png)![BlockNote image](./screenshots/dialog-rongshu-product.png)
 
-**C. 权益来源 = 第三方**
+**C. 是否权益平台兑换 = 否**
 
 先选择"外部权益链接"与"是否有详情页"两个关键字段;
 
@@ -291,7 +263,7 @@
 | 权益副标题 | 否   | 最长 40 字符 |
 | 权益图标 | 是   | 上传 1 张,建议尺寸 80×80px |
 
-注:第三方权益没有"权益类型"与"库存数"字段。
+注:是否权益平台兑换 = 否时不显示"商品类型"与"库存数"字段。
 
 ![BlockNote image](./screenshots/2-2-equity-add-third-detail.png)
 
@@ -299,18 +271,18 @@
 
 (2)详情信息
 
-**显示条件**:权益来源 = 银行自有 / 荣数商品;或 权益来源 = 第三方 **且** "是否有详情页 = 有"。
+**显示条件**:是否权益平台兑换 = 是;或 是否权益平台兑换 = 否 **且** "是否有详情页 = 有"。
 
-当权益来源 = 第三方 **且** "是否有详情页 = 没有"时,整个详情信息卡片不显示。
+当是否权益平台兑换 = 否 **且** "是否有详情页 = 没有"时,整个详情信息卡片不显示。
 
 | 字段  | 必填  | 说明  |
 | --- | --- | --- |
 | 权益主图 | 是   | 上传 1 张,建议尺寸 716×400px |
 | 权益介绍 | 是   | 多行文本,最长 500 字符,带字数实时提示 |
-| 权益有效期 | 是   | • 权益来源 = 银行自有 / 荣数商品:圆点单选「取自发放计划 / 自定义输入」,选"自定义输入"时下方出现文本框(最长 50 字符,带字数提示) • 权益来源 = 第三方:直接输入文本框(最长 50 字符) |
+| 权益有效期 | 是   | • 是否权益平台兑换 = 是:圆点单选「取自发放计划 / 自定义输入」,选"自定义输入"时下方出现文本框(最长 50 字符,带字数提示) • 是否权益平台兑换 = 否:直接输入文本框(最长 50 字符) |
 | 权益内容 | 是   | 富文本编辑器,需支持PDF上传,可自定义PDF链接文本 |
 | 权益说明 | 是   | 富文本编辑器,需支持PDF上传,可自定义链接文本 |
-| 下单成功短信 | 否   | **仅银行自有 / 荣数商品显示。** 开关 + 短信模板下拉。开启后选择已配置的短信模板,模板内容会在下方实时回显。模板支持占位符:`${productName}` 权益名称、`${expireDate}` 结束日期、`${exchangeNum}` 卡号、`${exchangePwd}` 卡密、`${qrCodeDownPaths}` 券码路径 |
+| 下单成功短信 | 否   | **仅是否权益平台兑换 = 是时显示。** 开关 + 短信模板下拉。开启后选择已配置的短信模板,模板内容会在下方实时回显。模板支持占位符:`${productName}` 权益名称、`${expireDate}` 结束日期、`${exchangeNum}` 卡号、`${exchangePwd}` 卡密、`${qrCodeDownPaths}` 券码路径 |
 | 领取成功按钮 | 是   | 默认值"马上去使用",可修改 |
 
 2.2.2 第二步:设置规则
@@ -390,7 +362,7 @@
 
 **字段编辑约束**:
 
--   **权益来源** 不可编辑(圆点单选禁用),保持创建时选定的来源;其余字段(含第三方分支的"外部权益链接 / 是否有详情页"、银行自有的"权益类型")均可正常编辑
+-   **是否权益平台兑换** 不可编辑(圆点单选禁用),保持创建时选定的值;其余字段(含是否权益平台兑换 = 否时的"外部权益链接 / 是否有详情页"、商品类型)均可正常编辑
     
 
 **操作按钮**:
@@ -555,7 +527,7 @@
 
 ## 4\. 券码管理
 
-**适用范围**:仅对**商品来源 = 银行自有**且**商品类型 = 券码**的权益开放。**操作入口**:借记卡权益列表 → 行【操作】→【更多】→【券码管理】点击后跳转至统一资源管理后台现有【码库管理】模块,默认填充商品编号。
+**适用范围**:仅对**是否权益平台兑换 = 是**且**商品类型 = 券码**的权益开放。**操作入口**:借记卡权益列表 → 行【操作】→【更多】→【券码管理】点击后跳转至统一资源管理后台现有【码库管理】模块,默认填充商品编号。
 
 ### 4.1 批次列表字段
 
@@ -623,7 +595,7 @@
     
 -   移动端"展示顺序"由后台【调整显示顺序】决定
     
--   第三方权益的"是否有详情页"决定用户在 App 列表层级还是详情层级跳出("没有" = 首页/列表页直接跳出;"有" = 进入权益详情页后再跳出)
+-   是否权益平台兑换 = 否时的"是否有详情页"决定用户在 App 列表层级还是详情层级跳出("没有" = 首页/列表页直接跳出;"有" = 进入权益详情页后再跳出)
     
 -   微信立减金在单独的微信立减金列表展示,统一通过"我的立减金"入口领用
     
@@ -681,7 +653,7 @@
 
 **页面结构**:三步骤步骤条 —— `权益信息 → 设置规则 → 更多设置`,全部控件 disabled,按"添加权益"的同款向导只读展示提交时的快照内容:
 
--   **步骤 1 权益信息**:基本信息(权益来源、权益类型 / 外部权益链接 / 是否有详情页、权益名称、副标题、SIP 商品编号、商户名称、权益图标);详情信息(权益主图、权益介绍、权益有效期、权益内容、权益说明、领取成功按钮)。详情信息卡片显示条件同 §2.2.1(银行自有 / 荣数商品;或第三方 + 有详情页)
+-   **步骤 1 权益信息**:基本信息(是否权益平台兑换、商品类型 / 外部权益链接 / 是否有详情页、权益名称、副标题、SIP 商品编号、商户名称、权益图标);详情信息(权益主图、权益介绍、权益有效期、权益内容、权益说明、领取成功按钮)。详情信息卡片显示条件同 §2.2.1(是否权益平台兑换 = 是;或否 + 有详情页)
     
 -   **步骤 2 设置规则**:展示规则(展示时间限制、展示客群限制)+ 领取规则(领取时间限制、领取客群限制)开关 + 已配置内容只读回显
     
@@ -916,7 +888,7 @@
 | 校验 (sample) | "详情"链接(可点击打开弹窗查看 sample 数据)/ "正在运行"(灰)/ "未运行"(灰);右侧附【重新校验】按钮,仅当任务状态允许重跑时可点。重新校验仅重跑 count + sample,不影响 fulllist |
 | 全量圈客 (fulllist) | "未运行"(红)/ "正在运行"(灰)/ "已完成"(绿) |
 
-**sample 抽样规则**(行内返回):count < 30000 取 5 个;30000~~50000 取 8 个;50000~~150000 取 12 个;> 150000 取 15 个;结果不足 5 个则全部返回
+**sample 抽样规则**(行内返回):小于30000,取5个、30000到50000,取8个、50000到150000,取12个、150000以上,取15个,sample从行内数据库随机抽取,若结果不足5个则全部返回为sample
 
 **底部按钮**:返回。
 
@@ -1695,7 +1667,7 @@ Campaign 的列表操作与 Channel 保持一致:
 
 ## 4\. 与权益管理的关联
 
--   《二、权益管理》→ 添加 / 编辑权益商品 → 第一步【下单成功短信】开关开启后,引用本模块维护的短信模板(仅银行自有 / 荣数商品来源可见)
+-   《二、权益管理》→ 添加 / 编辑权益商品 → 第一步【下单成功短信】开关开启后,引用本模块维护的短信模板(仅是否权益平台兑换 = 是时可见)
     
 -   **发放计划侧的"短信通知"** 使用独立的发放短信模板(`GRANT_SMS_001` 系列),不与本模块的模板池共享,详见 §四 发放计划 §3