From a6fa7ee721b028f5008972f38d96dfa4c80708cf Mon Sep 17 00:00:00 2001
From: hejianhao <15708179461@qq.com>
Date: 星期一, 24 八月 2026 16:33:35 +0800
Subject: [PATCH] Merge branch 'dev-0806-wql'

---
 tcm-training-admin-backend/pom.xml                                                                                                   |    8 
 traditionalApp/pages/home/home.vue                                                                                                   |    2 
 traditionalApp/pages/publish/service.js                                                                                              |    6 
 tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/vo/HealthPopularizationDetailVO.java                            |    1 
 traditionalApp/pages/healthCoursesHub/healthCoursesHub.vue                                                                           |    8 
 tcm-training-admin/src/pages/live/health-promotion/service.ts                                                                        |   55 +
 traditionalApp/pages/healthPopularization/service.js                                                                                 |    6 
 traditionalApp/pages/weizanLive/weizanLive.vue                                                                                       |   61 +
 tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/popularization/controller/AppHealthPopularizationController.java |    8 
 tcm-training-admin-backend/src/main/java/com/tcm/training/admin/bootstrap/DataInitializer.java                                       |   34 
 tcm-training-admin-backend/sql/20260806_admin.sql                                                                                    |   59 +
 tcm-training-admin/src/pages/live/health-promotion/style.less                                                                        |  223 ++++++
 traditionalApp/pages/articleDetail/articleDetail.vue                                                                                 |   39 +
 tcm-training-admin/src/pages/live/health-popularization/manage.tsx                                                                   |    4 
 traditionalApp/utils/weizan-pay-bridge.js                                                                                            |  185 ++++
 tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/dto/HealthPopularizationSaveRequest.java                        |    3 
 traditionalApp/pages/publish/publish.vue                                                                                             |   69 +
 traditionalApp/pages/healthPopularization/healthPopularization.vue                                                                   |   69 +
 tcm-training-admin-backend/sql/20260806_prd.sql                                                                                      |  569 ++++++++++++++++
 tcm-training-admin/src/pages/live/health-popularization/index.tsx                                                                    |    8 
 tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/entity/HealthPopularization.java                                |    3 
 tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/popularization/vo/AppHealthPopularizationDetailVO.java           |    4 
 tcm-training-admin/src/access.js                                                                                                     |    6 
 tcm-training-admin/config/routes.ts                                                                                                  |  147 ++-
 tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/popularization/service/AppHealthPopularizationService.java       |   16 
 tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/service/HealthPopularizationAppService.java                     |    3 
 tcm-training-admin/src/pages/live/health-promotion/manage.tsx                                                                        |  240 ++++++
 traditionalApp/pages.json                                                                                                            |    6 
 tcm-training-admin/src/pages/live/project-introduction/manage.tsx                                                                    |    2 
 tcm-training-admin/src/pages/live/health-promotion/index.tsx                                                                         |  240 ++++++
 tcm-training-admin/src/pages/live/project-introduction/index.tsx                                                                     |    4 
 traditionalApp/manifest.json                                                                                                         |    4 
 32 files changed, 1,918 insertions(+), 174 deletions(-)

diff --git a/tcm-training-admin-backend/pom.xml b/tcm-training-admin-backend/pom.xml
index 8616947..7d4750f 100644
--- a/tcm-training-admin-backend/pom.xml
+++ b/tcm-training-admin-backend/pom.xml
@@ -153,6 +153,14 @@
             <plugin>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.7.18</version>  <!-- 改成你用的 Spring Boot 版本 -->
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
             </plugin>
         </plugins>
     </build>
diff --git a/tcm-training-admin-backend/sql/20260806_admin.sql b/tcm-training-admin-backend/sql/20260806_admin.sql
index 20c2baa..bf5e6a6 100644
--- a/tcm-training-admin-backend/sql/20260806_admin.sql
+++ b/tcm-training-admin-backend/sql/20260806_admin.sql
@@ -151,4 +151,61 @@
 
 ALTER TABLE `tcm_health_popularization`
 ADD COLUMN `video_description` VARCHAR(255) DEFAULT NULL COMMENT '视频介绍'
-AFTER `video_file_name`;
\ No newline at end of file
+AFTER `video_file_name`;
+
+
+-- ----------------------------
+-- 新增二级菜单:宣传知识(与课程管理平级,父级为课程与学习 3000)
+-- 并将「项目介绍」「项目介绍密码」菜单从课程管理(3050)迁移到宣传知识下
+-- 添加时间:2026-08-22
+-- ----------------------------
+
+-- 宣传知识菜单(id: 6100)
+INSERT INTO sys_menu (id, parent_id, name, menu_code, type, path, component, icon, sort, status, visible, permission_key, remark, deleted)
+VALUES (6100, 3000, '宣传知识', 'live_promotion_root', 'M', '/live/promotion', NULL, NULL, 20, 1, 1, NULL, '宣传知识目录', 0)
+ON DUPLICATE KEY UPDATE parent_id = VALUES(parent_id), name = VALUES(name), menu_code = VALUES(menu_code), type = VALUES(type), path = VALUES(path), component = VALUES(component), sort = VALUES(sort), status = VALUES(status), visible = VALUES(visible), permission_key = VALUES(permission_key), remark = VALUES(remark), deleted = 0;
+
+-- 将「项目介绍」(6010) 迁移到「宣传知识」(6100) 下,并将路由前缀改为 /live/promotion
+UPDATE sys_menu SET parent_id = 6100, path = '/live/promotion/project-introduction' WHERE id = 6010;
+
+-- 将「项目介绍密码」(6014) 迁移到「宣传知识」(6100) 下,并将路由前缀改为 /live/promotion
+UPDATE sys_menu SET parent_id = 6100, path = '/live/promotion/project-introduction-password' WHERE id = 6014;
+
+-- ----------------------------
+-- 「健康科普」改名为「健康知识」,并从课程管理(3050)迁移到宣传知识(6100)下
+-- 主菜单 id: 3120,子按钮 3121/3122/3123 随父级一起迁移(parent_id 不变,无需单独处理)
+-- 添加时间:2026-08-22
+-- ----------------------------
+UPDATE sys_menu
+SET parent_id = 6100,
+    name = '健康知识',
+    path = '/live/promotion/health-popularization',
+    remark = '健康知识菜单'
+WHERE id = 3120;
+
+-- 子按钮随主菜单改名(parent_id 仍为 3120,不变)
+UPDATE sys_menu SET name = '新增健康知识', remark = '健康知识新增按钮' WHERE id = 3121;
+UPDATE sys_menu SET name = '编辑健康知识', remark = '健康知识编辑按钮' WHERE id = 3122;
+UPDATE sys_menu SET name = '删除健康知识', remark = '健康知识删除按钮' WHERE id = 3123;
+
+-- ----------------------------
+-- 新增「养生科普」菜单及按钮权限(宣传知识 6100 下,与健康知识平级)
+-- 养生科普与健康知识共用 tcm_health_popularization 表,contentType=2(仅视频)
+-- 主菜单 id: 6110,子按钮 6111/6112/6113
+-- 添加时间:2026-08-22
+-- ----------------------------
+INSERT INTO sys_menu (id, parent_id, name, menu_code, type, path, component, icon, sort, status, visible, permission_key, remark, deleted)
+VALUES (6110, 6100, '养生科普', 'live_health_promotion_manage', 'C', '/live/promotion/health-promotion', 'Live/HealthPromotionList', NULL, 51, 1, 1, 'live:health-promotion:view', '养生科普菜单', 0)
+ON DUPLICATE KEY UPDATE parent_id = VALUES(parent_id), name = VALUES(name), menu_code = VALUES(menu_code), type = VALUES(type), path = VALUES(path), component = VALUES(component), sort = VALUES(sort), status = VALUES(status), visible = VALUES(visible), permission_key = VALUES(permission_key), remark = VALUES(remark), deleted = 0;
+
+INSERT INTO sys_menu (id, parent_id, name, menu_code, type, path, component, icon, sort, status, visible, permission_key, remark, deleted)
+VALUES (6111, 6110, '新增养生科普', 'live_health_promotion_add', 'B', NULL, NULL, NULL, 1, 1, 1, 'live:health-promotion:add', '养生科普新增按钮', 0)
+ON DUPLICATE KEY UPDATE parent_id = VALUES(parent_id), name = VALUES(name), menu_code = VALUES(menu_code), type = VALUES(type), sort = VALUES(sort), status = VALUES(status), visible = VALUES(visible), permission_key = VALUES(permission_key), remark = VALUES(remark), deleted = 0;
+
+INSERT INTO sys_menu (id, parent_id, name, menu_code, type, path, component, icon, sort, status, visible, permission_key, remark, deleted)
+VALUES (6112, 6110, '编辑养生科普', 'live_health_promotion_edit', 'B', NULL, NULL, NULL, 2, 1, 1, 'live:health-promotion:edit', '养生科普编辑按钮', 0)
+ON DUPLICATE KEY UPDATE parent_id = VALUES(parent_id), name = VALUES(name), menu_code = VALUES(menu_code), type = VALUES(type), sort = VALUES(sort), status = VALUES(status), visible = VALUES(visible), permission_key = VALUES(permission_key), remark = VALUES(remark), deleted = 0;
+
+INSERT INTO sys_menu (id, parent_id, name, menu_code, type, path, component, icon, sort, status, visible, permission_key, remark, deleted)
+VALUES (6113, 6110, '删除养生科普', 'live_health_promotion_delete', 'B', NULL, NULL, NULL, 3, 1, 1, 'live:health-promotion:delete', '养生科普删除按钮', 0)
+ON DUPLICATE KEY UPDATE parent_id = VALUES(parent_id), name = VALUES(name), menu_code = VALUES(menu_code), type = VALUES(type), sort = VALUES(sort), status = VALUES(status), visible = VALUES(visible), permission_key = VALUES(permission_key), remark = VALUES(remark), deleted = 0;
\ No newline at end of file
diff --git a/tcm-training-admin-backend/sql/20260806_prd.sql b/tcm-training-admin-backend/sql/20260806_prd.sql
new file mode 100644
index 0000000..1b232a2
--- /dev/null
+++ b/tcm-training-admin-backend/sql/20260806_prd.sql
@@ -0,0 +1,569 @@
+-- 2026-08-06 变更前数据备份
+DROP TABLE IF EXISTS `tcm_live_course_2026_0806_back`;
+CREATE TABLE `tcm_live_course_2026_0806_back` LIKE `tcm_live_course`;
+INSERT INTO `tcm_live_course_2026_0806_back` SELECT * FROM `tcm_live_course`;
+
+DROP TABLE IF EXISTS `tcm_clinic_2026_0806_back`;
+CREATE TABLE `tcm_clinic_2026_0806_back` LIKE `tcm_clinic`;
+INSERT INTO `tcm_clinic_2026_0806_back` SELECT * FROM `tcm_clinic`;
+
+DROP TABLE IF EXISTS `tcm_health_popularization_2026_0806_back`;
+CREATE TABLE `tcm_health_popularization_2026_0806_back` LIKE `tcm_health_popularization`;
+INSERT INTO `tcm_health_popularization_2026_0806_back` SELECT * FROM `tcm_health_popularization`;
+
+DROP TABLE IF EXISTS `sys_menu_2026_0806_back`;
+CREATE TABLE `sys_menu_2026_0806_back` LIKE `sys_menu`;
+INSERT INTO `sys_menu_2026_0806_back` SELECT * FROM `sys_menu`;
+
+DROP TABLE IF EXISTS `sys_role_menu_2026_0806_back`;
+CREATE TABLE `sys_role_menu_2026_0806_back` LIKE `sys_role_menu`;
+INSERT INTO `sys_role_menu_2026_0806_back` SELECT * FROM `sys_role_menu`;
+
+ALTER TABLE tcm_live_course
+ADD COLUMN `password` VARCHAR(255) DEFAULT NULL COMMENT '直播间密码' AFTER `status`;
+
+CREATE TABLE tcm_provincial_agent (
+    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '代理ID,主键,自增',
+    agent_name VARCHAR(50) NOT NULL COMMENT '省区负责人姓名',
+    province VARCHAR(20) NOT NULL COMMENT '负责省份名称(如:四川省)',
+    bank_name VARCHAR(100) COMMENT '开户银行名称(如:中国建设银行)',
+    account_number VARCHAR(30) COMMENT '银行账号',
+    account_holder VARCHAR(50) COMMENT '账户名称/户名(即开户人姓名或公司名称)',
+    branch_name VARCHAR(100) COMMENT '开户支行名称(如:成都高新支行)',
+    contact_info VARCHAR(200) COMMENT '联系信息(可填电话、邮箱、手机号等)',
+    status TINYINT NOT NULL DEFAULT 1 COMMENT '状态:1启用,0禁用,2注销',
+    address VARCHAR(255) COMMENT '详细地址(如:成都市高新区天府大道XX号)',
+    `deleted` tinyint(1) NOT NULL DEFAULT '0',
+  `created_by` varchar(64) NOT NULL DEFAULT '系统初始化' COMMENT '创建人',
+  `updated_by` varchar(64) NOT NULL DEFAULT '系统初始化' COMMENT '更新人',
+  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
+) COMMENT='省代理人员信息表,存储代理的基本资料及银行账户信息';
+
+CREATE TABLE tcm_agent_region (
+    id BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '记录ID,主键,自增',
+    agent_id BIGINT NOT NULL COMMENT '关联省代理人员ID,外键指向 provincial_agent.id',
+    region_code CHAR(6) NOT NULL COMMENT '6位行政区划编码(如:510101 表示成都市辖区)',
+    region_name VARCHAR(100) COMMENT '区域名称(冗余字段,便于直接展示,如:成都市)',
+    region_level TINYINT COMMENT '区域行政级别:1-省级,2-市级,3-区县级,4-乡镇级(可根据编码前缀判断)',
+    created_at DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '记录创建时间',
+    UNIQUE KEY uk_agent_region (agent_id, region_code) COMMENT '联合唯一索引,防止同一代理重复添加同一区域'
+) COMMENT='代理负责区域表,存储每个省代理所管辖的具体区域(一对多关系,一个代理可负责多个区域)';
+
+-- 为 tcm_clinic 表新增代理关联字段
+ALTER TABLE tcm_clinic
+ADD COLUMN agent_id BIGINT COMMENT '负责该诊所的省代理ID,tcm_provincial_agent.id'
+AFTER name;
+
+-- 为 tcm_clinic 表新增银行信息字段(全部加在 status 字段后面)
+ALTER TABLE tcm_clinic
+ADD COLUMN bank_name VARCHAR(100) COMMENT '开户银行名称(如:中国建设银行)' AFTER status,
+ADD COLUMN account_number VARCHAR(30) COMMENT '银行账号' AFTER bank_name,
+ADD COLUMN account_holder VARCHAR(50) COMMENT '账户名称/户名(即开户人姓名或公司名称)' AFTER account_number,
+ADD COLUMN branch_name VARCHAR(100) COMMENT '开户支行名称(如:成都高新支行)' AFTER account_holder;
+
+-- 微赞直播间单例设置:仅保留 Banner 图片地址和直播间地址两个业务字段
+CREATE TABLE IF NOT EXISTS tcm_live_room_setting (
+    banner_image_url VARCHAR(500) NOT NULL COMMENT 'Banner图片地址',
+    live_room_url VARCHAR(500) NULL COMMENT '直播间地址'
+) COMMENT='微赞直播间设置';
+
+-- ----------------------------
+-- 项目介绍表
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `tcm_project_introduction` (
+  `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
+  `title` VARCHAR(128) NOT NULL COMMENT '标题',
+  `cover_img` VARCHAR(512) DEFAULT NULL COMMENT '封面图',
+  `category` VARCHAR(32) NOT NULL COMMENT '类别:platform(平台介绍)、mode(营销模式)、action(营销动作)',
+  `content_type` TINYINT NOT NULL COMMENT '类型:1图文 2视频',
+  `content` MEDIUMTEXT COMMENT '图文内容(富文本HTML)',
+  `video_url` VARCHAR(512) DEFAULT NULL COMMENT '视频地址',
+  `video_file_name` VARCHAR(255) DEFAULT NULL COMMENT '视频文件名',
+  `video_description` VARCHAR(255) DEFAULT NULL COMMENT '视频介绍',
+  `click_count` INT NOT NULL DEFAULT 0 COMMENT '点击量',
+  `status` TINYINT NOT NULL DEFAULT 1 COMMENT '状态:1启用 0禁用',
+  `deleted` TINYINT(1) NOT NULL DEFAULT 0,
+  `created_by` VARCHAR(64) NOT NULL DEFAULT '系统' COMMENT '创建人',
+  `updated_by` VARCHAR(64) NOT NULL DEFAULT '系统' COMMENT '更新人',
+  `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  PRIMARY KEY (`id`),
+  KEY `idx_category` (`category`),
+  KEY `idx_content_type` (`content_type`),
+  KEY `idx_status` (`status`),
+  KEY `idx_created_at` (`created_at`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='项目介绍表';
+
+-- ----------------------------
+-- 项目介绍密码配置表
+-- ----------------------------
+CREATE TABLE IF NOT EXISTS `tcm_project_introduction_password` (
+  `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
+  `password_enabled` TINYINT NOT NULL DEFAULT 0 COMMENT '是否启用密码访问:1启用 0不启用',
+  `password` VARCHAR(255) DEFAULT NULL COMMENT '访问密码(加密)',
+  `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  `updated_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='项目介绍密码配置表';
+
+INSERT INTO `tcm_project_introduction_password` (`id`, `password_enabled`, `password`, `created_at`, `updated_at`) VALUES (1, 0, NULL, '2026-08-20 13:12:52', '2026-08-21 15:21:01');
+
+
+ALTER TABLE `tcm_health_popularization`
+ADD COLUMN `video_description` VARCHAR(255) DEFAULT NULL COMMENT '视频介绍'
+AFTER `video_file_name`;
+
+
+/*
+ Navicat Premium Dump SQL
+
+ Source Server         : local
+ Source Server Type    : MySQL
+ Source Server Version : 80030 (8.0.30)
+ Source Host           : localhost:3306
+ Source Schema         : tcm_training_admin
+
+ Target Server Type    : MySQL
+ Target Server Version : 80030 (8.0.30)
+ File Encoding         : 65001
+
+ Date: 24/08/2026 15:04:16
+*/
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ----------------------------
+-- Table structure for sys_menu
+-- ----------------------------
+DROP TABLE IF EXISTS `sys_menu`;
+CREATE TABLE `sys_menu`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `parent_id` bigint NOT NULL DEFAULT 0 COMMENT '父级ID,0表示根节点',
+  `name` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '权限/菜单名称',
+  `menu_code` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '菜单编码',
+  `type` char(1) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '类型:M模块 C菜单 B按钮',
+  `path` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '路由路径',
+  `component` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '前端组件',
+  `icon` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '图标',
+  `sort` int NOT NULL DEFAULT 0 COMMENT '排序值',
+  `status` tinyint NOT NULL DEFAULT 1 COMMENT '状态:1启用 0禁用',
+  `visible` tinyint(1) NOT NULL DEFAULT 1 COMMENT '是否显示:1显示 0隐藏',
+  `permission_key` varchar(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '权限标识',
+  `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '备注',
+  `deleted` tinyint(1) NOT NULL DEFAULT 0,
+  `created_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '系统初始化' COMMENT '创建人',
+  `updated_by` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL DEFAULT '系统初始化' COMMENT '更新人',
+  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_sys_menu_code`(`menu_code` ASC) USING BTREE,
+  INDEX `idx_sys_menu_parent_id`(`parent_id` ASC) USING BTREE,
+  INDEX `idx_sys_menu_type`(`type` ASC) USING BTREE,
+  INDEX `idx_sys_menu_status`(`status` ASC) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 6114 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '后台菜单与权限表' ROW_FORMAT = DYNAMIC;
+
+-- ----------------------------
+-- Records of sys_menu
+-- ----------------------------
+INSERT INTO `sys_menu` VALUES (1000, 0, '系统与安全', 'system_security', 'M', '/system', NULL, 'setting', 100, 1, 1, NULL, '系统与安全模块', 0, '系统初始化', '系统初始化', '2026-03-19 06:33:33', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1100, 1000, '帐号管理', 'system_account', 'C', '/system/account', 'Account/UserList', NULL, 10, 1, 1, 'system:account:view', '帐号管理菜单', 0, '系统初始化', '系统初始化', '2026-03-19 06:33:33', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1101, 1100, '新增帐号', 'system_account_add', 'B', NULL, NULL, NULL, 1, 1, 1, 'system:account:add', '帐号新增按钮', 0, '系统初始化', '系统初始化', '2026-03-19 06:33:33', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1102, 1100, '编辑帐号', 'system_account_edit', 'B', NULL, NULL, NULL, 2, 1, 1, 'system:account:edit', '帐号编辑按钮', 0, '系统初始化', '系统初始化', '2026-03-19 06:33:33', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1103, 1100, '启用禁用', 'system_account_status', 'B', NULL, NULL, NULL, 3, 1, 1, 'system:account:status', '帐号状态按钮', 0, '系统初始化', '系统初始化', '2026-03-19 06:33:33', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1104, 1100, '重置密码', 'system_account_reset_password', 'B', NULL, NULL, NULL, 4, 1, 1, 'system:account:reset-password', '重置密码按钮', 0, '系统初始化', '系统初始化', '2026-03-19 06:33:33', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1105, 1100, '删除帐号', 'system_account_delete', 'B', NULL, NULL, NULL, 5, 1, 1, 'system:account:delete', '删除帐号按钮', 0, '系统初始化', '系统初始化', '2026-03-19 14:48:43', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1200, 1000, '角色管理', 'system_role', 'C', '/system/role', 'Account/RoleList', NULL, 20, 1, 1, 'system:role:view', '角色管理菜单', 0, '系统初始化', '系统初始化', '2026-03-19 06:33:33', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1201, 1200, '角色详情', 'system_role_detail', 'B', NULL, NULL, NULL, 1, 1, 1, 'system:role:detail', '角色详情按钮', 0, '系统初始化', '系统初始化', '2026-03-19 06:33:33', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1202, 1200, '新增角色', 'system_role_add', 'B', NULL, NULL, NULL, 2, 1, 1, 'system:role:add', '角色新增按钮', 0, '系统初始化', '系统初始化', '2026-03-19 06:33:33', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1203, 1200, '编辑角色', 'system_role_edit', 'B', NULL, NULL, NULL, 3, 1, 1, 'system:role:edit', '角色编辑按钮', 0, '系统初始化', '系统初始化', '2026-03-19 06:33:33', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1204, 1200, '删除角色', 'system_role_delete', 'B', NULL, NULL, NULL, 4, 1, 1, 'system:role:delete', '角色删除按钮', 0, '系统初始化', '系统初始化', '2026-03-19 06:33:33', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1300, 1000, '系统设置', 'system_setting_group', 'M', '/system/settings', NULL, NULL, 30, 1, 1, NULL, '系统设置目录', 0, '系统初始化', '系统初始化', '2026-03-21 08:07:45', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1305, 1300, '系统设置', 'system_basic_settings', 'C', '/system/settings/basic', 'System/BasicSettings', NULL, 5, 1, 1, 'system:basic-settings:view', '系统设置菜单', 0, '系统初始化', '系统初始化', '2026-03-26 15:34:59', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1306, 1305, '编辑系统设置', 'system_basic_settings_edit', 'B', NULL, NULL, NULL, 1, 1, 1, 'system:basic-settings:edit', '系统设置编辑按钮', 0, '系统初始化', '系统初始化', '2026-03-26 15:34:59', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1307, 1300, 'APP版本设置', 'system_app_version_settings', 'C', '/system/settings/app-version', 'System/AppVersionSettings', NULL, 15, 1, 1, 'system:app-version:view', 'APP版本设置菜单', 0, '系统初始化', '系统初始化', '2026-03-26 08:13:45', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1308, 1307, '新增APP版本', 'system_app_version_settings_add', 'B', NULL, NULL, NULL, 1, 1, 1, 'system:app-version:add', '新增APP版本按钮', 0, '系统初始化', '系统初始化', '2026-03-26 08:13:45', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1309, 1307, '查看APP版本', 'system_app_version_settings_detail', 'B', NULL, NULL, NULL, 2, 1, 1, 'system:app-version:detail', '查看APP版本按钮', 0, '系统初始化', '系统初始化', '2026-03-26 08:13:45', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1310, 1300, '积分设置', 'system_points_settings', 'C', '/system/settings/points', 'System/PointsSettings', NULL, 10, 1, 1, 'system:points-settings:view', '积分设置菜单', 0, '系统初始化', '系统初始化', '2026-03-21 08:07:45', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (1311, 1310, '编辑积分设置', 'system_points_settings_edit', 'B', NULL, NULL, NULL, 1, 1, 1, 'system:points-settings:edit', '积分设置编辑按钮', 0, '系统初始化', '系统初始化', '2026-03-21 08:07:45', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (1312, 1300, '消息推送配置', 'system_message_push_settings', 'C', '/system/settings/message-push', 'System/MessagePushSettings', NULL, 20, 1, 1, 'system:message-push:view', '消息推送配置菜单', 0, '系统初始化', '系统初始化', '2026-03-26 08:51:05', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1313, 1312, '编辑消息推送配置', 'system_message_push_settings_edit', 'B', NULL, NULL, NULL, 1, 1, 1, 'system:message-push:edit', '消息推送配置编辑按钮', 0, '系统初始化', '系统初始化', '2026-03-26 08:51:05', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1314, 1300, 'Banner配置', 'system_banner_settings', 'C', '/system/settings/banner', 'System/BannerSettings', NULL, 12, 1, 1, 'system:banner:view', 'Banner配置菜单', 0, '系统初始化', '系统初始化', '2026-03-26 09:28:36', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1315, 1314, '新增Banner', 'system_banner_settings_add', 'B', NULL, NULL, NULL, 1, 1, 1, 'system:banner:add', 'Banner新增按钮', 0, '系统初始化', '系统初始化', '2026-03-26 09:28:36', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1316, 1314, '编辑Banner', 'system_banner_settings_edit', 'B', NULL, NULL, NULL, 2, 1, 1, 'system:banner:edit', 'Banner编辑按钮', 0, '系统初始化', '系统初始化', '2026-03-26 09:28:36', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1317, 1314, '查看Banner', 'system_banner_settings_detail', 'B', NULL, NULL, NULL, 3, 1, 1, 'system:banner:detail', 'Banner查看按钮', 0, '系统初始化', '系统初始化', '2026-03-26 09:28:36', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1318, 1314, '删除Banner', 'system_banner_settings_delete', 'B', NULL, NULL, NULL, 4, 1, 1, 'system:banner:delete', 'Banner删除按钮', 0, '系统初始化', '系统初始化', '2026-03-26 09:28:36', '2026-08-24 10:14:04');
+INSERT INTO `sys_menu` VALUES (1319, 1314, '批量删除Banner', 'system_banner_settings_batch_delete', 'B', NULL, NULL, NULL, 5, 1, 1, 'system:banner:batch-delete', 'Banner批量删除按钮', 0, '系统初始化', '系统初始化', '2026-03-26 09:28:36', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (1320, 1314, '切换Banner上架状态', 'system_banner_settings_publish_status', 'B', NULL, NULL, NULL, 6, 1, 1, 'system:banner:publish-status', 'Banner上架状态按钮', 0, '系统初始化', '系统初始化', '2026-03-26 09:28:36', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (1321, 1300, '活动通知', 'system_activity_notice', 'C', '/system/settings/activity-notice', 'System/ActivityNotice', NULL, 13, 1, 1, 'system:activity-notice:view', '活动通知菜单', 0, '系统初始化', '系统初始化', '2026-03-26 10:07:49', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (1322, 1321, '新增活动通知', 'system_activity_notice_add', 'B', NULL, NULL, NULL, 1, 1, 1, 'system:activity-notice:add', '活动通知新增按钮', 0, '系统初始化', '系统初始化', '2026-03-26 10:07:49', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (1323, 1321, '删除活动通知', 'system_activity_notice_delete', 'B', NULL, NULL, NULL, 2, 1, 1, 'system:activity-notice:delete', '活动通知删除按钮', 0, '系统初始化', '系统初始化', '2026-03-26 10:07:49', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (1324, 1300, '平台资质', 'system_platform_qualification', 'C', '/system/settings/platform-qualification', 'System/PlatformQualification', NULL, 14, 1, 1, 'system:platform-qualification:view', '平台资质菜单', 0, '系统初始化', '系统初始化', '2026-03-26 11:29:12', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (1325, 1324, '新增平台资质', 'system_platform_qualification_add', 'B', NULL, NULL, NULL, 1, 1, 1, 'system:platform-qualification:add', '平台资质新增按钮', 0, '系统初始化', '系统初始化', '2026-03-26 11:29:12', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (1326, 1324, '查看平台资质', 'system_platform_qualification_detail', 'B', NULL, NULL, NULL, 2, 1, 1, 'system:platform-qualification:detail', '平台资质详情按钮', 0, '系统初始化', '系统初始化', '2026-03-26 11:29:12', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (1327, 1324, '编辑平台资质', 'system_platform_qualification_edit', 'B', NULL, NULL, NULL, 3, 1, 1, 'system:platform-qualification:edit', '平台资质编辑按钮', 0, '系统初始化', '系统初始化', '2026-03-26 11:29:12', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (1328, 1324, '删除平台资质', 'system_platform_qualification_delete', 'B', NULL, NULL, NULL, 4, 1, 1, 'system:platform-qualification:delete', '平台资质删除按钮', 0, '系统初始化', '系统初始化', '2026-03-26 11:29:12', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (1329, 1324, '切换平台资质上架状态', 'system_platform_qualification_publish_status', 'B', NULL, NULL, NULL, 5, 1, 1, 'system:platform-qualification:publish-status', '平台资质上架状态按钮', 0, '系统初始化', '系统初始化', '2026-03-26 11:29:12', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (1330, 1300, '协议内容', 'system_agreement_content', 'C', '/system/settings/agreement-content', 'System/AgreementContent', NULL, 16, 1, 1, 'system:agreement-content:view', '协议内容菜单', 0, '系统初始化', '系统初始化', '2026-03-26 11:58:15', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (1331, 1330, '编辑协议内容', 'system_agreement_content_edit', 'B', NULL, NULL, NULL, 1, 1, 1, 'system:agreement-content:edit', '协议内容编辑按钮', 0, '系统初始化', '系统初始化', '2026-03-26 11:58:15', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (1332, 1300, '常见问题', 'system_common_question', 'C', '/system/settings/common-question', 'System/CommonQuestion', NULL, 17, 1, 1, 'system:common-question:view', '常见问题菜单', 0, '系统初始化', '系统初始化', '2026-03-26 12:25:39', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (1333, 1332, '新增常见问题', 'system_common_question_add', 'B', NULL, NULL, NULL, 1, 1, 1, 'system:common-question:add', '常见问题新增按钮', 0, '系统初始化', '系统初始化', '2026-03-26 12:25:39', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (1334, 1332, '编辑常见问题', 'system_common_question_edit', 'B', NULL, NULL, NULL, 2, 1, 1, 'system:common-question:edit', '常见问题编辑按钮', 0, '系统初始化', '系统初始化', '2026-03-26 12:25:39', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (1335, 1332, '删除常见问题', 'system_common_question_delete', 'B', NULL, NULL, NULL, 3, 1, 1, 'system:common-question:delete', '常见问题删除按钮', 0, '系统初始化', '系统初始化', '2026-03-26 12:25:39', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (1336, 1300, '用户意见反馈', 'system_user_feedback', 'C', '/system/settings/user-feedback', 'System/UserFeedback', NULL, 18, 1, 1, 'system:user-feedback:view', '用户意见反馈菜单', 0, '系统初始化', '系统初始化', '2026-03-26 12:43:32', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (2000, 0, '用户与会员', 'member_root', 'M', '/member', NULL, 'team', 200, 1, 1, NULL, '用户与会员模块', 0, '系统初始化', '系统初始化', '2026-03-20 06:36:03', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (2100, 2000, '用户', 'member_user_group', 'M', '/member/user', NULL, NULL, 10, 1, 1, NULL, '用户分组菜单', 0, '系统初始化', '系统初始化', '2026-03-20 06:36:03', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (2110, 2100, '用户管理', 'member_user_manage', 'C', '/member/user/manage', 'Member/UserList', NULL, 10, 1, 1, 'member:user:view', '用户管理菜单', 0, '系统初始化', '系统初始化', '2026-03-20 06:36:03', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (2111, 2110, '用户详情', 'member_user_detail', 'B', NULL, NULL, NULL, 1, 1, 1, 'member:user:detail', '用户详情按钮', 0, '系统初始化', '系统初始化', '2026-03-20 06:36:03', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (2112, 2110, '编辑用户', 'member_user_edit', 'B', NULL, NULL, NULL, 2, 1, 1, 'member:user:edit', '编辑用户按钮', 0, '系统初始化', '系统初始化', '2026-03-20 06:36:03', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (2113, 2110, '启用禁用用户', 'member_user_status', 'B', NULL, NULL, NULL, 3, 1, 1, 'member:user:status', '启用禁用用户按钮', 0, '系统初始化', '系统初始化', '2026-03-20 06:36:03', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (2114, 2110, '重置用户密码', 'member_user_reset_password', 'B', NULL, NULL, NULL, 4, 1, 1, 'member:user:reset-password', '重置用户密码按钮', 0, '系统初始化', '系统初始化', '2026-03-20 06:36:03', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (2115, 2110, '删除用户', 'member_user_delete', 'B', NULL, NULL, NULL, 5, 1, 1, 'member:user:delete', '删除用户按钮', 0, '系统初始化', '系统初始化', '2026-03-20 06:36:03', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (2116, 2110, '导出用户', 'member_user_export', 'B', NULL, NULL, NULL, 6, 1, 1, 'member:user:export', '导出用户按钮', 0, '系统初始化', '系统初始化', '2026-03-20 06:36:03', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (2117, 2110, '解绑微信', 'member_user_unbind_wechat', 'B', NULL, NULL, NULL, 7, 1, 1, 'member:user:unbind-wechat', '解绑微信按钮', 0, '系统初始化', '系统初始化', '2026-03-20 06:36:03', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (2118, 2100, '诊所管理', 'member_clinic_manage', 'C', '/member/user/clinic', 'Member/ClinicList', NULL, 11, 1, 1, 'member:clinic:view', '诊所管理菜单', 0, '系统初始化', '系统初始化', '2026-03-23 19:49:56', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (2119, 2100, '会员用户', 'member_only_user_manage', 'C', '/member/user/member-users', 'Member/MemberUserList', NULL, 12, 1, 1, 'member:user:member:view', '会员用户菜单', 0, '系统初始化', '系统初始化', '2026-03-23 22:00:08', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (2200, 2000, '会员', 'member_vip_group', 'M', '/member/vip', NULL, NULL, 20, 1, 1, NULL, '会员分组菜单', 0, '系统初始化', '系统初始化', '2026-03-23 22:00:08', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (2210, 2200, '会员价格设置', 'member_vip_price_settings', 'C', '/member/vip/price', 'Member/VipPriceSettings', NULL, 10, 1, 1, 'member:vip-price:view', '会员价格设置菜单', 0, '系统初始化', '系统初始化', '2026-03-23 22:00:08', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (2211, 2210, '编辑会员价格设置', 'member_vip_price_settings_edit', 'B', NULL, NULL, NULL, 1, 1, 1, 'member:vip-price:edit', '会员价格设置编辑按钮', 0, '系统初始化', '系统初始化', '2026-03-23 22:00:08', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (2220, 2200, '会员介绍设置', 'member_vip_intro_settings', 'C', '/member/vip/intro', 'Member/VipIntroSettings', NULL, 20, 1, 1, 'member:vip-intro:view', '会员介绍设置菜单', 0, '系统初始化', '系统初始化', '2026-03-23 22:00:08', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (2221, 2220, '编辑会员介绍设置', 'member_vip_intro_settings_edit', 'B', NULL, NULL, NULL, 1, 1, 1, 'member:vip-intro:edit', '会员介绍设置编辑按钮', 0, '系统初始化', '系统初始化', '2026-03-23 22:00:08', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3000, 0, '课程与学习', 'live_root', 'M', '/live', NULL, 'read', 300, 1, 1, NULL, '课程与学习模块', 0, '系统初始化', '系统初始化', '2026-03-20 08:03:03', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3050, 3000, '课程管理', 'live_course_manage_root', 'M', '/live/course', NULL, NULL, 10, 1, 1, NULL, '课程管理目录', 0, '系统初始化', '系统初始化', '2026-03-20 09:58:00', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3060, 3050, '养生直播', 'live_course_broadcast_manage', 'C', '/live/course/broadcast', 'Live/BroadcastList', NULL, 10, 1, 1, 'live:course:view', '养生直播菜单', 0, '系统初始化', '系统初始化', '2026-03-20 09:58:00', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3061, 3060, '直播详情', 'live_course_detail', 'B', NULL, NULL, NULL, 1, 1, 1, 'live:course:detail', '养生直播详情按钮', 0, '系统初始化', '系统初始化', '2026-03-20 09:58:00', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3062, 3060, '编辑直播', 'live_course_edit', 'B', NULL, NULL, NULL, 2, 1, 1, 'live:course:edit', '养生直播编辑按钮', 0, '系统初始化', '系统初始化', '2026-03-20 09:58:00', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3063, 3060, '启用禁用直播', 'live_course_status', 'B', NULL, NULL, NULL, 3, 1, 1, 'live:course:status', '养生直播状态按钮', 0, '系统初始化', '系统初始化', '2026-03-20 09:58:00', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3064, 3060, '设置直播间密码', 'live_course_password', 'B', NULL, NULL, NULL, 4, 1, 1, 'live:course:password', '设置直播间密码按钮', 0, '系统初始化', '系统初始化', '2026-08-19 10:27:29', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3070, 3060, '场次管理', 'live_session_manage', 'B', NULL, NULL, NULL, 10, 1, 1, 'live:session:detail', '直播场次管理权限', 0, '系统初始化', '系统初始化', '2026-03-20 09:58:00', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3071, 3060, '新增场次', 'live_session_add', 'B', NULL, NULL, NULL, 11, 1, 1, 'live:session:add', '直播场次新增按钮', 0, '系统初始化', '系统初始化', '2026-03-20 09:58:00', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3072, 3060, '编辑场次', 'live_session_edit', 'B', NULL, NULL, NULL, 12, 1, 1, 'live:session:edit', '直播场次编辑按钮', 0, '系统初始化', '系统初始化', '2026-03-20 09:58:00', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3073, 3060, '开播场次', 'live_session_start', 'B', NULL, NULL, NULL, 13, 1, 1, 'live:session:start', '直播场次开播按钮', 0, '系统初始化', '系统初始化', '2026-03-20 09:58:00', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3074, 3060, '结束场次', 'live_session_end', 'B', NULL, NULL, NULL, 14, 1, 1, 'live:session:end', '直播场次结束按钮', 0, '系统初始化', '系统初始化', '2026-03-20 09:58:00', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3075, 3060, '复制场次', 'live_session_copy', 'B', NULL, NULL, NULL, 15, 1, 1, 'live:session:copy', '直播场次复制按钮', 0, '系统初始化', '系统初始化', '2026-03-20 09:58:00', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3076, 3060, '删除场次', 'live_session_delete', 'B', NULL, NULL, NULL, 16, 1, 1, 'live:session:delete', '直播场次删除按钮', 0, '系统初始化', '系统初始化', '2026-03-20 09:58:00', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3077, 3060, '推送开播提醒', 'live_session_push_notification', 'B', NULL, NULL, NULL, 17, 1, 1, 'live:session:push-notification', '直播场次推送提醒按钮', 0, '系统初始化', '系统初始化', '2026-03-20 09:58:00', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3080, 3050, '直播预约记录', 'live_reserve_view', 'C', '/live/course/reserve-records', 'Live/ReserveRecords', NULL, 20, 1, 1, 'live:reserve:view', '直播预约记录菜单', 0, '系统初始化', '系统初始化', '2026-03-20 09:58:00', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3081, 3050, '直播观看记录', 'live_watch_view', 'C', '/live/course/watch-records', 'Live/WatchRecords', NULL, 21, 1, 1, 'live:watch:view', '直播观看记录菜单', 0, '系统初始化', '系统初始化', '2026-03-20 09:58:00', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3082, 3060, '答题记录', 'live_quiz_view', 'B', NULL, NULL, NULL, 22, 1, 1, 'live:quiz:view', '直播答题记录查看权限', 0, '系统初始化', '系统初始化', '2026-03-20 09:58:00', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3090, 3050, '分类管理', 'live_category_manage', 'C', '/live/course/category', 'Live/CategoryList', NULL, 22, 1, 1, 'live:category:view', '分类管理菜单', 0, '系统初始化', '系统初始化', '2026-03-24 10:59:54', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3091, 3090, '新增分类', 'live_category_add', 'B', NULL, NULL, NULL, 1, 1, 1, 'live:category:add', '分类新增按钮', 0, '系统初始化', '系统初始化', '2026-03-24 10:59:54', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3092, 3090, '编辑分类', 'live_category_edit', 'B', NULL, NULL, NULL, 2, 1, 1, 'live:category:edit', '分类编辑按钮', 0, '系统初始化', '系统初始化', '2026-03-24 10:59:54', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3093, 3090, '删除分类', 'live_category_delete', 'B', NULL, NULL, NULL, 3, 1, 1, 'live:category:delete', '分类删除按钮', 0, '系统初始化', '系统初始化', '2026-03-24 10:59:54', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3100, 3050, '授课专家管理', 'live_expert_manage', 'C', '/live/course/expert', 'Live/ExpertList', NULL, 30, 1, 1, 'live:expert:view', '授课专家管理菜单', 0, '系统初始化', '系统初始化', '2026-03-20 08:03:03', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3101, 3100, '新增授课专家', 'live_expert_add', 'B', NULL, NULL, NULL, 1, 1, 1, 'live:expert:add', '授课专家新增按钮', 0, '系统初始化', '系统初始化', '2026-03-20 08:03:03', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3102, 3100, '编辑授课专家', 'live_expert_edit', 'B', NULL, NULL, NULL, 2, 1, 1, 'live:expert:edit', '授课专家编辑按钮', 0, '系统初始化', '系统初始化', '2026-03-20 08:03:03', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3103, 3100, '启用禁用授课专家', 'live_expert_status', 'B', NULL, NULL, NULL, 3, 1, 1, 'live:expert:status', '授课专家状态按钮', 0, '系统初始化', '系统初始化', '2026-03-20 08:03:03', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3104, 3100, '删除授课专家', 'live_expert_delete', 'B', NULL, NULL, NULL, 4, 1, 1, 'live:expert:delete', '授课专家删除按钮', 0, '系统初始化', '系统初始化', '2026-03-20 08:03:03', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3110, 3050, '养生课程', 'live_health_course_manage', 'C', '/live/course/health', 'Live/HealthCourseList', NULL, 40, 1, 1, 'live:health-course:view', '养生课程菜单', 0, '系统初始化', '系统初始化', '2026-03-24 05:50:17', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3111, 3110, '养生课程详情', 'live_health_course_detail', 'B', NULL, NULL, NULL, 1, 1, 1, 'live:health-course:detail', '养生课程详情按钮', 0, '系统初始化', '系统初始化', '2026-03-24 05:50:17', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3112, 3110, '新增养生课程', 'live_health_course_add', 'B', NULL, NULL, NULL, 2, 1, 1, 'live:health-course:add', '养生课程新增按钮', 0, '系统初始化', '系统初始化', '2026-03-24 05:50:17', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3113, 3110, '编辑养生课程', 'live_health_course_edit', 'B', NULL, NULL, NULL, 3, 1, 1, 'live:health-course:edit', '养生课程编辑按钮', 0, '系统初始化', '系统初始化', '2026-03-24 05:50:17', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3114, 3110, '删除养生课程', 'live_health_course_delete', 'B', NULL, NULL, NULL, 4, 1, 1, 'live:health-course:delete', '养生课程删除按钮', 0, '系统初始化', '系统初始化', '2026-03-24 05:50:17', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (3115, 3110, '启用禁用养生课程', 'live_health_course_status', 'B', NULL, NULL, NULL, 5, 1, 1, 'live:health-course:status', '养生课程状态按钮', 0, '系统初始化', '系统初始化', '2026-03-24 05:50:17', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (3116, 3110, '导出养生课程', 'live_health_course_export', 'B', NULL, NULL, NULL, 6, 1, 1, 'live:health-course:export', '养生课程导出按钮', 0, '系统初始化', '系统初始化', '2026-03-24 05:50:17', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (3117, 3110, '新增视频课程', 'live_health_course_video_add', 'B', NULL, NULL, NULL, 7, 1, 1, 'live:health-course:video:add', '养生课程视频新增按钮', 0, '系统初始化', '系统初始化', '2026-03-24 05:50:17', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (3118, 3110, '编辑视频课程', 'live_health_course_video_edit', 'B', NULL, NULL, NULL, 8, 1, 1, 'live:health-course:video:edit', '养生课程视频编辑按钮', 0, '系统初始化', '系统初始化', '2026-03-24 05:50:17', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (3119, 3110, '删除视频课程', 'live_health_course_video_delete', 'B', NULL, NULL, NULL, 9, 1, 1, 'live:health-course:video:delete', '养生课程视频删除按钮', 0, '系统初始化', '系统初始化', '2026-03-24 05:50:17', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (3120, 6100, '健康知识', 'live_health_popularization_manage', 'C', '/live/promotion/health-popularization', 'Live/HealthPopularizationList', NULL, 50, 1, 1, 'live:health-popularization:view', '健康知识菜单', 0, '系统初始化', '系统初始化', '2026-03-25 13:30:33', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (3121, 3120, '新增健康知识', 'live_health_popularization_add', 'B', NULL, NULL, NULL, 1, 1, 1, 'live:health-popularization:add', '健康知识新增按钮', 0, '系统初始化', '系统初始化', '2026-03-25 13:30:33', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (3122, 3120, '编辑健康知识', 'live_health_popularization_edit', 'B', NULL, NULL, NULL, 2, 1, 1, 'live:health-popularization:edit', '健康知识编辑按钮', 0, '系统初始化', '系统初始化', '2026-03-25 13:30:33', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (3123, 3120, '删除健康知识', 'live_health_popularization_delete', 'B', NULL, NULL, NULL, 3, 1, 1, 'live:health-popularization:delete', '健康知识删除按钮', 0, '系统初始化', '系统初始化', '2026-03-25 13:30:33', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (4000, 0, '交易与财务', 'trade_root', 'M', '/trade', NULL, 'moneyCollect', 400, 1, 1, NULL, '交易与财务模块', 0, '系统初始化', '系统初始化', '2026-03-21 08:07:45', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (4100, 4000, '订单', 'trade_order_group', 'M', '/trade/order', NULL, NULL, 10, 1, 1, NULL, '订单目录', 0, '系统初始化', '系统初始化', '2026-03-21 08:07:45', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (4110, 4100, '积分兑换', 'trade_points_exchange', 'C', '/trade/order/points-exchange', 'Trade/PointsExchange', NULL, 10, 1, 1, 'points:exchange:view', '积分兑换菜单', 0, '系统初始化', '系统初始化', '2026-03-21 08:07:45', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (4111, 4110, '兑换详情', 'trade_points_exchange_detail', 'B', NULL, NULL, NULL, 1, 1, 1, 'points:exchange:detail', '积分兑换详情按钮', 0, '系统初始化', '系统初始化', '2026-03-21 08:07:45', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (4112, 4110, '积分兑换发货', 'trade_points_exchange_ship', 'B', NULL, NULL, NULL, 2, 1, 1, 'points:exchange:ship', '积分兑换发货按钮', 0, '系统初始化', '系统初始化', '2026-03-21 08:07:45', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (4113, 4110, '积分兑换删除', 'trade_points_exchange_delete', 'B', NULL, NULL, NULL, 3, 1, 1, 'points:exchange:delete', '积分兑换删除按钮', 0, '系统初始化', '系统初始化', '2026-03-21 08:07:45', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (4114, 4110, '积分兑换导出', 'trade_points_exchange_export', 'B', NULL, NULL, NULL, 4, 1, 1, 'points:exchange:export', '积分兑换导出按钮', 0, '系统初始化', '系统初始化', '2026-03-21 08:07:45', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (4120, 4100, '会员购买订单', 'trade_member_purchase_order', 'C', '/trade/order/member-purchase', 'Trade/MemberPurchase', NULL, 9, 1, 1, 'member:purchase-order:view', '会员购买订单菜单', 0, '系统初始化', '系统初始化', '2026-03-25 14:59:13', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (4121, 4120, '导出会员购买订单', 'trade_member_purchase_order_export', 'B', NULL, NULL, NULL, 1, 1, 1, 'member:purchase-order:export', '会员购买订单导出按钮', 0, '系统初始化', '系统初始化', '2026-03-25 14:59:13', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (4122, 4120, '退款会员购买订单', 'trade_member_purchase_order_refund', 'B', NULL, NULL, NULL, 2, 1, 1, 'member:purchase-order:refund', '会员购买订单退款按钮', 0, '系统初始化', '系统初始化', '2026-03-25 14:59:13', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (4123, 4120, '删除会员购买订单', 'trade_member_purchase_order_delete', 'B', NULL, NULL, NULL, 3, 1, 1, 'member:purchase-order:delete', '会员购买订单删除按钮', 0, '系统初始化', '系统初始化', '2026-03-25 14:59:13', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (4130, 4100, '养生课程购买订单', 'trade_health_course_purchase_order', 'C', '/trade/order/course-purchase', 'Trade/CoursePurchase', NULL, 8, 1, 1, 'course:purchase-order:view', '养生课程购买订单菜单', 0, '系统初始化', '系统初始化', '2026-03-25 16:18:55', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (4131, 4130, '导出养生课程购买订单', 'trade_health_course_purchase_order_export', 'B', NULL, NULL, NULL, 1, 1, 1, 'course:purchase-order:export', '养生课程购买订单导出按钮', 0, '系统初始化', '系统初始化', '2026-03-25 16:18:55', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (4132, 4130, '退款养生课程购买订单', 'trade_health_course_purchase_order_refund', 'B', NULL, NULL, NULL, 2, 1, 1, 'course:purchase-order:refund', '养生课程购买订单退款按钮', 0, '系统初始化', '系统初始化', '2026-03-25 16:18:55', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (4133, 4130, '删除养生课程购买订单', 'trade_health_course_purchase_order_delete', 'B', NULL, NULL, NULL, 3, 1, 1, 'course:purchase-order:delete', '养生课程购买订单删除按钮', 0, '系统初始化', '系统初始化', '2026-03-25 16:18:55', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (4200, 4000, '财务流水', 'trade_finance_flow_group', 'M', '/trade/flow', NULL, NULL, 20, 1, 1, NULL, '财务流水目录', 0, '系统初始化', '系统初始化', '2026-03-21 09:30:56', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (4210, 4200, '积分收支明细', 'trade_points_ledger', 'C', '/trade/flow/points-ledger', 'Trade/PointsLedger', NULL, 30, 1, 1, 'points:ledger:view', '积分收支明细菜单', 0, '系统初始化', '系统初始化', '2026-03-21 09:30:56', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (4211, 4210, '导出积分收支明细', 'trade_points_ledger_export', 'B', NULL, NULL, NULL, 1, 1, 1, 'points:ledger:export', '积分收支明细导出按钮', 0, '系统初始化', '系统初始化', '2026-03-21 09:30:56', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (4220, 4200, '支付流水', 'trade_payment_flow', 'C', '/trade/flow/payment-flow', 'Trade/PaymentFlow', NULL, 10, 1, 1, 'payment:flow:view', '支付流水菜单', 0, '系统初始化', '系统初始化', '2026-03-25 09:40:43', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (4221, 4220, '导出支付流水', 'trade_payment_flow_export', 'B', NULL, NULL, NULL, 1, 1, 1, 'payment:flow:export', '支付流水导出按钮', 0, '系统初始化', '系统初始化', '2026-03-25 09:40:43', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (4230, 4200, '退费流水', 'trade_refund_flow', 'C', '/trade/flow/refund-flow', 'Trade/RefundFlow', NULL, 20, 1, 1, 'refund:flow:view', '退费流水菜单', 0, '系统初始化', '系统初始化', '2026-03-25 20:51:18', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (4231, 4230, '导出退费流水', 'trade_refund_flow_export', 'B', NULL, NULL, NULL, 1, 1, 1, 'refund:flow:export', '退费流水导出按钮', 0, '系统初始化', '系统初始化', '2026-03-25 20:51:18', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (5000, 0, '统计', 'statistics_root', 'M', '/statistics', NULL, 'barChart', 150, 1, 1, NULL, '统计模块', 0, '系统初始化', '系统初始化', '2026-03-26 21:07:19', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (5010, 5000, '用户数据', 'statistics_user_data', 'C', '/statistics/user-data', 'Statistics/UserData', NULL, 10, 1, 1, 'statistics:user-data:view', '用户数据菜单', 0, '系统初始化', '系统初始化', '2026-03-26 13:56:30', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (5020, 5000, '内容数据', 'statistics_content_data', 'C', '/statistics/content-data', 'Statistics/ContentData', NULL, 20, 1, 1, 'statistics:content-data:view', '内容数据菜单', 0, '系统初始化', '系统初始化', '2026-03-26 23:06:29', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (5030, 5000, '营收数据', 'statistics_revenue', 'C', '/statistics/revenue', 'Statistics/Revenue', NULL, 30, 1, 1, 'statistics:revenue:view', '营收数据菜单', 0, '系统初始化', '系统初始化', '2026-03-26 21:07:19', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (5031, 5030, '导出营收报表', 'statistics_revenue_export', 'B', NULL, NULL, NULL, 1, 1, 1, 'statistics:revenue:export', '营收数据导出按钮', 0, '系统初始化', '系统初始化', '2026-03-26 21:07:19', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (5045, 2118, '编辑', 'member_clinic_edit', 'B', NULL, NULL, NULL, 1, 1, 1, 'member:clinic:edit', '编辑诊所按钮', 0, '系统初始化', '系统初始化', '2026-08-19 10:27:30', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (5046, 2100, '省代理管理', 'member_agent_manage', 'C', '/member/user/agent', 'Member/AgentList', NULL, 12, 1, 1, 'member:agent:view', '省代理管理菜单', 0, '系统初始化', '系统初始化', '2026-08-19 10:27:29', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (5047, 5046, '新增省代理', 'member_agent_add', 'B', NULL, NULL, NULL, 1, 1, 1, 'member:agent:add', '新增省代理按钮', 0, '系统初始化', '系统初始化', '2026-08-19 10:27:29', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (5048, 5046, '编辑省代理', 'member_agent_edit', 'B', NULL, NULL, NULL, 2, 1, 1, 'member:agent:edit', '编辑省代理按钮', 0, '系统初始化', '系统初始化', '2026-08-19 10:27:29', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (5049, 5046, '删除省代理', 'member_agent_delete', 'B', NULL, NULL, NULL, 3, 1, 1, 'member:agent:delete', '删除省代理按钮', 0, '系统初始化', '系统初始化', '2026-08-19 10:27:29', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (5050, 5046, '省代理详情', 'member_agent_detail', 'B', NULL, NULL, NULL, 4, 1, 1, 'member:agent:detail', '省代理详情按钮', 0, '系统初始化', '系统初始化', '2026-08-19 10:27:29', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (6000, 3050, '微赞直播间设置', 'live_room_setting', 'C', '/live/course/live-room-setting', 'Live/LiveRoomSetting', NULL, 18, 1, 1, 'live:room-setting:view', '微赞直播间设置菜单', 0, '系统初始化', '系统初始化', '2026-08-19 16:22:09', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (6001, 6000, '编辑微赞直播间设置', 'live_room_setting_edit', 'B', NULL, NULL, NULL, 1, 1, 1, 'live:room-setting:edit', '微赞直播间设置编辑按钮', 0, '系统初始化', '系统初始化', '2026-08-19 16:22:09', '2026-08-24 10:14:05');
+INSERT INTO `sys_menu` VALUES (6010, 6100, '项目介绍', 'live_project_introduction_manage', 'C', '/live/promotion/project-introduction', 'Live/ProjectIntroductionList', NULL, 60, 1, 1, 'live:project-introduction:view', '项目介绍菜单', 0, '系统初始化', '系统初始化', '2026-08-20 12:10:14', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (6011, 6010, '新增项目介绍', 'live_project_introduction_add', 'B', NULL, NULL, NULL, 1, 1, 1, 'live:project-introduction:add', '项目介绍新增按钮', 0, '系统初始化', '系统初始化', '2026-08-20 12:10:14', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (6012, 6010, '编辑项目介绍', 'live_project_introduction_edit', 'B', NULL, NULL, NULL, 2, 1, 1, 'live:project-introduction:edit', '项目介绍编辑按钮', 0, '系统初始化', '系统初始化', '2026-08-20 12:10:14', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (6013, 6010, '删除项目介绍', 'live_project_introduction_delete', 'B', NULL, NULL, NULL, 3, 1, 1, 'live:project-introduction:delete', '项目介绍删除按钮', 0, '系统初始化', '系统初始化', '2026-08-20 12:10:14', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (6014, 6100, '项目介绍密码', 'live_project_introduction_password', 'C', '/live/promotion/project-introduction-password', 'Live/ProjectIntroductionPassword', NULL, 61, 1, 1, 'live:project-introduction-password:view', '项目介绍密码菜单', 0, '系统初始化', '系统初始化', '2026-08-20 13:05:55', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (6015, 6014, '编辑项目介绍密码', 'live_project_introduction_password_edit', 'B', NULL, NULL, NULL, 1, 1, 1, 'live:project-introduction-password:edit', '项目介绍密码编辑按钮', 0, '系统初始化', '系统初始化', '2026-08-20 13:05:55', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (6100, 3000, '宣传知识', 'live_promotion_root', 'M', '/live/promotion', NULL, NULL, 20, 1, 1, NULL, '宣传知识目录', 0, '系统初始化', '系统初始化', '2026-08-22 11:09:24', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (6110, 6100, '养生科普', 'live_health_promotion_manage', 'C', '/live/promotion/health-promotion', 'Live/HealthPromotionList', NULL, 51, 1, 1, 'live:health-promotion:view', '养生科普菜单', 0, '系统初始化', '系统初始化', '2026-08-22 12:12:19', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (6111, 6110, '新增养生科普', 'live_health_promotion_add', 'B', NULL, NULL, NULL, 1, 1, 1, 'live:health-promotion:add', '养生科普新增按钮', 0, '系统初始化', '系统初始化', '2026-08-22 12:12:19', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (6112, 6110, '编辑养生科普', 'live_health_promotion_edit', 'B', NULL, NULL, NULL, 2, 1, 1, 'live:health-promotion:edit', '养生科普编辑按钮', 0, '系统初始化', '系统初始化', '2026-08-22 12:12:19', '2026-08-24 10:14:06');
+INSERT INTO `sys_menu` VALUES (6113, 6110, '删除养生科普', 'live_health_promotion_delete', 'B', NULL, NULL, NULL, 3, 1, 1, 'live:health-promotion:delete', '养生科普删除按钮', 0, '系统初始化', '系统初始化', '2026-08-22 12:12:19', '2026-08-24 10:14:06');
+
+-- ----------------------------
+-- Table structure for sys_role_menu
+-- ----------------------------
+DROP TABLE IF EXISTS `sys_role_menu`;
+CREATE TABLE `sys_role_menu`  (
+  `id` bigint NOT NULL AUTO_INCREMENT,
+  `role_id` bigint NOT NULL COMMENT '角色ID',
+  `menu_id` bigint NOT NULL COMMENT '菜单/权限ID',
+  `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  PRIMARY KEY (`id`) USING BTREE,
+  UNIQUE INDEX `uk_sys_role_menu`(`role_id` ASC, `menu_id` ASC) USING BTREE,
+  INDEX `idx_sys_role_menu_menu_id`(`menu_id` ASC) USING BTREE
+) ENGINE = InnoDB AUTO_INCREMENT = 2429 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '角色菜单权限关联表' ROW_FORMAT = DYNAMIC;
+
+-- ----------------------------
+-- Records of sys_role_menu
+-- ----------------------------
+INSERT INTO `sys_role_menu` VALUES (35, 2, 1000, '2026-03-19 15:15:13');
+INSERT INTO `sys_role_menu` VALUES (36, 2, 1100, '2026-03-19 15:15:13');
+INSERT INTO `sys_role_menu` VALUES (37, 2, 1101, '2026-03-19 15:15:13');
+INSERT INTO `sys_role_menu` VALUES (38, 2, 1102, '2026-03-19 15:15:13');
+INSERT INTO `sys_role_menu` VALUES (39, 2, 1103, '2026-03-19 15:15:13');
+INSERT INTO `sys_role_menu` VALUES (40, 2, 1104, '2026-03-19 15:15:13');
+INSERT INTO `sys_role_menu` VALUES (41, 2, 1105, '2026-03-19 15:15:13');
+INSERT INTO `sys_role_menu` VALUES (42, 2, 1200, '2026-03-19 15:15:13');
+INSERT INTO `sys_role_menu` VALUES (43, 2, 1201, '2026-03-19 15:15:13');
+INSERT INTO `sys_role_menu` VALUES (44, 2, 1202, '2026-03-19 15:15:13');
+INSERT INTO `sys_role_menu` VALUES (45, 2, 1203, '2026-03-19 15:15:13');
+INSERT INTO `sys_role_menu` VALUES (46, 2, 1204, '2026-03-19 15:15:13');
+INSERT INTO `sys_role_menu` VALUES (66, 1, 1100, '2026-03-19 15:47:23');
+INSERT INTO `sys_role_menu` VALUES (67, 1, 1101, '2026-03-19 15:47:23');
+INSERT INTO `sys_role_menu` VALUES (68, 1, 1102, '2026-03-19 15:47:23');
+INSERT INTO `sys_role_menu` VALUES (69, 1, 1103, '2026-03-19 15:47:23');
+INSERT INTO `sys_role_menu` VALUES (70, 1, 1104, '2026-03-19 15:47:23');
+INSERT INTO `sys_role_menu` VALUES (71, 1, 1105, '2026-03-19 15:47:23');
+INSERT INTO `sys_role_menu` VALUES (72, 1, 1200, '2026-03-19 15:47:23');
+INSERT INTO `sys_role_menu` VALUES (73, 1, 1201, '2026-03-19 15:47:23');
+INSERT INTO `sys_role_menu` VALUES (74, 1, 1202, '2026-03-19 15:47:23');
+INSERT INTO `sys_role_menu` VALUES (75, 1, 1203, '2026-03-19 15:47:23');
+INSERT INTO `sys_role_menu` VALUES (76, 1, 1204, '2026-03-19 15:47:23');
+INSERT INTO `sys_role_menu` VALUES (89, 1, 1000, '2026-03-19 16:13:15');
+INSERT INTO `sys_role_menu` VALUES (90, 4, 1100, '2026-03-19 16:41:05');
+INSERT INTO `sys_role_menu` VALUES (91, 4, 1101, '2026-03-19 16:41:05');
+INSERT INTO `sys_role_menu` VALUES (92, 4, 1102, '2026-03-19 16:41:05');
+INSERT INTO `sys_role_menu` VALUES (93, 4, 1103, '2026-03-19 16:41:05');
+INSERT INTO `sys_role_menu` VALUES (94, 4, 1104, '2026-03-19 16:41:05');
+INSERT INTO `sys_role_menu` VALUES (95, 4, 1105, '2026-03-19 16:41:05');
+INSERT INTO `sys_role_menu` VALUES (108, 1, 2000, '2026-03-20 06:36:03');
+INSERT INTO `sys_role_menu` VALUES (109, 1, 2100, '2026-03-20 06:36:03');
+INSERT INTO `sys_role_menu` VALUES (110, 1, 2110, '2026-03-20 06:36:03');
+INSERT INTO `sys_role_menu` VALUES (111, 1, 2111, '2026-03-20 06:36:03');
+INSERT INTO `sys_role_menu` VALUES (112, 1, 2112, '2026-03-20 06:36:03');
+INSERT INTO `sys_role_menu` VALUES (113, 1, 2113, '2026-03-20 06:36:03');
+INSERT INTO `sys_role_menu` VALUES (114, 1, 2114, '2026-03-20 06:36:03');
+INSERT INTO `sys_role_menu` VALUES (115, 1, 2115, '2026-03-20 06:36:03');
+INSERT INTO `sys_role_menu` VALUES (116, 1, 2116, '2026-03-20 06:36:03');
+INSERT INTO `sys_role_menu` VALUES (117, 1, 2117, '2026-03-20 06:36:03');
+INSERT INTO `sys_role_menu` VALUES (240, 1, 3000, '2026-03-20 08:03:03');
+INSERT INTO `sys_role_menu` VALUES (241, 1, 3100, '2026-03-20 08:03:03');
+INSERT INTO `sys_role_menu` VALUES (242, 1, 3101, '2026-03-20 08:03:03');
+INSERT INTO `sys_role_menu` VALUES (243, 1, 3102, '2026-03-20 08:03:03');
+INSERT INTO `sys_role_menu` VALUES (244, 1, 3103, '2026-03-20 08:03:03');
+INSERT INTO `sys_role_menu` VALUES (245, 1, 3104, '2026-03-20 08:03:03');
+INSERT INTO `sys_role_menu` VALUES (268, 1, 3050, '2026-03-20 09:58:00');
+INSERT INTO `sys_role_menu` VALUES (269, 1, 3060, '2026-03-20 09:58:00');
+INSERT INTO `sys_role_menu` VALUES (270, 1, 3061, '2026-03-20 09:58:00');
+INSERT INTO `sys_role_menu` VALUES (271, 1, 3062, '2026-03-20 09:58:00');
+INSERT INTO `sys_role_menu` VALUES (272, 1, 3063, '2026-03-20 09:58:00');
+INSERT INTO `sys_role_menu` VALUES (273, 1, 3070, '2026-03-20 09:58:00');
+INSERT INTO `sys_role_menu` VALUES (274, 1, 3071, '2026-03-20 09:58:00');
+INSERT INTO `sys_role_menu` VALUES (275, 1, 3072, '2026-03-20 09:58:00');
+INSERT INTO `sys_role_menu` VALUES (276, 1, 3073, '2026-03-20 09:58:00');
+INSERT INTO `sys_role_menu` VALUES (277, 1, 3074, '2026-03-20 09:58:00');
+INSERT INTO `sys_role_menu` VALUES (278, 1, 3075, '2026-03-20 09:58:00');
+INSERT INTO `sys_role_menu` VALUES (279, 1, 3076, '2026-03-20 09:58:00');
+INSERT INTO `sys_role_menu` VALUES (280, 1, 3077, '2026-03-20 09:58:00');
+INSERT INTO `sys_role_menu` VALUES (281, 1, 3080, '2026-03-20 09:58:00');
+INSERT INTO `sys_role_menu` VALUES (282, 1, 3081, '2026-03-20 09:58:00');
+INSERT INTO `sys_role_menu` VALUES (283, 1, 3082, '2026-03-20 09:58:00');
+INSERT INTO `sys_role_menu` VALUES (358, 4, 1300, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (359, 2, 1300, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (360, 1, 1300, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (361, 4, 1310, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (362, 2, 1310, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (363, 1, 1310, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (364, 4, 1311, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (365, 2, 1311, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (366, 1, 1311, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (367, 4, 4000, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (368, 2, 4000, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (369, 1, 4000, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (370, 4, 4100, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (371, 2, 4100, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (372, 1, 4100, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (373, 4, 4110, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (374, 2, 4110, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (375, 1, 4110, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (376, 4, 4111, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (377, 2, 4111, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (378, 1, 4111, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (379, 4, 4112, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (380, 2, 4112, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (381, 1, 4112, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (382, 4, 4113, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (383, 2, 4113, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (384, 1, 4113, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (385, 4, 4114, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (386, 2, 4114, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (387, 1, 4114, '2026-03-21 08:07:45');
+INSERT INTO `sys_role_menu` VALUES (433, 4, 4200, '2026-03-21 09:30:56');
+INSERT INTO `sys_role_menu` VALUES (434, 2, 4200, '2026-03-21 09:30:56');
+INSERT INTO `sys_role_menu` VALUES (435, 1, 4200, '2026-03-21 09:30:56');
+INSERT INTO `sys_role_menu` VALUES (436, 4, 4210, '2026-03-21 09:30:56');
+INSERT INTO `sys_role_menu` VALUES (437, 2, 4210, '2026-03-21 09:30:56');
+INSERT INTO `sys_role_menu` VALUES (438, 1, 4210, '2026-03-21 09:30:56');
+INSERT INTO `sys_role_menu` VALUES (439, 4, 4211, '2026-03-21 09:30:56');
+INSERT INTO `sys_role_menu` VALUES (440, 2, 4211, '2026-03-21 09:30:56');
+INSERT INTO `sys_role_menu` VALUES (441, 1, 4211, '2026-03-21 09:30:56');
+INSERT INTO `sys_role_menu` VALUES (451, 1, 2118, '2026-03-23 19:49:56');
+INSERT INTO `sys_role_menu` VALUES (452, 1, 2119, '2026-03-23 22:00:08');
+INSERT INTO `sys_role_menu` VALUES (453, 1, 2200, '2026-03-23 22:00:08');
+INSERT INTO `sys_role_menu` VALUES (454, 1, 2210, '2026-03-23 22:00:08');
+INSERT INTO `sys_role_menu` VALUES (455, 1, 2211, '2026-03-23 22:00:08');
+INSERT INTO `sys_role_menu` VALUES (456, 1, 2220, '2026-03-23 22:00:08');
+INSERT INTO `sys_role_menu` VALUES (457, 1, 2221, '2026-03-23 22:00:08');
+INSERT INTO `sys_role_menu` VALUES (458, 1, 3090, '2026-03-24 10:59:54');
+INSERT INTO `sys_role_menu` VALUES (459, 1, 3091, '2026-03-24 10:59:54');
+INSERT INTO `sys_role_menu` VALUES (460, 1, 3092, '2026-03-24 10:59:54');
+INSERT INTO `sys_role_menu` VALUES (461, 1, 3093, '2026-03-24 10:59:54');
+INSERT INTO `sys_role_menu` VALUES (530, 1, 3110, '2026-03-24 05:50:17');
+INSERT INTO `sys_role_menu` VALUES (531, 1, 3111, '2026-03-24 05:50:17');
+INSERT INTO `sys_role_menu` VALUES (532, 1, 3112, '2026-03-24 05:50:17');
+INSERT INTO `sys_role_menu` VALUES (533, 1, 3113, '2026-03-24 05:50:17');
+INSERT INTO `sys_role_menu` VALUES (534, 1, 3114, '2026-03-24 05:50:17');
+INSERT INTO `sys_role_menu` VALUES (535, 1, 3115, '2026-03-24 05:50:17');
+INSERT INTO `sys_role_menu` VALUES (536, 1, 3116, '2026-03-24 05:50:17');
+INSERT INTO `sys_role_menu` VALUES (537, 1, 3117, '2026-03-24 05:50:17');
+INSERT INTO `sys_role_menu` VALUES (538, 1, 3118, '2026-03-24 05:50:17');
+INSERT INTO `sys_role_menu` VALUES (539, 1, 3119, '2026-03-24 05:50:17');
+INSERT INTO `sys_role_menu` VALUES (608, 1, 4120, '2026-03-25 14:59:13');
+INSERT INTO `sys_role_menu` VALUES (609, 1, 4121, '2026-03-25 14:59:13');
+INSERT INTO `sys_role_menu` VALUES (610, 1, 4122, '2026-03-25 14:59:13');
+INSERT INTO `sys_role_menu` VALUES (611, 1, 4123, '2026-03-25 14:59:13');
+INSERT INTO `sys_role_menu` VALUES (776, 1, 4130, '2026-03-25 16:18:55');
+INSERT INTO `sys_role_menu` VALUES (777, 1, 4131, '2026-03-25 16:18:55');
+INSERT INTO `sys_role_menu` VALUES (778, 1, 4132, '2026-03-25 16:18:55');
+INSERT INTO `sys_role_menu` VALUES (779, 1, 4133, '2026-03-25 16:18:55');
+INSERT INTO `sys_role_menu` VALUES (780, 1, 4220, '2026-03-25 09:40:43');
+INSERT INTO `sys_role_menu` VALUES (781, 1, 4221, '2026-03-25 09:40:43');
+INSERT INTO `sys_role_menu` VALUES (868, 1, 4230, '2026-03-25 20:51:18');
+INSERT INTO `sys_role_menu` VALUES (869, 1, 4231, '2026-03-25 20:51:18');
+INSERT INTO `sys_role_menu` VALUES (870, 1, 3120, '2026-03-25 13:30:33');
+INSERT INTO `sys_role_menu` VALUES (871, 1, 3121, '2026-03-25 13:30:33');
+INSERT INTO `sys_role_menu` VALUES (872, 1, 3122, '2026-03-25 13:30:33');
+INSERT INTO `sys_role_menu` VALUES (873, 1, 3123, '2026-03-25 13:30:33');
+INSERT INTO `sys_role_menu` VALUES (964, 1, 1305, '2026-03-26 15:34:59');
+INSERT INTO `sys_role_menu` VALUES (965, 1, 1306, '2026-03-26 15:34:59');
+INSERT INTO `sys_role_menu` VALUES (1062, 1, 1307, '2026-03-26 08:13:45');
+INSERT INTO `sys_role_menu` VALUES (1063, 1, 1308, '2026-03-26 08:13:45');
+INSERT INTO `sys_role_menu` VALUES (1064, 1, 1309, '2026-03-26 08:13:45');
+INSERT INTO `sys_role_menu` VALUES (1161, 1, 1312, '2026-03-26 08:51:05');
+INSERT INTO `sys_role_menu` VALUES (1162, 1, 1313, '2026-03-26 08:51:05');
+INSERT INTO `sys_role_menu` VALUES (1262, 1, 1314, '2026-03-26 09:28:36');
+INSERT INTO `sys_role_menu` VALUES (1263, 1, 1315, '2026-03-26 09:28:36');
+INSERT INTO `sys_role_menu` VALUES (1264, 1, 1316, '2026-03-26 09:28:36');
+INSERT INTO `sys_role_menu` VALUES (1265, 1, 1317, '2026-03-26 09:28:36');
+INSERT INTO `sys_role_menu` VALUES (1266, 1, 1318, '2026-03-26 09:28:36');
+INSERT INTO `sys_role_menu` VALUES (1267, 1, 1319, '2026-03-26 09:28:36');
+INSERT INTO `sys_role_menu` VALUES (1268, 1, 1320, '2026-03-26 09:28:36');
+INSERT INTO `sys_role_menu` VALUES (1370, 1, 1321, '2026-03-26 10:07:49');
+INSERT INTO `sys_role_menu` VALUES (1371, 1, 1322, '2026-03-26 10:07:49');
+INSERT INTO `sys_role_menu` VALUES (1372, 1, 1323, '2026-03-26 10:07:49');
+INSERT INTO `sys_role_menu` VALUES (1481, 1, 1324, '2026-03-26 11:29:12');
+INSERT INTO `sys_role_menu` VALUES (1482, 1, 1325, '2026-03-26 11:29:12');
+INSERT INTO `sys_role_menu` VALUES (1483, 1, 1326, '2026-03-26 11:29:12');
+INSERT INTO `sys_role_menu` VALUES (1484, 1, 1327, '2026-03-26 11:29:12');
+INSERT INTO `sys_role_menu` VALUES (1485, 1, 1328, '2026-03-26 11:29:12');
+INSERT INTO `sys_role_menu` VALUES (1486, 1, 1329, '2026-03-26 11:29:12');
+INSERT INTO `sys_role_menu` VALUES (1598, 1, 1330, '2026-03-26 11:58:15');
+INSERT INTO `sys_role_menu` VALUES (1599, 1, 1331, '2026-03-26 11:58:15');
+INSERT INTO `sys_role_menu` VALUES (1727, 1, 1332, '2026-03-26 12:25:39');
+INSERT INTO `sys_role_menu` VALUES (1728, 1, 1333, '2026-03-26 12:25:39');
+INSERT INTO `sys_role_menu` VALUES (1729, 1, 1334, '2026-03-26 12:25:39');
+INSERT INTO `sys_role_menu` VALUES (1730, 1, 1335, '2026-03-26 12:25:39');
+INSERT INTO `sys_role_menu` VALUES (1855, 1, 1336, '2026-03-26 12:43:32');
+INSERT INTO `sys_role_menu` VALUES (1981, 1, 5000, '2026-03-26 21:07:20');
+INSERT INTO `sys_role_menu` VALUES (1982, 1, 5030, '2026-03-26 21:07:20');
+INSERT INTO `sys_role_menu` VALUES (1983, 1, 5031, '2026-03-26 21:07:20');
+INSERT INTO `sys_role_menu` VALUES (2111, 1, 5010, '2026-03-26 21:57:36');
+INSERT INTO `sys_role_menu` VALUES (2112, 1, 5020, '2026-03-26 23:06:29');
+INSERT INTO `sys_role_menu` VALUES (2367, 5, 1312, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2368, 5, 1313, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2369, 5, 1336, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2370, 5, 2110, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2371, 5, 2111, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2372, 5, 2112, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2373, 5, 2113, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2374, 5, 2114, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2375, 5, 2115, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2376, 5, 2116, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2377, 5, 2117, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2378, 5, 2118, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2379, 5, 2119, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2380, 5, 2210, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2381, 5, 2211, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2382, 5, 2220, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2383, 5, 2221, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2384, 5, 3080, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2385, 5, 3081, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2386, 5, 4110, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2387, 5, 4111, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2388, 5, 4112, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2389, 5, 4113, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2390, 5, 4114, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2391, 5, 4120, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2392, 5, 4121, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2393, 5, 4122, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2394, 5, 4123, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2395, 5, 4130, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2396, 5, 4131, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2397, 5, 4132, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2398, 5, 4133, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2399, 5, 4210, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2400, 5, 4211, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2401, 5, 4230, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2402, 5, 4231, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2403, 5, 5010, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2404, 5, 5020, '2026-04-28 10:24:25');
+INSERT INTO `sys_role_menu` VALUES (2405, 1, 5045, '2026-08-19 10:38:59');
+INSERT INTO `sys_role_menu` VALUES (2406, 1, 5046, '2026-08-19 10:38:59');
+INSERT INTO `sys_role_menu` VALUES (2407, 1, 5047, '2026-08-19 10:38:59');
+INSERT INTO `sys_role_menu` VALUES (2408, 1, 5048, '2026-08-19 10:38:59');
+INSERT INTO `sys_role_menu` VALUES (2409, 1, 5049, '2026-08-19 10:38:59');
+INSERT INTO `sys_role_menu` VALUES (2410, 1, 5050, '2026-08-19 10:38:59');
+INSERT INTO `sys_role_menu` VALUES (2411, 1, 3064, '2026-08-19 10:38:59');
+INSERT INTO `sys_role_menu` VALUES (2416, 1, 6000, '2026-08-19 16:22:28');
+INSERT INTO `sys_role_menu` VALUES (2417, 1, 6001, '2026-08-19 16:22:28');
+INSERT INTO `sys_role_menu` VALUES (2418, 1, 6010, '2026-08-20 12:10:14');
+INSERT INTO `sys_role_menu` VALUES (2419, 1, 6011, '2026-08-20 12:10:14');
+INSERT INTO `sys_role_menu` VALUES (2420, 1, 6012, '2026-08-20 12:10:14');
+INSERT INTO `sys_role_menu` VALUES (2421, 1, 6013, '2026-08-20 12:10:14');
+INSERT INTO `sys_role_menu` VALUES (2422, 1, 6014, '2026-08-20 13:05:56');
+INSERT INTO `sys_role_menu` VALUES (2423, 1, 6015, '2026-08-20 13:05:56');
+INSERT INTO `sys_role_menu` VALUES (2424, 1, 6100, '2026-08-22 11:09:25');
+INSERT INTO `sys_role_menu` VALUES (2425, 1, 6110, '2026-08-22 12:12:19');
+INSERT INTO `sys_role_menu` VALUES (2426, 1, 6111, '2026-08-22 12:12:19');
+INSERT INTO `sys_role_menu` VALUES (2427, 1, 6112, '2026-08-22 12:12:19');
+INSERT INTO `sys_role_menu` VALUES (2428, 1, 6113, '2026-08-22 12:12:19');
+
+SET FOREIGN_KEY_CHECKS = 1;
diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/popularization/controller/AppHealthPopularizationController.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/popularization/controller/AppHealthPopularizationController.java
index 9769c59..a11f045 100644
--- a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/popularization/controller/AppHealthPopularizationController.java
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/popularization/controller/AppHealthPopularizationController.java
@@ -8,6 +8,7 @@
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
 import java.util.List;
@@ -31,10 +32,13 @@
 
     /**
      * 获取 APP 健康科普列表。
+     *
+     * @param contentType 内容类型:1 健康知识、2 养生科普;不传则返回全部。
      */
     @GetMapping("/health-popularizations")
-    public ApiResponse<List<AppHealthPopularizationListItemVO>> list() {
-        return ApiResponse.ok(appHealthPopularizationService.list());
+    public ApiResponse<List<AppHealthPopularizationListItemVO>> list(
+            @RequestParam(value = "contentType", required = false) Integer contentType) {
+        return ApiResponse.ok(appHealthPopularizationService.list(contentType));
     }
 
     /**
diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/popularization/service/AppHealthPopularizationService.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/popularization/service/AppHealthPopularizationService.java
index f4436bf..ec784cd 100644
--- a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/popularization/service/AppHealthPopularizationService.java
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/popularization/service/AppHealthPopularizationService.java
@@ -6,6 +6,7 @@
 import com.tcm.training.admin.live.entity.HealthPopularization;
 import com.tcm.training.admin.live.mapper.HealthPopularizationMapper;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -30,12 +31,15 @@
 
     /**
      * 获取 APP 健康科普列表页数据。
+     *
+     * @param contentType 内容类型:1 健康知识、2 养生科普;为空则返回全部。
      */
-    public List<AppHealthPopularizationListItemVO> list() {
+    public List<AppHealthPopularizationListItemVO> list(Integer contentType) {
         List<HealthPopularization> items = healthPopularizationMapper.selectList(new LambdaQueryWrapper<HealthPopularization>()
                 .eq(HealthPopularization::getDeleted, 0)
                 .eq(HealthPopularization::getStatus, STATUS_ENABLED)
-                .orderByAsc(HealthPopularization::getSort)
+                .eq(contentType != null, HealthPopularization::getContentType, contentType)
+                .orderByDesc(HealthPopularization::getSort)
                 .orderByDesc(HealthPopularization::getId));
         if (items == null || items.isEmpty()) {
             return Collections.emptyList();
@@ -55,10 +59,14 @@
     }
 
     /**
-     * 获取 APP 健康科普详情页数据。
+     * 获取 APP 健康科普详情页数据,并在每次访问时累加点击量。
      */
+    @Transactional
     public AppHealthPopularizationDetailVO detail(Long popularizationId) {
         HealthPopularization item = requireEnabledItem(popularizationId);
+        // 参考项目介绍,APP 进入详情后累加点击量并回写。
+        item.setClickCount(defaultNumber(item.getClickCount()) + 1);
+        healthPopularizationMapper.updateById(item);
         AppHealthPopularizationDetailVO detailVO = new AppHealthPopularizationDetailVO();
         detailVO.setId(item.getId());
         detailVO.setTitle(trimToEmpty(item.getTitle()));
@@ -68,6 +76,8 @@
         detailVO.setContent(trimToEmpty(item.getContent()));
         detailVO.setVideoUrl(trimToEmpty(item.getVideoUrl()));
         detailVO.setVideoFileName(trimToEmpty(item.getVideoFileName()));
+        detailVO.setVideoDescription(trimToEmpty(item.getVideoDescription()));
+        detailVO.setClickCount(defaultNumber(item.getClickCount()));
         return detailVO;
     }
 
diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/popularization/vo/AppHealthPopularizationDetailVO.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/popularization/vo/AppHealthPopularizationDetailVO.java
index 556e4ef..d62a011 100644
--- a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/popularization/vo/AppHealthPopularizationDetailVO.java
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/app/popularization/vo/AppHealthPopularizationDetailVO.java
@@ -25,4 +25,8 @@
     private String videoUrl;
 
     private String videoFileName;
+
+    private String videoDescription;
+
+    private Integer clickCount;
 }
diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/bootstrap/DataInitializer.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/bootstrap/DataInitializer.java
index 144d0fa..eb01d3a 100644
--- a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/bootstrap/DataInitializer.java
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/bootstrap/DataInitializer.java
@@ -316,24 +316,34 @@
                 null, null, null, 8, "live:health-course:video:edit", "养生课程视频编辑按钮"));
         menuIds.add(saveMenu(3119L, 3110L, "删除视频课程", "live_health_course_video_delete", "B",
                 null, null, null, 9, "live:health-course:video:delete", "养生课程视频删除按钮"));
-        menuIds.add(saveMenu(3120L, 3050L, "健康科普", "live_health_popularization_manage", "C",
-                "/live/course/health-popularization", "Live/HealthPopularizationList", null, 50, "live:health-popularization:view", "健康科普菜单"));
-        menuIds.add(saveMenu(3121L, 3120L, "新增健康科普", "live_health_popularization_add", "B",
-                null, null, null, 1, "live:health-popularization:add", "健康科普新增按钮"));
-        menuIds.add(saveMenu(3122L, 3120L, "编辑健康科普", "live_health_popularization_edit", "B",
-                null, null, null, 2, "live:health-popularization:edit", "健康科普编辑按钮"));
-        menuIds.add(saveMenu(3123L, 3120L, "删除健康科普", "live_health_popularization_delete", "B",
-                null, null, null, 3, "live:health-popularization:delete", "健康科普删除按钮"));
-        menuIds.add(saveMenu(6010L, 3050L, "项目介绍", "live_project_introduction_manage", "C",
-                "/live/course/project-introduction", "Live/ProjectIntroductionList", null, 60, "live:project-introduction:view", "项目介绍菜单"));
+        menuIds.add(saveMenu(3120L, 6100L, "健康知识", "live_health_popularization_manage", "C",
+                "/live/promotion/health-popularization", "Live/HealthPopularizationList", null, 50, "live:health-popularization:view", "健康知识菜单"));
+        menuIds.add(saveMenu(3121L, 3120L, "新增健康知识", "live_health_popularization_add", "B",
+                null, null, null, 1, "live:health-popularization:add", "健康知识新增按钮"));
+        menuIds.add(saveMenu(3122L, 3120L, "编辑健康知识", "live_health_popularization_edit", "B",
+                null, null, null, 2, "live:health-popularization:edit", "健康知识编辑按钮"));
+        menuIds.add(saveMenu(3123L, 3120L, "删除健康知识", "live_health_popularization_delete", "B",
+                null, null, null, 3, "live:health-popularization:delete", "健康知识删除按钮"));
+        menuIds.add(saveMenu(6110L, 6100L, "养生科普", "live_health_promotion_manage", "C",
+                "/live/promotion/health-promotion", "Live/HealthPromotionList", null, 51, "live:health-promotion:view", "养生科普菜单"));
+        menuIds.add(saveMenu(6111L, 6110L, "新增养生科普", "live_health_promotion_add", "B",
+                null, null, null, 1, "live:health-promotion:add", "养生科普新增按钮"));
+        menuIds.add(saveMenu(6112L, 6110L, "编辑养生科普", "live_health_promotion_edit", "B",
+                null, null, null, 2, "live:health-promotion:edit", "养生科普编辑按钮"));
+        menuIds.add(saveMenu(6113L, 6110L, "删除养生科普", "live_health_promotion_delete", "B",
+                null, null, null, 3, "live:health-promotion:delete", "养生科普删除按钮"));
+        menuIds.add(saveMenu(6100L, 3000L, "宣传知识", "live_promotion_root", "M",
+                "/live/promotion", null, null, 20, null, "宣传知识目录"));
+        menuIds.add(saveMenu(6010L, 6100L, "项目介绍", "live_project_introduction_manage", "C",
+                "/live/promotion/project-introduction", "Live/ProjectIntroductionList", null, 60, "live:project-introduction:view", "项目介绍菜单"));
         menuIds.add(saveMenu(6011L, 6010L, "新增项目介绍", "live_project_introduction_add", "B",
                 null, null, null, 1, "live:project-introduction:add", "项目介绍新增按钮"));
         menuIds.add(saveMenu(6012L, 6010L, "编辑项目介绍", "live_project_introduction_edit", "B",
                 null, null, null, 2, "live:project-introduction:edit", "项目介绍编辑按钮"));
         menuIds.add(saveMenu(6013L, 6010L, "删除项目介绍", "live_project_introduction_delete", "B",
                 null, null, null, 3, "live:project-introduction:delete", "项目介绍删除按钮"));
-        menuIds.add(saveMenu(6014L, 3050L, "项目介绍密码", "live_project_introduction_password", "C",
-                "/live/course/project-introduction-password", "Live/ProjectIntroductionPassword", null, 61, "live:project-introduction-password:view", "项目介绍密码菜单"));
+        menuIds.add(saveMenu(6014L, 6100L, "项目介绍密码", "live_project_introduction_password", "C",
+                "/live/promotion/project-introduction-password", "Live/ProjectIntroductionPassword", null, 61, "live:project-introduction-password:view", "项目介绍密码菜单"));
         menuIds.add(saveMenu(6015L, 6014L, "编辑项目介绍密码", "live_project_introduction_password_edit", "B",
                 null, null, null, 1, "live:project-introduction-password:edit", "项目介绍密码编辑按钮"));
         menuIds.add(saveMenu(4000L, 0L, "交易与财务", "trade_root", "M",
diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/dto/HealthPopularizationSaveRequest.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/dto/HealthPopularizationSaveRequest.java
index 9037336..9e069f8 100644
--- a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/dto/HealthPopularizationSaveRequest.java
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/dto/HealthPopularizationSaveRequest.java
@@ -34,6 +34,9 @@
     @Size(max = 255, message = "视频文件名长度不能超过255个字符")
     private String videoFileName;
 
+    @Size(max = 255, message = "视频介绍长度不能超过255个字符")
+    private String videoDescription;
+
     @NotNull(message = "请选择是否启用")
     private Integer status;
 
diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/entity/HealthPopularization.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/entity/HealthPopularization.java
index a14d43d..6e8559c 100644
--- a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/entity/HealthPopularization.java
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/entity/HealthPopularization.java
@@ -40,6 +40,9 @@
     @TableField("video_file_name")
     private String videoFileName;
 
+    @TableField("video_description")
+    private String videoDescription;
+
     private Integer status;
 
     @TableField("is_home_recommend")
diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/service/HealthPopularizationAppService.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/service/HealthPopularizationAppService.java
index f77cd77..3ea3a5f 100644
--- a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/service/HealthPopularizationAppService.java
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/service/HealthPopularizationAppService.java
@@ -96,6 +96,7 @@
             item.setContent(content);
             item.setVideoUrl(null);
             item.setVideoFileName(null);
+            item.setVideoDescription(null);
             return;
         }
 
@@ -106,6 +107,7 @@
         item.setContent(null);
         item.setVideoUrl(videoUrl);
         item.setVideoFileName(trimToNull(req.getVideoFileName()));
+        item.setVideoDescription(trimToNull(req.getVideoDescription()));
     }
 
     private int validateContentType(Integer contentType) {
@@ -153,6 +155,7 @@
         vo.setContent(item.getContent());
         vo.setVideoUrl(item.getVideoUrl());
         vo.setVideoFileName(item.getVideoFileName());
+        vo.setVideoDescription(item.getVideoDescription());
         vo.setStatus(item.getStatus());
         vo.setIsHomeRecommend(item.getIsHomeRecommend());
         vo.setClickCount(defaultNumber(item.getClickCount()));
diff --git a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/vo/HealthPopularizationDetailVO.java b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/vo/HealthPopularizationDetailVO.java
index 40a4efa..e2ddc87 100644
--- a/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/vo/HealthPopularizationDetailVO.java
+++ b/tcm-training-admin-backend/src/main/java/com/tcm/training/admin/live/vo/HealthPopularizationDetailVO.java
@@ -17,6 +17,7 @@
     private String content;
     private String videoUrl;
     private String videoFileName;
+    private String videoDescription;
     private Integer status;
     private Integer isHomeRecommend;
     private Integer clickCount;
diff --git a/tcm-training-admin/config/routes.ts b/tcm-training-admin/config/routes.ts
index 201f113..484ca6e 100644
--- a/tcm-training-admin/config/routes.ts
+++ b/tcm-training-admin/config/routes.ts
@@ -343,52 +343,6 @@
             component: './live/health',
           },
           {
-            name: '健康科普',
-            path: '/live/course/health-popularization',
-            access: 'live:health-popularization:view',
-            component: './live/health-popularization',
-          },
-          {
-            name: '新增健康科普',
-            path: '/live/course/health-popularization/create',
-            hideInMenu: true,
-            access: 'live:health-popularization:add',
-            component: './live/health-popularization/manage',
-          },
-          {
-            name: '编辑健康科普',
-            path: '/live/course/health-popularization/:id/edit',
-            hideInMenu: true,
-            access: 'live:health-popularization:edit',
-            component: './live/health-popularization/manage',
-          },
-          {
-            name: '项目介绍',
-            path: '/live/course/project-introduction',
-            access: 'live:project-introduction:view',
-            component: './live/project-introduction',
-          },
-          {
-            name: '新增项目介绍',
-            path: '/live/course/project-introduction/create',
-            hideInMenu: true,
-            access: 'live:project-introduction:add',
-            component: './live/project-introduction/manage',
-          },
-          {
-            name: '编辑项目介绍',
-            path: '/live/course/project-introduction/:id/edit',
-            hideInMenu: true,
-            access: 'live:project-introduction:edit',
-            component: './live/project-introduction/manage',
-          },
-          {
-            name: '项目介绍密码',
-            path: '/live/course/project-introduction-password',
-            access: 'live:project-introduction:view',
-            component: './live/project-introduction-password',
-          },
-          {
             name: '视频与课程资源管理',
             path: '/live/course/video-resources',
             access: 'live:health-course:view',
@@ -463,6 +417,107 @@
             access: 'live:expert:view',
             component: './live/expert',
           },
+          {
+            path: '/live/course/project-introduction/create',
+            hideInMenu: true,
+            redirect: '/live/promotion/project-introduction/create',
+          },
+          {
+            path: '/live/course/project-introduction',
+            hideInMenu: true,
+            redirect: '/live/promotion/project-introduction',
+          },
+          {
+            path: '/live/course/project-introduction-password',
+            hideInMenu: true,
+            redirect: '/live/promotion/project-introduction-password',
+          },
+          {
+            path: '/live/course/health-popularization/create',
+            hideInMenu: true,
+            redirect: '/live/promotion/health-popularization/create',
+          },
+          {
+            path: '/live/course/health-popularization',
+            hideInMenu: true,
+            redirect: '/live/promotion/health-popularization',
+          },
+        ],
+      },
+      {
+        path: '/live/promotion',
+        name: '宣传知识',
+        routes: [
+          {
+            path: '/live/promotion',
+            redirect: '/live/promotion/project-introduction',
+          },
+          {
+            name: '健康知识',
+            path: '/live/promotion/health-popularization',
+            access: 'live:health-popularization:view',
+            component: './live/health-popularization',
+          },
+          {
+            name: '新增健康知识',
+            path: '/live/promotion/health-popularization/create',
+            hideInMenu: true,
+            access: 'live:health-popularization:add',
+            component: './live/health-popularization/manage',
+          },
+          {
+            name: '编辑健康知识',
+            path: '/live/promotion/health-popularization/:id/edit',
+            hideInMenu: true,
+            access: 'live:health-popularization:edit',
+            component: './live/health-popularization/manage',
+          },
+          {
+            name: '养生科普',
+            path: '/live/promotion/health-promotion',
+            access: 'live:health-promotion:view',
+            component: './live/health-promotion',
+          },
+          {
+            name: '新增养生科普',
+            path: '/live/promotion/health-promotion/create',
+            hideInMenu: true,
+            access: 'live:health-promotion:add',
+            component: './live/health-promotion/manage',
+          },
+          {
+            name: '编辑养生科普',
+            path: '/live/promotion/health-promotion/:id/edit',
+            hideInMenu: true,
+            access: 'live:health-promotion:edit',
+            component: './live/health-promotion/manage',
+          },
+          {
+            name: '项目介绍',
+            path: '/live/promotion/project-introduction',
+            access: 'live:project-introduction:view',
+            component: './live/project-introduction',
+          },
+          {
+            name: '新增项目介绍',
+            path: '/live/promotion/project-introduction/create',
+            hideInMenu: true,
+            access: 'live:project-introduction:add',
+            component: './live/project-introduction/manage',
+          },
+          {
+            name: '编辑项目介绍',
+            path: '/live/promotion/project-introduction/:id/edit',
+            hideInMenu: true,
+            access: 'live:project-introduction:edit',
+            component: './live/project-introduction/manage',
+          },
+          {
+            name: '项目介绍密码',
+            path: '/live/promotion/project-introduction-password',
+            access: 'live:project-introduction:view',
+            component: './live/project-introduction-password',
+          },
         ],
       },
     ],
diff --git a/tcm-training-admin/src/access.js b/tcm-training-admin/src/access.js
index be9aa14..8fcb466 100644
--- a/tcm-training-admin/src/access.js
+++ b/tcm-training-admin/src/access.js
@@ -39,7 +39,11 @@
       !!permission?.['live:category:view'] ||
       !!permission?.['live:reserve:view'] ||
       !!permission?.['live:watch:view'] ||
-      !!permission?.['live:expert:view'],
+      !!permission?.['live:expert:view'] ||
+      !!permission?.['live:project-introduction:view'] ||
+      !!permission?.['live:project-introduction-password:view'] ||
+      !!permission?.['live:health-popularization:view'] ||
+      !!permission?.['live:health-promotion:view'],
     canViewTradeFinanceModule:
       !!permission?.['course:purchase-order:view'] ||
       !!permission?.['member:purchase-order:view'] ||
diff --git a/tcm-training-admin/src/pages/live/health-popularization/index.tsx b/tcm-training-admin/src/pages/live/health-popularization/index.tsx
index 2b45dc5..73543a2 100644
--- a/tcm-training-admin/src/pages/live/health-popularization/index.tsx
+++ b/tcm-training-admin/src/pages/live/health-popularization/index.tsx
@@ -87,7 +87,7 @@
 
   const handleDelete = (record: PopularizationItem) => {
     Modal.confirm({
-      title: '确定要删除该健康科普吗?',
+      title: '确定要删除该健康知识吗?',
       okText: '删除',
       cancelText: '取消',
       onOk: async () => {
@@ -159,7 +159,7 @@
           {canEdit ? (
             <button
               type="button"
-              onClick={() => history.push(`/live/course/health-popularization/${record.id}/edit`)}
+              onClick={() => history.push(`/live/promotion/health-popularization/${record.id}/edit`)}
             >
               编辑
             </button>
@@ -177,7 +177,7 @@
   return (
     <div className="health-popularization-page">
       <div className="health-popularization-page__panel">
-        <div className="health-popularization-page__title">健康科普</div>
+        <div className="health-popularization-page__title">健康知识</div>
         <div className="health-popularization-search-card">
           <Form form={searchForm} layout="horizontal" className="health-popularization-search-form">
             <Form.Item label="标题" name="keyword">
@@ -204,7 +204,7 @@
 
         <div className="health-popularization-toolbar">
           {canAdd ? (
-            <Button type="primary" onClick={() => history.push('/live/course/health-popularization/create')}>
+            <Button type="primary" onClick={() => history.push('/live/promotion/health-popularization/create')}>
               添加
             </Button>
           ) : null}
diff --git a/tcm-training-admin/src/pages/live/health-popularization/manage.tsx b/tcm-training-admin/src/pages/live/health-popularization/manage.tsx
index d176f15..25cfcf3 100644
--- a/tcm-training-admin/src/pages/live/health-popularization/manage.tsx
+++ b/tcm-training-admin/src/pages/live/health-popularization/manage.tsx
@@ -20,7 +20,7 @@
   const [coverImg, setCoverImg] = useState('');
   const pathname = history.location.pathname;
   const isCreate = pathname.endsWith('/create');
-  const listPagePath = '/live/course/health-popularization';
+  const listPagePath = '/live/promotion/health-popularization';
   const recordId = useMemo(() => {
     if (isCreate) {
       return '';
@@ -96,7 +96,7 @@
   return (
     <div className="health-popularization-page">
       <div className="health-popularization-page__panel">
-        <div className="health-popularization-page__title">{isCreate ? '添加健康科普' : '编辑健康科普'}</div>
+        <div className="health-popularization-page__title">{isCreate ? '添加健康知识' : '编辑健康知识'}</div>
         <Form form={form} layout="vertical" className="health-popularization-edit-form">
           <div className="health-popularization-edit-form__section-title">信息</div>
           <div className="health-popularization-edit-form__grid">
diff --git a/tcm-training-admin/src/pages/live/health-promotion/index.tsx b/tcm-training-admin/src/pages/live/health-promotion/index.tsx
new file mode 100644
index 0000000..a1cec60
--- /dev/null
+++ b/tcm-training-admin/src/pages/live/health-promotion/index.tsx
@@ -0,0 +1,240 @@
+import {
+  deleteHealthPromotion,
+  getHealthPromotionPage,
+} from './service';
+import { history, useAccess } from '@umijs/max';
+import { Button, Form, Image, Input, Modal, Pagination, Select, Space, Table, message } from 'antd';
+import type { ColumnsType } from 'antd/es/table';
+import React, { useEffect, useState } from 'react';
+import './style.less';
+
+type SearchValues = {
+  keyword?: string;
+  status?: number;
+};
+
+type PromotionItem = {
+  id: number;
+  title: string;
+  coverImg?: string;
+  clickCount?: number;
+  sort?: number;
+  contentType: number;
+  status: number;
+  createdAt: string;
+};
+
+const contentTypeOptions = [
+  { label: '图文', value: 1 },
+  { label: '视频', value: 2 },
+];
+
+const statusOptions = [
+  { label: '启用', value: 1 },
+  { label: '禁用', value: 0 },
+];
+
+// 养生科普只有视频内容,固定 contentType=2
+const trimSearchValues = (values: SearchValues) => ({
+  keyword: values.keyword?.trim() || undefined,
+  contentType: 2,
+  status: values.status,
+});
+
+const contentTypeText = (value?: number) =>
+  contentTypeOptions.find((item) => item.value === value)?.label || '-';
+
+const statusText = (value?: number) => (value === 1 ? '启用' : '禁用');
+
+const HealthPromotionPage: React.FC = () => {
+  const access = useAccess();
+  const [searchForm] = Form.useForm<SearchValues>();
+  const [list, setList] = useState<PromotionItem[]>([]);
+  const [loading, setLoading] = useState(false);
+  const [pagination, setPagination] = useState({ page: 1, pageSize: 10, total: 0 });
+
+  const canView = access['live:health-promotion:view'];
+  const canAdd = access['live:health-promotion:add'];
+  const canEdit = access['live:health-promotion:edit'];
+  const canDelete = access['live:health-promotion:delete'];
+  const refreshKey = history.location.search;
+
+  const loadList = async (page = pagination.page, pageSize = pagination.pageSize) => {
+    setLoading(true);
+    try {
+      const res = await getHealthPromotionPage({
+        page,
+        pageSize,
+        ...trimSearchValues(searchForm.getFieldsValue()),
+      });
+      setList(res.data.list || []);
+      setPagination({
+        page: Number(res.data.page || page),
+        pageSize: Number(res.data.pageSize || pageSize),
+        total: Number(res.data.total || 0),
+      });
+    } finally {
+      setLoading(false);
+    }
+  };
+
+  useEffect(() => {
+    if (!canView) {
+      history.replace('/Welcome');
+      return;
+    }
+    loadList(1, 10);
+  }, [canView, refreshKey]);
+
+  const handleDelete = (record: PromotionItem) => {
+    Modal.confirm({
+      title: '确定要删除该养生科普吗?',
+      okText: '删除',
+      cancelText: '取消',
+      onOk: async () => {
+        await deleteHealthPromotion(record.id);
+        message.success('删除成功');
+        const nextPage = list.length === 1 && pagination.page > 1 ? pagination.page - 1 : pagination.page;
+        await loadList(nextPage, pagination.pageSize);
+      },
+    });
+  };
+
+  const columns: ColumnsType<PromotionItem> = [
+    {
+      title: '序号',
+      width: 72,
+      render: (_, __, index) => (pagination.page - 1) * pagination.pageSize + index + 1,
+    },
+    {
+      title: '标题',
+      dataIndex: 'title',
+      width: 320,
+      render: (_, record) => (
+        <div className="health-promotion-table__title">
+          {record.coverImg ? (
+            <Image src={record.coverImg} width={64} height={40} preview={false} />
+          ) : (
+            <div className="health-promotion-table__cover-placeholder">
+              {record.title?.slice(0, 2) || '-'}
+            </div>
+          )}
+          <span>{record.title || '-'}</span>
+        </div>
+      ),
+    },
+    {
+      title: '点击量',
+      dataIndex: 'clickCount',
+      width: 120,
+      render: (value) => value || 0,
+    },
+    {
+      title: '排序',
+      dataIndex: 'sort',
+      width: 100,
+      render: (value) => value ?? 0,
+    },
+    {
+      title: '类型',
+      dataIndex: 'contentType',
+      width: 100,
+      render: (value) => contentTypeText(value),
+    },
+    {
+      title: '状态',
+      dataIndex: 'status',
+      width: 100,
+      render: (value) => statusText(value),
+    },
+    {
+      title: '创建时间',
+      dataIndex: 'createdAt',
+      width: 180,
+    },
+    {
+      title: '操作',
+      width: 180,
+      render: (_, record) => (
+        <Space size={16} className="health-promotion-table__actions">
+          {canEdit ? (
+            <button
+              type="button"
+              onClick={() => history.push(`/live/promotion/health-promotion/${record.id}/edit`)}
+            >
+              编辑
+            </button>
+          ) : null}
+          {canDelete ? (
+            <button type="button" onClick={() => handleDelete(record)}>
+              删除
+            </button>
+          ) : null}
+        </Space>
+      ),
+    },
+  ];
+
+  return (
+    <div className="health-promotion-page">
+      <div className="health-promotion-page__panel">
+        <div className="health-promotion-page__title">养生科普</div>
+        <div className="health-promotion-search-card">
+          <Form form={searchForm} layout="horizontal" className="health-promotion-search-form">
+            <Form.Item label="标题" name="keyword">
+              <Input placeholder="请输入" allowClear />
+            </Form.Item>
+            <Form.Item label="状态" name="status">
+              <Select placeholder="全部" allowClear options={statusOptions} />
+            </Form.Item>
+            <div className="health-promotion-search-form__actions">
+              <Button
+                onClick={async () => {
+                  searchForm.resetFields();
+                  await loadList(1, pagination.pageSize);
+                }}
+              >
+                重置
+              </Button>
+              <Button type="primary" onClick={() => loadList(1, pagination.pageSize)}>
+                搜索
+              </Button>
+            </div>
+          </Form>
+        </div>
+
+        <div className="health-promotion-toolbar">
+          {canAdd ? (
+            <Button type="primary" onClick={() => history.push('/live/promotion/health-promotion/create')}>
+              添加
+            </Button>
+          ) : null}
+        </div>
+
+        <div className="health-promotion-table-card">
+          <Table<PromotionItem>
+            rowKey="id"
+            columns={columns}
+            dataSource={list}
+            loading={loading}
+            pagination={false}
+            scroll={{ x: 980 }}
+          />
+          <div className="health-promotion-pagination">
+            <Pagination
+              current={pagination.page}
+              pageSize={pagination.pageSize}
+              total={pagination.total}
+              showSizeChanger
+              showQuickJumper
+              showTotal={(total) => `共 ${total} 条`}
+              onChange={(page, pageSize) => loadList(page, pageSize)}
+            />
+          </div>
+        </div>
+      </div>
+    </div>
+  );
+};
+
+export default HealthPromotionPage;
diff --git a/tcm-training-admin/src/pages/live/health-promotion/manage.tsx b/tcm-training-admin/src/pages/live/health-promotion/manage.tsx
new file mode 100644
index 0000000..86109d7
--- /dev/null
+++ b/tcm-training-admin/src/pages/live/health-promotion/manage.tsx
@@ -0,0 +1,240 @@
+import {
+  createHealthPromotion,
+  getHealthPromotionDetail,
+  updateHealthPromotion,
+  uploadHealthPromotionImage,
+  uploadHealthPromotionVideo,
+} from './service';
+import { PlusOutlined, UploadOutlined } from '@ant-design/icons';
+import { history, useAccess } from '@umijs/max';
+import { Button, Form, Image, Input, InputNumber, Switch, Upload, message } from 'antd';
+import React, { useEffect, useMemo, useState } from 'react';
+import './style.less';
+
+const HealthPromotionManagePage: React.FC = () => {
+  const access = useAccess();
+  const [form] = Form.useForm();
+  const [loading, setLoading] = useState(false);
+  const [submitting, setSubmitting] = useState(false);
+  const [uploadingCover, setUploadingCover] = useState(false);
+  const [uploadingVideo, setUploadingVideo] = useState(false);
+  const [coverImg, setCoverImg] = useState('');
+  const pathname = history.location.pathname;
+  const isCreate = pathname.endsWith('/create');
+  const listPagePath = '/live/promotion/health-promotion';
+  const recordId = useMemo(() => {
+    if (isCreate) {
+      return '';
+    }
+    const segments = pathname.split('/');
+    return segments[segments.length - 2] || '';
+  }, [isCreate, pathname]);
+  const canAccess = isCreate ? access['live:health-promotion:add'] : access['live:health-promotion:edit'];
+
+  useEffect(() => {
+    if (!canAccess) {
+      history.replace('/Welcome');
+      return;
+    }
+    const bootstrap = async () => {
+      setLoading(true);
+      try {
+        if (isCreate) {
+          setCoverImg('');
+          form.setFieldsValue({
+            title: '',
+            videoUrl: '',
+            videoFileName: '',
+            videoDescription: '',
+            sort: 0,
+            status: true,
+            isHomeRecommend: true,
+          });
+          return;
+        }
+        const res = await getHealthPromotionDetail(recordId);
+        const detail = res.data;
+        setCoverImg(detail.coverImg || '');
+        form.setFieldsValue({
+          title: detail.title,
+          coverImg: detail.coverImg,
+          videoUrl: detail.videoUrl || '',
+          videoFileName: detail.videoFileName || '',
+          videoDescription: detail.videoDescription || '',
+          sort: detail.sort ?? 0,
+          status: detail.status === 1,
+          isHomeRecommend: detail.isHomeRecommend === 1,
+        });
+      } finally {
+        setLoading(false);
+      }
+    };
+    bootstrap();
+  }, [canAccess, form, isCreate, recordId]);
+
+  const handleSubmit = async () => {
+    const values = await form.validateFields();
+    const payload = {
+      title: values.title?.trim(),
+      coverImg,
+      // 养生科普固定为视频类型
+      contentType: 2,
+      videoUrl: values.videoUrl?.trim(),
+      videoFileName: values.videoFileName?.trim(),
+      videoDescription: values.videoDescription?.trim(),
+      sort: values.sort,
+      status: values.status ? 1 : 0,
+      isHomeRecommend: values.isHomeRecommend ? 1 : 0,
+    };
+    setSubmitting(true);
+    try {
+      if (isCreate) {
+        await createHealthPromotion(payload);
+        message.success('新增成功');
+      } else {
+        await updateHealthPromotion(recordId, payload);
+        message.success('保存成功');
+      }
+      history.replace(`${listPagePath}?refresh=${Date.now()}`);
+    } finally {
+      setSubmitting(false);
+    }
+  };
+
+  return (
+    <div className="health-promotion-page">
+      <div className="health-promotion-page__panel">
+        <div className="health-promotion-page__title">{isCreate ? '添加养生科普' : '编辑养生科普'}</div>
+        <Form form={form} layout="vertical" className="health-promotion-edit-form">
+          <div className="health-promotion-edit-form__section-title">信息</div>
+          <div className="health-promotion-edit-form__grid">
+            <Form.Item label="标题" name="title" rules={[{ required: true, message: '请输入标题' }]}>
+              <Input placeholder="请输入" maxLength={128} disabled={loading} />
+            </Form.Item>
+            <Form.Item label="视频封面图" className="health-promotion-edit-form__upload" required>
+              <Form.Item name="coverImg" rules={[{ required: true, message: '请上传视频封面图' }]} hidden>
+                <Input />
+              </Form.Item>
+              <Upload
+                accept="image/*"
+                showUploadList={false}
+                customRequest={async (options) => {
+                  setUploadingCover(true);
+                  try {
+                    const res = await uploadHealthPromotionImage(options.file as File);
+                    const url = res.data?.url;
+                    if (!url) {
+                      throw new Error('upload failed');
+                    }
+                    setCoverImg(url);
+                    form.setFieldsValue({ coverImg: url });
+                    options.onSuccess?.(res);
+                  } catch (error) {
+                    message.error('封面图上传失败');
+                    options.onError?.(error as Error);
+                  } finally {
+                    setUploadingCover(false);
+                  }
+                }}
+              >
+                <div className="health-promotion-edit-form__cover-box">
+                  {coverImg ? (
+                    <Image src={coverImg} width={96} height={96} preview={false} />
+                  ) : uploadingCover ? (
+                    '上传中...'
+                  ) : (
+                    <PlusOutlined />
+                  )}
+                </div>
+              </Upload>
+            </Form.Item>
+            <div className="health-promotion-edit-form__switch-group">
+              <div className="health-promotion-edit-form__switch-item">
+                <span className="health-promotion-edit-form__switch-label">是否启用</span>
+                <Form.Item name="status" valuePropName="checked" rules={[{ required: true, message: '请选择是否启用' }]}>
+                  <Switch />
+                </Form.Item>
+              </div>
+              <div className="health-promotion-edit-form__switch-item">
+                <span className="health-promotion-edit-form__switch-label">首页推荐</span>
+                <Form.Item
+                  name="isHomeRecommend"
+                  valuePropName="checked"
+                  rules={[{ required: true, message: '请选择是否首页推荐' }]}
+                >
+                  <Switch />
+                </Form.Item>
+              </div>
+            </div>
+            <Form.Item label="排序" name="sort" rules={[{ required: true, message: '请输入排序' }]}>
+              <InputNumber min={0} precision={0} placeholder="请输入" style={{ width: '100%' }} disabled={loading} />
+            </Form.Item>
+            <Form.Item
+              label="视频地址"
+              name="videoUrl"
+              extra="本地视频和视频地址必须填一个"
+              rules={[{ required: true, message: '请填写视频地址或上传本地视频' }]}
+            >
+              <Input placeholder="请输入" disabled={loading} />
+            </Form.Item>
+            <Form.Item
+              label="视频介绍"
+              name="videoDescription"
+              rules={[{ required: true, message: '请输入视频介绍' }]}
+            >
+              <Input.TextArea placeholder="请输入视频介绍" maxLength={255} rows={3} disabled={loading} />
+            </Form.Item>
+            <Form.Item label="本地视频" extra="本地视频和视频地址必须填一个">
+              <div className="health-promotion-edit-form__video-upload">
+                <Upload
+                  accept="video/*"
+                  showUploadList={false}
+                  customRequest={async (options) => {
+                    setUploadingVideo(true);
+                    try {
+                      const res = await uploadHealthPromotionVideo(options.file as File);
+                      const url = res.data?.url;
+                      if (!url) {
+                        throw new Error('upload failed');
+                      }
+                      form.setFieldsValue({
+                        videoUrl: url,
+                        videoFileName: res.data?.fileName || (options.file as File).name,
+                      });
+                      message.success('视频上传成功');
+                      options.onSuccess?.(res);
+                    } catch (error) {
+                      message.error('视频上传失败');
+                      options.onError?.(error as Error);
+                    } finally {
+                      setUploadingVideo(false);
+                    }
+                  }}
+                >
+                  <Button icon={<UploadOutlined />} loading={uploadingVideo}>
+                    上传
+                  </Button>
+                </Upload>
+                <span>
+                  {form.getFieldValue('videoFileName') ||
+                    (form.getFieldValue('videoUrl') ? '已填写视频地址' : '未上传视频文件')}
+                </span>
+              </div>
+              <Form.Item name="videoFileName" hidden>
+                <Input />
+              </Form.Item>
+            </Form.Item>
+          </div>
+          <div className="health-promotion-edit-form__footer">
+            <Button onClick={() => history.push(listPagePath)}>取消</Button>
+            <Button type="primary" loading={submitting} onClick={handleSubmit}>
+              保存
+            </Button>
+          </div>
+        </Form>
+      </div>
+    </div>
+  );
+};
+
+export default HealthPromotionManagePage;
diff --git a/tcm-training-admin/src/pages/live/health-promotion/service.ts b/tcm-training-admin/src/pages/live/health-promotion/service.ts
new file mode 100644
index 0000000..60a62fd
--- /dev/null
+++ b/tcm-training-admin/src/pages/live/health-promotion/service.ts
@@ -0,0 +1,55 @@
+import { request } from '@umijs/max';
+
+// 养生科普与健康知识共用后端接口(同一张表 tcm_health_popularization),
+// 通过 contentType=2(视频)区分养生科普,contentType=1(图文)区分健康知识。
+
+export async function getHealthPromotionPage(params?: Record<string, any>) {
+  return request('/health-popularizations', {
+    method: 'GET',
+    params,
+  });
+}
+
+export async function getHealthPromotionDetail(id: number | string) {
+  return request(`/health-popularizations/${id}`, {
+    method: 'GET',
+  });
+}
+
+export async function createHealthPromotion(data: Record<string, any>) {
+  return request('/health-popularizations', {
+    method: 'POST',
+    data,
+  });
+}
+
+export async function updateHealthPromotion(id: number | string, data: Record<string, any>) {
+  return request(`/health-popularizations/${id}`, {
+    method: 'PUT',
+    data,
+  });
+}
+
+export async function deleteHealthPromotion(id: number | string) {
+  return request(`/health-popularizations/${id}`, {
+    method: 'DELETE',
+  });
+}
+
+export async function uploadHealthPromotionImage(file: File) {
+  const formData = new FormData();
+  formData.append('file', file);
+  return request('/upload/image', {
+    method: 'POST',
+    data: formData,
+  });
+}
+
+export async function uploadHealthPromotionVideo(file: File) {
+  const formData = new FormData();
+  formData.append('file', file);
+  return request('/upload/video', {
+    method: 'POST',
+    data: formData,
+  });
+}
diff --git a/tcm-training-admin/src/pages/live/health-promotion/style.less b/tcm-training-admin/src/pages/live/health-promotion/style.less
new file mode 100644
index 0000000..af2eaca
--- /dev/null
+++ b/tcm-training-admin/src/pages/live/health-promotion/style.less
@@ -0,0 +1,223 @@
+.health-promotion-page {
+  min-height: calc(100vh - 48px);
+  padding: 18px 20px 24px;
+  background: #f2f5f9;
+}
+
+.health-promotion-page__panel {
+  padding: 18px 18px 24px;
+  border-radius: 10px;
+  background: #fff;
+  box-shadow: 0 2px 10px rgba(15, 23, 42, 0.04);
+}
+
+.health-promotion-page__title {
+  margin-bottom: 16px;
+  color: #303133;
+  font-size: 20px;
+  font-weight: 500;
+}
+
+.health-promotion-search-card {
+  padding: 16px 18px 10px;
+  border: 1px solid #e7edf4;
+  border-radius: 6px;
+}
+
+.health-promotion-search-form {
+  display: grid;
+  grid-template-columns: repeat(4, minmax(200px, 1fr)) auto;
+  gap: 10px 18px;
+  align-items: start;
+}
+
+.health-promotion-search-form .ant-form-item {
+  margin-bottom: 0;
+}
+
+.health-promotion-search-form .ant-form-item-row {
+  display: grid;
+  grid-template-columns: 64px minmax(0, 1fr);
+  align-items: center;
+  column-gap: 12px;
+}
+
+.health-promotion-search-form .ant-form-item-label {
+  padding: 0;
+}
+
+.health-promotion-search-form__actions {
+  display: flex;
+  justify-content: flex-end;
+  gap: 12px;
+  min-width: 160px;
+}
+
+.health-promotion-toolbar {
+  display: flex;
+  justify-content: flex-end;
+  margin: 16px 0 10px;
+}
+
+.health-promotion-table-card {
+  overflow: hidden;
+  border: 1px solid #e7edf4;
+  border-radius: 6px;
+}
+
+.health-promotion-table-card .ant-table-thead > tr > th {
+  background: #f8fafc;
+  color: #303133;
+  font-weight: 500;
+}
+
+.health-promotion-table__title {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+}
+
+.health-promotion-table__cover-placeholder {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 64px;
+  height: 40px;
+  border-radius: 6px;
+  background: #edf2f7;
+  color: #64748b;
+  font-size: 14px;
+  font-weight: 600;
+}
+
+.health-promotion-table__actions {
+  button {
+    padding: 0;
+    border: none;
+    background: none;
+    color: #1677ff;
+    cursor: pointer;
+  }
+}
+
+.health-promotion-pagination {
+  display: flex;
+  justify-content: flex-end;
+  padding: 16px 18px;
+}
+
+.health-promotion-edit-form__section-title {
+  margin-bottom: 16px;
+  padding-left: 8px;
+  border-left: 3px solid #1677ff;
+  color: #303133;
+  font-size: 15px;
+  font-weight: 500;
+}
+
+.health-promotion-edit-form__grid {
+  display: grid;
+  grid-template-columns: repeat(3, minmax(0, 1fr));
+  gap: 0 36px;
+  align-items: start;
+}
+
+.health-promotion-edit-form .ant-form-item {
+  margin-bottom: 18px;
+}
+
+.health-promotion-edit-form__upload {
+  grid-column: span 1;
+}
+
+.health-promotion-edit-form__cover-box {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  width: 96px;
+  height: 96px;
+  overflow: hidden;
+  border: 1px dashed #cbd5e1;
+  border-radius: 8px;
+  background: #f8fafc;
+  color: #94a3b8;
+  font-size: 28px;
+  cursor: pointer;
+}
+
+.health-promotion-edit-form__switch-group {
+  display: flex;
+  align-items: center;
+  gap: 28px;
+  min-height: 72px;
+}
+
+.health-promotion-edit-form__switch-item {
+  display: flex;
+  align-items: center;
+  gap: 10px;
+}
+
+.health-promotion-edit-form__switch-item .ant-form-item {
+  margin-bottom: 0;
+}
+
+.health-promotion-edit-form__switch-label {
+  color: #606266;
+  white-space: nowrap;
+}
+
+.health-promotion-edit-form__video-upload {
+  display: flex;
+  align-items: center;
+  gap: 12px;
+}
+
+.health-promotion-edit-form__video-upload span {
+  color: #606266;
+  word-break: break-all;
+}
+
+.health-promotion-edit-form__footer {
+  display: flex;
+  gap: 12px;
+  margin-top: 12px;
+}
+
+@media (max-width: 1200px) {
+  .health-promotion-search-form {
+    grid-template-columns: repeat(2, minmax(200px, 1fr));
+  }
+
+  .health-promotion-edit-form__grid {
+    grid-template-columns: repeat(2, minmax(0, 1fr));
+  }
+}
+
+@media (max-width: 768px) {
+  .health-promotion-page {
+    padding: 12px;
+  }
+
+  .health-promotion-page__panel {
+    padding: 16px;
+  }
+
+  .health-promotion-search-form {
+    grid-template-columns: 1fr;
+  }
+
+  .health-promotion-search-form__actions {
+    justify-content: flex-start;
+  }
+
+  .health-promotion-edit-form__grid {
+    grid-template-columns: 1fr;
+  }
+
+  .health-promotion-edit-form__switch-group,
+  .health-promotion-edit-form__video-upload {
+    flex-direction: column;
+    align-items: flex-start;
+  }
+}
diff --git a/tcm-training-admin/src/pages/live/project-introduction/index.tsx b/tcm-training-admin/src/pages/live/project-introduction/index.tsx
index ab4df30..c041dd5 100644
--- a/tcm-training-admin/src/pages/live/project-introduction/index.tsx
+++ b/tcm-training-admin/src/pages/live/project-introduction/index.tsx
@@ -177,7 +177,7 @@
           {canEdit ? (
             <button
               type="button"
-              onClick={() => history.push(`/live/course/project-introduction/${record.id}/edit`)}
+              onClick={() => history.push(`/live/promotion/project-introduction/${record.id}/edit`)}
             >
               编辑
             </button>
@@ -228,7 +228,7 @@
 
         <div className="project-introduction-toolbar">
           {canAdd ? (
-            <Button type="primary" onClick={() => history.push('/live/course/project-introduction/create')}>
+            <Button type="primary" onClick={() => history.push('/live/promotion/project-introduction/create')}>
               添加
             </Button>
           ) : null}
diff --git a/tcm-training-admin/src/pages/live/project-introduction/manage.tsx b/tcm-training-admin/src/pages/live/project-introduction/manage.tsx
index 0f6797b..9dffd59 100644
--- a/tcm-training-admin/src/pages/live/project-introduction/manage.tsx
+++ b/tcm-training-admin/src/pages/live/project-introduction/manage.tsx
@@ -33,7 +33,7 @@
   const [coverImg, setCoverImg] = useState('');
   const pathname = history.location.pathname;
   const isCreate = pathname.endsWith('/create');
-  const listPagePath = '/live/course/project-introduction';
+  const listPagePath = '/live/promotion/project-introduction';
   const recordId = useMemo(() => {
     if (isCreate) {
       return '';
diff --git a/traditionalApp/manifest.json b/traditionalApp/manifest.json
index aa91d68..71fca00 100644
--- a/traditionalApp/manifest.json
+++ b/traditionalApp/manifest.json
@@ -1,9 +1,9 @@
 {
     "sassImplementationName" : "node-sass",
     "name" : "海诊康道",
-    "appid" : "__UNI__B2F54BE",
+    "appid" : "__UNI__101009D",
     "description" : "",
-    "versionName" : "1.0.22",
+    "versionName" : "1.0.23",
     "versionCode" : 122,
     "transformPx" : false,
     /* 5+App特有相关 */
diff --git a/traditionalApp/pages.json b/traditionalApp/pages.json
index 8506151..0d9da6e 100644
--- a/traditionalApp/pages.json
+++ b/traditionalApp/pages.json
@@ -170,6 +170,12 @@
 			}
 		},
 		{
+			"path": "pages/weizanLive/weizanLive",
+			"style": {
+				"navigationBarTitleText": "微赞直播"
+			}
+		},
+		{
 			"path": "pages/feedback/feedback",
 			"style": {
 				"navigationStyle": "custom"
diff --git a/traditionalApp/pages/articleDetail/articleDetail.vue b/traditionalApp/pages/articleDetail/articleDetail.vue
index cbbb0f5..90597c9 100644
--- a/traditionalApp/pages/articleDetail/articleDetail.vue
+++ b/traditionalApp/pages/articleDetail/articleDetail.vue
@@ -26,6 +26,11 @@
 			<rich-text v-if="!isVideoType" :nodes="contentNodes" class="rich-content"></rich-text>
 			<view v-if="loading" class="status-text">加载中...</view>
 			<view v-else-if="!detail.id" class="status-text">暂无详情内容</view>
+
+			<!-- 视频介绍:仅视频类型且有介绍文案时展示 -->
+			<view v-if="isVideoType && videoDescription" class="video-intro">
+				<text class="video-intro-text">{{ videoDescription }}</text>
+			</view>
 		</view>
 	</view>
 </template>
@@ -45,6 +50,7 @@
 		content : string
 		videoUrl : string
 		videoFileName : string
+		videoDescription : string
 	}
 
 	const statusBarHeight = ref(0)
@@ -66,6 +72,7 @@
 			content: '',
 			videoUrl: '',
 			videoFileName: '',
+			videoDescription: '',
 		}
 	}
 
@@ -83,12 +90,18 @@
 	})
 
 	/**
+	 * 视频介绍文案,去除首尾空白后用于详情底部展示。
+	 */
+	const videoDescription = computed(() => String(detail.value.videoDescription || '').trim())
+
+	/**
 	 * 将富文本正文转换为 `rich-text` 可直接消费的节点字符串。
 	 */
 	const contentNodes = computed(() => buildRichTextNodes(detail.value.content, '暂无详情内容'))
 
 	/**
-	 * 初始化导航栏所需的状态栏高度。
+	 * 初始化导航栏所需的状态栏高度;详情加载已在 onLoad 中完成,
+	 * 此处仅在 onLoad 未取到主键时做一次兜底,避免详情接口被请求两次。
 	 */
 	onMounted(() => {
 		uni.getSystemInfo({
@@ -96,12 +109,15 @@
 				statusBarHeight.value = res.statusBarHeight || 0
 			}
 		})
+		if (popularizationId.value) {
+			return
+		}
 		setTimeout(() => {
 			const pageOptions = getCurrentPageOptions()
-			if (!popularizationId.value) {
-				popularizationId.value = normalizeRouteParam(pageOptions?.id)
+			popularizationId.value = normalizeRouteParam(pageOptions?.id)
+			if (popularizationId.value) {
+				loadDetail()
 			}
-			loadDetail()
 		}, 0)
 	})
 
@@ -285,4 +301,19 @@
 		line-height: 40rpx;
 		color: #86909C;
 	}
+
+	.video-intro {
+		margin-top: 32rpx;
+		padding-top: 24rpx;
+		border-top: 1rpx solid #EBEDF0;
+		display: flex;
+		flex-direction: column;
+	}
+
+	.video-intro-text {
+		font-size: 28rpx;
+		line-height: 1.8;
+		color: #5B6475;
+		white-space: pre-wrap;
+	}
 </style>
diff --git a/traditionalApp/pages/healthCoursesHub/healthCoursesHub.vue b/traditionalApp/pages/healthCoursesHub/healthCoursesHub.vue
index 48956ac..7d12012 100644
--- a/traditionalApp/pages/healthCoursesHub/healthCoursesHub.vue
+++ b/traditionalApp/pages/healthCoursesHub/healthCoursesHub.vue
@@ -39,20 +39,20 @@
 }
 
 /**
- * 进入复制后的养生科普二级页。
+ * 进入复制后的养生科普二级页(contentType=2 仅视频)。
  */
 const goHealthPopularization = () => {
 	uni.navigateTo({
-		url: '/pages/healthPopularization/healthPopularization'
+		url: '/pages/healthPopularization/healthPopularization?contentType=2'
 	})
 }
 
 /**
- * 进入原健康科普页,作为「健康知识」二级页。
+ * 进入原健康科普页,作为「健康知识」二级页(contentType=1 仅图文)。
  */
 const goHealthKnowledge = () => {
 	uni.navigateTo({
-		url: '/pages/publish/publish'
+		url: '/pages/publish/publish?contentType=1'
 	})
 }
 </script>
diff --git a/traditionalApp/pages/healthPopularization/healthPopularization.vue b/traditionalApp/pages/healthPopularization/healthPopularization.vue
index 140f81a..8a8045f 100644
--- a/traditionalApp/pages/healthPopularization/healthPopularization.vue
+++ b/traditionalApp/pages/healthPopularization/healthPopularization.vue
@@ -12,9 +12,7 @@
 			<view v-if="articleList.length" class="article-list">
 				<view class="article-item" v-for="item in articleList" :key="item.id" @tap="goToDetail(item.id)">
 					<image class="article-img" :src="item.coverImage || defaultCoverImage" mode="aspectFill"></image>
-					<view class="article-shadow">
-						<text class="article-text">{{ item.title }}</text>
-					</view>
+					<text class="article-title">{{ item.title }}</text>
 				</view>
 			</view>
 			<view v-else-if="loading" class="status-text">加载中...</view>
@@ -25,7 +23,7 @@
 
 <script setup lang="ts">
 import { ref, onMounted } from 'vue';
-import { onPullDownRefresh } from '@dcloudio/uni-app'
+import { onLoad, onPullDownRefresh } from '@dcloudio/uni-app'
 import { getHealthPopularizationList } from './service'
 
 interface PopularizationListItem {
@@ -40,6 +38,18 @@
 const loading = ref(false)
 const articleList = ref<PopularizationListItem[]>([])
 const defaultCoverImage = '/static/image/home/zixun.png'
+// 内容类型:2 养生科普,默认按养生科普过滤。
+const contentType = ref<number>(2)
+
+/**
+ * 读取路由参数中的内容类型,用于按类型过滤列表。
+ */
+onLoad((options) => {
+	const raw = Number(options?.contentType)
+	if (!Number.isNaN(raw) && raw > 0) {
+		contentType.value = raw
+	}
+})
 
 /**
  * 页面加载时初始化状态栏高度并拉取养生科普列表。
@@ -84,7 +94,7 @@
 async function loadPopularizationList() {
 	loading.value = true
 	try {
-		const response = await getHealthPopularizationList()
+		const response = await getHealthPopularizationList(contentType.value)
 		if (response?.code !== 0 || !Array.isArray(response.data)) {
 			articleList.value = []
 			return
@@ -163,43 +173,36 @@
 
 .article-list {
 	display: flex;
-	justify-content: space-between;
-	flex-wrap: wrap;
+	flex-direction: column;
 }
 
 .article-item {
-	width: 328rpx;
-	height: 328rpx;
-	border-radius: 16rpx;
-	position: relative;
-	overflow: hidden;
-	margin-bottom: 24rpx;
-}
-
-.article-img {
-	width: 100%;
-	height: 100%;
-}
-
-.article-shadow {
-	position: absolute;
-	bottom: 0;
-	left: 0;
-	width: 100%;
-	height: 64rpx;
-	background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.8) 100%);
 	display: flex;
 	align-items: center;
-	padding: 0 16rpx;
+	width: 100%;
+	padding: 24rpx 0;
+	border-bottom: 1rpx solid #F0F0F0;
 	box-sizing: border-box;
 }
 
-.article-text {
-	color: #FFFFFF;
-	font-size: 24rpx;
-	white-space: nowrap;
+.article-img {
+	width: 200rpx;
+	height: 150rpx;
+	border-radius: 12rpx;
+	flex-shrink: 0;
+	background-color: #F5F6F8;
+}
+
+.article-title {
+	flex: 1;
+	margin-left: 24rpx;
+	font-size: 30rpx;
+	line-height: 44rpx;
+	color: #333;
+	display: -webkit-box;
+	-webkit-box-orient: vertical;
+	-webkit-line-clamp: 2;
 	overflow: hidden;
 	text-overflow: ellipsis;
-	width: 100%;
 }
 </style>
diff --git a/traditionalApp/pages/healthPopularization/service.js b/traditionalApp/pages/healthPopularization/service.js
index 419cab1..66cc99b 100644
--- a/traditionalApp/pages/healthPopularization/service.js
+++ b/traditionalApp/pages/healthPopularization/service.js
@@ -2,7 +2,9 @@
 
 /**
  * 获取 APP 养生科普列表(与原健康科普共用接口)。
+ * @param {number} [contentType] 内容类型:1 健康知识、2 养生科普;不传返回全部。
  */
-export const getHealthPopularizationList = () => {
-	return request.get('/api/app/health-popularizations', {}, false, false)
+export const getHealthPopularizationList = (contentType) => {
+	const params = contentType == null ? {} : { contentType }
+	return request.get('/api/app/health-popularizations', params, false, false)
 }
diff --git a/traditionalApp/pages/home/home.vue b/traditionalApp/pages/home/home.vue
index 0cc782e..8d4761b 100644
--- a/traditionalApp/pages/home/home.vue
+++ b/traditionalApp/pages/home/home.vue
@@ -379,7 +379,7 @@
 				return;
 			}
 
-			const webviewUrl = `/pages/webview/webview?url=${encodeURIComponent(targetUrl)}&title=${encodeURIComponent('微赞直播')}&clearCache=1`;
+			const webviewUrl = `/pages/weizanLive/weizanLive?url=${encodeURIComponent(targetUrl)}&title=${encodeURIComponent('微赞直播')}`;
 			console.log('[goWeiZanLive] 准备跳转 WebView:', webviewUrl);
 
 			uni.navigateTo({
diff --git a/traditionalApp/pages/publish/publish.vue b/traditionalApp/pages/publish/publish.vue
index 9f48c75..e13aa36 100644
--- a/traditionalApp/pages/publish/publish.vue
+++ b/traditionalApp/pages/publish/publish.vue
@@ -15,9 +15,7 @@
 			<view v-if="articleList.length" class="article-list">
 				<view class="article-item" v-for="item in articleList" :key="item.id" @tap="goToDetail(item.id)">
 					<image class="article-img" :src="item.coverImage || defaultCoverImage" mode="aspectFill"></image>
-					<view class="article-shadow">
-						<text class="article-text">{{ item.title }}</text>
-					</view>
+					<text class="article-title">{{ item.title }}</text>
 				</view>
 			</view>
 			<view v-else-if="loading" class="status-text">加载中...</view>
@@ -28,7 +26,7 @@
 
 <script setup lang="ts">
 import { ref, onMounted } from 'vue';
-import { onPullDownRefresh } from '@dcloudio/uni-app'
+import { onLoad, onPullDownRefresh } from '@dcloudio/uni-app'
 import { getHealthPopularizationList } from './service'
 
 interface PopularizationListItem {
@@ -43,6 +41,18 @@
 const loading = ref(false)
 const articleList = ref<PopularizationListItem[]>([])
 const defaultCoverImage = '/static/image/home/zixun.png'
+// 内容类型:1 健康知识,默认按健康知识过滤。
+const contentType = ref<number>(1)
+
+/**
+ * 读取路由参数中的内容类型,用于按类型过滤列表。
+ */
+onLoad((options) => {
+	const raw = Number(options?.contentType)
+	if (!Number.isNaN(raw) && raw > 0) {
+		contentType.value = raw
+	}
+})
 
 /**
  * 页面加载时初始化状态栏高度并拉取健康知识列表。
@@ -87,7 +97,7 @@
 async function loadPopularizationList() {
 	loading.value = true
 	try {
-		const response = await getHealthPopularizationList()
+		const response = await getHealthPopularizationList(contentType.value)
 		if (response?.code !== 0 || !Array.isArray(response.data)) {
 			articleList.value = []
 			return
@@ -166,43 +176,36 @@
 
 .article-list {
 	display: flex;
-	justify-content: space-between;
-	flex-wrap: wrap;
+	flex-direction: column;
 }
 
 .article-item {
-	width: 328rpx;
-	height: 328rpx;
-	border-radius: 16rpx;
-	position: relative;
-	overflow: hidden;
-	margin-bottom: 24rpx;
-}
-
-.article-img {
-	width: 100%;
-	height: 100%;
-}
-
-.article-shadow {
-	position: absolute;
-	bottom: 0;
-	left: 0;
-	width: 100%;
-	height: 64rpx;
-	background: linear-gradient(180deg, rgba(0, 0, 0, 0) 0%, rgba(0, 0, 0, 0.8) 100%);
 	display: flex;
 	align-items: center;
-	padding: 0 16rpx;
+	width: 100%;
+	padding: 24rpx 0;
+	border-bottom: 1rpx solid #F0F0F0;
 	box-sizing: border-box;
 }
 
-.article-text {
-	color: #FFFFFF;
-	font-size: 24rpx;
-	white-space: nowrap;
+.article-img {
+	width: 200rpx;
+	height: 150rpx;
+	border-radius: 12rpx;
+	flex-shrink: 0;
+	background-color: #F5F6F8;
+}
+
+.article-title {
+	flex: 1;
+	margin-left: 24rpx;
+	font-size: 30rpx;
+	line-height: 44rpx;
+	color: #333;
+	display: -webkit-box;
+	-webkit-box-orient: vertical;
+	-webkit-line-clamp: 2;
 	overflow: hidden;
 	text-overflow: ellipsis;
-	width: 100%;
 }
 </style>
diff --git a/traditionalApp/pages/publish/service.js b/traditionalApp/pages/publish/service.js
index a42ca25..914e865 100644
--- a/traditionalApp/pages/publish/service.js
+++ b/traditionalApp/pages/publish/service.js
@@ -2,7 +2,9 @@
 
 /**
  * 获取 APP 健康科普列表。
+ * @param {number} [contentType] 内容类型:1 健康知识、2 养生科普;不传返回全部。
  */
-export const getHealthPopularizationList = () => {
-	return request.get('/api/app/health-popularizations', {}, false, false)
+export const getHealthPopularizationList = (contentType) => {
+	const params = contentType == null ? {} : { contentType }
+	return request.get('/api/app/health-popularizations', params, false, false)
 }
diff --git a/traditionalApp/pages/weizanLive/weizanLive.vue b/traditionalApp/pages/weizanLive/weizanLive.vue
new file mode 100644
index 0000000..d9f0f57
--- /dev/null
+++ b/traditionalApp/pages/weizanLive/weizanLive.vue
@@ -0,0 +1,61 @@
+<template>
+	<view class="container">
+		<web-view v-if="webViewUrl" class="webview-content" :src="webViewUrl"></web-view>
+		<view v-else class="empty-box"><text class="empty-text">链接地址无效</text></view>
+	</view>
+</template>
+<script setup>
+import { ref } from 'vue'
+import { onLoad, onUnload } from '@dcloudio/uni-app'
+import { clearWebViewData } from '@/utils/webview-cache.js'
+
+const webViewUrl = ref('')
+const WEIXIN_APP_ID = 'wx074c1f0cf5a0ecf4'
+let originalUserAgent = ''
+
+onLoad((options) => {
+	const url = decodeValue(options?.url)
+	const title = decodeValue(options?.title)
+	if (title) uni.setNavigationBarTitle({ title })
+	// #ifdef APP-PLUS
+	clearWebViewData()
+	injectUserAgent()
+	console.log('[weizanLive] 跳转前完整 UA:', plus.navigator.getUserAgent() || '')
+	// #endif
+	webViewUrl.value = url
+})
+
+onUnload(() => {
+	// #ifdef APP-PLUS
+	if (originalUserAgent) {
+		try { plus.navigator.setUserAgent(originalUserAgent, false) } catch (e) {}
+		originalUserAgent = ''
+	}
+	// #endif
+})
+
+function injectUserAgent() {
+	// #ifdef APP-PLUS
+	try {
+		const baseUA = plus.navigator.getUserAgent() || ''
+		if (baseUA.indexOf('webchatPay/') >= 0) {
+			originalUserAgent = baseUA.replace(/\s*webchatPay\/\S+/g, '')
+			return
+		}
+		originalUserAgent = baseUA
+		plus.navigator.setUserAgent(`${baseUA} webchatPay/${WEIXIN_APP_ID}`.trim(), false)
+	} catch (e) { console.error('[weizanLive] UA 注入失败:', e) }
+	// #endif
+}
+
+function decodeValue(value) {
+	if (typeof value !== 'string' || !value.trim()) return ''
+	try { return decodeURIComponent(value) } catch (e) { return value.trim() }
+}
+</script>
+<style lang="scss" scoped>
+.container { width: 100vw; min-height: 100vh; background: #fff; }
+.webview-content { width: 100%; height: 100vh; }
+.empty-box { min-height: 100vh; display: flex; align-items: center; justify-content: center; }
+.empty-text { font-size: 28rpx; color: #999; }
+</style>
diff --git a/traditionalApp/utils/weizan-pay-bridge.js b/traditionalApp/utils/weizan-pay-bridge.js
index 677c954..e910e86 100644
--- a/traditionalApp/utils/weizan-pay-bridge.js
+++ b/traditionalApp/utils/weizan-pay-bridge.js
@@ -17,6 +17,7 @@
 
 const PAY_BRIDGE_NAME = 'jumpToMiniProgramPay'
 const PAY_BRIDGE_ANDROID_KEY = 'android' // H5 调 window.android.xxx
+const LOG_TAG = '[weizanPay]'
 
 /**
  * 给指定 webview 注册微赞支付 JSBridge。
@@ -52,9 +53,12 @@
 	try {
 		const platform = String(uni.getSystemInfoSync().platform || '').toLowerCase()
 		if (platform === 'android') {
-			// Android 移除注入的 JS 接口
+			// Android 移除注入的 JS 接口(同样要作用在原生 WebView 上)
 			try {
-				plus.android.invoke(webviewInstance, 'removeJavascriptInterface', PAY_BRIDGE_ANDROID_KEY)
+				const nativeWebView = getAndroidNativeWebView(webviewInstance)
+				if (nativeWebView) {
+					plus.android.invoke(nativeWebView, 'removeJavascriptInterface', PAY_BRIDGE_ANDROID_KEY)
+				}
 			} catch (e) {}
 		}
 		// iOS:WKUserContentController 的 messageHandler 通常随 webview 销毁自动回收,
@@ -115,15 +119,33 @@
 
 // ===== Android 实现:注入 window.android.jumpToMiniProgramPay =====
 function registerAndroidPayBridge(webviewInstance, onPay) {
+	console.log(LOG_TAG, '[Android] 开始注册 JSBridge,注入 key=', PAY_BRIDGE_ANDROID_KEY, '方法名=', PAY_BRIDGE_NAME)
+	console.log(LOG_TAG, '[Android] webviewInstance=', webviewInstance ? '[Object]' : 'null')
+	// plus.webview.create 返回的是 JS 包装对象,不能直接反射;
+	// 必须先取底层原生 WebView(5+ ADWebView,是 android.webkit.WebView 的子类)再反射,
+	// 否则 getSettings / addJavascriptInterface 都会失败。
+	const nativeWebView = getAndroidNativeWebView(webviewInstance)
+	console.log(LOG_TAG, '[Android] nativeInstanceObject=', nativeWebView ? '[Object]' : 'null')
+	// 反射验证是否是真原生 WebView(应暴露 getSettings)
+	const settings = safeAndroidInvoke(nativeWebView, 'getSettings')
+	console.log(LOG_TAG, '[Android] getSettings 反射结果=', settings ? '[Object]' : 'null')
+	if (!settings) {
+		console.error(LOG_TAG, '[Android] 未取到原生 WebView 或不暴露 getSettings,注册中止')
+		console.error(LOG_TAG, '[Android] 请确认调用方传入的是 plus.webview.create 创建的子 webview,而不是 currentWebview()')
+		return
+	}
 	try {
-		const JsInterface = plus.android.implements('io.dcloud.js.WeizanPayJsInterface', {
+		// java.io.Serializable 一定存在、无强制方法,足以承载动态代理
+		// H5 调 window.android.xxx 时由 Proxy 拦截转发到 JS 函数
+		const JsInterface = plus.android.implements('java.io.Serializable', {
 			[PAY_BRIDGE_NAME]: function (paramsJson) {
-				// 注意:此日志运行在原生子线程
-				console.log('[weizanPay][Android] JS 接口被触发, 收到原始字符串:', paramsJson)
+				console.log(LOG_TAG, '===== [Android] H5 调用 window.android.' + PAY_BRIDGE_NAME + ' =====')
+				console.log(LOG_TAG, '[Android] 原始 paramsJson=', safeStringify(paramsJson))
 				// JS 接口回调在原生子线程,必须切回 UI 线程才能拉起微信 SDK
 				plus.android.runOnUiThread(() => {
-					console.log('[weizanPay][Android] 已切回 UI 线程, 开始解析参数')
+					console.log(LOG_TAG, '[Android] 已进入 UI 线程,开始解析参数')
 					const params = normalizePayParams(parseJsonSafe(paramsJson))
+					console.log(LOG_TAG, '[Android] 解析后 params=', safeStringify(params))
 					if (typeof onPay === 'function') {
 						try { onPay(params) } catch (e) {}
 					}
@@ -131,64 +153,189 @@
 				})
 			}
 		})
-		plus.android.invoke(webviewInstance, 'addJavascriptInterface', JsInterface, PAY_BRIDGE_ANDROID_KEY)
-		console.log('[weizanPay][Android] JSBridge 已注册')
+		console.log(LOG_TAG, '[Android] JsInterface 已创建:', JsInterface ? '[Object]' : 'null')
+		// 注入到原生 WebView(而非 JS 包装对象),H5 端才能拿到 window.android.xxx
+		plus.android.invoke(nativeWebView, 'addJavascriptInterface', JsInterface, PAY_BRIDGE_ANDROID_KEY)
+		console.log(LOG_TAG, '[Android] addJavascriptInterface 完成,window.' + PAY_BRIDGE_ANDROID_KEY + ' 已注入')
+		// 通过 evalJS 验证 H5 端 window.android 是否真的能访问到
+		try {
+			if (typeof webviewInstance.evalJS === 'function') {
+				webviewInstance.evalJS(`
+					try {
+						if (typeof window.android === 'undefined' || window.android === null) {
+							console.log('[weizanPay][H5] window.android 不存在');
+						} else {
+							console.log('[weizanPay][H5] window.android 存在, keys=' + Object.keys(window.android).join(','));
+							console.log('[weizanPay][H5] window.android.${PAY_BRIDGE_NAME} 类型=' + typeof window.android.${PAY_BRIDGE_NAME});
+						}
+					} catch (e) {
+						console.log('[weizanPay][H5] 检查 window.android 异常: ' + e.message);
+					}
+				`)
+			}
+		} catch (e) {
+			console.warn(LOG_TAG, '[Android] evalJS 验证失败:', e && e.message)
+		}
 	} catch (e) {
-		console.error('[weizanPay][Android] 注册失败:', e)
+		console.error(LOG_TAG, '[Android] 注册 JSBridge 失败:', e)
+		console.error(LOG_TAG, '[Android] 异常 message=', e && e.message)
+	}
+}
+
+/**
+ * 取 plus.webview 实例底层的原生 android.webkit.WebView。
+ * plus.webview.create 返回的是 JS 包装对象,直接反射 getSettings/addJavascriptInterface 会失败,
+ * 必须先取到原生 WebView。优先用官方 nativeInstanceObject(),失败再退回 obtainWebview()。
+ */
+function getAndroidNativeWebView(webview) {
+	if (!webview) {
+		return null
+	}
+	// 1. 官方 API:WebviewObject.nativeInstanceObject() 返回原生 WebView
+	if (typeof webview.nativeInstanceObject === 'function') {
+		try {
+			const nativeObj = webview.nativeInstanceObject()
+			if (nativeObj) {
+				return nativeObj
+			}
+		} catch (e) {
+			console.warn(LOG_TAG, '[Android] nativeInstanceObject 调用失败:', e && e.message)
+		}
+	}
+	// 2. 兼容:部分运行时通过 obtainWebview 取原生 WebView
+	if (typeof webview.obtainWebview === 'function') {
+		try {
+			const obtained = webview.obtainWebview()
+			if (obtained) {
+				return obtained
+			}
+		} catch (e) {}
+	}
+	return null
+}
+
+/**
+ * 安全调用 plus.android.invoke,失败返回 null。
+ */
+function safeAndroidInvoke(obj, methodName, ...args) {
+	try {
+		return plus.android.invoke(obj, methodName, ...args)
+	} catch (e) {
+		return null
 	}
 }
 
 // ===== iOS 实现:注册 window.webkit.messageHandlers.jumpToMiniProgramPay =====
 function registerIOSPayBridge(webviewInstance, onPay) {
+	console.log(LOG_TAG, '[iOS] 开始注册 JSBridge,handler name=', PAY_BRIDGE_NAME)
+	console.log(LOG_TAG, '[iOS] webviewInstance=', webviewInstance ? '[Object]' : 'null')
 	try {
 		// 实现 WKScriptMessageHandler 协议
 		const MessageHandler = plus.ios.implements('NSObject<WKScriptMessageHandler>', {
 			'userContentController:didReceiveScriptMessage:': function (controller, message) {
-				console.log('[weizanPay][iOS] messageHandler 被触发, message=', message)
+				console.log(LOG_TAG, '===== [iOS] didReceiveScriptMessage 被调用 =====')
 				if (!message) {
-					console.warn('[weizanPay][iOS] message 为空,终止')
+					console.warn(LOG_TAG, '[iOS] message 为空,跳过')
 					return
 				}
 				// message.name === 'jumpToMiniProgramPay',message.body 是 H5 传的参数
 				let raw = message
 				try {
 					const body = plus.ios.invoke(message, 'body')
-					console.log('[weizanPay][iOS] message.body=', body, '类型:', typeof body)
+					console.log(LOG_TAG, '[iOS] message.body=', safeStringify(body))
 					if (body !== undefined && body !== null) {
 						raw = body
 					}
-				} catch (e) {
-					console.error('[weizanPay][iOS] 取 message.body 失败:', e)
-				}
+				} catch (e) {}
+				console.log(LOG_TAG, '[iOS] 原始 raw=', safeStringify(raw))
 				const params = normalizePayParams(parseJsonSafe(raw))
+				console.log(LOG_TAG, '[iOS] 解析后 params=', safeStringify(params))
 				if (typeof onPay === 'function') {
 					try { onPay(params) } catch (e) {}
 				}
 				jumpToMiniProgramPay(params)
 			}
 		})
+		console.log(LOG_TAG, '[iOS] MessageHandler 已创建:', MessageHandler ? '[Object]' : 'null')
 		// 取底层 WKWebView:plus.webview 实例 → valueForKey('webView') 或直接复用
+		console.log(LOG_TAG, '[iOS] 尝试 valueForKey:webView')
 		const wkWebView = safeIosInvoke(webviewInstance, 'valueForKey:', 'webView') || webviewInstance
+		console.log(LOG_TAG, '[iOS] wkWebView=', wkWebView ? '[Object]' : 'null')
 		const configuration = safeIosInvoke(wkWebView, 'configuration')
+		console.log(LOG_TAG, '[iOS] configuration=', configuration ? '[Object]' : 'null')
 		if (!configuration) {
-			console.error('[weizanPay][iOS] 未拿到 WKWebView configuration')
+			console.error(LOG_TAG, '[iOS] 未拿到 WKWebView configuration,注册中止')
+			console.error(LOG_TAG, '[iOS] 请确认传入的是 plus.webview.create 创建的子 webview')
 			return
 		}
 		const userContentController = safeIosInvoke(configuration, 'userContentController')
+		console.log(LOG_TAG, '[iOS] userContentController=', userContentController ? '[Object]' : 'null')
 		if (!userContentController) {
-			console.error('[weizanPay][iOS] 未拿到 userContentController')
+			console.error(LOG_TAG, '[iOS] 未拿到 userContentController,注册中止')
 			return
 		}
 		plus.ios.invoke(userContentController, 'addScriptMessageHandler:name:', MessageHandler, PAY_BRIDGE_NAME)
-		console.log('[weizanPay][iOS] JSBridge 已注册')
+		console.log(LOG_TAG, '[iOS] addScriptMessageHandler 完成,window.webkit.messageHandlers.' + PAY_BRIDGE_NAME + ' 已注册')
+		// 验证 H5 端是否能访问到 messageHandlers
+		try {
+			if (typeof webviewInstance.evalJS === 'function') {
+				webviewInstance.evalJS(`
+					try {
+						if (!window.webkit || !window.webkit.messageHandlers) {
+							console.log('[weizanPay][H5] window.webkit.messageHandlers 不存在');
+						} else {
+							var names = Object.keys(window.webkit.messageHandlers);
+							console.log('[weizanPay][H5] messageHandlers names=' + names.join(','));
+							var handler = window.webkit.messageHandlers.${PAY_BRIDGE_NAME};
+							console.log('[weizanPay][H5] ${PAY_BRIDGE_NAME} handler 类型=' + typeof handler);
+						}
+					} catch (e) {
+						console.log('[weizanPay][H5] 检查 messageHandlers 异常: ' + e.message);
+					}
+				`)
+			}
+		} catch (e) {
+			console.warn(LOG_TAG, '[iOS] evalJS 验证失败:', e && e.message)
+		}
 	} catch (e) {
-		console.error('[weizanPay][iOS] 注册失败:', e)
+		console.error(LOG_TAG, '[iOS] 注册 JSBridge 失败:', e)
+		console.error(LOG_TAG, '[iOS] 异常 message=', e && e.message)
 	}
 }
 
 // ===== 辅助函数 =====
 
 /**
+ * 安全序列化任意值,用于日志打印。原生对象、循环引用、undefined 都不会抛错。
+ */
+function safeStringify(value) {
+	try {
+		if (value === undefined) {
+			return 'undefined'
+		}
+		if (value === null) {
+			return 'null'
+		}
+		if (typeof value === 'string') {
+			return value
+		}
+		if (typeof value === 'number' || typeof value === 'boolean') {
+			return String(value)
+		}
+		if (typeof value === 'function') {
+			return '[Function]'
+		}
+		return JSON.stringify(value)
+	} catch (e) {
+		try {
+			return String(value)
+		} catch (e2) {
+			return '[Unserializable]'
+		}
+	}
+}
+
+/**
  * 把 H5 传过来的 params 归一化为标准结构。
  * 同时兼容下划线命名(order_id)与驼峰命名(orderId)。
  *

--
Gitblit v1.7.1