Przeglądaj źródła

init: full project upload - Enagic Kangen water mini-program platform

Spring Boot + Vue 2 + UniApp extending Lilishop B2B2C.
Includes code (Java/Vue/UniApp), requirements docs, courseware, and AGENTS.md.
liaoxg 4 miesięcy temu
rodzic
commit
55198805af
89 zmienionych plików z 10568 dodań i 0 usunięć
  1. 76 0
      AGENTS.md
  2. 164 0
      代码/README.md
  3. 572 0
      代码/SPEC.md
  4. 335 0
      代码/enagic-lilishop/enagic-plugin/DB/enagic_init.sql
  5. 48 0
      代码/enagic-lilishop/enagic-plugin/build.sh
  6. 78 0
      代码/enagic-lilishop/enagic-plugin/config/application-enagic.yml
  7. 76 0
      代码/enagic-lilishop/enagic-plugin/docker-compose.yml
  8. 258 0
      代码/enagic-lilishop/enagic-plugin/docs/DEPLOYMENT.md
  9. 196 0
      代码/enagic-lilishop/enagic-plugin/docs/INTEGRATION.md
  10. 157 0
      代码/enagic-lilishop/enagic-plugin/docs/PHASE0_SETUP.md
  11. 32 0
      代码/enagic-lilishop/enagic-plugin/docs/README.md
  12. 200 0
      代码/enagic-lilishop/enagic-plugin/docs/TEST_CHECKLIST.md
  13. 86 0
      代码/enagic-lilishop/enagic-plugin/enagic-admin/README.md
  14. 37 0
      代码/enagic-lilishop/enagic-plugin/enagic-admin/pom.xml
  15. 160 0
      代码/enagic-lilishop/enagic-plugin/enagic-admin/src/main/vue/api/enagic.js
  16. 54 0
      代码/enagic-lilishop/enagic-plugin/enagic-admin/src/main/vue/router/index.js
  17. 166 0
      代码/enagic-lilishop/enagic-plugin/enagic-admin/src/main/vue/views/enagic/ai/conversation-log.vue
  18. 229 0
      代码/enagic-lilishop/enagic-plugin/enagic-admin/src/main/vue/views/enagic/ai/knowledge-list.vue
  19. 103 0
      代码/enagic-lilishop/enagic-plugin/enagic-admin/src/main/vue/views/enagic/deduction/account-list.vue
  20. 199 0
      代码/enagic-lilishop/enagic-plugin/enagic-admin/src/main/vue/views/enagic/health-advisor/list.vue
  21. 170 0
      代码/enagic-lilishop/enagic-plugin/enagic-admin/src/main/vue/views/enagic/health-advisor/medal.vue
  22. 234 0
      代码/enagic-lilishop/enagic-plugin/enagic-admin/src/main/vue/views/enagic/operation/flow-list.vue
  23. 142 0
      代码/enagic-lilishop/enagic-plugin/enagic-admin/src/main/vue/views/enagic/operation/plan-list.vue
  24. 131 0
      代码/enagic-lilishop/enagic-plugin/enagic-admin/src/main/vue/views/enagic/transfer/list.vue
  25. 147 0
      代码/enagic-lilishop/enagic-plugin/enagic-admin/src/main/vue/views/enagic/vip/config-list.vue
  26. 69 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/pom.xml
  27. 50 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/common/ResultUtil.java
  28. 20 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/config/EnagicApiAutoConfiguration.java
  29. 101 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/controller/buyer/AiChatController.java
  30. 50 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/controller/buyer/DeductionBuyerController.java
  31. 175 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/controller/buyer/HealthAdvisorBuyerController.java
  32. 60 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/controller/buyer/OperationBuyerController.java
  33. 67 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/controller/manager/AiKnowledgeManagerController.java
  34. 68 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/controller/manager/DeductionManagerController.java
  35. 101 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/controller/manager/HealthAdvisorManagerController.java
  36. 110 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/controller/manager/OperationManagerController.java
  37. 106 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/controller/manager/TransferManagerController.java
  38. 97 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/controller/manager/VipManagerController.java
  39. 9 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/AdvisorMedalMapper.java
  40. 9 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/AiConversationMapper.java
  41. 9 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/AiKnowledgeMapper.java
  42. 9 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/DeductionLogMapper.java
  43. 9 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/EnagicVipConfigMapper.java
  44. 9 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/HealthAdvisorMapper.java
  45. 9 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/MemberDeductionMapper.java
  46. 9 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/MemberTransferMapper.java
  47. 9 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/MemberVipMapper.java
  48. 9 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/OperationFlowMapper.java
  49. 9 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/OperationPlanMapper.java
  50. 9 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/OperationRecordMapper.java
  51. 243 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/service/AiChatService.java
  52. 190 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/service/DeductionService.java
  53. 169 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/service/HealthAdvisorService.java
  54. 60 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/service/OperationFlowService.java
  55. 218 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/service/OperationPlanService.java
  56. 56 0
      代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/service/VipService.java
  57. 48 0
      代码/enagic-lilishop/enagic-plugin/enagic-consumer/pom.xml
  58. 115 0
      代码/enagic-lilishop/enagic-plugin/enagic-consumer/src/main/java/com/enagic/modules/enagic/consumer/OperationRemindJob.java
  59. 157 0
      代码/enagic-lilishop/enagic-plugin/enagic-consumer/src/main/java/com/enagic/modules/enagic/consumer/OrderEventConsumer.java
  60. 22 0
      代码/enagic-lilishop/enagic-plugin/enagic-entity/pom.xml
  61. 65 0
      代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/AdvisorMedal.java
  62. 65 0
      代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/AiConversation.java
  63. 75 0
      代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/AiKnowledge.java
  64. 35 0
      代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/ArticleQr.java
  65. 37 0
      代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/BehaviorLog.java
  66. 71 0
      代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/DeductionLog.java
  67. 84 0
      代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/EnagicVipConfig.java
  68. 111 0
      代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/HealthAdvisor.java
  69. 61 0
      代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/MemberDeduction.java
  70. 80 0
      代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/MemberTransfer.java
  71. 81 0
      代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/MemberVip.java
  72. 63 0
      代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/OperationFlow.java
  73. 87 0
      代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/OperationPlan.java
  74. 74 0
      代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/OperationRecord.java
  75. 102 0
      代码/enagic-lilishop/enagic-plugin/pom.xml
  76. 58 0
      代码/enagic-lilishop/pom.xml
  77. 135 0
      代码/enagic-uniapp/README.md
  78. 61 0
      代码/enagic-uniapp/api/enagic.js
  79. 310 0
      代码/enagic-uniapp/pages/enagic/ai-chat/index.vue
  80. 291 0
      代码/enagic-uniapp/pages/enagic/deduction/index.vue
  81. 214 0
      代码/enagic-uniapp/pages/enagic/health-advisor/customers.vue
  82. 326 0
      代码/enagic-uniapp/pages/enagic/health-advisor/home.vue
  83. 167 0
      代码/enagic-uniapp/pages/enagic/health-advisor/medals.vue
  84. 318 0
      代码/enagic-uniapp/pages/enagic/operation/my-plans.vue
  85. 215 0
      代码/enagic-uniapp/pages/enagic/vip/index.vue
  86. 249 0
      代码/enagic-uniapp/pages/enagic/vip/my-vip.vue
  87. BIN
      需求文档/本希甄选小程序0212.pdf
  88. BIN
      需求文档/本希甄选小程序0225.xlsx
  89. 623 0
      需求文档/本希甄选小程序需求文档.md

+ 76 - 0
AGENTS.md

@@ -0,0 +1,76 @@
+# PROJECT KNOWLEDGE BASE
+
+**Generated:** 2026-05-07
+**Branch:** master
+
+## OVERVIEW
+Enagic (元気) 本希甄选 — WeChat mini-program platform for Kangen water business. Spring Boot + Vue 2 + UniApp, extending Lilishop B2B2C.
+
+## STRUCTURE
+```
+enagic/
+├── 课件/          # Courseware materials
+├── 资料文档/       # Reference documentation
+├── 资料/          # Misc materials (PDFs, XLSX)
+├── 需求文档/       # Requirement docs (PDF, XLSX, MD)
+├── 测试文档/       # Test docs (reserved)
+├── 代码/          # Source code
+│   ├── SPEC.md                    # Tech spec (requirements, design, API, DB)
+│   ├── enagic-lilishop/           # Backend: Maven multi-module plugin
+│   │   ├── enagic-entity/         # Entity layer (14 new tables)
+│   │   ├── enagic-api/            # Business API (core extension)
+│   │   ├── enagic-admin/          # Admin panel (Vue 2 + ViewUI)
+│   │   └── enagic-consumer/       # Event consumer / scheduled tasks
+│   └── enagic-uniapp/             # Mini-program (forked from lilishop-uniapp)
+└── AGENTS.md
+```
+
+## WHERE TO LOOK
+| Task | Location |
+|------|----------|
+| Tech spec & API docs | `代码/SPEC.md` |
+| Backend (Spring Boot + Maven) | `代码/enagic-lilishop/enagic-plugin/` |
+| Admin frontend (Vue 2) | `代码/enagic-lilishop/enagic-plugin/enagic-admin/` |
+| Mini-program (UniApp) | `代码/enagic-uniapp/` |
+| Database schema | `代码/enagic-lilishop/enagic-plugin/DB/enagic_init.sql` |
+| Deployment guide | `代码/enagic-lilishop/enagic-plugin/docs/` |
+| Requirements docs | `需求文档/` |
+| Courseware | `课件/` |
+
+## KEY MODULES
+| Module | Tech | Description |
+|--------|------|-------------|
+| AI Digital Human | Java + SiliconFlow API | Real-time AI chat with knowledge base |
+| Health Advisor | Java + UniApp | Referral system, achievements, medals |
+| VIP System | Java + UniApp | No-expiry membership, gratitude reminders |
+| Deduction Account | Java + UniApp | Independent balance for order payments |
+| Operation Flow | Java + RocketMQ | Auto-generate maintenance plans after order |
+| QR Code Sharing | Java + UniApp | Track referral relationships |
+
+## ARCHITECTURE
+- **Plugin pattern**: Maven module `enagic-plugin` injected via Spring `@Component`
+- **API isolation**: `/enagic/**` namespace, no conflict with Lilishop originals
+- **Event-driven**: RocketMQ listens to Lilishop order events
+- **Scheduled tasks**: XXL-Job for maintenance plan scans, VIP reminders
+
+## DATABASE
+14 new tables with prefix `li_enagic_` (see `SPEC.md` §4 for full schema).
+
+## CONVENTIONS
+- Java: Spring Boot 2.4 + MyBatis-Plus, standard Maven layout
+- Vue: Vue 2 + ViewUI (iView), single-file components
+- UniApp: uView UI framework
+- API: RESTful under `/enagic/buyer/` (customer) and `/enagic/manager/` (admin)
+
+## COMMANDS
+```bash
+git pull origin master           # Sync repo
+mvn clean package -DskipTests    # Build (requires Lilishop v4.3 source)
+```
+
+## NOTES
+- Depends on Lilishop B2B2C v4.3 source code for compilation
+- Do NOT modify Lilishop core code — all extensions in `enagic-plugin/`
+- Chinese filenames common. Use `chcp 65001` for Unicode in PowerShell
+- Remote: `http://git.iwintrue.com/liaoxg/enagic.git`
+- Full tech spec: `代码/SPEC.md`

+ 164 - 0
代码/README.md

@@ -0,0 +1,164 @@
+# Enagic 本希甄选小程序项目
+
+> **项目路径:** `/mnt/e/workspace/enagic/代码/enagic-lilishop` 和 `/mnt/e/workspace/enagic/代码/enagic-uniapp`
+
+## 项目组成
+
+```
+代码/
+├── SPEC.md                          # 技术方案文档(完整需求、设计、API、数据库)
+│
+├── enagic-lilishop/                # 基于 Lilishop 的后台项目
+│   ├── enagic-plugin/               # Enagic 插件模块(Maven)
+│   │   ├── pom.xml                   # 聚合 POM
+│   │   │
+│   │   ├── enagic-entity/            # 实体层(14 张新表)
+│   │   │   └── src/main/java/com/enagic/modules/enagic/entity/dos/
+│   │   │       ├── HealthAdvisor.java       # 健康布施者
+│   │   │       ├── AdvisorMedal.java        # 荣誉勋章
+│   │   │       ├── EnagicVipConfig.java      # VIP 配置
+│   │   │       ├── MemberVip.java           # 会员 VIP
+│   │   │       ├── MemberDeduction.java     # 抵扣金账户
+│   │   │       ├── DeductionLog.java        # 抵扣金流水
+│   │   │       ├── OperationFlow.java      # 运维流程模板
+│   │   │       ├── OperationPlan.java      # 运维计划
+│   │   │       ├── OperationRecord.java     # 运维记录
+│   │   │       ├── MemberTransfer.java       # 客户移交
+│   │   │       ├── ArticleQr.java           # 素材二维码
+│   │   │       ├── BehaviorLog.java         # 行为日志
+│   │   │       ├── AiConversation.java     # AI 对话记录
+│   │   │       └── AiKnowledge.java         # AI 知识库
+│   │   │
+│   │   ├── enagic-api/               # 业务 API(核心扩展)
+│   │   │   └── src/main/java/com/enagic/modules/enagic/
+│   │   │       ├── config/
+│   │   │       │   └── EnagicApiAutoConfiguration.java  # Spring 自动配置
+│   │   │       ├── controller/
+│   │   │       │   ├── buyer/
+│   │   │       │   │   ├── AiChatController.java         # AI 数字人
+│   │   │       │   │   └── HealthAdvisorBuyerController.java  # 健康布施者
+│   │   │       │   └── manager/
+│   │   │       │       └── HealthAdvisorManagerController.java  # 后台管理
+│   │   │       ├── service/
+│   │   │       │   ├── AiChatService.java         # AI 业务逻辑
+│   │   │       │   ├── HealthAdvisorService.java  # 健康布施者业务
+│   │   │       │   ├── VipService.java            # VIP 业务
+│   │   │       │   └── OperationPlanService.java # 运维计划业务
+│   │   │       └── mapper/
+│   │   │           └── *Mapper.java (MyBatis-Plus)
+│   │   │
+│   │   ├── enagic-admin/             # PC 后台管理 Vue 页面
+│   │   │   ├── pom.xml
+│   │   │   └── src/main/vue/
+│   │   │       ├── views/enagic/     # 页面组件
+│   │   │       └── api/enagic.js     # API 调用
+│   │   │
+│   │   └── enagic-consumer/          # 事件消费者(定时任务)
+│   │       └── src/main/java/com/enagic/modules/enagic/consumer/
+│   │           ├── OrderEventConsumer.java    # RocketMQ 订单事件监听
+│   │           └── OperationRemindJob.java    # 运维提醒定时任务
+│   │
+│   └── README.md
+│
+└── enagic-uniapp/                    # 小程序(forked from lilishop-uniapp)
+    ├── api/
+    │   └── enagic.js                # Enagic API 调用层
+    ├── pages/
+    │   └── enagic/
+    │       └── ai-chat/
+    │           └── index.vue         # AI 数字人对话页
+    └── README.md
+```
+
+## 技术架构
+
+### 后端扩展方式
+
+1. **新增 Maven 模块** (`enagic-plugin`) 作为 Lilishop 的扩展
+2. **通过 Spring `@ComponentScan`** 自动注册到 Lilishop 应用上下文
+3. **独立 API 命名空间** (`/enagic/buyer/*`, `/enagic/manager/*`) 不干扰原有 API
+4. **事件驱动**:RocketMQ 监听 Lilishop 订单事件,触发运维流程
+5. **定时任务**:XXL-Job 定时扫描运维计划、VIP 感恩提醒
+
+### 数据库
+
+- 14 张新表,前缀 `li_enagic_*`,与 Lilishop 原有表共存
+- 扩展原有表:`li_member`(health_advisor_id、advisor_credits)、`li_distribution`(medal_level、permanent_bind)
+
+### 小程序改造
+
+- fork `/mnt/e/workspace/uniapp/lilishop` 为 `enagic-uniapp`
+- 新增 `pages/enagic/` 目录(分包),包含 AI聊天、健康布施者中心、VIP、抵扣金、运维等页面
+- 新增 `api/enagic.js` 统一封装 Enagic 扩展 API
+
+## 快速开始
+
+### 1. 初始化数据库
+
+```sql
+-- 在 Lilishop 数据库中执行以下 DDL
+--(详见 SPEC.md 第四章数据库设计)
+CREATE TABLE li_enagic_health_advisor (...);
+CREATE TABLE li_enagic_advisor_medal (...);
+CREATE TABLE li_enagic_vip_config (...);
+CREATE TABLE li_enagic_member_vip (...);
+CREATE TABLE li_enagic_deduction (...);
+CREATE TABLE li_enagic_deduction_log (...);
+CREATE TABLE li_enagic_operation_flow (...);
+CREATE TABLE li_enagic_operation_plan (...);
+CREATE TABLE li_enagic_operation_record (...);
+CREATE TABLE li_enagic_member_transfer (...);
+CREATE TABLE li_enagic_behavior_log (...);
+CREATE TABLE li_enagic_article_qr (...);
+CREATE TABLE li_enagic_ai_conversation (...);
+CREATE TABLE li_enagic_ai_knowledge (...);
+```
+
+### 2. 部署 enagic-plugin
+
+```bash
+cd enagic-lilishop/enagic-plugin
+mvn clean install -DskipTests
+
+# 将生成的 JAR 加入 Lilishop 部署
+cp enagic-*/target/enagic-*.jar /path/to/lilishop/lib/
+```
+
+### 3. 启动 Lilishop
+
+```bash
+# Lilishop 重启后,Enagic 的 Controller、Service 会自动注册
+cd /path/to/lilishop
+java -jar lilishop.jar
+```
+
+### 4. 运行小程序
+
+```bash
+cd enagic-uniapp
+# 在 HBuilderX 中打开
+# 运行 → 运行到小程序模拟器 → 微信开发者工具
+```
+
+## 主要功能一览
+
+| 功能 | 模块 | 说明 |
+|------|------|------|
+| AI 数字人对话 | enagic-api + enagic-uniapp | 对接硅基流动,实时对话 |
+| 健康布施者中心 | enagic-api + enagic-uniapp | 邀请客户、查看业绩、勋章 |
+| VIP 开通 | enagic-api + enagic-uniapp | 无到期时间,分享激励 |
+| 抵扣金账户 | enagic-api + enagic-uniapp | 独立账户,订单抵扣 |
+| 运维流程 | enagic-consumer | 订单发货后自动生成运维计划 |
+| PC 后台管理 | enagic-admin | 健康布施者、VIP、运维、AI知识库管理 |
+
+## 配置项
+
+```yaml
+# application.yml
+enagic:
+  ai:
+    provider: siliconflow          # 或 aliyun
+    api-key: ${AI_API_KEY}          # 从环境变量读取
+    model: Qwen/Qwen2.5-7B-Instruct
+    base-url: https://api.siliconflow.cn/v1
+```

+ 572 - 0
代码/SPEC.md

@@ -0,0 +1,572 @@
+# Enagic 本希甄选小程序 - 技术方案文档
+
+> **项目版本:** V1.0
+>
+> **编制日期:** 2025-05-07
+>
+> **基于:** Lilishop B2B2C 商城系统 V4.3
+>
+> **方案:** B(核心用 Lilishop,差异化自研)
+
+---
+
+## 一、项目概述
+
+### 1.1 项目背景
+
+本希甄选小程序是一个集商品销售、素材共享、健康顾问服务于一体的高端消费者服务平台。系统基于 Lilishop B2B2C 开源商城进行扩展开发,保留 Lilishop成熟的电商核心能力,叠加差异化业务功能(AI 数字人、健康布施者体系、客户运维流程等)。
+
+### 1.2 技术选型
+
+| 层级 | 技术选型 | 说明 |
+|------|---------|------|
+| 后端框架 | Spring Boot 2.4 + MyBatis-Plus | 复用 Lilishop |
+| 数据库 | MySQL + Redis + MongoDB | 复用 Lilishop |
+| 搜索引擎 | Elasticsearch | 复用 Lilishop |
+| 消息队列 | RocketMQ | 复用 Lilishop |
+| 认证 | JWT | 复用 Lilishop |
+| PC 管理前端 | Vue 2 + ViewUI (iView) | 扩展 |
+| 移动端小程序 | UniApp + uView UI | 扩展 |
+| AI 大模型 | 硅基流动 / 阿里云百炼 | 新增 |
+
+---
+
+## 二、项目结构
+
+```
+代码/
+├── enagic-lilishop/                 # 基于 Lilishop 的后台项目
+│   ├── lilishop/                    # Lilishop 源码(forked)
+│   │   ├── framework/               # 框架层(实体、工具类、插件接口)
+│   │   ├── buyer-api/               # 买家端 API
+│   │   ├── seller-api/              # 商家端 API
+│   │   ├── manager-api/             # 平台管理端 API
+│   │   ├── admin/                    # PC 管理端页面(Vue)
+│   │   ├── common-api/              # 公共 API
+│   │   ├── consumer/                 # 消息消费者
+│   │   ├── im-api/                  # IM 即时通讯 API
+│   │   └── pom.xml
+│   │
+│   └── enagic-plugin/                # Enagic 插件模块(新增)
+│       ├── enagic-admin/             # 后台管理插件
+│       │   ├── src/main/java/        # Java 源码
+│       │   ├── src/main/resources/   # 配置文件
+│       │   ├── src/main/vue/         # Vue 管理页面
+│       │   └── pom.xml
+│       │
+│       ├── enagic-api/               # 业务 API 插件
+│       │   ├── src/main/java/        # Java 源码
+│       │   ├── src/main/resources/   # 配置文件
+│       │   └── pom.xml
+│       │
+│       ├── enagic-entity/            # 实体和 DTO
+│       │   ├── src/main/java/
+│       │   └── pom.xml
+│       │
+│       ├── enagic-consumer/          # 消息消费者(事件驱动)
+│       │   ├── src/main/java/
+│       │   └── pom.xml
+│       │
+│       └── pom.xml                   # 聚合 POM
+│
+└── enagic-uniapp/                    # 小程序项目(forked from lilishop-uniapp)
+    ├── api/                          # API 调用层(新增 enagic 相关)
+    ├── pages/                        # 页面
+    ├── store/                        # Vuex 状态管理
+    ├── config/                       # 配置文件
+    └── uview-ui/                     # UI 框架
+```
+
+---
+
+## 三、插件架构设计
+
+### 3.1 为什么用插件架构
+
+Lilishop 没有 OSGi 或 Spring Boot auto-configuration 那种热插拔插件系统,但它的 **Factory + Plugin 模式**和 **Spring 组件扫描**机制足够实现模块扩展:
+
+- **现有插件示例**:短信插件(`SmsPlugin`)、物流插件(`LogisticsPlugin`)、支付插件(`PaymentPlugin`)
+- **扩展方式**:新增 Maven 模块,通过 Spring `@Component` + `@Configuration` 自动注册到 Lilishop 应用上下文
+- **API 隔离**:新增 API 使用独立命名空间(`/enagic/**`),不影响 Lilishop 原有 API
+- **事件驱动**:利用 RocketMQ 消费者监听 Lilishop 事件(订单创建、支付完成等),触发自定义业务逻辑
+
+### 3.2 插件模块职责划分
+
+| 模块 | 职责 | 部署方式 |
+|------|------|---------|
+| `enagic-entity` | 实体类、DTO、枚举、常量 | 打成 JAR,被其他模块依赖 |
+| `enagic-api` | 业务 API(健康布施者、VIP、抵扣金、AI数字人、客户运维) | 与 `buyer-api`/`manager-api` 合并部署 |
+| `enagic-admin` | PC 后台管理 Vue 页面 + 管理 API | 与 `admin` 合并部署 |
+| `enagic-consumer` | 事件监听(RocketMQ)、定时任务 | 与 `consumer` 合并部署 |
+
+### 3.3 与 Lilishop 的集成方式
+
+#### API 扩展(enagic-api)
+
+新增 Controller 使用与 Lilishop 相同的包命名规则:
+
+```
+com.dan.modules.enagic.*    # 复用 dan 包名,自动被 Spring 扫描
+```
+
+API 路径前缀:`/enagic/buyer/`、`/enagic/manager/`
+
+**无需修改 Lilishop 源码**,只需在 `enagic-api` 模块的 `spring.factories` 或自动配置类中注册新的 Controller。
+
+#### 事件监听(enagic-consumer)
+
+```java
+// 监听 Lilishop 的订单创建事件
+@RocketMQMessageListener(
+    topic = "order_topic",
+    consumerGroup = "enagic-consumer-group"
+)
+public class EnagicOrderListener implements RocketMQListener<Order> {
+    // 触发:客户运维流程生成、健康布施者业绩统计
+}
+```
+
+#### 后台管理(enagic-admin)
+
+Vue 页面通过 **路由配置** 和 **菜单 API** 动态注册到 Lilishop 管理后台:
+- 新增 `/enagic/**` 路由
+- 菜单数据通过 `manager-api` 动态返回
+
+---
+
+## 四、数据库设计
+
+### 4.1 新增表清单
+
+| 序号 | 表名 | 说明 | 主要字段 |
+|------|------|------|---------|
+| 1 | `li_enagic_health_advisor` | 健康布施者表 | member_id, name, id_number, medal_level, total_invites, status |
+| 2 | `li_enagic_advisor_medal` | 荣誉勋章表 | id, advisor_id, medal_type, medal_level, grant_time, grant_reason |
+| 3 | `li_enagic_vip_config` | VIP 配置表 | id, vip_name, price, upgrade_conditions(JSON), benefits(JSON), no_expiry |
+| 4 | `li_enagic_member_vip` | 会员 VIP 表 | id, member_id, vip_config_id, open_time, gratitude_remind_time |
+| 5 | `li_enagic_deduction` | 抵扣金账户表 | id, member_id, deduction_balance, frozen_balance |
+| 6 | `li_enagic_deduction_log` | 抵扣金流水表 | id, deduction_id, amount, type, order_sn, create_time |
+| 7 | `li_enagic_operation_flow` | 运维流程模板表 | id, product_id, flow_name, nodes(JSON) |
+| 8 | `li_enagic_operation_plan` | 运维计划表 | id, flow_id, member_id, product_id, order_sn, status, next_remind_time |
+| 9 | `li_enagic_operation_record` | 运维记录表 | id, plan_id, operator_id, content, result, operate_time |
+| 10 | `li_enagic_member_transfer` | 客户移交记录表 | id, original_advisor_id, new_advisor_id, member_id, transfer_reason, transfer_time, status |
+| 11 | `li_enagic_behavior_log` | 行为日志表 | id, member_id, event_type, event_data(JSON), create_time |
+| 12 | `li_enagic_article_qr` | 素材二维码表 | id, article_id, qr_url, bind_member_id, create_time |
+| 13 | `li_enagic_ai_conversation` | AI 对话记录表 | id, member_id, question, answer, model, create_time |
+| 14 | `li_enagic_ai_knowledge` | AI 知识库表 | id, category, question, answer, status, create_time |
+
+### 4.2 扩展的 Lilishop 原有表
+
+| 表名 | 新增字段 | 说明 |
+|------|---------|------|
+| `li_member` | `health_advisor_id`, `advisor_credits` | 关联健康布施者、顾问积分 |
+| `li_member_grade` | `upgrade_conditions` (JSON) | 升级条件(金额/积分/人数组合) |
+| `li_article` | `view_role` (VARCHAR) | 可见角色:ALL/CONSUMER_ONLY |
+| `li_distribution` | `medal_level`, `permanent_bind` | 勋章等级、永久绑定标志 |
+| `li_goods` | `operation_flow_id` | 关联运维流程模板 |
+
+### 4.3 ER 关系简图
+
+```
+li_member
+├── health_advisor_id → li_enagic_health_advisor.id
+└── advisor_credits → 顾问积分
+
+li_enagic_health_advisor
+├── medal_level → li_enagic_advisor_medal.medal_type
+└── member_id → li_member.id (一对一)
+
+li_enagic_vip_config ←→ li_enagic_member_vip (一对多)
+                         └── member_id → li_member.id
+
+li_enagic_operation_flow ←→ li_enagic_operation_plan (一对多)
+                              └── order_sn → li_order.sn
+
+li_goods.operation_flow_id → li_enagic_operation_flow.id
+```
+
+---
+
+## 五、API 设计
+
+### 5.1 新增 API 端点
+
+#### 买家端 API(`/enagic/buyer/`)
+
+| 端点 | 方法 | 说明 |
+|------|------|------|
+| `/enagic/buyer/advisor/info` | GET | 获取健康布施者信息 |
+| `/enagic/buyer/advisor/my-customers` | GET | 获取我的客户列表(分页) |
+| `/enagic/buyer/advisor/invite-qr` | GET | 获取邀请二维码 |
+| `/enagic/buyer/vip/info` | GET | 获取 VIP 信息 |
+| `/enagic/buyer/vip/open` | POST | 开通 VIP |
+| `/enagic/buyer/deduction/info` | GET | 获取抵扣金账户 |
+| `/enagic/buyer/deduction/log` | GET | 获取抵扣金流水 |
+| `/enagic/buyer/ai/chat` | POST | AI 数字人对话 |
+| `/enagic/buyer/ai/history` | GET | AI 对话历史 |
+| `/enagic/buyer/operation/my-plans` | GET | 获取我的运维计划 |
+| `/enagic/buyer/operation/record` | GET | 获取运维记录 |
+| `/enagic/buyer/article/qr/{articleId}` | GET | 获取素材带参数的二维码 |
+
+#### 管理端 API(`/enagic/manager/`)
+
+| 端点 | 方法 | 说明 |
+|------|------|------|
+| `/enagic/manager/advisor/page` | GET | 健康布施者分页列表 |
+| `/enagic/manager/advisor/medal/grant` | POST | 发放勋章 |
+| `/enagic/manager/vip/config/page` | GET | VIP 配置分页 |
+| `/enagic/manager/vip/config/save` | POST | 保存 VIP 配置 |
+| `/enagic/manager/deduction/page` | GET | 抵扣金账户分页 |
+| `/enagic/manager/operation/flow/page` | GET | 运维流程模板分页 |
+| `/enagic/manager/operation/flow/save` | POST | 保存运维流程模板 |
+| `/enagic/manager/operation/plan/page` | GET | 运维计划分页 |
+| `/enagic/manager/operation/plan/remind` | POST | 手动触发提醒 |
+| `/enagic/manager/transfer/page` | GET | 客户移交记录分页 |
+| `/enagic/manager/transfer/process` | POST | 处理移交申请 |
+| `/enagic/manager/ai/knowledge/page` | GET | AI 知识库分页 |
+| `/enagic/manager/ai/knowledge/save` | POST | 保存 AI 知识库 |
+| `/enagic/manager/article/qr/list` | GET | 素材二维码列表 |
+
+### 5.2 复用 Lilishop 的 API
+
+| Lilishop API | 用于 |
+|--------------|------|
+| `/buyer/passport/member/*` | 用户注册、登录 |
+| `/buyer/goods/*` | 商品浏览、搜索 |
+| `/buyer/trade/carts/*` | 购物车 |
+| `/buyer/order/order/*` | 订单(创建、支付、退款) |
+| `/buyer/wallet/*` | 余额、充值、提现 |
+| `/buyer/member/memberPointsHistory/*` | 积分 |
+| `/buyer/promotion/coupon/*` | 优惠券 |
+| `/buyer/distribution/*` | 分销(复用为健康布施者底层) |
+| `/buyer/message/*` | 消息中心 |
+| `/buyer/broadcast/studio/*` | 直播(AI数字人交互页可复用) |
+| `/manager/goods/*` | 商品管理 |
+| `/manager/order/*` | 订单管理 |
+| `/manager/member/*` | 会员管理 |
+| `/manager/page/*` | 页面装修 |
+
+---
+
+## 六、功能模块详细设计
+
+### 6.1 AI 数字人
+
+**架构:**
+```
+UniApp → enagic-api → AI 大模型(硅基流动/阿里云百炼)
+         ↓
+   enagic-entity (LiEnagicAiConversation)
+```
+
+**知识库分类:**
+- 产品知识库(产品功效、使用方法、注意事项)
+- 健康知识库(健康信息、营养建议)
+- 常见问题库(FAQ)
+
+**对话流程:**
+1. 用户发送消息 → `/enagic/buyer/ai/chat`
+2. 敏感词过滤 → 知识库检索 → AI 大模型回答
+3. 对话记录存储到 `li_enagic_ai_conversation`
+4. 返回答案给用户
+
+**触发场景:**
+- 小程序「AI 健康顾问」入口 → 进入 AI 数字人对话界面
+- 商品详情页 → 快捷咨询按钮 → 调用 AI 接口
+
+### 6.2 健康布施者荣誉体系
+
+**邀请关系建立:**
+```
+用户扫码注册 → 解析 URL 中的 inviter_id → 写入 health_advisor_id
+(永久绑定,即使健康布施者注销也不解除)
+```
+
+**勋章机制:**
+| 勋章类型 | 触发条件 | 显示 |
+|----------|---------|------|
+| 布施新星 | 首次成功邀请 | ⭐ |
+| 布施达人 | 邀请 5 人 | ⭐⭐ |
+| 布施导师 | 邀请 20 人 | ⭐⭐⭐ |
+| 布施宗师 | 邀请 50 人 | 🌟 |
+
+**健康布施者权益:**
+- 被邀请客户的消费贡献积分
+- 专属客服通道
+- 荣誉展示(个人中心显示勋章)
+
+### 6.3 客户运维流程引擎
+
+**流程定义:**
+```json
+{
+  "flowName": "产品A 运维流程",
+  "productId": 123,
+  "nodes": [
+    {"day": 1, "name": "发货提醒", "content": "您的订单已发货", "remindType": "WECHAT_MSG"},
+    {"day": 3, "name": "收货确认", "content": "请确认收货并指导使用", "remindType": "WECHAT_MSG"},
+    {"day": 7, "name": "使用指导", "content": "开始使用产品", "remindType": "AI_REMINDER"},
+    {"day": 30, "name": "使用回访", "content": "使用体验如何", "remindType": "WECHAT_MSG"}
+  ]
+}
+```
+
+**自动触发:**
+- 订单状态变为「已发货」→ 生成运维计划
+- `enagic-consumer` 监听订单事件 → 创建 `li_enagic_operation_plan`
+- 定时任务(XXL-Job)扫描 `li_enagic_operation_plan`,到达 `next_remind_time` → 发送微信通知
+
+**客户自动转移:**
+- 三次运维节点被跳过(无人服务)→ 触发转移
+- 转移时记录 `li_enagic_member_transfer`,原健康布施者归属权和收益权终止
+
+### 6.4 VIP 无到期时间
+
+**原有 Lilishop VIP**:`MemberGrade` 绑定有效期,到期自动失效
+
+**改造方案:**
+- 新增 `li_enagic_vip_config.no_expiry = true` 字段
+- 新增 `li_enagic_member_vip.gratitude_remind_time` 字段
+- 移除到期检查定时任务,改为「分享激励感恩提醒」定时任务
+- 触发条件:VIP 客户每 30 天无分享行为 → 发送感恩提醒消息
+
+### 6.5 抵扣金账户
+
+**获取途径:**
+- 充值赠送(后台配置赠送比例)
+- 活动奖励
+- 退款返还(退款时优先退抵扣金)
+
+**使用规则:**
+- 订单支付时可使用抵扣金(抵扣部分金额)
+- 支持部分抵扣(最低抵扣 1 元)
+- 抵扣金不能提现
+
+**冻结机制:**
+- 下单时冻结对应抵扣金
+- 订单完成/取消时解冻
+
+### 6.6 素材二维码分享
+
+**生成逻辑:**
+- 用户打开素材详情页 → 调用 `/enagic/buyer/article/qr/{articleId}`
+- 后台生成二维码,内容包含:素材ID + 分享者 memberId + 有效期
+- 二维码存储到 `li_enagic_article_qr`
+
+**分享流程:**
+1. 分享者打开素材 → 生成分享二维码
+2. 被分享者扫码 → 跳转小程序,自动携带分享者信息
+3. 被分享者注册后,自动绑定关系(无需手动关联)
+
+### 6.7 素材角色权限
+
+**实现:**
+- `li_article.view_role = 'ALL' | 'CONSUMER_ONLY'`
+- 商家端上传素材时可设置可见角色
+- 用户端 API 查询素材时根据 `view_role` + 用户角色过滤
+- 消费商:看全部素材
+- 纯用户:只看 `view_role = 'ALL'` 或 `'CONSUMER_ONLY'`
+
+---
+
+## 七、小程序端设计
+
+### 7.1 页面结构
+
+在 `enagic-uniapp` 中新增以下页面(通过分包机制):
+
+```
+pages/
+├── tabbar/                          # 已有(首页/分类/购物车/我的)
+├── enagic/                          # Enagic 新增页面(分包)
+│   ├── ai-chat/                     # AI 数字人对话
+│   │   └── index.vue
+│   ├── health-advisor/              # 健康布施者中心
+│   │   ├── home.vue                 # 推广首页(展示客户、业绩、勋章)
+│   │   ├── customers.vue            # 我的客户列表
+│   │   ├── invite-qr.vue            # 邀请二维码
+│   │   └── medals.vue               # 我的勋章
+│   ├── vip/                         # VIP 中心
+│   │   ├── index.vue                 # VIP 介绍和开通
+│   │   └── my-vip.vue                # 我的 VIP
+│   ├── deduction/                   # 抵扣金
+│   │   ├── index.vue                 # 抵扣金账户
+│   │   └── log.vue                   # 抵扣金明细
+│   ├── operation/                   # 运维(消费商视角)
+│   │   ├── my-plans.vue              # 我的运维计划
+│   │   └── record.vue                # 运维记录
+│   └── transfer/                    # 客户移交
+│       └── history.vue              # 移交历史
+```
+
+### 7.2 既有页面改造
+
+| 页面 | 改造内容 |
+|------|---------|
+| `pages/tabbar/user/my.vue` | 新增:健康布施者入口、VIP 入口、AI 顾问入口 |
+| `pages/mine/msgTips/main.vue` | 新增:运维提醒消息类型 |
+| `pages/passport/login.vue` | 新增:健康布施者邀请登录参数解析 |
+| `pages/product/goods.vue` | 新增:AI 咨询快捷入口、商品详情页添加运维计划入口 |
+
+### 7.3 API 调用层
+
+新增 `enagic-uniapp/api/enagic.js`:
+
+```javascript
+// AI 数字人
+export const aiChat = (data) => uni.request({ url: '/enagic/buyer/ai/chat', data })
+export const aiHistory = (params) => uni.request({ url: '/enagic/buyer/ai/history', params })
+
+// 健康布施者
+export const getAdvisorInfo = () => uni.request({ url: '/enagic/buyer/advisor/info' })
+export const getMyCustomers = (params) => uni.request({ url: '/enagic/buyer/advisor/my-customers', params })
+export const getInviteQr = () => uni.request({ url: '/enagic/buyer/advisor/invite-qr' })
+
+// VIP
+export const getVipInfo = () => uni.request({ url: '/enagic/buyer/vip/info' })
+export const openVip = (data) => uni.request({ url: '/enagic/buyer/vip/open', data })
+
+// 抵扣金
+export const getDeductionInfo = () => uni.request({ url: '/enagic/buyer/deduction/info' })
+export const getDeductionLog = (params) => uni.request({ url: '/enagic/buyer/deduction/log', params })
+
+// 运维
+export const getMyOperationPlans = (params) => uni.request({ url: '/enagic/buyer/operation/my-plans', params })
+```
+
+---
+
+## 八、实施计划
+
+### 阶段划分
+
+| 阶段 | 时间 | 内容 | 交付物 |
+|------|------|------|--------|
+| **Phase 0** | Week 1 | 环境搭建 + Lilishop 源码 fork + 项目初始化 | 项目目录结构、Maven 依赖调试通过 |
+| **Phase 1** | Week 2-3 | 基础数据层:数据库表创建 + entity + 基础 API(健康布施者、VIP配置) | API 可调用、数据库表就绪 |
+| **Phase 2** | Week 4-5 | 核心业务开发:健康布施者体系 + VIP 无到期 + 抵扣金 | 功能完整可用 |
+| **Phase 3** | Week 6-7 | 客户运维流程引擎 + 事件监听(RocketMQ) | 运维流程自动触发 |
+| **Phase 4** | Week 8-9 | AI 数字人:知识库 + 对话接口 + 小程序页面 | AI 对话可用 |
+| **Phase 5** | Week 10-11 | PC 后台管理页面(Vue)+ 素材权限 + 二维码分享 | 后台功能完整 |
+| **Phase 6** | Week 12 | 小程序端 UI 改造 + 联调测试 | 小程序可运行 |
+| **Phase 7** | Week 13-14 | 系统联调 + 性能优化 + 部署 | 可上线版本 |
+
+**总工期:约 14 周(100-105 人天)**
+
+### 关键依赖路径
+
+```
+Phase 0 (项目初始化)
+    ↓
+Phase 1 (数据层) ───────────────────────────────────────┐
+    ↓                                                    │
+Phase 2 (核心业务)                                       │
+    ↓                                                    │
+Phase 3 (运维引擎) ←──────── Phase 2 完成后解锁           │
+    ↓                                                    │
+Phase 4 (AI数字人) ←── Phase 1 完成后可并行              │
+    ↓                                                    │
+Phase 5 (后台页面) ←── Phase 1+2 完成后可并行            │
+    ↓                                                    │
+Phase 6 (小程序) ←────────── Phase 1~5 完成后开始        │
+    ↓                                                    │
+Phase 7 (联调上线)                                       │
+```
+
+### 并行机会
+
+| 并行组合 | 说明 |
+|---------|------|
+| Phase 2 + Phase 4 | 核心业务和 AI 可同时开发 |
+| Phase 2 + Phase 5 | 后台管理和业务逻辑可同时开发 |
+| Phase 3 + Phase 5 | 事件监听和后台管理可同时开发 |
+
+---
+
+## 九、技术要点
+
+### 9.1 Lilishop 源码集成
+
+将 `enagic-plugin` 作为 Maven 子模块加入 Lilishop 的 `pom.xml`:
+
+```xml
+<modules>
+    <module>framework</module>
+    <module>buyer-api</module>
+    <module>manager-api</module>
+    <module>seller-api</module>
+    <module>common-api</module>
+    <module>consumer</module>
+    <module>admin</module>
+    <module>im-api</module>
+    <!-- 新增 -->
+    <module>enagic-plugin</module>
+</modules>
+```
+
+### 9.2 定时任务
+
+使用 Lilishop 内置的 **XXL-Job**:
+
+| 任务名称 | cron | 说明 |
+|---------|------|------|
+| `enagic-operation-remind` | `0 0 9 * * ?` | 运维计划提醒扫描 |
+| `enagic-gratitude-remind` | `0 0 10 * * ?` | VIP 感恩提醒扫描 |
+| `enagic-transfer-check` | `0 0 12 * * ?` | 客户自动转移检查 |
+| `enagic-medal-check` | `0 0 8 * * ?` | 勋章发放检查 |
+
+### 9.3 AI 大模型接入
+
+推荐使用 **硅基流动(SiliconFlow)** API:
+
+```java
+// 配置:enagic-api/src/main/resources/application.yml
+enagic:
+  ai:
+    provider: siliconflow   # 或 aliyun
+    api-key: ${AI_API_KEY}
+    model: Qwen/Qwen2.5-7B-Instruct  # 模型名称
+    base-url: https://api.siliconflow.cn/v1
+```
+
+### 9.4 微信消息通知
+
+利用 Lilishop 已有的消息中心,扩展消息模板:
+
+| 模板类型 | 触发场景 |
+|---------|---------|
+| 运维提醒 | 到达运维节点时 |
+| 客户转移通知 | 客户被自动转移时 |
+| 勋章发放通知 | 健康布施者获得新勋章时 |
+| VIP 感恩提醒 | VIP 客户长期无分享时 |
+
+---
+
+## 十、注意事项
+
+1. **不修改 Lilishop 核心代码**:所有扩展通过新增模块实现,便于后续 Lilishop 版本升级时合并
+2. **数据库表前缀统一使用 `li_enagic_`**:与 Lilishop 原有表(`li_*`)保持一致
+3. **API 命名空间隔离**:`/enagic/**` 前缀确保不与 Lilishop 原有 API 冲突
+4. **事件驱动解耦**:核心业务逻辑通过 RocketMQ 事件触发,不直接依赖 Lilishop 内部类
+5. **AGPL 协议注意**:Lilishop 遵循 AGPL-3.0,商业使用需联系官方授权
+
+---
+
+## 附录:文件清单
+
+```
+代码/
+├── enagic-lilishop/
+│   ├── SPEC.md                          # 本文档
+│   ├── lilishop/                        # Lilishop 源码(forked)
+│   └── enagic-plugin/                   # Enagic 插件
+│       ├── README.md
+│       ├── pom.xml                       # 聚合 POM
+│       ├── enagic-entity/               # 实体层
+│       ├── enagic-api/                  # 业务 API
+│       ├── enagic-admin/                # PC 管理插件
+│       └── enagic-consumer/              # 事件消费者
+└── enagic-uniapp/                        # 小程序
+    ├── README.md
+    └── pages/enagic/                     # 新增页面
+```

+ 335 - 0
代码/enagic-lilishop/enagic-plugin/DB/enagic_init.sql

@@ -0,0 +1,335 @@
+-- ============================================================
+-- Enagic 本希甄选小程序 - 数据库初始化脚本
+-- 基于 Lilishop B2B2C V4.3
+-- 执行顺序: 1. 本文件 → 2. version upgrade SQL(如有)
+-- ============================================================
+
+SET NAMES utf8mb4;
+SET FOREIGN_KEY_CHECKS = 0;
+
+-- ------------------------------------------------------------
+-- 1. 健康布施者表
+-- ------------------------------------------------------------
+DROP TABLE IF EXISTS `li_enagic_health_advisor`;
+CREATE TABLE `li_enagic_health_advisor` (
+    `id`                BIGINT        NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+    `member_id`         BIGINT        NOT NULL                COMMENT '关联会员ID',
+    `member_name`       VARCHAR(100)   DEFAULT NULL           COMMENT '会员名称',
+    `name`              VARCHAR(50)    DEFAULT NULL           COMMENT '真实姓名',
+    `id_number`         VARCHAR(20)    DEFAULT NULL           COMMENT '身份证号',
+    `medal_level`       VARCHAR(20)    DEFAULT 'STAR_1'       COMMENT '勋章等级',
+    `total_invites`     INT             DEFAULT 0            COMMENT '累计邀请人数',
+    `total_commission`   DECIMAL(12,2)  DEFAULT 0.00         COMMENT '累计佣金总额',
+    `available_commission` DECIMAL(12,2) DEFAULT 0.00         COMMENT '可用佣金',
+    `frozen_commission`   DECIMAL(12,2)  DEFAULT 0.00         COMMENT '冻结佣金',
+    `advisor_credits`   INT             DEFAULT 0            COMMENT '顾问积分',
+    `status`            VARCHAR(20)     DEFAULT 'ACTIVE'     COMMENT '状态',
+    `permanent_bind`    TINYINT(1)      DEFAULT 1            COMMENT '是否永久绑定',
+    `approve_time`      DATETIME        DEFAULT NULL         COMMENT '审核时间',
+    `create_time`       DATETIME        DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_time`       DATETIME        DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+    `delete_flag`       TINYINT         DEFAULT 0            COMMENT '删除标记',
+    PRIMARY KEY (`id`),
+    KEY `idx_member_id` (`member_id`),
+    KEY `idx_status` (`status`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='健康布施者表';
+
+-- ------------------------------------------------------------
+-- 2. 荣誉勋章表
+-- ------------------------------------------------------------
+DROP TABLE IF EXISTS `li_enagic_advisor_medal`;
+CREATE TABLE `li_enagic_advisor_medal` (
+    `id`              BIGINT      NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+    `advisor_id`      BIGINT      NOT NULL                COMMENT '健康布施者ID',
+    `medal_type`      VARCHAR(20)  DEFAULT NULL           COMMENT '勋章类型',
+    `medal_level`     INT          DEFAULT 1              COMMENT '勋章等级',
+    `grant_reason`    VARCHAR(200) DEFAULT NULL           COMMENT '授予原因',
+    `grant_time`      DATETIME     DEFAULT NULL           COMMENT '授予时间',
+    `trigger_member_id` BIGINT     DEFAULT NULL           COMMENT '触发勋章的客户ID',
+    `displayed`       TINYINT(1)   DEFAULT 0              COMMENT '是否已展示',
+    `create_time`     DATETIME     DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_advisor_id` (`advisor_id`),
+    KEY `idx_grant_time` (`grant_time`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='荣誉勋章表';
+
+-- ------------------------------------------------------------
+-- 3. VIP 配置表
+-- ------------------------------------------------------------
+DROP TABLE IF EXISTS `li_enagic_vip_config`;
+CREATE TABLE `li_enagic_vip_config` (
+    `id`                  BIGINT        NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+    `vip_name`            VARCHAR(50)   DEFAULT NULL           COMMENT 'VIP名称',
+    `vip_image`           VARCHAR(255)  DEFAULT NULL           COMMENT 'VIP图标',
+    `price`               DECIMAL(10,2)  DEFAULT 0.00         COMMENT '价格(分)',
+    `upgrade_conditions` TEXT           COMMENT '升级条件JSON',
+    `benefits`            TEXT           COMMENT '会员权益JSON',
+    `no_expiry`           TINYINT(1)    DEFAULT 1            COMMENT '是否无到期时间',
+    `gratitude_remind_days` INT         DEFAULT 30           COMMENT '感恩提醒周期(天)',
+    `sort`                INT          DEFAULT 0             COMMENT '排序',
+    `status`              VARCHAR(20)   DEFAULT 'OPEN'       COMMENT '状态',
+    `create_time`         DATETIME      DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_time`          DATETIME      DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+    PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='VIP配置表';
+
+INSERT INTO `li_enagic_vip_config` (`vip_name`, `price`, `no_expiry`, `status`, `benefits`, `upgrade_conditions`) VALUES
+('普通会员', 0, 1, 'OPEN', '[{"type":"EXCLUSIVE_SERVICE","value":false}]', '[{"type":"INVITE_COUNT","value":0}]'),
+('银牌会员', 99.00, 1, 'OPEN', '[{"type":"EXCLUSIVE_SERVICE","value":true},{"type":"DISCOUNT_RATE","value":0.95}]', '[{"type":"INVITE_COUNT","value":5}]'),
+('金牌会员', 299.00, 1, 'OPEN', '[{"type":"EXCLUSIVE_SERVICE","value":true},{"type":"DISCOUNT_RATE","value":0.90},{"type":"PRIORITY_SHIPMENT","value":true}]', '[{"type":"INVITE_COUNT","value":20},{"type":"CONSUME_AMOUNT","value":5000}]'),
+('钻石会员', 999.00, 1, 'OPEN', '[{"type":"EXCLUSIVE_SERVICE","value":true},{"type":"DISCOUNT_RATE","value":0.85},{"type":"PRIORITY_SHIPMENT","value":true},{"type":"EXCLUSIVE_PRODUCT","value":true}]', '[{"type":"INVITE_COUNT","value":50},{"type":"CONSUME_AMOUNT","value":20000}]');
+
+-- ------------------------------------------------------------
+-- 4. 会员VIP记录表
+-- ------------------------------------------------------------
+DROP TABLE IF EXISTS `li_enagic_member_vip`;
+CREATE TABLE `li_enagic_member_vip` (
+    `id`                    BIGINT      NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+    `member_id`             BIGINT      NOT NULL                COMMENT '会员ID',
+    `member_name`           VARCHAR(100) DEFAULT NULL           COMMENT '会员名称',
+    `vip_config_id`         BIGINT      DEFAULT NULL           COMMENT 'VIP配置ID',
+    `vip_name`              VARCHAR(50)  DEFAULT NULL           COMMENT 'VIP名称(冗余)',
+    `open_time`             DATETIME     DEFAULT NULL           COMMENT '开通时间',
+    `last_gratitude_remind_time` DATETIME DEFAULT NULL        COMMENT '上次感恩提醒时间',
+    `next_gratitude_remind_time` DATETIME DEFAULT NULL        COMMENT '下次感恩提醒时间',
+    `total_consume_amount`   DECIMAL(12,2) DEFAULT 0.00       COMMENT '累计消费金额',
+    `status`               VARCHAR(20)   DEFAULT 'ACTIVE'      COMMENT '状态',
+    `create_time`          DATETIME      DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_time`           DATETIME      DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_member_id` (`member_id`),
+    KEY `idx_status` (`status`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员VIP记录表';
+
+-- ------------------------------------------------------------
+-- 5. 抵扣金账户表
+-- ------------------------------------------------------------
+DROP TABLE IF EXISTS `li_enagic_deduction`;
+CREATE TABLE `li_enagic_deduction` (
+    `id`                BIGINT        NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+    `member_id`         BIGINT        NOT NULL                COMMENT '会员ID',
+    `member_name`       VARCHAR(100)   DEFAULT NULL           COMMENT '会员名称',
+    `deduction_balance` DECIMAL(12,2)  DEFAULT 0.00         COMMENT '可用抵扣金余额',
+    `frozen_balance`     DECIMAL(12,2)  DEFAULT 0.00         COMMENT '冻结中的抵扣金',
+    `pay_password`       VARCHAR(100)   DEFAULT NULL           COMMENT '支付密码',
+    `create_time`       DATETIME        DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_time`       DATETIME        DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+    PRIMARY KEY (`id`),
+    UNIQUE KEY `uk_member_id` (`member_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='抵扣金账户表';
+
+-- ------------------------------------------------------------
+-- 6. 抵扣金流水表
+-- ------------------------------------------------------------
+DROP TABLE IF EXISTS `li_enagic_deduction_log`;
+CREATE TABLE `li_enagic_deduction_log` (
+    `id`            BIGINT        NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+    `deduction_id` BIGINT        NOT NULL                COMMENT '抵扣金账户ID',
+    `member_id`     BIGINT        NOT NULL                COMMENT '会员ID',
+    `amount`        DECIMAL(12,2) NOT NULL               COMMENT '变动金额',
+    `before_balance` DECIMAL(12,2) DEFAULT NULL          COMMENT '变动前余额',
+    `after_balance`  DECIMAL(12,2) DEFAULT NULL          COMMENT '变动后余额',
+    `type`          VARCHAR(30)   NOT NULL                COMMENT '类型',
+    `order_sn`      VARCHAR(50)    DEFAULT NULL           COMMENT '关联订单号',
+    `remark`        VARCHAR(255)   DEFAULT NULL           COMMENT '备注',
+    `create_time`   DATETIME        DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_deduction_id` (`deduction_id`),
+    KEY `idx_member_id` (`member_id`),
+    KEY `idx_type` (`type`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='抵扣金流水表';
+
+-- ------------------------------------------------------------
+-- 7. 运维流程模板表
+-- ------------------------------------------------------------
+DROP TABLE IF EXISTS `li_enagic_operation_flow`;
+CREATE TABLE `li_enagic_operation_flow` (
+    `id`          BIGINT        NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+    `flow_name`   VARCHAR(100)  NOT NULL                COMMENT '流程名称',
+    `product_id`  BIGINT         DEFAULT NULL           COMMENT '关联商品ID(null=通用)',
+    `nodes`       TEXT           NOT NULL                COMMENT '流程节点JSON',
+    `status`      VARCHAR(20)    DEFAULT 'OPEN'          COMMENT '状态',
+    `create_time` DATETIME        DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_time` DATETIME        DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_product_id` (`product_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='运维流程模板表';
+
+-- ------------------------------------------------------------
+-- 8. 运维计划表
+-- ------------------------------------------------------------
+DROP TABLE IF EXISTS `li_enagic_operation_plan`;
+CREATE TABLE `li_enagic_operation_plan` (
+    `id`                BIGINT      NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+    `flow_id`           BIGINT      NOT NULL                COMMENT '运维流程ID',
+    `member_id`         BIGINT      NOT NULL                COMMENT '客户ID',
+    `member_name`       VARCHAR(100) DEFAULT NULL           COMMENT '客户名称',
+    `product_id`        BIGINT       DEFAULT NULL           COMMENT '关联商品ID',
+    `order_sn`          VARCHAR(50)  DEFAULT NULL           COMMENT '关联订单号',
+    `current_node_index` INT        DEFAULT 0              COMMENT '当前节点索引',
+    `current_node_name` VARCHAR(100) DEFAULT NULL          COMMENT '当前节点名称',
+    `next_node_time`    DATETIME     DEFAULT NULL           COMMENT '下一个节点计划时间',
+    `skip_count`        INT          DEFAULT 0              COMMENT '连续跳过次数',
+    `status`            VARCHAR(20)  DEFAULT 'IN_PROGRESS'  COMMENT '状态',
+    `create_time`       DATETIME     DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_time`       DATETIME     DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_member_id` (`member_id`),
+    KEY `idx_status` (`status`),
+    KEY `idx_next_node_time` (`next_node_time`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='运维计划表';
+
+-- ------------------------------------------------------------
+-- 9. 运维记录表
+-- ------------------------------------------------------------
+DROP TABLE IF EXISTS `li_enagic_operation_record`;
+CREATE TABLE `li_enagic_operation_record` (
+    `id`             BIGINT      NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+    `plan_id`        BIGINT      NOT NULL                COMMENT '运维计划ID',
+    `node_name`      VARCHAR(100) DEFAULT NULL           COMMENT '运维节点名称',
+    `operator_id`    BIGINT       DEFAULT NULL           COMMENT '操作人ID',
+    `operator_name`  VARCHAR(100) DEFAULT NULL           COMMENT '操作人名称',
+    `content`        TEXT         DEFAULT NULL           COMMENT '操作内容',
+    `result`         VARCHAR(255)  DEFAULT NULL           COMMENT '执行结果',
+    `confirm_status` VARCHAR(20)  DEFAULT 'PENDING'     COMMENT '客户确认状态',
+    `operate_time`   DATETIME     DEFAULT NULL           COMMENT '执行时间',
+    `confirm_time`   DATETIME     DEFAULT NULL           COMMENT '确认时间',
+    `create_time`    DATETIME     DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_plan_id` (`plan_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='运维记录表';
+
+-- ------------------------------------------------------------
+-- 10. 客户移交记录表
+-- ------------------------------------------------------------
+DROP TABLE IF EXISTS `li_enagic_member_transfer`;
+CREATE TABLE `li_enagic_member_transfer` (
+    `id`                    BIGINT      NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+    `member_id`             BIGINT      NOT NULL                COMMENT '客户ID',
+    `member_name`           VARCHAR(100) DEFAULT NULL           COMMENT '客户名称',
+    `original_advisor_id`   BIGINT       DEFAULT NULL           COMMENT '原健康布施者ID',
+    `original_advisor_name` VARCHAR(100) DEFAULT NULL           COMMENT '原健康布施者名称',
+    `new_advisor_id`        BIGINT       DEFAULT NULL           COMMENT '接收方ID',
+    `new_advisor_name`      VARCHAR(100) DEFAULT NULL           COMMENT '接收方名称',
+    `transfer_reason`       VARCHAR(200) DEFAULT NULL           COMMENT '移交原因',
+    `trigger_type`          VARCHAR(20)   DEFAULT 'AUTO'       COMMENT '触发类型',
+    `status`                VARCHAR(20)   DEFAULT 'COMPLETED'  COMMENT '状态',
+    `transfer_time`         DATETIME      DEFAULT NULL           COMMENT '转移时间',
+    `create_time`           DATETIME      DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_member_id` (`member_id`),
+    KEY `idx_trigger_type` (`trigger_type`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='客户移交记录表';
+
+-- ------------------------------------------------------------
+-- 11. 行为日志表
+-- ------------------------------------------------------------
+DROP TABLE IF EXISTS `li_enagic_behavior_log`;
+CREATE TABLE `li_enagic_behavior_log` (
+    `id`          BIGINT       NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+    `member_id`   BIGINT        DEFAULT NULL           COMMENT '会员ID',
+    `member_name` VARCHAR(100)  DEFAULT NULL           COMMENT '会员名称',
+    `event_type`  VARCHAR(50)   NOT NULL                COMMENT '事件类型',
+    `event_data`  TEXT          DEFAULT NULL           COMMENT '事件数据JSON',
+    `page_url`    VARCHAR(255)   DEFAULT NULL           COMMENT '页面URL',
+    `device_info` VARCHAR(200)   DEFAULT NULL           COMMENT '设备信息',
+    `ip`          VARCHAR(50)    DEFAULT NULL           COMMENT 'IP地址',
+    `create_time` DATETIME      DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_member_id` (`member_id`),
+    KEY `idx_event_type` (`event_type`),
+    KEY `idx_create_time` (`create_time`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='行为日志表';
+
+-- ------------------------------------------------------------
+-- 12. 素材二维码表
+-- ------------------------------------------------------------
+DROP TABLE IF EXISTS `li_enagic_article_qr`;
+CREATE TABLE `li_enagic_article_qr` (
+    `id`              BIGINT       NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+    `article_id`      BIGINT       NOT NULL                COMMENT '素材ID',
+    `qr_url`          VARCHAR(500)  DEFAULT NULL           COMMENT '二维码URL',
+    `qr_content`      VARCHAR(500)  DEFAULT NULL           COMMENT '二维码内容',
+    `bind_member_id`   BIGINT        DEFAULT NULL           COMMENT '绑定分享者ID',
+    `bind_member_name` VARCHAR(100)  DEFAULT NULL           COMMENT '绑定分享者名称',
+    `expire_time`     DATETIME      DEFAULT NULL           COMMENT '过期时间',
+    `create_time`     DATETIME      DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_article_id` (`article_id`),
+    KEY `idx_bind_member_id` (`bind_member_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='素材二维码表';
+
+-- ------------------------------------------------------------
+-- 13. AI对话记录表
+-- ------------------------------------------------------------
+DROP TABLE IF EXISTS `li_enagic_ai_conversation`;
+CREATE TABLE `li_enagic_ai_conversation` (
+    `id`                  BIGINT       NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+    `member_id`           BIGINT        DEFAULT NULL           COMMENT '会员ID',
+    `session_id`          VARCHAR(64)   DEFAULT NULL           COMMENT '会话ID',
+    `question`            TEXT          NOT NULL                COMMENT '提问',
+    `answer`              TEXT          NOT NULL                COMMENT '回答',
+    `model`               VARCHAR(100)   DEFAULT NULL           COMMENT 'AI模型',
+    `question_type`       VARCHAR(30)   DEFAULT 'OTHER'        COMMENT '问题类型',
+    `has_product_recommend` TINYINT(1)  DEFAULT 0            COMMENT '是否包含产品推荐',
+    `create_time`         DATETIME      DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_member_id` (`member_id`),
+    KEY `idx_session_id` (`session_id`),
+    KEY `idx_create_time` (`create_time`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI对话记录表';
+
+-- ------------------------------------------------------------
+-- 14. AI知识库表
+-- ------------------------------------------------------------
+DROP TABLE IF EXISTS `li_enagic_ai_knowledge`;
+CREATE TABLE `li_enagic_ai_knowledge` (
+    `id`          BIGINT       NOT NULL AUTO_INCREMENT COMMENT '主键ID',
+    `category`   VARCHAR(30)   NOT NULL                COMMENT '分类',
+    `title`       VARCHAR(200)  NOT NULL                COMMENT '标题/问题',
+    `content`     TEXT          NOT NULL                COMMENT '答案内容',
+    `goods_id`    BIGINT         DEFAULT NULL           COMMENT '关联商品ID',
+    `goods_name`  VARCHAR(200)  DEFAULT NULL           COMMENT '关联商品名称',
+    `keywords`    VARCHAR(500)  DEFAULT NULL           COMMENT '关键词',
+    `status`     VARCHAR(20)   DEFAULT 'ACTIVE'        COMMENT '状态',
+    `use_count`   INT            DEFAULT 0             COMMENT '使用次数',
+    `create_time` DATETIME      DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+    `update_time` DATETIME      DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+    PRIMARY KEY (`id`),
+    KEY `idx_category` (`category`),
+    KEY `idx_goods_id` (`goods_id`),
+    KEY `idx_status` (`status`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='AI知识库表';
+
+-- ------------------------------------------------------------
+-- 扩展原有 Lilishop 表
+-- ------------------------------------------------------------
+-- 会员表扩展
+ALTER TABLE `li_member`
+    ADD COLUMN `health_advisor_id` BIGINT DEFAULT NULL COMMENT '关联健康布施者ID' AFTER `store_id`,
+    ADD COLUMN `advisor_credits` INT DEFAULT 0 COMMENT '顾问积分' AFTER `health_advisor_id`,
+    ADD INDEX `idx_health_advisor_id` (`health_advisor_id`);
+
+-- 会员等级表扩展
+ALTER TABLE `li_member_grade`
+    ADD COLUMN `upgrade_conditions` TEXT DEFAULT NULL COMMENT '升级条件JSON' AFTER `description`;
+
+-- 素材/文章表扩展
+ALTER TABLE `li_article`
+    ADD COLUMN `view_role` VARCHAR(20) DEFAULT 'ALL' COMMENT '可见角色:ALL/CONSUMER_ONLY' AFTER `status`;
+
+-- 分销表扩展
+ALTER TABLE `li_distribution`
+    ADD COLUMN `medal_level` VARCHAR(20) DEFAULT NULL COMMENT '勋章等级' AFTER `distribution_status`,
+    ADD COLUMN `permanent_bind` TINYINT(1) DEFAULT 1 COMMENT '是否永久绑定' AFTER `medal_level`;
+
+-- 商品表扩展(关联运维流程)
+ALTER TABLE `li_goods`
+    ADD COLUMN `operation_flow_id` BIGINT DEFAULT NULL COMMENT '关联运维流程ID' AFTER `goods_type`,
+    ADD INDEX `idx_operation_flow_id` (`operation_flow_id`);
+
+SET FOREIGN_KEY_CHECKS = 1;
+
+-- ============================================================
+-- 初始化完成
+-- ============================================================

+ 48 - 0
代码/enagic-lilishop/enagic-plugin/build.sh

@@ -0,0 +1,48 @@
+#!/bin/bash
+set -e
+
+PROJECT_ROOT="$(cd "$(dirname "$0")" && pwd)"
+cd "$PROJECT_ROOT"
+
+echo "=== Enagic Plugin Build Script ==="
+echo "Project: $PROJECT_ROOT"
+
+case "${1:-install}" in
+  install)
+    echo "[1/4] Building enagic-entity..."
+    cd enagic-entity && mvn clean install -DskipTests -q && cd ..
+
+    echo "[2/4] Building enagic-api..."
+    cd enagic-api && mvn clean install -DskipTests -q && cd ..
+
+    echo "[3/4] Building enagic-consumer..."
+    cd enagic-consumer && mvn clean install -DskipTests -q && cd ..
+
+    echo "[4/4] Building enagic-admin..."
+    cd enagic-admin && mvn clean install -DskipTests -q && cd ..
+
+    echo ""
+    echo "=== Build Complete ==="
+    echo "JAR files:"
+    find . -name "*.jar" -path "*/target/*" ! -name "*-sources.jar" ! -name "*-javadoc.jar" 2>/dev/null
+    ;;
+
+  package)
+    mvn clean package -DskipTests
+    echo "=== Package Complete ==="
+    ls -la enagic-*/target/*.jar 2>/dev/null || echo "  (run 'install' first)"
+    ;;
+
+  clean)
+    mvn clean
+    rm -rf enagic-*/target
+    echo "=== Clean Complete ==="
+    ;;
+
+  *)
+    echo "Usage: $0 [install|package|clean]"
+    echo "  install - Clean install all modules (default)"
+    echo "  package - Package all modules (with full build)"
+    echo "  clean   - Clean all build artifacts"
+    ;;
+esac

+ 78 - 0
代码/enagic-lilishop/enagic-plugin/config/application-enagic.yml

@@ -0,0 +1,78 @@
+# ============================================================
+# Enagic 配置 - 适用于 Lilishop Spring Boot 项目
+# 复制到 Lilishop 的 config/ 目录或作为 application-enagic.yml
+# ============================================================
+
+enagic:
+  # AI 数字人配置
+  ai:
+    provider: siliconflow
+    api-key: ${AI_API_KEY:}
+    model: Qwen/Qwen2.5-7B-Instruct
+    base-url: https://api.siliconflow.cn/v1
+    timeout: 30000
+
+  # 健康布施者配置
+  health-advisor:
+    # 勋章触发条件
+    medal-conditions:
+      STAR_1: 1       # 首次邀请
+      STAR_2: 5       # 邀请5人
+      STAR_3: 20      # 邀请20人
+      MASTER: 50     # 邀请50人
+    # 永久绑定
+    permanent-bind: true
+
+  # VIP 配置
+  vip:
+    # 默认无到期时间
+    default-no-expiry: true
+    # 感恩提醒周期(天)
+    default-gratitude-days: 30
+
+  # 运维流程配置
+  operation:
+    # 最大跳过次数(超过则自动转移)
+    max-skip-count: 3
+    # 自动转移目标(0=平台客服)
+    transfer-target-id: 0
+    transfer-target-name: 平台客服
+
+  # 抵扣金配置
+  deduction:
+    # 最低抵扣金额(元)
+    min-deduction: 1
+    # 支持部分抵扣
+    allow-partial: true
+
+# RocketMQ 配置(确保与 Lilishop 一致)
+rocketmq:
+  name-server: ${ROCKETMQ_NAMESRV_ADDR:127.0.0.1:9876}
+  producer:
+    group: enagic-producer-group
+
+# XXL-Job 配置
+xxl:
+  job:
+    admin:
+      addresses: ${XXL_JOB_ADMIN_ADDRESSES:http://127.0.0.1:8080/xxl-job-admin}
+    executor:
+      appname: enagic-executor
+      port: 9999
+      logpath: /data/applogs/xxl-job/enagic-executor
+    access-token: ${XXL_JOB_ACCESS_TOKEN:}
+
+# 数据库连接(如果是独立部署)
+spring:
+  datasource:
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: ${DB_URL:jdbc:mysql://127.0.0.1:3306/lilishop?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai}
+    username: ${DB_USER:root}
+    password: ${DB_PASSWORD:123456}
+
+# Redis 配置
+  redis:
+    host: ${REDIS_HOST:127.0.0.1}
+    port: ${REDIS_PORT:6379}
+    password: ${REDIS_PASSWORD:}
+    database: 0

+ 76 - 0
代码/enagic-lilishop/enagic-plugin/docker-compose.yml

@@ -0,0 +1,76 @@
+version: '3.8'
+
+services:
+  mysql:
+    image: mysql:8.0
+    container_name: enagic-mysql
+    environment:
+      MYSQL_ROOT_PASSWORD: 123456
+      MYSQL_DATABASE: lilishop
+      MYSQL_USER: enagic
+      MYSQL_PASSWORD: enagic123
+    ports:
+      - "3306:3306"
+    volumes:
+      - mysql-data:/var/lib/mysql
+      - ./DB/enagic_init.sql:/docker-entrypoint-initdb.d/02_enagic.sql
+    command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
+    healthcheck:
+      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
+      interval: 10s
+      timeout: 5s
+      retries: 5
+
+  redis:
+    image: redis:6-alpine
+    container_name: enagic-redis
+    ports:
+      - "6379:6379"
+    volumes:
+      - redis-data:/data
+    command: redis-server --appendonly yes
+
+  rocketmq:
+    image: apache/rocketmq:4.9.4
+    container_name: enagic-rocketmq
+    ports:
+      - "9876:9876"
+      - "10911:10911"
+    volumes:
+      - rocketmq-data:/opt/rocketmq/store
+    environment:
+      JAVA_OPTS: "-Drocketmq.namesrv.addr=localhost:9876"
+    command: sh mqnamesrv
+
+  lilishop:
+    image: pickmall/lilishop:4.3
+    container_name: enagic-lilishop
+    ports:
+      - "8080:8080"
+    environment:
+      SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/lilishop?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
+      SPRING_DATASOURCE_USERNAME: root
+      SPRING_DATASOURCE_PASSWORD: 123456
+      SPRING_REDIS_HOST: redis
+      SPRING_REDIS_PORT: 6379
+      ROCKETMQ_NAMESRV_ADDR: rocketmq:9876
+    depends_on:
+      mysql:
+        condition: service_healthy
+      redis:
+        condition: service_started
+      rocketmq:
+        condition: service_started
+    volumes:
+      - ./enagic-plugin/target/enagic-*.jar:/app/libs/enagic-plugin.jar
+    extra_hosts:
+      - "host.docker.internal:host-gateway"
+
+volumes:
+  mysql-data:
+  redis-data:
+  rocketmq-data:
+
+networks:
+  default:
+    name: enagic-network

+ 258 - 0
代码/enagic-lilishop/enagic-plugin/docs/DEPLOYMENT.md

@@ -0,0 +1,258 @@
+# Enagic 部署指南
+
+本文档介绍 Enagic 插件的生产环境部署方案。
+
+## 环境要求
+
+| 组件 | 版本要求 | 说明 |
+|------|---------|------|
+| JDK | 1.8+ | 推荐 JDK 11 |
+| MySQL | 8.0+ | 需要 UTF8MB4 编码 |
+| Redis | 6.0+ | |
+| RocketMQ | 4.9+ | |
+| Nginx | 1.18+ | 用于静态资源 |
+
+## 部署模式
+
+### 模式一:Docker Compose(开发/测试)
+
+```bash
+# 启动所有服务
+docker-compose up -d
+
+# 查看日志
+docker-compose logs -f
+
+# 停止
+docker-compose down
+```
+
+### 模式二:Kubernetes(生产)
+
+创建部署清单:
+
+```yaml
+# k8s/enagic-deployment.yaml
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+  name: enagic-lilishop
+spec:
+  replicas: 2
+  selector:
+    matchLabels:
+      app: enagic-lilishop
+  template:
+    metadata:
+      labels:
+        app: enagic-lilishop
+    spec:
+      containers:
+      - name: lilishop
+        image: enagic/lilishop:4.3
+        ports:
+        - containerPort: 8080
+        env:
+        - name: SPRING_PROFILES_ACTIVE
+          value: prod
+        - name: DB_HOST
+          valueFrom:
+            configMapKeyRef:
+              name: enagic-config
+              key: db.host
+```
+
+## 配置清单
+
+### 环境变量
+
+```bash
+# AI 配置
+export AI_API_KEY="sk-xxxxx"
+export AI_PROVIDER="siliconflow"
+
+# 数据库
+export DB_HOST="mysql"
+export DB_PORT="3306"
+export DB_NAME="lilishop"
+export DB_USER="root"
+export DB_PASSWORD="123456"
+
+# Redis
+export REDIS_HOST="redis"
+export REDIS_PORT="6379"
+
+# RocketMQ
+export ROCKETMQ_NAMESRV_ADDR="rocketmq:9876"
+```
+
+### 配置文件
+
+```yaml
+# application-prod.yml
+spring:
+  datasource:
+    url: jdbc:mysql://${DB_HOST}:${DB_PORT}/${DB_NAME}?useUnicode=true&characterEncoding=utf8
+    username: ${DB_USER}
+    password: ${DB_PASSWORD}
+  redis:
+    host: ${REDIS_HOST}
+    port: ${REDIS_PORT}
+
+rocketmq:
+  name-server: ${ROCKETMQ_NAMESRV_ADDR}
+
+enagic:
+  ai:
+    api-key: ${AI_API_KEY}
+```
+
+## 部署步骤
+
+### 1. 准备数据库
+
+```bash
+# 执行 DDL
+mysql -h $DB_HOST -u $DB_USER -p$DB_PASSWORD $DB_NAME < DB/enagic_init.sql
+```
+
+### 2. 上传 JAR 包
+
+```bash
+# 方式一:独立上传
+scp enagic-*.jar user@server:/app/lib/
+
+# 方式二:Docker 镜像
+docker build -t enagic/lilishop:4.3 .
+docker push enagic/lilishop:4.3
+```
+
+### 3. 启动服务
+
+```bash
+# 直接启动
+java -jar -Dspring.profiles.active=prod lilishop.jar
+
+# 或 Docker
+docker run -d -p 8080:8080 --env-file .env enagic/lilishop:4.3
+```
+
+### 4. 配置 Nginx
+
+```nginx
+# /etc/nginx/conf.d/enagic.conf
+upstream lilishop {
+    server 127.0.0.1:8080;
+}
+
+server {
+    listen 80;
+    server_name enagic.example.com;
+    
+    location / {
+        proxy_pass http://lilishop;
+        proxy_set_header Host $host;
+        proxy_set_header X-Real-IP $remote_addr;
+    }
+    
+    location /enagic/ {
+        proxy_pass http://lilishop/enagic/;
+    }
+    
+    location /api/ {
+        proxy_pass http://lilishop/api/;
+    }
+}
+```
+
+## 健康检查
+
+### 端点检查
+
+```bash
+# API 健康
+curl http://localhost:8080/enagic/manager/advisor/page
+
+# 应用健康
+curl http://localhost:8080/health
+
+# DB 连接
+mysql -h $DB_HOST -u $DB_USER -p$DB_PASSWORD -e "SELECT 1"
+```
+
+### 监控指标
+
+```bash
+# RocketMQ 消费者状态
+curl http://localhost:8080/actuator/metrics/rocketmq.consume.thread
+
+# JVM 状态
+curl http://localhost:8080/actuator/metrics/jvm.memory.used
+```
+
+## 回滚方案
+
+### 回滚 JAR
+
+```bash
+# 记录当前版本
+docker tag enagic/lilishop:4.3 enagic/lilishop:rollback-$(date +%Y%m%d)
+
+# 回滚到上一版本
+docker pull enagic/lilishop:4.3-previous
+docker-compose up -d
+```
+
+### 回滚数据库
+
+```bash
+# 备份当前数据
+mysqldump -h $DB_HOST -u $DB_USER -p$DB_PASSWORD $DB_NAME > backup_$(date +%Y%m%d).sql
+
+# 如需回滚表结构(谨慎)
+# 编辑 enagic_init.sql 注释掉需要保留的数据
+```
+
+## 运维命令
+
+```bash
+# 重启消费者
+docker restart enagic-consumer
+
+# 查看日志
+docker logs -f enagic-lilishop --tail 100
+
+# 查看 RocketMQ 消费情况
+mqadmin consumerProgress -n localhost:9876 -g enagic-order-consumer-group
+
+# 手动触发运维提醒
+curl -X POST http://localhost:8080/enagic/manager/operation/plan/remind \
+  -H "Content-Type: application/json" \
+  -d '{"id": 1}'
+```
+
+## 性能优化
+
+### 数据库
+
+```sql
+-- 关键索引
+CREATE INDEX idx_enagic_member_mobile ON li_enagic_member(mobile);
+CREATE INDEX idx_enagic_order_create ON li_enagic_order(create_time);
+```
+
+### Redis
+
+```yaml
+# 配置缓存
+spring:
+  cache:
+    type: redis
+    redis:
+      time-to-live: 3600000
+```
+
+### JVM
+
+```bash
+java -jar -Xms2g -Xmx4g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 lilishop.jar

+ 196 - 0
代码/enagic-lilishop/enagic-plugin/docs/INTEGRATION.md

@@ -0,0 +1,196 @@
+# Enagic 插件集成指南
+
+本文档详细介绍如何将 Enagic 插件集成到 Lilishop 商城系统。
+
+## 集成架构
+
+```
+┌─────────────────────────────────────────────────────┐
+│                   Lilishop B2B2C                     │
+│  ┌─────────────────────────────────────────────┐    │
+│  │           enagic-plugin (4个Maven模块)       │    │
+│  │  ┌──────────┐ ┌────────┐ ┌─────────┐ ┌────┐  │    │
+│  │  │enagic-   │ │enagic- │ │enagic-  │ │ena-│  │    │
+│  │  │entity    │ │api     │ │consumer │ │gic │  │    │
+│  │  │(14张表)  │ │(30+API)│ │(MQ监听) │ │-ad │  │    │
+│  │  └──────────┘ └────────┘ └─────────┘ │min │  │    │
+│  │                                      └────┘  │    │
+│  └─────────────────────────────────────────────┘    │
+└─────────────────────────────────────────────────────┘
+```
+
+## 集成步骤
+
+### 1. 数据库集成
+
+#### 1.1 创建数据库表
+
+```sql
+-- 执行 DDL 脚本创建 14 张新表
+mysql -u root -p lilishop < DB/enagic_init.sql
+```
+
+DDL 脚本包含:
+- 14 张新表:`li_enagic_*`
+- 5 个 ALTER TABLE:扩展原有 Lilishop 表
+
+#### 1.2 验证表创建
+
+```sql
+SHOW TABLES LIKE 'li_enagic_%';
+-- 应显示 14 张表
+
+-- 验证扩展字段
+SHOW COLUMNS FROM li_member LIKE 'healthAdviserId';
+SHOW COLUMNS FROM li_distribution LIKE 'medal_level';
+```
+
+### 2. 后端集成
+
+#### 2.1 构建 enagic-plugin
+
+```bash
+cd enagic-plugin
+./build.sh install
+
+# 或手动构建
+cd enagic-entity && mvn clean install
+cd ../enagic-api && mvn clean install
+cd ../enagic-consumer && mvn clean install
+cd ../enagic-admin && mvn clean install
+```
+
+#### 2.2 部署 JAR
+
+**方式一:独立部署(推荐)**
+```bash
+# 拷贝到 Lilishop 的 lib 目录
+cp enagic-api/target/enagic-api-1.0.0.jar $LILISHOP_HOME/lib/
+cp enagic-entity/target/enagic-entity-1.0.0.jar $LILISHOP_HOME/lib/
+cp enagic-consumer/target/enagic-consumer-1.0.0.jar $LILISHOP_HOME/lib/
+cp enagic-admin/target/enagic-admin-1.0.0.jar $LILISHOP_HOME/lib/
+```
+
+**方式二:POM 依赖**
+```xml
+<!-- 在 Lilishop 的 pom.xml 中添加 -->
+<dependency>
+    <groupId>com.enagic</groupId>
+    <artifactId>enagic-api</artifactId>
+    <version>1.0.0</version>
+</dependency>
+```
+
+#### 2.3 配置
+
+将 `config/application-enagic.yml` 合并到 Lilishop 的 `application.yml`:
+
+```yaml
+enagic:
+  ai:
+    provider: siliconflow
+    api-key: ${AI_API_KEY}
+    model: Qwen/Qwen2.5-7B-Instruct
+    base-url: https://api.siliconflow.cn/v1
+  
+  health-advisor:
+    enabled: true
+    permanent-bind: true
+  
+  vip:
+    enabled: true
+    no-expiry: true
+  
+  deduction:
+    enabled: true
+  
+  operation:
+    enabled: true
+    default-flow-id: 1
+```
+
+### 3. 前端集成
+
+#### 3.1 PC 管理后台
+
+```bash
+# 构建 Vue
+cd enagic-admin
+npm install
+npm run build
+
+# 部署到 Lilishop admin
+cp -r dist/* $LILISHOP_ADMIN/public/enagic-admin/
+```
+
+或在 Lilishop admin 源码中:
+```bash
+# 复制到现有 admin 项目
+cp -r enagic-admin/src/main/vue/* $LILISHOP_ADMIN/src/views/enagic/
+```
+
+#### 3.2 小程序端
+
+```bash
+# fork 并改造 UniApp
+# 参考 enagic-uniapp 项目
+```
+
+### 4. 消息队列集成
+
+确保 RocketMQ 监听 `order_topic`:
+
+```yaml
+# RocketMQ 配置
+rocketmq:
+  name-server: localhost:9876
+  consumer:
+    group: enagic-order-consumer-group
+```
+
+监听的事件类型:
+- `ORDER_CREATED` - 订单创建
+- `ORDER_DELIVERED` - 订单发货(触发运维计划)
+- `ORDER_COMPLETED` - 订单完成
+- `ORDER_CANCELLED` - 订单取消
+
+## 验证清单
+
+### API 验证
+
+```bash
+# 健康布施者 API
+curl -X GET http://localhost:8080/enagic/manager/advisor/page
+
+# VIP 配置
+curl -X GET http://localhost:8080/enagic/manager/vip/config/page
+
+# 运维流程
+curl -X GET http://localhost:8080/enagic/manager/operation/flow/page
+
+# AI 知识库
+curl -X GET http://localhost:8080/enagic/manager/ai/knowledge/page
+```
+
+### 功能验证
+
+- [ ] 14 张新表创建成功
+- [ ] Maven 编译通过
+- [ ] 管理端 API 返回正常
+- [ ] 买家端 API 可访问
+- [ ] RocketMQ 消费者启动
+- [ ] 定时任务可执行
+
+## 常见问题
+
+### Q1: 编译报错 "找不到 Lilishop 类"
+**解决**:确保 Lilishop 依赖在 pom.xml 中正确配置
+
+### Q2: API 404
+**解决**:检查 `@ComponentScan("com.enagic")` 是否生效
+
+### Q3: RocketMQ 消息不消费
+**解决**:检查 consumer group 名称是否与 producer 一致
+
+### Q4: 小程序页面 404
+**解决**:检查 pages.json 配置和路由注册

+ 157 - 0
代码/enagic-lilishop/enagic-plugin/docs/PHASE0_SETUP.md

@@ -0,0 +1,157 @@
+# Phase 0: 环境搭建指南
+
+## 前置条件
+
+- JDK 1.8+
+- Maven 3.6+
+- MySQL 5.7+ / 8.0+
+- Redis 6+
+- Git
+
+## Step 1: 设置 Lilishop 源码工作树
+
+```bash
+# 进入 enagic 项目目录
+cd /mnt/e/workspace/enagic/代码/enagic-lilishop
+
+# 创建 Lilishop 源码工作树(不复制文件,只建立 git 关联)
+git worktree add ../lilishop-worktree /mnt/e/workspace/iwt/lilishop
+
+# 确认工作树创建成功
+git worktree list
+```
+
+预期输出:
+```
+/mnt/e/workspace/enagic/代码/enagic-lilishop   38f3a1c [master]
+/mnt/e/workspace/enagic/代码/lilishop-worktree  abc1234 master
+```
+
+## Step 2: 初始化数据库
+
+```bash
+# 登录 MySQL
+mysql -u root -p
+
+# 创建数据库(如果尚未创建)
+CREATE DATABASE IF NOT EXISTS lilishop DEFAULT CHARACTER SET utf8mb4;
+
+# 执行 Enagic DDL
+SOURCE /mnt/e/workspace/enagic/代码/enagic-lilishop/enagic-plugin/DB/enagic_init.sql;
+```
+
+## Step 3: 构建 Lilishop 源码
+
+```bash
+cd /mnt/e/workspace/enagic/代码/lilishop-worktree
+
+# 编译所有模块(跳过测试以加快速度)
+mvn clean install -DskipTests -q
+
+# 预期输出:BUILD SUCCESS(如果依赖完整)
+```
+
+## Step 4: 集成 enagic-plugin
+
+**方式 A:在 Lilishop pom.xml 中添加模块(推荐)**
+
+```bash
+cd /mnt/e/workspace/iwt/lilishop
+
+# 将 enagic-plugin 目录链接到 Lilishop 模块目录
+cp -r /mnt/e/workspace/enagic/代码/enagic-lilishop/enagic-plugin ./
+
+# 在 Lilishop pom.xml 的 <modules> 中添加
+# <module>enagic-plugin</module>
+
+# 编辑 pom.xml
+# 在 </modules> 前添加:
+#     <module>enagic-plugin</module>
+```
+
+**方式 B:通过 Maven 依赖引用**
+
+```bash
+cd /mnt/e/workspace/enagic/代码/enagic-lilishop/enagic-plugin
+
+# 安装 enagic-plugin 到本地 Maven 仓库
+mvn clean install -DskipTests -q
+
+# 然后在 Lilishop 的 pom.xml dependencies 中添加:
+# <dependency>
+#     <groupId>com.enagic</groupId>
+#     <artifactId>enagic-entity</artifactId>
+#     <version>1.0.0</version>
+# </dependency>
+# <dependency>
+#     <groupId>com.enagic</groupId>
+#     <artifactId>enagic-api</artifactId>
+#     <version>1.0.0</version>
+# </dependency>
+# ... 其他模块同理
+```
+
+## Step 5: 重新构建并验证
+
+```bash
+cd /mnt/e/workspace/iwt/lilishop
+
+# 完整编译
+mvn clean compile -DskipTests
+
+# 如果无编译错误,说明集成成功
+```
+
+## Step 6: 配置并启动
+
+```bash
+# 复制配置文件
+cp /mnt/e/workspace/enagic/代码/enagic-lilishop/enagic-plugin/config/application-enagic.yml \
+   /path/to/lilishop/config/application.yml
+
+# 编辑配置(填写数据库、AI API Key 等)
+vim /path/to/lilishop/config/application.yml
+
+# 启动 Lilishop
+java -jar /path/to/lilishop/lilishop.jar
+```
+
+## Step 7: 验证集成
+
+```bash
+# 验证 API 是否注册成功
+curl http://localhost:8080/enagic/buyer/ai/hot-questions
+
+# 预期返回 JSON
+```
+
+## 常见问题
+
+### 编译报错:找不到 com.dan 包
+→ 说明 Lilishop 源码未正确编译。执行 `mvn clean install -DskipTests` 安装所有 Lilishop 模块。
+
+### 编译报错:找不到 enagic-entity
+→ 先 `cd enagic-plugin && mvn install -DskipTests` 安装 enagic 模块。
+
+### 数据库报错:表已存在
+→ DDL 中使用 `DROP TABLE IF EXISTS`,重新执行不会冲突。如果报错外键约束,执行 `SET FOREIGN_KEY_CHECKS = 0;` 后重试。
+
+### Redis 未连接
+→ 确保 Redis 服务启动,且 `application.yml` 中的 Redis 配置正确。
+
+## 目录结构(集成后)
+
+```
+/path/to/lilishop/
+├── lilishop.jar                    # Lilishop 主 JAR
+├── config/
+│   └── application.yml             # 配置文件(含 enagic 配置)
+├── lib/                            # 外部依赖 JAR
+│   └── (enagic-*.jar)              # 如果用方式 B 部署
+├── enagic-plugin/                   # Enagic 插件(方式 A)
+│   ├── enagic-entity/
+│   ├── enagic-api/
+│   ├── enagic-admin/
+│   └── enagic-consumer/
+└── ... Lilishop 原目录
+```

+ 32 - 0
代码/enagic-lilishop/enagic-plugin/docs/README.md

@@ -0,0 +1,32 @@
+# Enagic 插件文档
+
+本文档目录包含 Enagic 插件的部署、集成和测试文档。
+
+## 文档列表
+
+| 文档 | 说明 |
+|------|------|
+| [PHASE0_SETUP.md](./PHASE0_SETUP.md) | 开发环境搭建指南 |
+| [INTEGRATION.md](./INTEGRATION.md) | 集成指南 - 如何将 Enagic 插件集成到 Lilishop |
+| [DEPLOYMENT.md](./DEPLOYMENT.md) | 部署指南 - 生产环境部署方案 |
+| [TEST_CHECKLIST.md](./TEST_CHECKLIST.md) | 测试检查清单 - 完整的测试验证项 |
+
+## 快速导航
+
+### 开发人员
+- 首次开发环境搭建 → [PHASE0_SETUP.md](./PHASE0_SETUP.md)
+- 本地运行调试 → [INTEGRATION.md](./INTEGRATION.md) 集成步骤
+
+### 运维人员
+- 生产环境部署 → [DEPLOYMENT.md](./DEPLOYMENT.md)
+- Docker/K8s 部署 → 同上文档
+
+### 测试人员
+- 测试用例 → [TEST_CHECKLIST.md](./TEST_CHECKLIST.md)
+- 验证清单 → 同上文档
+
+## 相关资源
+
+- **SPEC.md** - 完整技术规格文档(位于代码目录)
+- **README.md** - 项目概览和快速开始(位于代码目录)
+- **DDL** - 数据库初始化脚本(位于 DB/enagic_init.sql)

+ 200 - 0
代码/enagic-lilishop/enagic-plugin/docs/TEST_CHECKLIST.md

@@ -0,0 +1,200 @@
+# Enagic 集成测试检查清单
+
+## 阶段一:环境验证
+
+### 1.1 数据库
+- [ ] MySQL 8.0+ 运行正常
+- [ ] 14 张新表创建成功 (`li_enagic_*`)
+- [ ] 5 个 ALTER TABLE 扩展成功
+- [ ] 表结构和 SPEC.md 一致
+- [ ] 索引创建完成
+
+### 1.2 构建
+- [ ] Maven 编译通过(无错误)
+- [ ] 所有模块 JAR 生成成功
+- [ ] 无警告信息
+
+### 1.3 配置
+- [ ] application-enagic.yml 加载成功
+- [ ] AI API Key 配置正确
+- [ ] RocketMQ 连接成功
+- [ ] Redis 连接成功
+
+## 阶段二:管理端 API
+
+### 2.1 健康布施者管理
+- [ ] GET `/enagic/manager/advisor/page` 返回 200
+- [ ] 分页参数正常(pageNum, pageSize)
+- [ ] 搜索功能正常(keyword)
+- [ ] 状态过滤正常(status)
+
+### 2.2 VIP 配置
+- [ ] GET `/enagic/manager/vip/config/page` 返回 200
+- [ ] POST `/enagic/manager/vip/config/save` 创建成功
+- [ ] PUT `/enagic/manager/vip/config/{id}` 更新成功
+- [ ] DELETE `/enagic/manager/vip/config/{id}` 删除成功
+
+### 2.3 运维流程
+- [ ] GET `/enagic/manager/operation/flow/page` 返回 200
+- [ ] POST `/enagic/manager/operation/flow/save` 创建成功
+- [ ] GET `/enagic/manager/operation/plan/page` 返回 200
+- [ ] POST `/enagic/manager/operation/plan/remind` 触发提醒
+
+### 2.4 AI 知识库
+- [ ] GET `/enagic/manager/ai/knowledge/page` 返回 200
+- [ ] POST `/enagic/manager/ai/knowledge/save` 创建成功
+- [ ] DELETE `/enagic/manager/ai/knowledge/{id}` 删除成功
+- [ ] GET `/enagic/manager/ai/conversation-log` 返回对话记录
+
+### 2.5 客户移交
+- [ ] GET `/enagic/manager/transfer/page` 返回 200
+- [ ] POST `/enagic/manager/transfer/process` 处理移交
+
+### 2.6 抵扣金
+- [ ] GET `/enagic/manager/deduction/page` 返回 200
+- [ ] GET `/enagic/manager/deduction/log` 返回流水
+
+## 阶段三:买家端 API
+
+### 3.1 AI 数字人
+- [ ] POST `/enagic/buyer/ai/chat` 返回 AI 回复
+- [ ] GET `/enagic/buyer/ai/history` 返回历史对话
+- [ ] GET `/enagic/buyer/ai/hot-questions` 返回热门问题
+
+### 3.2 健康布施者
+- [ ] GET `/enagic/buyer/advisor/info` 返回布施者信息
+- [ ] GET `/enagic/buyer/advisor/my-customers` 返回客户列表
+- [ ] GET `/enagic/buyer/advisor/invite-qr` 生成邀请二维码
+- [ ] POST `/enagic/buyer/advisor/apply` 申请成为布施者
+
+### 3.3 VIP
+- [ ] GET `/enagic/buyer/vip/info` 返回 VIP 信息
+- [ ] POST `/enagic/buyer/vip/open` 开通 VIP
+- [ ] GET `/enagic/buyer/vip/config-list` 返回配置列表
+
+### 3.4 抵扣金
+- [ ] GET `/enagic/buyer/deduction/info` 返回账户信息
+- [ ] GET `/enagic/buyer/deduction/log` 返回流水
+
+### 3.5 运维计划
+- [ ] GET `/enagic/buyer/operation/my-plans` 返回我的计划
+- [ ] GET `/enagic/buyer/operation/detail/{id}` 返回详情
+- [ ] GET `/enagic/buyer/operation/records/{planId}` 返回记录
+
+### 3.6 素材二维码
+- [ ] GET `/enagic/buyer/article/qr/{articleId}` 返回二维码
+
+## 阶段四:事件驱动
+
+### 4.1 RocketMQ 消费者
+- [ ] 消费者启动成功
+- [ ] 监听 `order_topic` 正常
+- [ ] ORDER_CREATED 事件处理
+- [ ] ORDER_DELIVERED 事件触发运维计划创建
+- [ ] ORDER_COMPLETED 事件处理
+- [ ] ORDER_CANCELLED 事件处理
+
+### 4.2 定时任务
+- [ ] 运维提醒任务执行正常
+- [ ] VIP 感恩提醒任务执行正常
+
+## 阶段五:前端页面
+
+### 5.1 PC 管理后台
+- [ ] 健康布施者列表页正常显示
+- [ ] 勋章管理功能正常
+- [ ] VIP 配置 CRUD 正常
+- [ ] 抵扣金账户显示正常
+- [ ] 运维计划列表显示正常
+- [ ] 运维流程模板 CRUD 正常
+- [ ] AI 知识库管理正常
+- [ ] 对话记录查看正常
+- [ ] 客户移交记录显示正常
+- [ ] 分页、搜索、筛选功能正常
+
+### 5.2 小程序端
+- [ ] AI 聊天页面可交互
+- [ ] 健康布施者中心显示正常
+- [ ] 客户列表显示正常
+- [ ] 勋章展示正常
+- [ ] VIP 页面显示正常
+- [ ] 抵扣金页面显示正常
+- [ ] 运维计划页面显示正常
+
+## 阶段六:集成测试
+
+### 6.1 业务流程
+- [ ] 用户注册 → 成为客户
+- [ ] 申请成为布施者 → 审核通过
+- [ ] 邀请客户 → 绑定关系建立
+- [ ] 客户下单 → 订单发货 → 运维计划自动创建
+- [ ] 运维提醒 → 客户响应
+- [ ] 开通 VIP → 享受权益
+- [ ] 使用抵扣金 → 订单抵扣
+
+### 6.2 边界情况
+- [ ] 无布施者时的默认流程
+- [ ] 无运维流程模板时的处理
+- [ ] 抵扣金余额不足时的提示
+- [ ] VIP 无到期时间的处理
+
+## 阶段七:性能与安全
+
+### 7.1 性能
+- [ ] API 响应时间 < 500ms (95th percentile)
+- [ ] 数据库查询有适当索引
+- [ ] Redis 缓存生效
+
+### 7.2 安全
+- [ ] API 权限控制正常
+- [ ] 敏感数据加密存储
+- [ ] 输入验证正常
+- [ ] SQL 注入防护
+
+## 阶段八:数据验证
+
+### 8.1 数据完整性
+- [ ] 布施者信息完整
+- [ ] VIP 记录正确
+- [ ] 抵扣金计算正确
+- [ ] 运维记录完整
+
+### 8.2 数据一致性
+- [ ] 客户和布施者关系正确
+- [ ] 订单和运维计划关联正确
+- [ ] VIP 和抵扣金状态一致
+
+---
+
+## 测试报告模板
+
+```markdown
+## 测试结果汇总
+
+| 阶段 | 通过 | 失败 | 跳过 | 总计 |
+|------|------|------|------|------|
+| 环境验证 | - | - | - | - |
+| 管理端 API | - | - | - | - |
+| 买家端 API | - | - | - | - |
+| 事件驱动 | - | - | - | - |
+| 前端页面 | - | - | - | - |
+| 集成测试 | - | - | - | - |
+
+## 问题记录
+
+| # | 阶段 | 问题描述 | 严重程度 | 状态 |
+|---|------|---------|---------|------|
+| 1 | | | | |
+
+## 测试结论
+
+- [ ] 可以上线
+- [ ] 需要修复后上线
+- [ ] 需要进一步验证
+```
+
+---
+
+**测试负责人**:________________  
+**测试日期**:________________  
+**版本号**:________________

+ 86 - 0
代码/enagic-lilishop/enagic-plugin/enagic-admin/README.md

@@ -0,0 +1,86 @@
+# Enagic Admin Plugin - 后台管理 Vue 页面
+
+本目录包含 PC 后台管理的 Enagic 扩展页面,打包后部署到 Lilishop admin 项目的 `static/enagic-admin/` 目录。
+
+## 目录结构
+
+```
+src/
+├── views/
+│   └── enagic/
+│       ├── health-advisor/              # 健康布施者管理
+│       │   ├── list.vue                # 健康布施者列表
+│       │   ├── detail.vue             # 健康布施者详情
+│       │   ├── medal.vue              # 勋章管理
+│       │   └── statistics.vue         # 数据统计
+│       │
+│       ├── vip/                        # VIP 管理
+│       │   ├── config-list.vue         # VIP 配置列表
+│       │   ├── config-form.vue         # VIP 配置表单
+│       │   └── member-vip.vue          # 会员 VIP 列表
+│       │
+│       ├── deduction/                   # 抵扣金管理
+│       │   ├── account-list.vue       # 抵扣金账户列表
+│       │   └── log-list.vue            # 抵扣金流水
+│       │
+│       ├── operation/                  # 运维流程管理
+│       │   ├── flow-list.vue          # 流程模板列表
+│       │   ├── flow-form.vue          # 流程模板表单
+│       │   ├── plan-list.vue          # 运维计划列表
+│       │   └── record-list.vue        # 运维记录
+│       │
+│       ├── ai/                         # AI 数字人管理
+│       │   ├── knowledge-list.vue     # 知识库列表
+│       │   ├── knowledge-form.vue     # 知识库编辑
+│       │   └── conversation-log.vue   # 对话记录
+│       │
+│       ├── transfer/                   # 客户移交管理
+│       │   └── list.vue               # 移交记录
+│       │
+│       └── article/                    # 素材二维码管理
+│           └── qr-list.vue             # 素材二维码列表
+│
+├── api/
+│   └── enagic.js                      # Enagic 管理端 API 调用
+│
+└── router/
+    └── index.js                       # 路由配置
+```
+
+## 集成方式
+
+### 方式一:独立部署
+```bash
+cd enagic-admin
+npm install
+npm run build
+# 将 dist 目录拷贝到 Lilishop admin 的 public/enagic-admin/
+```
+
+### 方式二:合并到 Lilishop admin
+将 `src/vue/views/enagic/` 复制到 Lilishop admin 的 `src/views/` 下,将 `api/enagic.js` 合并到 Lilishop 的 API 目录。
+
+## 主要功能
+
+### 健康布施者管理
+- 查看所有健康布施者列表
+- 查看详情和客户列表
+- 发放勋章
+- 查看数据统计
+
+### VIP 配置
+- 配置 VIP 等级名称、价格、升级条件、权益
+- 设置无到期时间模式
+- 查看会员 VIP 开通记录
+
+### 运维流程管理
+- 创建运维流程模板(节点配置)
+- 查看运维计划执行情况
+- 手动触发运维提醒
+- 查看运维记录
+
+### AI 知识库
+- 管理产品知识库
+- 管理健康知识库
+- 管理 FAQ
+- 查看对话记录

+ 37 - 0
代码/enagic-lilishop/enagic-plugin/enagic-admin/pom.xml

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>com.enagic</groupId>
+        <artifactId>enagic-plugin</artifactId>
+        <version>1.0.0</version>
+    </parent>
+
+    <artifactId>enagic-admin</artifactId>
+    <packaging>jar</packaging>
+    <name>Enagic Admin Plugin</name>
+    <description>Enagic PC 后台管理插件 - Vue 页面</description>
+
+    <!-- Vue 前端页面作为资源打包到此 JAR -->
+    <!-- Lilishop admin 项目通过 /static/enagic-admin/ 路径引用 -->
+    <build>
+        <resources>
+            <resource>
+                <directory>src/main/vue</directory>
+                <targetPath>static/enagic-admin</targetPath>
+            </resource>
+        </resources>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.enagic</groupId>
+            <artifactId>enagic-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+
+</project>

+ 160 - 0
代码/enagic-lilishop/enagic-plugin/enagic-admin/src/main/vue/api/enagic.js

@@ -0,0 +1,160 @@
+/**
+ * Enagic 管理端 API
+ */
+
+import request from '@/libs/util'
+import axios from 'axios'
+
+// 健康布施者管理
+export const getAdvisorPage = (params) => {
+  return request({
+    url: '/enagic/manager/advisor/page',
+    method: 'get',
+    params
+  })
+}
+
+export const getAdvisorDetail = (id) => {
+  return request({
+    url: `/enagic/manager/advisor/${id}`,
+    method: 'get'
+  })
+}
+
+export const grantMedal = (data) => {
+  return request({
+    url: '/enagic/manager/advisor/medal/grant',
+    method: 'post',
+    data
+  })
+}
+
+export const getAdvisorStatistics = () => {
+  return request({
+    url: '/enagic/manager/advisor/statistics',
+    method: 'get'
+  })
+}
+
+// VIP 配置
+export const getVipConfigPage = (params) => {
+  return request({
+    url: '/enagic/manager/vip/config/page',
+    method: 'get',
+    params
+  })
+}
+
+export const saveVipConfig = (data) => {
+  return request({
+    url: '/enagic/manager/vip/config/save',
+    method: 'post',
+    data
+  })
+}
+
+export const deleteVipConfig = (id) => {
+  return request({
+    url: `/enagic/manager/vip/config/${id}`,
+    method: 'delete'
+  })
+}
+
+// 运维流程
+export const getOperationFlowPage = (params) => {
+  return request({
+    url: '/enagic/manager/operation/flow/page',
+    method: 'get',
+    params
+  })
+}
+
+export const saveOperationFlow = (data) => {
+  return request({
+    url: '/enagic/manager/operation/flow/save',
+    method: 'post',
+    data
+  })
+}
+
+export const getOperationPlanPage = (params) => {
+  return request({
+    url: '/enagic/manager/operation/plan/page',
+    method: 'get',
+    params
+  })
+}
+
+export const remindOperationPlan = (id) => {
+  return request({
+    url: `/enagic/manager/operation/plan/remind`,
+    method: 'post',
+    data: { id }
+  })
+}
+
+// AI 知识库
+export const getAiKnowledgePage = (params) => {
+  return request({
+    url: '/enagic/manager/ai/knowledge/page',
+    method: 'get',
+    params
+  })
+}
+
+export const saveAiKnowledge = (data) => {
+  return request({
+    url: '/enagic/manager/ai/knowledge/save',
+    method: 'post',
+    data
+  })
+}
+
+export const deleteAiKnowledge = (id) => {
+  return request({
+    url: `/enagic/manager/ai/knowledge/${id}`,
+    method: 'delete'
+  })
+}
+
+export const getAiConversationLog = (params) => {
+  return request({
+    url: '/enagic/manager/ai/conversation-log',
+    method: 'get',
+    params
+  })
+}
+
+// 客户移交
+export const getTransferPage = (params) => {
+  return request({
+    url: '/enagic/manager/transfer/page',
+    method: 'get',
+    params
+  })
+}
+
+export const processTransfer = (data) => {
+  return request({
+    url: '/enagic/manager/transfer/process',
+    method: 'post',
+    data
+  })
+}
+
+// 抵扣金
+export const getDeductionPage = (params) => {
+  return request({
+    url: '/enagic/manager/deduction/page',
+    method: 'get',
+    params
+  })
+}
+
+export const getDeductionLog = (params) => {
+  return request({
+    url: '/enagic/manager/deduction/log',
+    method: 'get',
+    params
+  })
+}

+ 54 - 0
代码/enagic-lilishop/enagic-plugin/enagic-admin/src/main/vue/router/index.js

@@ -0,0 +1,54 @@
+import Vue from 'vue'
+import VueRouter from 'vue-router'
+
+Vue.use(VueRouter)
+
+export default new VueRouter({
+  routes: [
+    {
+      path: '/enagic/health-advisor/list',
+      component: () => import('../views/enagic/health-advisor/list.vue'),
+      meta: { title: '健康布施者' }
+    },
+    {
+      path: '/enagic/health-advisor/medal',
+      component: () => import('../views/enagic/health-advisor/medal.vue'),
+      meta: { title: '勋章管理' }
+    },
+    {
+      path: '/enagic/vip/config-list',
+      component: () => import('../views/enagic/vip/config-list.vue'),
+      meta: { title: 'VIP配置' }
+    },
+    {
+      path: '/enagic/deduction/account-list',
+      component: () => import('../views/enagic/deduction/account-list.vue'),
+      meta: { title: '抵扣金账户' }
+    },
+    {
+      path: '/enagic/operation/plan-list',
+      component: () => import('../views/enagic/operation/plan-list.vue'),
+      meta: { title: '运维计划' }
+    },
+    {
+      path: '/enagic/operation/flow-list',
+      component: () => import('../views/enagic/operation/flow-list.vue'),
+      meta: { title: '运维流程' }
+    },
+    {
+      path: '/enagic/ai/knowledge-list',
+      component: () => import('../views/enagic/ai/knowledge-list.vue'),
+      meta: { title: 'AI知识库' }
+    },
+    {
+      path: '/enagic/ai/conversation-log',
+      component: () => import('../views/enagic/ai/conversation-log.vue'),
+      meta: { title: '对话记录' }
+    },
+    {
+      path: '/enagic/transfer/list',
+      component: () => import('../views/enagic/transfer/list.vue'),
+      meta: { title: '客户移交' }
+    }
+  ]
+})

+ 166 - 0
代码/enagic-lilishop/enagic-plugin/enagic-admin/src/main/vue/views/enagic/ai/conversation-log.vue

@@ -0,0 +1,166 @@
+<template>
+  <div class="enagic-page">
+    <Card>
+      <p slot="title">AI对话记录</p>
+      <Form inline :label-width="80">
+        <FormItem label="会员ID">
+          <Input v-model="searchForm.memberId" placeholder="会员ID" style="width:200px" clearable @on-enter="loadData" />
+        </FormItem>
+        <FormItem label="问题类型">
+          <Select v-model="searchForm.questionType" style="width:150px" clearable placeholder="全部" @on-change="loadData">
+            <Option value="PRODUCT">产品咨询</Option>
+            <Option value="HEALTH">健康咨询</Option>
+            <Option value="FAQ">常见问题</Option>
+            <Option value="OTHER">其他</Option>
+          </Select>
+        </FormItem>
+        <FormItem>
+          <Button type="primary" icon="ios-search" @click="loadData">查询</Button>
+          <Button style="margin-left:8px" @click="resetSearch">重置</Button>
+        </FormItem>
+      </Form>
+
+      <Table :columns="columns" :data="tableData" :loading="loading" border>
+        <template slot-scope="{ row }" slot="questionType">
+          <Tag :color="questionTypeColor(row.questionType)">{{ questionTypeLabel(row.questionType) }}</Tag>
+        </template>
+        <template slot-scope="{ row }" slot="productRecommend">
+          <span v-if="row.productRecommend">{{ row.productRecommend }}</span>
+          <span v-else style="color:#c5c8ce">-</span>
+        </template>
+      </Table>
+
+      <Page
+        style="margin-top:16px"
+        :total="total"
+        :current="pageNum"
+        :page-size="pageSize"
+        show-total
+        show-elevator
+        @on-change="onPageChange"
+      />
+    </Card>
+
+    <!-- 对话详情弹窗 -->
+    <Modal v-model="detailModal" title="对话详情" width="700" :mask-closable="false">
+      <div v-if="currentRow">
+        <div style="margin-bottom:16px">
+          <Row :gutter="16">
+            <Col span="8"><span style="color:#808695">会员:</span>{{ currentRow.memberName }}</Col>
+            <Col span="8"><span style="color:#808695">会话ID:</span>{{ currentRow.conversationId }}</Col>
+            <Col span="8"><span style="color:#808695">时间:</span>{{ currentRow.createTime }}</Col>
+          </Row>
+        </div>
+        <Divider />
+        <div class="conversation-block">
+          <div class="msg msg-user">
+            <div class="msg-label">用户提问</div>
+            <div class="msg-content">{{ currentRow.question }}</div>
+          </div>
+          <div class="msg msg-ai">
+            <div class="msg-label">AI回答</div>
+            <div class="msg-content">{{ currentRow.answer }}</div>
+          </div>
+          <div v-if="currentRow.productRecommend" class="msg msg-product">
+            <div class="msg-label">产品推荐</div>
+            <div class="msg-content">{{ currentRow.productRecommend }}</div>
+          </div>
+        </div>
+      </div>
+      <div slot="footer">
+        <Button @click="detailModal = false">关闭</Button>
+      </div>
+    </Modal>
+  </div>
+</template>
+
+<script>
+import { getAiConversationLog } from '../../api/enagic'
+
+export default {
+  name: 'AiConversationLog',
+  data() {
+    return {
+      searchForm: { memberId: '', questionType: '' },
+      columns: [
+        { title: '会员', key: 'memberName', width: 120 },
+        { title: '会话ID', key: 'conversationId', width: 140 },
+        { title: '问题类型', key: 'questionType', width: 110, slot: 'questionType' },
+        { title: '产品推荐', slot: 'productRecommend', minWidth: 150 },
+        { title: '时间', key: 'createTime', width: 160 },
+        {
+          title: '操作', width: 100, fixed: 'right',
+          render: (h, params) => {
+            return h('Button', {
+              props: { type: 'primary', size: 'small' },
+              on: { click: () => { this.showDetail(params.row) } }
+            }, '查看详情')
+          }
+        }
+      ],
+      tableData: [],
+      loading: false,
+      total: 0,
+      pageNum: 1,
+      pageSize: 10,
+      detailModal: false,
+      currentRow: null
+    }
+  },
+  mounted() {
+    this.loadData()
+  },
+  methods: {
+    loadData() {
+      this.loading = true
+      getAiConversationLog({
+        memberId: this.searchForm.memberId,
+        questionType: this.searchForm.questionType,
+        pageNum: this.pageNum,
+        pageSize: this.pageSize
+      }).then(res => {
+        if (res.success) {
+          this.tableData = res.data.records || []
+          this.total = res.data.total || 0
+        }
+      }).catch(() => {
+        this.$Message.error('查询失败,请稍后重试')
+      }).finally(() => {
+        this.loading = false
+      })
+    },
+    resetSearch() {
+      this.searchForm = { memberId: '', questionType: '' }
+      this.pageNum = 1
+      this.loadData()
+    },
+    onPageChange(page) {
+      this.pageNum = page
+      this.loadData()
+    },
+    questionTypeColor(type) {
+      var map = { PRODUCT: 'blue', HEALTH: 'green', FAQ: 'orange', OTHER: 'default' }
+      return map[type] || 'default'
+    },
+    questionTypeLabel(type) {
+      var map = { PRODUCT: '产品咨询', HEALTH: '健康咨询', FAQ: '常见问题', OTHER: '其他' }
+      return map[type] || type
+    },
+    showDetail(row) {
+      this.currentRow = row
+      this.detailModal = true
+    }
+  }
+}
+</script>
+
+<style scoped>
+.enagic-page { padding: 16px; }
+.conversation-block { padding: 8px 0; }
+.msg { margin-bottom: 16px; }
+.msg-label { font-weight: bold; margin-bottom: 4px; font-size: 13px; }
+.msg-user .msg-label { color: #2d8cf0; }
+.msg-ai .msg-label { color: #19be6b; }
+.msg-product .msg-label { color: #ff9900; }
+.msg-content { background: #f8f8f9; border-radius: 4px; padding: 10px 12px; line-height: 1.6; white-space: pre-wrap; }
+</style>

+ 229 - 0
代码/enagic-lilishop/enagic-plugin/enagic-admin/src/main/vue/views/enagic/ai/knowledge-list.vue

@@ -0,0 +1,229 @@
+<template>
+  <div class="enagic-page">
+    <Card>
+      <p slot="title">AI知识库管理</p>
+      <Form inline :label-width="80">
+        <FormItem label="标题">
+          <Input v-model="searchForm.title" placeholder="知识标题" style="width:200px" clearable @on-enter="loadData" />
+        </FormItem>
+        <FormItem label="分类">
+          <Select v-model="searchForm.category" style="width:150px" clearable placeholder="全部" @on-change="loadData">
+            <Option value="PRODUCT">产品知识</Option>
+            <Option value="HEALTH">健康知识</Option>
+            <Option value="FAQ">常见问题</Option>
+          </Select>
+        </FormItem>
+        <FormItem label="状态">
+          <Select v-model="searchForm.status" style="width:150px" clearable placeholder="全部" @on-change="loadData">
+            <Option value="OPEN">启用</Option>
+            <Option value="CLOSE">停用</Option>
+          </Select>
+        </FormItem>
+        <FormItem>
+          <Button type="primary" icon="ios-search" @click="loadData">查询</Button>
+          <Button style="margin-left:8px" @click="resetSearch">重置</Button>
+        </FormItem>
+      </Form>
+
+      <div style="margin-bottom:16px">
+        <Button type="primary" icon="md-add" @click="openForm(null)">新增知识</Button>
+      </div>
+
+      <Table :columns="columns" :data="tableData" :loading="loading" border>
+        <template slot-scope="{ row }" slot="category">
+          <Tag :color="categoryColor(row.category)">{{ categoryLabel(row.category) }}</Tag>
+        </template>
+        <template slot-scope="{ row }" slot="status">
+          <Tag :color="row.status === 'OPEN' ? 'success' : 'default'">
+            {{ row.status === 'OPEN' ? '启用' : '停用' }}
+          </Tag>
+        </template>
+        <template slot-scope="{ row }" slot="action">
+          <Button type="primary" size="small" @click="openForm(row)" style="margin-right:8px">编辑</Button>
+          <Poptip confirm title="确认删除该知识条目?" @on-ok="handleDelete(row.id)">
+            <Button type="error" size="small">删除</Button>
+          </Poptip>
+        </template>
+      </Table>
+
+      <Page
+        style="margin-top:16px"
+        :total="total"
+        :current="pageNum"
+        :page-size="pageSize"
+        show-total
+        show-elevator
+        @on-change="onPageChange"
+      />
+    </Card>
+
+    <!-- 新增/编辑弹窗 -->
+    <Modal v-model="formModal" :title="isEdit ? '编辑知识' : '新增知识'" width="650" :mask-closable="false">
+      <Form ref="knowledgeForm" :model="knowledgeForm" :rules="knowledgeRules" :label-width="100">
+        <FormItem label="标题" prop="title">
+          <Input v-model="knowledgeForm.title" placeholder="请输入知识标题" />
+        </FormItem>
+        <FormItem label="分类" prop="category">
+          <Select v-model="knowledgeForm.category" placeholder="请选择分类">
+            <Option value="PRODUCT">产品知识</Option>
+            <Option value="HEALTH">健康知识</Option>
+            <Option value="FAQ">常见问题</Option>
+          </Select>
+        </FormItem>
+        <FormItem label="内容" prop="content">
+          <Input v-model="knowledgeForm.content" type="textarea" :rows="8" placeholder="请输入知识内容" />
+        </FormItem>
+        <FormItem label="状态" prop="status">
+          <Select v-model="knowledgeForm.status" placeholder="请选择">
+            <Option value="OPEN">启用</Option>
+            <Option value="CLOSE">停用</Option>
+          </Select>
+        </FormItem>
+      </Form>
+      <div slot="footer">
+        <Button @click="formModal = false">取消</Button>
+        <Button type="primary" :loading="formLoading" @click="submitForm">保存</Button>
+      </div>
+    </Modal>
+  </div>
+</template>
+
+<script>
+import { getAiKnowledgePage, saveAiKnowledge, deleteAiKnowledge } from '../../api/enagic'
+
+export default {
+  name: 'AiKnowledgeList',
+  data() {
+    return {
+      searchForm: { title: '', category: '', status: '' },
+      columns: [
+        { title: '标题', key: 'title', minWidth: 150 },
+        { title: '分类', key: 'category', width: 120, slot: 'category' },
+        { title: '状态', key: 'status', width: 90, slot: 'status' },
+        { title: '使用次数', key: 'useCount', width: 100 },
+        { title: '创建时间', key: 'createTime', width: 160 },
+        { title: '操作', slot: 'action', width: 160, fixed: 'right' }
+      ],
+      tableData: [],
+      loading: false,
+      total: 0,
+      pageNum: 1,
+      pageSize: 10,
+      formModal: false,
+      formLoading: false,
+      isEdit: false,
+      knowledgeForm: {
+        id: '',
+        title: '',
+        category: '',
+        content: '',
+        status: 'OPEN'
+      },
+      knowledgeRules: {
+        title: [{ required: true, message: '请输入知识标题', trigger: 'blur' }],
+        category: [{ required: true, message: '请选择分类', trigger: 'change' }],
+        content: [{ required: true, message: '请输入知识内容', trigger: 'blur' }],
+        status: [{ required: true, message: '请选择状态', trigger: 'change' }]
+      }
+    }
+  },
+  mounted() {
+    this.loadData()
+  },
+  methods: {
+    loadData() {
+      this.loading = true
+      getAiKnowledgePage({
+        title: this.searchForm.title,
+        category: this.searchForm.category,
+        status: this.searchForm.status,
+        pageNum: this.pageNum,
+        pageSize: this.pageSize
+      }).then(res => {
+        if (res.success) {
+          this.tableData = res.data.records || []
+          this.total = res.data.total || 0
+        }
+      }).catch(() => {
+        this.$Message.error('查询失败,请稍后重试')
+      }).finally(() => {
+        this.loading = false
+      })
+    },
+    resetSearch() {
+      this.searchForm = { title: '', category: '', status: '' }
+      this.pageNum = 1
+      this.loadData()
+    },
+    onPageChange(page) {
+      this.pageNum = page
+      this.loadData()
+    },
+    categoryColor(category) {
+      var map = { PRODUCT: 'blue', HEALTH: 'green', FAQ: 'orange' }
+      return map[category] || 'default'
+    },
+    categoryLabel(category) {
+      var map = { PRODUCT: '产品知识', HEALTH: '健康知识', FAQ: '常见问题' }
+      return map[category] || category
+    },
+    openForm(row) {
+      if (row) {
+        this.isEdit = true
+        this.knowledgeForm = {
+          id: row.id,
+          title: row.title,
+          category: row.category,
+          content: row.content,
+          status: row.status
+        }
+      } else {
+        this.isEdit = false
+        this.knowledgeForm = {
+          id: '',
+          title: '',
+          category: '',
+          content: '',
+          status: 'OPEN'
+        }
+      }
+      this.formModal = true
+    },
+    submitForm() {
+      this.$refs.knowledgeForm.validate(function(valid) {
+        if (!valid) return
+        this.formLoading = true
+        saveAiKnowledge(this.knowledgeForm).then(function(res) {
+          if (res.success) {
+            this.$Message.success(this.isEdit ? '修改成功' : '新增成功')
+            this.formModal = false
+            this.loadData()
+          } else {
+            this.$Message.error(res.message || '保存失败')
+          }
+        }.bind(this)).catch(function() {
+          this.$Message.error('保存失败,请稍后重试')
+        }.bind(this)).finally(function() {
+          this.formLoading = false
+        }.bind(this))
+      }.bind(this))
+    },
+    handleDelete(id) {
+      deleteAiKnowledge(id).then(res => {
+        if (res.success) {
+          this.$Message.success('删除成功')
+          this.loadData()
+        } else {
+          this.$Message.error(res.message || '删除失败')
+        }
+      }).catch(() => {
+        this.$Message.error('删除失败,请稍后重试')
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.enagic-page { padding: 16px; }
+</style>

+ 103 - 0
代码/enagic-lilishop/enagic-plugin/enagic-admin/src/main/vue/views/enagic/deduction/account-list.vue

@@ -0,0 +1,103 @@
+<template>
+  <div class="enagic-page">
+    <Card>
+      <p slot="title">抵扣金账户管理</p>
+      <Form inline :label-width="80">
+        <FormItem label="会员名">
+          <Input v-model="searchForm.keyword" placeholder="会员名称" style="width:200px" clearable @on-enter="loadData" />
+        </FormItem>
+        <FormItem>
+          <Button type="primary" icon="ios-search" @click="loadData">查询</Button>
+        </FormItem>
+      </Form>
+
+      <Table :columns="columns" :data="tableData" :loading="loading" border />
+      <Page style="margin-top:16px" :total="total" :current="pageNum" :page-size="pageSize" show-total @on-change="onPageChange" />
+    </Card>
+
+    <Drawer v-model="logDrawer" title="抵扣金流水" width="600">
+      <Table :columns="logColumns" :data="logData" :loading="logLoading" size="small" border />
+      <Page style="margin-top:12px" :total="logTotal" :current="logPage" :page-size="10" show-total @on-change="onLogPageChange" />
+    </Drawer>
+  </div>
+</template>
+
+<script>
+import { getDeductionPage, getDeductionLog } from '../../api/enagic'
+
+export default {
+  name: 'DeductionAccountList',
+  data() {
+    return {
+      searchForm: { keyword: '' },
+      columns: [
+        { title: '会员ID', key: 'memberId', width: 100 },
+        { title: '会员名', key: 'memberName', width: 120 },
+        { title: '可用余额', key: 'deductionBalance', width: 120,
+          render: (h, p) => h('span', { style: { color: '#19be6b' } }, '¥' + (p.row.deductionBalance || 0)) },
+        { title: '冻结金额', key: 'frozenBalance', width: 120,
+          render: (h, p) => h('span', { style: { color: '#ff9900' } }, '¥' + (p.row.frozenBalance || 0)) },
+        { title: '总计', width: 120,
+          render: (h, p) => h('span', '¥' + ((p.row.deductionBalance || 0) + (p.row.frozenBalance || 0))) },
+        { title: '创建时间', key: 'createTime', width: 160 },
+        { title: '操作', width: 100, fixed: 'right',
+          render: (h, p) => h('Button', { props: { type: 'primary', size: 'small' }, on: { click: () => this.showLog(p.row) } }, '流水')
+        }
+      ],
+      tableData: [],
+      loading: false,
+      total: 0,
+      pageNum: 1,
+      pageSize: 10,
+      logDrawer: false,
+      logLoading: false,
+      logData: [],
+      logTotal: 0,
+      logPage: 1,
+      currentMemberId: null,
+      logColumns: [
+        { title: '类型', key: 'type', width: 120 },
+        { title: '金额', key: 'amount', width: 100,
+          render: (h, p) => h('span', { style: { color: p.row.amount >= 0 ? '#19be6b' : '#ed4014' } }, (p.row.amount >= 0 ? '+' : '') + p.row.amount) },
+        { title: '变更前', key: 'beforeBalance', width: 100 },
+        { title: '变更后', key: 'afterBalance', width: 100 },
+        { title: '备注', key: 'remark', width: 150 },
+        { title: '时间', key: 'createTime', width: 160 }
+      ]
+    }
+  },
+  mounted() { this.loadData() },
+  methods: {
+    loadData() {
+      this.loading = true
+      getDeductionPage({ keyword: this.searchForm.keyword, pageNum: this.pageNum, pageSize: this.pageSize }).then(res => {
+        if (res.success) {
+          this.tableData = res.data.records || []
+          this.total = res.data.total || 0
+        }
+      }).finally(() => { this.loading = false })
+    },
+    onPageChange(page) { this.pageNum = page; this.loadData() },
+    showLog(row) {
+      this.currentMemberId = row.memberId
+      this.logPage = 1
+      this.logDrawer = true
+      this.loadLogData()
+    },
+    loadLogData() {
+      this.logLoading = true
+      getDeductionLog({ memberId: this.currentMemberId, pageNum: this.logPage, pageSize: 10 }).then(res => {
+        if (res.success) {
+          this.logData = res.data.records || []
+          this.logTotal = res.data.total || 0
+        }
+      }).finally(() => { this.logLoading = false })
+    },
+    onLogPageChange(page) { this.logPage = page; this.loadLogData() }
+  }
+}
+</script>
+
+<style scoped>
+.enagic-page { padding: 16px; }
+</style>

+ 199 - 0
代码/enagic-lilishop/enagic-plugin/enagic-admin/src/main/vue/views/enagic/health-advisor/list.vue

@@ -0,0 +1,199 @@
+<template>
+  <div class="enagic-page">
+    <Card>
+      <p slot="title">健康布施者管理</p>
+      <Form inline :label-width="80">
+        <FormItem label="关键字">
+          <Input v-model="searchForm.keyword" placeholder="会员名/姓名" style="width:200px" clearable @on-enter="loadData" />
+        </FormItem>
+        <FormItem label="状态">
+          <Select v-model="searchForm.status" style="width:150px" clearable placeholder="全部" @on-change="loadData">
+            <Option value="ACTIVE">正常</Option>
+            <Option value="INACTIVE">停用</Option>
+          </Select>
+        </FormItem>
+        <FormItem>
+          <Button type="primary" icon="ios-search" @click="loadData">查询</Button>
+          <Button style="margin-left:8px" @click="resetSearch">重置</Button>
+        </FormItem>
+      </Form>
+
+      <Table :columns="columns" :data="tableData" :loading="loading" border>
+        <template slot-scope="{ row }" slot="medalLevel">
+          <Tag :color="medalColor(row.medalLevel)">{{ medalLabel(row.medalLevel) }}</Tag>
+        </template>
+        <template slot-scope="{ row }" slot="status">
+          <Tag :color="row.status === 'ACTIVE' ? 'success' : 'default'">
+            {{ row.status === 'ACTIVE' ? '正常' : '停用' }}
+          </Tag>
+        </template>
+        <template slot-scope="{ row }" slot="action">
+          <Button type="primary" size="small" @click="showDetail(row)" style="margin-right:8px">详情</Button>
+          <Button type="warning" size="small" @click="openGrantMedal(row)">发放勋章</Button>
+        </template>
+      </Table>
+
+      <Page
+        style="margin-top:16px"
+        :total="total"
+        :current="pageNum"
+        :page-size="pageSize"
+        show-total
+        show-elevator
+        @on-change="onPageChange"
+      />
+    </Card>
+
+    <!-- 详情弹窗 -->
+    <Modal v-model="detailModal" title="布施者详情" width="600" :mask-closable="false">
+      <Form v-if="currentRow" label-position="left" :label-width="100">
+        <FormItem label="会员名称">{{ currentRow.memberName }}</FormItem>
+        <FormItem label="真实姓名">{{ currentRow.name }}</FormItem>
+        <FormItem label="勋章等级">{{ medalLabel(currentRow.medalLevel) }}</FormItem>
+        <FormItem label="累计邀请">{{ currentRow.totalInvites }} 人</FormItem>
+        <FormItem label="累计佣金">¥{{ currentRow.totalCommission }}</FormItem>
+        <FormItem label="可用佣金">¥{{ currentRow.availableCommission }}</FormItem>
+        <FormItem label="顾问积分">{{ currentRow.advisorCredits }}</FormItem>
+        <FormItem label="永久绑定">{{ currentRow.permanentBind ? '是' : '否' }}</FormItem>
+        <FormItem label="注册时间">{{ currentRow.createTime }}</FormItem>
+      </Form>
+      <div slot="footer">
+        <Button @click="detailModal = false">关闭</Button>
+      </div>
+    </Modal>
+
+    <!-- 发放勋章弹窗 -->
+    <Modal v-model="medalModal" title="发放勋章" width="400" :mask-closable="false">
+      <Form ref="medalForm" :model="medalForm" :label-width="100">
+        <FormItem label="布施者">{{ currentRow ? currentRow.memberName : '' }}</FormItem>
+        <FormItem label="勋章类型" prop="medalType">
+          <Select v-model="medalForm.medalType" placeholder="请选择">
+            <Option value="STAR_1">⭐ 一星布施者</Option>
+            <Option value="STAR_2">⭐⭐ 二星布施者</Option>
+            <Option value="STAR_3">⭐⭐⭐ 三星布施者</Option>
+            <Option value="MASTER">👑 宗师</Option>
+          </Select>
+        </FormItem>
+        <FormItem label="发放原因" prop="reason">
+          <Input v-model="medalForm.reason" type="textarea" :rows="3" placeholder="请输入发放原因" />
+        </FormItem>
+      </Form>
+      <div slot="footer">
+        <Button @click="medalModal = false">取消</Button>
+        <Button type="primary" :loading="medalLoading" @click="submitMedal">确认发放</Button>
+      </div>
+    </Modal>
+  </div>
+</template>
+
+<script>
+import { getAdvisorPage, grantMedal } from '../../api/enagic'
+
+export default {
+  name: 'HealthAdvisorList',
+  data() {
+    return {
+      searchForm: { keyword: '', status: '' },
+      columns: [
+        { title: '会员名', key: 'memberName', width: 120 },
+        { title: '姓名', key: 'name', width: 100 },
+        { title: '勋章等级', key: 'medalLevel', width: 120, slot: 'medalLevel' },
+        { title: '累计邀请', key: 'totalInvites', width: 100 },
+        { title: '可用佣金', key: 'availableCommission', width: 120,
+          render: (h, p) => h('span', '¥' + (p.row.availableCommission || 0)) },
+        { title: '顾问积分', key: 'advisorCredits', width: 100 },
+        { title: '状态', key: 'status', width: 100, slot: 'status' },
+        { title: '注册时间', key: 'createTime', width: 160 },
+        { title: '操作', slot: 'action', width: 200, fixed: 'right' }
+      ],
+      tableData: [],
+      loading: false,
+      total: 0,
+      pageNum: 1,
+      pageSize: 10,
+      detailModal: false,
+      medalModal: false,
+      medalLoading: false,
+      currentRow: null,
+      medalForm: { medalType: '', reason: '' }
+    }
+  },
+  mounted() {
+    this.loadData()
+  },
+  methods: {
+    loadData() {
+      this.loading = true
+      getAdvisorPage({
+        keyword: this.searchForm.keyword,
+        status: this.searchForm.status,
+        pageNum: this.pageNum,
+        pageSize: this.pageSize
+      }).then(res => {
+        if (res.success) {
+          this.tableData = res.data.records || []
+          this.total = res.data.total || 0
+        }
+      }).catch(() => {
+        this.$Message.error('查询失败,请稍后重试')
+      }).finally(() => {
+        this.loading = false
+      })
+    },
+    resetSearch() {
+      this.searchForm = { keyword: '', status: '' }
+      this.pageNum = 1
+      this.loadData()
+    },
+    onPageChange(page) {
+      this.pageNum = page
+      this.loadData()
+    },
+    medalColor(level) {
+      var map = { STAR_1: 'blue', STAR_2: 'green', STAR_3: 'orange', MASTER: 'red' }
+      return map[level] || 'default'
+    },
+    medalLabel(level) {
+      var map = { STAR_1: '⭐一星', STAR_2: '⭐⭐二星', STAR_3: '⭐⭐⭐三星', MASTER: '👑宗师' }
+      return map[level] || level
+    },
+    showDetail(row) {
+      this.currentRow = row
+      this.detailModal = true
+    },
+    openGrantMedal(row) {
+      this.currentRow = row
+      this.medalForm = { medalType: '', reason: '' }
+      this.medalModal = true
+    },
+    submitMedal() {
+      if (!this.medalForm.medalType) {
+        this.$Message.warning('请选择勋章类型')
+        return
+      }
+      this.medalLoading = true
+      grantMedal({
+        advisorId: this.currentRow.id,
+        medalType: this.medalForm.medalType,
+        reason: this.medalForm.reason
+      }).then(res => {
+        if (res.success) {
+          this.$Message.success('发放成功')
+          this.medalModal = false
+          this.loadData()
+        } else {
+          this.$Message.error(res.message || '发放失败')
+        }
+      }).catch(() => {
+        this.$Message.error('发放失败,请稍后重试')
+      }).finally(() => {
+        this.medalLoading = false
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.enagic-page { padding: 16px; }
+</style>

+ 170 - 0
代码/enagic-lilishop/enagic-plugin/enagic-admin/src/main/vue/views/enagic/health-advisor/medal.vue

@@ -0,0 +1,170 @@
+<template>
+  <div class="enagic-page">
+    <Card>
+      <p slot="title">勋章管理</p>
+      <Form inline :label-width="80">
+        <FormItem label="布施者">
+          <Input v-model="searchForm.keyword" placeholder="布施者名称" style="width:200px" clearable @on-enter="loadData" />
+        </FormItem>
+        <FormItem label="勋章类型">
+          <Select v-model="searchForm.medalType" style="width:150px" clearable placeholder="全部" @on-change="loadData">
+            <Option value="STAR_1">⭐ 一星</Option>
+            <Option value="STAR_2">⭐⭐ 二星</Option>
+            <Option value="STAR_3">⭐⭐⭐ 三星</Option>
+            <Option value="MASTER">👑 宗师</Option>
+          </Select>
+        </FormItem>
+        <FormItem>
+          <Button type="primary" icon="ios-search" @click="loadData">查询</Button>
+          <Button style="margin-left:8px" @click="resetSearch">重置</Button>
+        </FormItem>
+      </Form>
+
+      <div style="margin-bottom:16px">
+        <Button type="primary" icon="md-add" @click="openGrant">发放勋章</Button>
+      </div>
+
+      <Table :columns="columns" :data="tableData" :loading="loading" border>
+        <template slot-scope="{ row }" slot="medalType">
+          <Tag :color="medalColor(row.medalType)">{{ medalLabel(row.medalType) }}</Tag>
+        </template>
+      </Table>
+
+      <Page
+        style="margin-top:16px"
+        :total="total"
+        :current="pageNum"
+        :page-size="pageSize"
+        show-total
+        show-elevator
+        @on-change="onPageChange"
+      />
+    </Card>
+
+    <!-- 发放勋章弹窗 -->
+    <Modal v-model="grantModal" title="发放勋章" width="450" :mask-closable="false">
+      <Form ref="grantForm" :model="grantForm" :rules="grantRules" :label-width="100">
+        <FormItem label="布施者ID" prop="advisorId">
+          <Input v-model="grantForm.advisorId" placeholder="请输入布施者ID" />
+        </FormItem>
+        <FormItem label="勋章类型" prop="medalType">
+          <Select v-model="grantForm.medalType" placeholder="请选择勋章类型">
+            <Option value="STAR_1">⭐ 一星布施者</Option>
+            <Option value="STAR_2">⭐⭐ 二星布施者</Option>
+            <Option value="STAR_3">⭐⭐⭐ 三星布施者</Option>
+            <Option value="MASTER">👑 宗师</Option>
+          </Select>
+        </FormItem>
+        <FormItem label="发放原因" prop="reason">
+          <Input v-model="grantForm.reason" type="textarea" :rows="3" placeholder="请输入发放原因" />
+        </FormItem>
+      </Form>
+      <div slot="footer">
+        <Button @click="grantModal = false">取消</Button>
+        <Button type="primary" :loading="grantLoading" @click="submitGrant">确认发放</Button>
+      </div>
+    </Modal>
+  </div>
+</template>
+
+<script>
+import { getAdvisorPage, grantMedal } from '../../api/enagic'
+
+export default {
+  name: 'AdvisorMedal',
+  data() {
+    return {
+      searchForm: { keyword: '', medalType: '' },
+      columns: [
+        { title: '布施者', key: 'advisorName', width: 120 },
+        { title: '勋章类型', key: 'medalType', width: 140, slot: 'medalType' },
+        { title: '级别', key: 'level', width: 80 },
+        { title: '发放原因', key: 'reason', minWidth: 200 },
+        { title: '发放时间', key: 'createTime', width: 160 }
+      ],
+      tableData: [],
+      loading: false,
+      total: 0,
+      pageNum: 1,
+      pageSize: 10,
+      grantModal: false,
+      grantLoading: false,
+      grantForm: { advisorId: '', medalType: '', reason: '' },
+      grantRules: {
+        advisorId: [{ required: true, message: '请输入布施者ID', trigger: 'blur' }],
+        medalType: [{ required: true, message: '请选择勋章类型', trigger: 'change' }]
+      }
+    }
+  },
+  mounted() {
+    this.loadData()
+  },
+  methods: {
+    loadData() {
+      this.loading = true
+      getAdvisorPage({
+        keyword: this.searchForm.keyword,
+        pageNum: this.pageNum,
+        pageSize: this.pageSize
+      }).then(res => {
+        if (res.success) {
+          this.tableData = res.data.records || []
+          this.total = res.data.total || 0
+        }
+      }).catch(() => {
+        this.$Message.error('查询失败,请稍后重试')
+      }).finally(() => {
+        this.loading = false
+      })
+    },
+    resetSearch() {
+      this.searchForm = { keyword: '', medalType: '' }
+      this.pageNum = 1
+      this.loadData()
+    },
+    onPageChange(page) {
+      this.pageNum = page
+      this.loadData()
+    },
+    medalColor(type) {
+      var map = { STAR_1: 'blue', STAR_2: 'green', STAR_3: 'orange', MASTER: 'red' }
+      return map[type] || 'default'
+    },
+    medalLabel(type) {
+      var map = { STAR_1: '⭐一星', STAR_2: '⭐⭐二星', STAR_3: '⭐⭐⭐三星', MASTER: '👑宗师' }
+      return map[type] || type
+    },
+    openGrant() {
+      this.grantForm = { advisorId: '', medalType: '', reason: '' }
+      this.grantModal = true
+    },
+    submitGrant() {
+      this.$refs.grantForm.validate(function(valid) {
+        if (!valid) return
+        this.grantLoading = true
+        grantMedal({
+          advisorId: this.grantForm.advisorId,
+          medalType: this.grantForm.medalType,
+          reason: this.grantForm.reason
+        }).then(function(res) {
+          if (res.success) {
+            this.$Message.success('发放成功')
+            this.grantModal = false
+            this.loadData()
+          } else {
+            this.$Message.error(res.message || '发放失败')
+          }
+        }.bind(this)).catch(function() {
+          this.$Message.error('发放失败,请稍后重试')
+        }.bind(this)).finally(function() {
+          this.grantLoading = false
+        }.bind(this))
+      }.bind(this))
+    }
+  }
+}
+</script>
+
+<style scoped>
+.enagic-page { padding: 16px; }
+</style>

+ 234 - 0
代码/enagic-lilishop/enagic-plugin/enagic-admin/src/main/vue/views/enagic/operation/flow-list.vue

@@ -0,0 +1,234 @@
+<template>
+  <div class="enagic-page">
+    <Card>
+      <p slot="title">运维流程模板</p>
+      <Form inline :label-width="80">
+        <FormItem label="流程名称">
+          <Input v-model="searchForm.name" placeholder="流程名称" style="width:200px" clearable @on-enter="loadData" />
+        </FormItem>
+        <FormItem label="状态">
+          <Select v-model="searchForm.status" style="width:150px" clearable placeholder="全部" @on-change="loadData">
+            <Option value="OPEN">开启</Option>
+            <Option value="CLOSE">关闭</Option>
+          </Select>
+        </FormItem>
+        <FormItem>
+          <Button type="primary" icon="ios-search" @click="loadData">查询</Button>
+          <Button style="margin-left:8px" @click="resetSearch">重置</Button>
+        </FormItem>
+      </Form>
+
+      <div style="margin-bottom:16px">
+        <Button type="primary" icon="md-add" @click="openForm(null)">新增流程</Button>
+      </div>
+
+      <Table :columns="columns" :data="tableData" :loading="loading" border>
+        <template slot-scope="{ row }" slot="status">
+          <Tag :color="row.status === 'OPEN' ? 'success' : 'default'">
+            {{ row.status === 'OPEN' ? '开启' : '关闭' }}
+          </Tag>
+        </template>
+        <template slot-scope="{ row }" slot="action">
+          <Button type="primary" size="small" @click="openForm(row)" style="margin-right:8px">编辑</Button>
+          <Button :type="row.status === 'OPEN' ? 'warning' : 'success'" size="small" @click="toggleStatus(row)">
+            {{ row.status === 'OPEN' ? '关闭' : '开启' }}
+          </Button>
+        </template>
+      </Table>
+
+      <Page
+        style="margin-top:16px"
+        :total="total"
+        :current="pageNum"
+        :page-size="pageSize"
+        show-total
+        show-elevator
+        @on-change="onPageChange"
+      />
+    </Card>
+
+    <!-- 新增/编辑弹窗 -->
+    <Modal v-model="formModal" :title="isEdit ? '编辑运维流程' : '新增运维流程'" width="650" :mask-closable="false">
+      <Form ref="flowForm" :model="flowForm" :rules="flowRules" :label-width="100">
+        <FormItem label="流程名称" prop="name">
+          <Input v-model="flowForm.name" placeholder="请输入流程名称" />
+        </FormItem>
+        <FormItem label="状态" prop="status">
+          <Select v-model="flowForm.status" placeholder="请选择">
+            <Option value="OPEN">开启</Option>
+            <Option value="CLOSE">关闭</Option>
+          </Select>
+        </FormItem>
+        <FormItem label="节点配置" prop="nodes">
+          <Input v-model="flowForm.nodes" type="textarea" :rows="10" placeholder="请输入节点JSON配置,例如:&#10;[&#10;  {&quot;name&quot;:&quot;发货后回访&quot;,&quot;delayDays&quot;:3,&quot;action&quot;:&quot;REMIND&quot;},&#10;  {&quot;name&quot;:&quot;使用指导&quot;,&quot;delayDays&quot;:7,&quot;action&quot;:&quot;REMIND&quot;},&#10;  {&quot;name&quot;:&quot;满意度调查&quot;,&quot;delayDays&quot;:14,&quot;action&quot;:&quot;REMIND&quot;}&#10;]" />
+          <div style="margin-top:4px;color:#808695;font-size:12px">
+            节点字段:name(节点名称)、delayDays(延迟天数)、action(动作:REMIND/NOTIFY)
+          </div>
+        </FormItem>
+      </Form>
+      <div slot="footer">
+        <Button @click="formModal = false">取消</Button>
+        <Button type="primary" :loading="formLoading" @click="submitForm">保存</Button>
+      </div>
+    </Modal>
+  </div>
+</template>
+
+<script>
+import { getOperationFlowPage, saveOperationFlow } from '../../api/enagic'
+
+export default {
+  name: 'OperationFlowList',
+  data() {
+    return {
+      searchForm: { name: '', status: '' },
+      columns: [
+        { title: '流程名称', key: 'name', minWidth: 150 },
+        { title: '节点数量', key: 'nodeCount', width: 100,
+          render: (h, p) => h('span', (p.row.nodes ? JSON.parse(p.row.nodes).length : 0)) },
+        { title: '状态', key: 'status', width: 100, slot: 'status' },
+        { title: '创建时间', key: 'createTime', width: 160 },
+        { title: '操作', slot: 'action', width: 180, fixed: 'right' }
+      ],
+      tableData: [],
+      loading: false,
+      total: 0,
+      pageNum: 1,
+      pageSize: 10,
+      formModal: false,
+      formLoading: false,
+      isEdit: false,
+      flowForm: {
+        id: '',
+        name: '',
+        status: 'OPEN',
+        nodes: ''
+      },
+      flowRules: {
+        name: [{ required: true, message: '请输入流程名称', trigger: 'blur' }],
+        status: [{ required: true, message: '请选择状态', trigger: 'change' }],
+        nodes: [
+          { required: true, message: '请输入节点配置', trigger: 'blur' },
+          { validator: this.validateNodesJson, trigger: 'blur' }
+        ]
+      }
+    }
+  },
+  mounted() {
+    this.loadData()
+  },
+  methods: {
+    validateNodesJson(rule, value, callback) {
+      if (!value) {
+        callback()
+        return
+      }
+      try {
+        var parsed = JSON.parse(value)
+        if (!Array.isArray(parsed)) {
+          callback(new Error('节点配置必须是JSON数组'))
+        } else {
+          callback()
+        }
+      } catch (e) {
+        callback(new Error('节点配置JSON格式错误'))
+      }
+    },
+    loadData() {
+      this.loading = true
+      getOperationFlowPage({
+        name: this.searchForm.name,
+        status: this.searchForm.status,
+        pageNum: this.pageNum,
+        pageSize: this.pageSize
+      }).then(res => {
+        if (res.success) {
+          this.tableData = res.data.records || []
+          this.total = res.data.total || 0
+        }
+      }).catch(() => {
+        this.$Message.error('查询失败,请稍后重试')
+      }).finally(() => {
+        this.loading = false
+      })
+    },
+    resetSearch() {
+      this.searchForm = { name: '', status: '' }
+      this.pageNum = 1
+      this.loadData()
+    },
+    onPageChange(page) {
+      this.pageNum = page
+      this.loadData()
+    },
+    openForm(row) {
+      if (row) {
+        this.isEdit = true
+        this.flowForm = {
+          id: row.id,
+          name: row.name,
+          status: row.status,
+          nodes: row.nodes || ''
+        }
+      } else {
+        this.isEdit = false
+        this.flowForm = {
+          id: '',
+          name: '',
+          status: 'OPEN',
+          nodes: ''
+        }
+      }
+      this.formModal = true
+    },
+    submitForm() {
+      this.$refs.flowForm.validate(function(valid) {
+        if (!valid) return
+        this.formLoading = true
+        saveOperationFlow(this.flowForm).then(function(res) {
+          if (res.success) {
+            this.$Message.success(this.isEdit ? '修改成功' : '新增成功')
+            this.formModal = false
+            this.loadData()
+          } else {
+            this.$Message.error(res.message || '保存失败')
+          }
+        }.bind(this)).catch(function() {
+          this.$Message.error('保存失败,请稍后重试')
+        }.bind(this)).finally(function() {
+          this.formLoading = false
+        }.bind(this))
+      }.bind(this))
+    },
+    toggleStatus(row) {
+      var newStatus = row.status === 'OPEN' ? 'CLOSE' : 'OPEN'
+      var action = newStatus === 'OPEN' ? '开启' : '关闭'
+      this.$Modal.confirm({
+        title: '确认操作',
+        content: '确认' + action + '流程"' + row.name + '"?',
+        onOk: function() {
+          saveOperationFlow({
+            id: row.id,
+            name: row.name,
+            status: newStatus,
+            nodes: row.nodes
+          }).then(function(res) {
+            if (res.success) {
+              this.$Message.success(action + '成功')
+              this.loadData()
+            } else {
+              this.$Message.error(res.message || action + '失败')
+            }
+          }.bind(this)).catch(function() {
+            this.$Message.error(action + '失败,请稍后重试')
+          }.bind(this))
+        }.bind(this)
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.enagic-page { padding: 16px; }
+</style>

+ 142 - 0
代码/enagic-lilishop/enagic-plugin/enagic-admin/src/main/vue/views/enagic/operation/plan-list.vue

@@ -0,0 +1,142 @@
+<template>
+  <div class="enagic-page">
+    <Card>
+      <p slot="title">运维计划管理</p>
+      <Form inline :label-width="80">
+        <FormItem label="状态">
+          <Select v-model="searchForm.status" style="width:150px" clearable placeholder="全部" @on-change="loadData">
+            <Option value="IN_PROGRESS">进行中</Option>
+            <Option value="COMPLETED">已完成</Option>
+            <Option value="TRANSFERRED">已转移</Option>
+          </Select>
+        </FormItem>
+        <FormItem label="会员名">
+          <Input v-model="searchForm.memberName" placeholder="会员名称" style="width:200px" clearable @on-enter="loadData" />
+        </FormItem>
+        <FormItem>
+          <Button type="primary" icon="ios-search" @click="loadData">查询</Button>
+        </FormItem>
+      </Form>
+
+      <Table :columns="columns" :data="tableData" :loading="loading" border>
+        <template slot-slot:status="{ row }">
+          <Tag :color="statusColor(row.status)">{{ statusLabel(row.status) }}</Tag>
+        </template>
+      </Table>
+      <Page style="margin-top:16px" :total="total" :current="pageNum" :page-size="pageSize" show-total @on-change="onPageChange" />
+    </Card>
+
+    <Drawer v-model="recordDrawer" title="运维记录" width="600">
+      <Table :columns="recordColumns" :data="recordData" :loading="recordLoading" size="small" border />
+      <Page style="margin-top:12px" :total="recordTotal" :current="recordPage" :page-size="10" show-total @on-change="onRecordPageChange" />
+    </Drawer>
+  </div>
+</template>
+
+<script>
+import { getOperationPlanPage, remindOperationPlan } from '../../api/enagic'
+
+export default {
+  name: 'OperationPlanList',
+  data() {
+    return {
+      searchForm: { status: '', memberName: '' },
+      columns: [
+        { title: '计划ID', key: 'id', width: 80 },
+        { title: '会员', key: 'memberName', width: 120 },
+        { title: '当前节点', key: 'currentNodeName', width: 140 },
+        { title: '节点索引', key: 'currentNodeIndex', width: 80 },
+        { title: '跳过次数', key: 'skipCount', width: 80 },
+        { title: '状态', slot: 'status', width: 100 },
+        { title: '下次节点时间', key: 'nextNodeTime', width: 160 },
+        { title: '创建时间', key: 'createTime', width: 160 },
+        { title: '操作', width: 180, fixed: 'right',
+          render: (h, p) => [
+            h('Button', { props: { type: 'primary', size: 'small' }, style: { marginRight: '8px' }, on: { click: () => this.showRecords(p.row) } }, '记录'),
+            h('Button', { props: { type: 'warning', size: 'small' }, style: { marginRight: '8px' }, on: { click: () => this.handleRemind(p.row) } }, '提醒'),
+            h('Button', { props: { type: 'success', size: 'small' }, on: { click: () => this.handleComplete(p.row) } }, '完成')
+          ]
+        }
+      ],
+      tableData: [],
+      loading: false,
+      total: 0,
+      pageNum: 1,
+      pageSize: 10,
+      recordDrawer: false,
+      recordLoading: false,
+      recordData: [],
+      recordTotal: 0,
+      recordPage: 1,
+      currentPlanId: null,
+      recordColumns: [
+        { title: '节点', key: 'nodeName', width: 120 },
+        { title: '内容', key: 'content', width: 200 },
+        { title: '结果', key: 'result', width: 100 },
+        { title: '操作时间', key: 'operateTime', width: 160 }
+      ]
+    }
+  },
+  mounted() { this.loadData() },
+  methods: {
+    loadData() {
+      this.loading = true
+      getOperationPlanPage({
+        status: this.searchForm.status,
+        memberName: this.searchForm.memberName,
+        pageNum: this.pageNum,
+        pageSize: this.pageSize
+      }).then(res => {
+        if (res.success) {
+          this.tableData = res.data.records || []
+          this.total = res.data.total || 0
+        }
+      }).finally(() => { this.loading = false })
+    },
+    onPageChange(page) { this.pageNum = page; this.loadData() },
+    statusColor(s) { return { IN_PROGRESS: 'blue', COMPLETED: 'success', TRANSFERRED: 'warning' }[s] || 'default' },
+    statusLabel(s) { return { IN_PROGRESS: '进行中', COMPLETED: '已完成', TRANSFERRED: '已转移' }[s] || s },
+    showRecords(row) {
+      this.currentPlanId = row.id
+      this.recordPage = 1
+      this.recordDrawer = true
+      this.loadRecordData()
+    },
+    loadRecordData() {
+      this.recordLoading = true
+      this.$axios.get(`/enagic/manager/operation/record/page`, { params: { planId: this.currentPlanId, pageNum: this.recordPage, pageSize: 10 } }).then(res => {
+        if (res.success) {
+          this.recordData = res.data.records || []
+          this.recordTotal = res.data.total || 0
+        }
+      }).finally(() => { this.recordLoading = false })
+    },
+    onRecordPageChange(page) { this.recordPage = page; this.loadRecordData() },
+    handleRemind(row) {
+      remindOperationPlan(row.id).then(res => {
+        if (res.success) {
+          this.$Message.success('提醒已发送')
+        }
+      })
+    },
+    handleComplete(row) {
+      this.$Modal.confirm({
+        title: '确认完成',
+        content: `确定要标记计划 #${row.id} 为已完成吗?`,
+        onOk: () => {
+          this.$axios.post('/enagic/manager/operation/plan/complete', { id: row.id }).then(res => {
+            if (res.success) {
+              this.$Message.success('操作成功')
+              this.loadData()
+            }
+          })
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.enagic-page { padding: 16px; }
+</style>

+ 131 - 0
代码/enagic-lilishop/enagic-plugin/enagic-admin/src/main/vue/views/enagic/transfer/list.vue

@@ -0,0 +1,131 @@
+<template>
+  <div class="enagic-page">
+    <Card>
+      <p slot="title">客户移交记录</p>
+      <Form inline :label-width="80">
+        <FormItem label="触发类型">
+          <Select v-model="searchForm.triggerType" style="width:150px" clearable placeholder="全部" @on-change="loadData">
+            <Option value="AUTO">自动移交</Option>
+            <Option value="MANUAL">手动移交</Option>
+          </Select>
+        </FormItem>
+        <FormItem label="布施者">
+          <Input v-model="searchForm.advisorName" placeholder="布施者名称" style="width:200px" clearable @on-enter="loadData" />
+        </FormItem>
+        <FormItem>
+          <Button type="primary" icon="ios-search" @click="loadData">查询</Button>
+          <Button style="margin-left:8px" @click="resetSearch">重置</Button>
+        </FormItem>
+      </Form>
+
+      <Table :columns="columns" :data="tableData" :loading="loading" border>
+        <template slot-scope="{ row }" slot="triggerType">
+          <Tag :color="row.triggerType === 'AUTO' ? 'blue' : 'orange'">
+            {{ row.triggerType === 'AUTO' ? '自动移交' : '手动移交' }}
+          </Tag>
+        </template>
+        <template slot-scope="{ row }" slot="action">
+          <Button type="primary" size="small" @click="showDetail(row)">详情</Button>
+        </template>
+      </Table>
+
+      <Page
+        style="margin-top:16px"
+        :total="total"
+        :current="pageNum"
+        :page-size="pageSize"
+        show-total
+        show-elevator
+        @on-change="onPageChange"
+      />
+    </Card>
+
+    <!-- 移交详情弹窗 -->
+    <Modal v-model="detailModal" title="移交详情" width="550" :mask-closable="false">
+      <Form v-if="currentRow" label-position="left" :label-width="100">
+        <FormItem label="会员">{{ currentRow.memberName }}</FormItem>
+        <FormItem label="原布施者">{{ currentRow.fromAdvisorName }}</FormItem>
+        <FormItem label="新布施者">{{ currentRow.toAdvisorName }}</FormItem>
+        <FormItem label="转移原因">{{ currentRow.reason || '-' }}</FormItem>
+        <FormItem label="触发类型">
+          <Tag :color="currentRow.triggerType === 'AUTO' ? 'blue' : 'orange'">
+            {{ currentRow.triggerType === 'AUTO' ? '自动移交' : '手动移交' }}
+          </Tag>
+        </FormItem>
+        <FormItem label="转移时间">{{ currentRow.createTime }}</FormItem>
+      </Form>
+      <div slot="footer">
+        <Button @click="detailModal = false">关闭</Button>
+      </div>
+    </Modal>
+  </div>
+</template>
+
+<script>
+import { getTransferPage } from '../../api/enagic'
+
+export default {
+  name: 'TransferList',
+  data() {
+    return {
+      searchForm: { triggerType: '', advisorName: '' },
+      columns: [
+        { title: '会员', key: 'memberName', width: 120 },
+        { title: '原布施者', key: 'fromAdvisorName', width: 120 },
+        { title: '新布施者', key: 'toAdvisorName', width: 120 },
+        { title: '转移原因', key: 'reason', minWidth: 180 },
+        { title: '类型', key: 'triggerType', width: 110, slot: 'triggerType' },
+        { title: '转移时间', key: 'createTime', width: 160 },
+        { title: '操作', slot: 'action', width: 100, fixed: 'right' }
+      ],
+      tableData: [],
+      loading: false,
+      total: 0,
+      pageNum: 1,
+      pageSize: 10,
+      detailModal: false,
+      currentRow: null
+    }
+  },
+  mounted() {
+    this.loadData()
+  },
+  methods: {
+    loadData() {
+      this.loading = true
+      getTransferPage({
+        triggerType: this.searchForm.triggerType,
+        advisorName: this.searchForm.advisorName,
+        pageNum: this.pageNum,
+        pageSize: this.pageSize
+      }).then(res => {
+        if (res.success) {
+          this.tableData = res.data.records || []
+          this.total = res.data.total || 0
+        }
+      }).catch(() => {
+        this.$Message.error('查询失败,请稍后重试')
+      }).finally(() => {
+        this.loading = false
+      })
+    },
+    resetSearch() {
+      this.searchForm = { triggerType: '', advisorName: '' }
+      this.pageNum = 1
+      this.loadData()
+    },
+    onPageChange(page) {
+      this.pageNum = page
+      this.loadData()
+    },
+    showDetail(row) {
+      this.currentRow = row
+      this.detailModal = true
+    }
+  }
+}
+</script>
+
+<style scoped>
+.enagic-page { padding: 16px; }
+</style>

+ 147 - 0
代码/enagic-lilishop/enagic-plugin/enagic-admin/src/main/vue/views/enagic/vip/config-list.vue

@@ -0,0 +1,147 @@
+<template>
+  <div class="enagic-page">
+    <Card>
+      <p slot="title">VIP 配置管理</p>
+      <Button type="primary" icon="md-add" slot="extra" @click="openForm(null)">新增配置</Button>
+
+      <Table :columns="columns" :data="tableData" :loading="loading" border>
+        <template slot-slot:status="{ row }">
+          <Tag :color="row.status === 'OPEN' ? 'success' : 'default'">{{ row.status === 'OPEN' ? '启用' : '停用' }}</Tag>
+        </template>
+      </Table>
+      <Page style="margin-top:16px" :total="total" :current="pageNum" :page-size="pageSize" show-total @on-change="onPageChange" />
+    </Card>
+
+    <Modal v-model="formModal" :title="formModel.id ? '编辑配置' : '新增配置'" width="500" :mask-closable="false">
+      <Form ref="configForm" :model="formModel" :rules="formRules" :label-width="110">
+        <FormItem label="配置名称" prop="name">
+          <Input v-model="formModel.name" placeholder="如:银卡VIP" />
+        </FormItem>
+        <FormItem label="VIP等级" prop="vipLevel">
+          <InputNumber v-model="formModel.vipLevel" :min="1" :max="10" />
+        </FormItem>
+        <FormItem label="价格(元)" prop="price">
+          <InputNumber v-model="formModel.price" :min="0" :precision="2" style="width:100%" />
+        </FormItem>
+        <FormItem label="升级条件" prop="upgradeCondition">
+          <Input v-model="formModel.upgradeCondition" placeholder="如:累计消费5000元" />
+        </FormItem>
+        <FormItem label="有效期(天)" prop="validityDays">
+          <InputNumber v-model="formModel.validityDays" :min="-1" placeholder="-1表示永久" style="width:100%" />
+          <p style="color:#999;font-size:12px">-1 表示无到期时间</p>
+        </FormItem>
+        <FormItem label="权益说明" prop="benefits">
+          <Input v-model="formModel.benefits" type="textarea" :rows="4" placeholder="VIP权益描述" />
+        </FormItem>
+        <FormItem label="状态">
+          <i-switch v-model="formModel.statusOpen" size="large">
+            <span slot="open">启用</span>
+            <span slot="close">停用</span>
+          </i-switch>
+        </FormItem>
+      </Form>
+      <div slot="footer">
+        <Button @click="formModal = false">取消</Button>
+        <Button type="primary" :loading="submitLoading" @click="submitForm">保存</Button>
+      </div>
+    </Modal>
+  </div>
+</template>
+
+<script>
+import { getVipConfigPage, saveVipConfig, deleteVipConfig } from '../../api/enagic'
+
+export default {
+  name: 'VipConfigList',
+  data() {
+    return {
+      columns: [
+        { title: '名称', key: 'name', width: 120 },
+        { title: 'VIP等级', key: 'vipLevel', width: 100 },
+        { title: '价格', key: 'price', width: 100, render: (h, p) => h('span', '¥' + (p.row.price || 0)) },
+        { title: '升级条件', key: 'upgradeCondition', width: 160 },
+        { title: '有效期', key: 'validityDays', width: 100,
+          render: (h, p) => h('span', p.row.validityDays === -1 ? '永久' : (p.row.validityDays + '天')) },
+        { title: '状态', slot: 'status', width: 80 },
+        { title: '创建时间', key: 'createTime', width: 160 },
+        { title: '操作', width: 150, fixed: 'right',
+          render: (h, p) => [
+            h('Button', { props: { type: 'primary', size: 'small' }, style: { marginRight: '8px' }, on: { click: () => this.openForm(p.row) } }, '编辑'),
+            h('Button', { props: { type: 'error', size: 'small' }, on: { click: () => this.handleDelete(p.row) } }, '删除')
+          ]
+        }
+      ],
+      tableData: [],
+      loading: false,
+      total: 0,
+      pageNum: 1,
+      pageSize: 10,
+      formModal: false,
+      submitLoading: false,
+      formModel: { id: null, name: '', vipLevel: 1, price: 0, upgradeCondition: '', validityDays: -1, benefits: '', statusOpen: true },
+      formRules: {
+        name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
+        vipLevel: [{ required: true, type: 'number', message: '请输入等级', trigger: 'change' }],
+        price: [{ required: true, type: 'number', message: '请输入价格', trigger: 'change' }]
+      }
+    }
+  },
+  mounted() { this.loadData() },
+  methods: {
+    loadData() {
+      this.loading = true
+      getVipConfigPage({ pageNum: this.pageNum, pageSize: this.pageSize }).then(res => {
+        if (res.success) {
+          this.tableData = res.data.records || []
+          this.total = res.data.total || 0
+        }
+      }).finally(() => { this.loading = false })
+    },
+    onPageChange(page) { this.pageNum = page; this.loadData() },
+    openForm(row) {
+      if (row) {
+        this.formModel = { ...row, statusOpen: row.status === 'OPEN' }
+      } else {
+        this.formModel = { id: null, name: '', vipLevel: 1, price: 0, upgradeCondition: '', validityDays: -1, benefits: '', statusOpen: true }
+      }
+      this.formModal = true
+    },
+    submitForm() {
+      this.$refs.configForm.validate(valid => {
+        if (!valid) return
+        this.submitLoading = true
+        saveVipConfig({
+          ...this.formModel,
+          status: this.formModel.statusOpen ? 'OPEN' : 'CLOSE'
+        }).then(res => {
+          if (res.success) {
+            this.$Message.success('保存成功')
+            this.formModal = false
+            this.loadData()
+          } else {
+            this.$Message.error(res.message || '保存失败')
+          }
+        }).finally(() => { this.submitLoading = false })
+      })
+    },
+    handleDelete(row) {
+      this.$Modal.confirm({
+        title: '确认删除',
+        content: `确定要删除VIP配置「${row.name}」吗?`,
+        onOk: () => {
+          deleteVipConfig(row.id).then(res => {
+            if (res.success) {
+              this.$Message.success('删除成功')
+              this.loadData()
+            }
+          })
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style scoped>
+.enagic-page { padding: 16px; }
+</style>

+ 69 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/pom.xml

@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>com.enagic</groupId>
+        <artifactId>enagic-plugin</artifactId>
+        <version>1.0.0</version>
+    </parent>
+
+    <artifactId>enagic-api</artifactId>
+    <packaging>jar</packaging>
+    <name>Enagic API</name>
+    <description>Enagic 业务 API - 差异化功能(健康布施者/AI数字人/VIP/运维)</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.enagic</groupId>
+            <artifactId>enagic-entity</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <!-- Lilishop API 依赖(buyer-api + manager-api) -->
+        <dependency>
+            <groupId>com.dan</groupId>
+            <artifactId>dan-shop-buyer-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.dan</groupId>
+            <artifactId>dan-shop-manager-api</artifactId>
+        </dependency>
+
+        <!-- Spring Boot Web -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <!-- MyBatis-Plus -->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-annotation</artifactId>
+            <version>3.5.5</version>
+        </dependency>
+
+        <!-- HTTP Client(调用 AI 大模型) -->
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-http</artifactId>
+            <version>5.8.24</version>
+        </dependency>
+
+        <!-- JSON 处理 -->
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-json</artifactId>
+            <version>5.8.24</version>
+        </dependency>
+
+        <!-- Redis(缓存) -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>

+ 50 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/common/ResultUtil.java

@@ -0,0 +1,50 @@
+package com.enagic.modules.enagic.common;
+
+import com.dan.common.enums.ResultCode;
+import com.dan.common.vo.ResultMessage;
+
+public class ResultUtil {
+
+    public static <T> ResultMessage<T> data(T data) {
+        ResultMessage<T> result = new ResultMessage<>();
+        result.setCode(ResultCode.SUCCESS.getCode());
+        result.setMessage(ResultCode.SUCCESS.getMessage());
+        result.setData(data);
+        return result;
+    }
+
+    public static <T> ResultMessage<T> success() {
+        ResultMessage<T> result = new ResultMessage<>();
+        result.setCode(ResultCode.SUCCESS.getCode());
+        result.setMessage(ResultCode.SUCCESS.getMessage());
+        return result;
+    }
+
+    public static <T> ResultMessage<T> success(String message) {
+        ResultMessage<T> result = new ResultMessage<>();
+        result.setCode(ResultCode.SUCCESS.getCode());
+        result.setMessage(message);
+        return result;
+    }
+
+    public static <T> ResultMessage<T> error(ResultCode resultCode) {
+        ResultMessage<T> result = new ResultMessage<>();
+        result.setCode(resultCode.getCode());
+        result.setMessage(resultCode.getMessage());
+        return result;
+    }
+
+    public static <T> ResultMessage<T> error(String message) {
+        ResultMessage<T> result = new ResultMessage<>();
+        result.setCode(ResultCode.ERROR.getCode());
+        result.setMessage(message);
+        return result;
+    }
+
+    public static <T> ResultMessage<T> error(Integer code, String message) {
+        ResultMessage<T> result = new ResultMessage<>();
+        result.setCode(code);
+        result.setMessage(message);
+        return result;
+    }
+}

+ 20 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/config/EnagicApiAutoConfiguration.java

@@ -0,0 +1,20 @@
+package com.enagic.modules.enagic.config;
+
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * Enagic API 自动配置
+ *
+ * 将此 JAR 加入 classpath 后,Spring Boot 会自动扫描 com.enagic 包
+ * 并将 Enagic 的 Controller、Service 注册到 Lilishop 应用上下文
+ *
+ * 使用方式:
+ * 1. 将 enagic-api-${version}.jar 放入 Lilishop 的 lib 目录
+ * 2. 或在 Lilishop 的 pom.xml 中添加依赖
+ * 3. 重启应用即可生效
+ */
+@Configuration
+@ComponentScan(basePackages = "com.enagic.modules.enagic")
+public class EnagicApiAutoConfiguration {
+}

+ 101 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/controller/buyer/AiChatController.java

@@ -0,0 +1,101 @@
+package com.enagic.modules.enagic.controller.buyer;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.RandomUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.dan.common.enums.ResultCode;
+import com.dan.common.security.context.UserContext;
+import com.dan.common.security.entity.MemberUser;
+import com.dan.common.vo.ResultMessage;
+import com.dan.modules.member.entity.dos.Member;
+import com.dan.modules.member.service.MemberService;
+import com.enagic.modules.enagic.entity.dos.AdvisorMedal;
+import com.enagic.modules.enagic.entity.dos.HealthAdvisor;
+import com.enagic.modules.enagic.mapper.AdvisorMedalMapper;
+import com.enagic.modules.enagic.mapper.HealthAdvisorMapper;
+import com.enagic.modules.enagic.service.AiChatService;
+import com.enagic.modules.enagic.service.HealthAdvisorService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.*;
+
+/**
+ * AI 数字人对话 - 买家端 API
+ * 路径前缀:/enagic/buyer/ai/*
+ */
+@Api(tags = "Enagic - AI 数字人")
+@RestController
+@RequestMapping("/enagic/buyer/ai")
+public class AiChatController {
+
+    @Autowired
+    private AiChatService aiChatService;
+
+    @ApiOperation("发送消息")
+    @PostMapping("/chat")
+    public ResultMessage<Map<String, String>> chat(
+            @RequestParam(required = false) Long memberId,
+            @RequestParam String question,
+            @RequestParam(required = false) String sessionId,
+            HttpServletRequest request) {
+
+        if (memberId == null && UserContext.getCurrentMember() != null) {
+            memberId = UserContext.getCurrentMember().getId();
+        }
+
+        if (sessionId == null || sessionId.isEmpty()) {
+            sessionId = IdUtil.getSnowflakeNextId() + "-" + RandomUtil.randomString(6);
+        }
+
+        String answer = aiChatService.chat(memberId, question, sessionId);
+
+        Map<String, String> result = new HashMap<>();
+        result.put("answer", answer);
+        result.put("sessionId", sessionId);
+        return ResultUtil.data(result);
+    }
+
+    @ApiOperation("获取对话历史")
+    @GetMapping("/history")
+    public ResultMessage<List<Map<String, Object>>> getHistory(
+            @RequestParam(required = false) Long memberId,
+            @RequestParam(required = false) String sessionId,
+            @RequestParam(defaultValue = "1") int page,
+            @RequestParam(defaultValue = "20") int pageSize) {
+
+        if (memberId == null && UserContext.getCurrentMember() != null) {
+            memberId = UserContext.getCurrentMember().getId();
+        }
+
+        var history = aiChatService.getHistory(memberId, sessionId, page, pageSize);
+
+        List<Map<String, Object>> result = new ArrayList<>();
+        for (var h : history) {
+            Map<String, Object> item = new HashMap<>();
+            item.put("id", h.getId());
+            item.put("question", h.getQuestion());
+            item.put("answer", h.getAnswer());
+            item.put("createTime", h.getCreateTime());
+            result.add(item);
+        }
+        return ResultUtil.data(result);
+    }
+
+    @ApiOperation("获取热门问题")
+    @GetMapping("/hot-questions")
+    public ResultMessage<List<String>> getHotQuestions() {
+        return ResultUtil.data(Arrays.asList(
+                "这个产品适合什么人群使用?",
+                "如何正确使用这款产品?",
+                "产品有哪些功效?",
+                "有什么注意事项?",
+                "如何购买和配送?"
+        ));
+    }
+}

+ 50 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/controller/buyer/DeductionBuyerController.java

@@ -0,0 +1,50 @@
+package com.enagic.modules.enagic.controller.buyer;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.dan.common.enums.ResultCode;
+import com.dan.common.security.context.UserContext;
+import com.dan.common.security.entity.MemberUser;
+import com.dan.common.vo.ResultMessage;
+import com.enagic.modules.enagic.common.ResultUtil;
+import com.enagic.modules.enagic.entity.dos.DeductionLog;
+import com.enagic.modules.enagic.entity.dos.MemberDeduction;
+import com.enagic.modules.enagic.service.DeductionService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@Api(tags = "Enagic - 抵扣金")
+@RestController
+@RequestMapping("/enagic/buyer/deduction")
+public class DeductionBuyerController {
+
+    @Autowired
+    private DeductionService deductionService;
+
+    @ApiOperation("获取抵扣金账户信息")
+    @GetMapping("/info")
+    public ResultMessage<MemberDeduction> getInfo() {
+        MemberUser currentUser = UserContext.getCurrentMember();
+        if (currentUser == null) {
+            return ResultUtil.error(ResultCode.USER_NOT_LOGIN);
+        }
+
+        MemberDeduction deduction = deductionService.getByMemberId(currentUser.getId());
+        return ResultUtil.data(deduction);
+    }
+
+    @ApiOperation("获取抵扣金流水")
+    @GetMapping("/log")
+    public ResultMessage<Page<DeductionLog>> getLog(
+            @RequestParam(defaultValue = "1") int page,
+            @RequestParam(defaultValue = "10") int pageSize) {
+        MemberUser currentUser = UserContext.getCurrentMember();
+        if (currentUser == null) {
+            return ResultUtil.error(ResultCode.USER_NOT_LOGIN);
+        }
+
+        Page<DeductionLog> result = deductionService.getLogPage(currentUser.getId(), page, pageSize);
+        return ResultUtil.data(result);
+    }
+}

+ 175 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/controller/buyer/HealthAdvisorBuyerController.java

@@ -0,0 +1,175 @@
+package com.enagic.modules.enagic.controller.buyer;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.RandomUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.dan.common.enums.ResultCode;
+import com.dan.common.security.context.UserContext;
+import com.dan.common.vo.ResultMessage;
+import com.dan.modules.member.entity.dos.Member;
+import com.dan.modules.member.service.MemberService;
+import com.enagic.modules.enagic.common.ResultUtil;
+import com.enagic.modules.enagic.entity.dos.AdvisorMedal;
+import com.enagic.modules.enagic.entity.dos.HealthAdvisor;
+import com.enagic.modules.enagic.mapper.AdvisorMedalMapper;
+import com.enagic.modules.enagic.mapper.HealthAdvisorMapper;
+import com.enagic.modules.enagic.service.HealthAdvisorService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.*;
+
+/**
+ * 健康布施者 - 买家端 API
+ * 路径前缀:/enagic/buyer/advisor/*
+ */
+@Api(tags = "Enagic - 健康布施者")
+@RestController
+@RequestMapping("/enagic/buyer/advisor")
+public class HealthAdvisorBuyerController {
+
+    @Autowired
+    private HealthAdvisorMapper healthAdvisorMapper;
+
+    @Autowired
+    private AdvisorMedalMapper advisorMedalMapper;
+
+    @Autowired
+    private HealthAdvisorService healthAdvisorService;
+
+    @ApiOperation("获取健康布施者信息")
+    @GetMapping("/info")
+    public ResultMessage<Map<String, Object>> getInfo(HttpServletRequest request) {
+        MemberUser currentUser = UserContext.getCurrentMember();
+        if (currentUser == null) {
+            return ResultUtil.error(ResultCode.USER_NOT_LOGIN);
+        }
+
+        HealthAdvisor advisor = healthAdvisorService.getByMemberId(currentUser.getId());
+        if (advisor == null) {
+            return ResultUtil.data(Collections.emptyMap());
+        }
+
+        List<AdvisorMedal> medals = advisorMedalMapper.selectList(
+                new LambdaQueryWrapper<AdvisorMedal>()
+                        .eq(AdvisorMedal::getAdvisorId, advisor.getId())
+                        .orderByDesc(AdvisorMedal::getGrantTime)
+        );
+
+        Map<String, Object> result = BeanUtil.beanToMap(advisor);
+        result.put("medals", medals);
+        result.put("medalCount", medals.size());
+        return ResultUtil.data(result);
+    }
+
+    @ApiOperation("获取我的客户列表")
+    @GetMapping("/my-customers")
+    public ResultMessage<Map<String, Object>> getMyCustomers(
+            @RequestParam(required = false) Integer page,
+            @RequestParam(required = false) Integer pageSize) {
+
+        MemberUser currentUser = UserContext.getCurrentMember();
+        if (currentUser == null) {
+            return ResultUtil.error(ResultCode.USER_NOT_LOGIN);
+        }
+
+        HealthAdvisor advisor = healthAdvisorService.getByMemberId(currentUser.getId());
+        if (advisor == null) {
+            return ResultUtil.data(Collections.emptyMap());
+        }
+
+        Page<Member> customers = healthAdvisorService.getMyCustomers(
+                advisor.getId(), page, pageSize);
+
+        return ResultUtil.data(customers);
+    }
+
+    @ApiOperation("获取邀请二维码")
+    @GetMapping("/invite-qr")
+    public ResultMessage<Map<String, String>> getInviteQr(HttpServletRequest request) {
+        MemberUser currentUser = UserContext.getCurrentMember();
+        if (currentUser == null) {
+            return ResultUtil.error(ResultCode.USER_NOT_LOGIN);
+        }
+
+        String scene = "inviter=" + currentUser.getId() + "&t=" + System.currentTimeMillis();
+        String qrUrl = "/pages/enagic/health-advisor/invite-qr?scene=" + scene;
+
+        Map<String, String> result = new HashMap<>();
+        result.put("qrUrl", qrUrl);
+        result.put("inviteLink", "https://enagic.com/invite?inviter=" + currentUser.getId());
+        result.put("inviteCode", String.valueOf(currentUser.getId()));
+        return ResultUtil.data(result);
+    }
+
+    @ApiOperation("成为健康布施者")
+    @PostMapping("/apply")
+    public ResultMessage<Void> apply(@RequestBody HealthAdvisor param) {
+        MemberUser currentUser = UserContext.getCurrentMember();
+        if (currentUser == null) {
+            return ResultUtil.error(ResultCode.USER_NOT_LOGIN);
+        }
+
+        healthAdvisorService.apply(currentUser.getId(), param.getName(), param.getIdNumber());
+        return ResultUtil.success();
+    }
+
+    @ApiOperation("获取勋章列表")
+    @GetMapping("/medals")
+    public ResultMessage<List<AdvisorMedal>> getMedals() {
+        MemberUser currentUser = UserContext.getCurrentMember();
+        if (currentUser == null) {
+            return ResultUtil.error(ResultCode.USER_NOT_LOGIN);
+        }
+
+        HealthAdvisor advisor = healthAdvisorService.getByMemberId(currentUser.getId());
+        if (advisor == null) {
+            return ResultUtil.data(Collections.emptyList());
+        }
+
+        List<AdvisorMedal> medals = advisorMedalMapper.selectList(
+                new LambdaQueryWrapper<AdvisorMedal>()
+                        .eq(AdvisorMedal::getAdvisorId, advisor.getId())
+                        .orderByDesc(AdvisorMedal::getGrantTime));
+
+        return ResultUtil.data(medals);
+    }
+
+    @ApiOperation("我的推广业绩")
+    @GetMapping("/achievement")
+    public ResultMessage<Map<String, Object>> getAchievement(HttpServletRequest request) {
+        MemberUser currentUser = UserContext.getCurrentMember();
+        if (currentUser == null) {
+            return ResultUtil.error(ResultCode.USER_NOT_LOGIN);
+        }
+
+        HealthAdvisor advisor = healthAdvisorService.getByMemberId(currentUser.getId());
+        if (advisor == null) {
+            return ResultUtil.data(Collections.emptyMap());
+        }
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("totalInvites", advisor.getTotalInvites());
+        result.put("totalCommission", advisor.getTotalCommission());
+        result.put("availableCommission", advisor.getAvailableCommission());
+        result.put("medalLevel", advisor.getMedalLevel());
+        result.put("advisorCredits", advisor.getAdvisorCredits());
+        result.put("medalName", getMedalName(advisor.getMedalLevel()));
+        return ResultUtil.data(result);
+    }
+
+    private String getMedalName(String medalLevel) {
+        return switch (medalLevel) {
+            case "STAR_1" -> "布施新星";
+            case "STAR_2" -> "布施达人";
+            case "STAR_3" -> "布施导师";
+            case "MASTER" -> "布施宗师";
+            default -> "普通用户";
+        };
+    }
+}

+ 60 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/controller/buyer/OperationBuyerController.java

@@ -0,0 +1,60 @@
+package com.enagic.modules.enagic.controller.buyer;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.enagic.modules.enagic.common.ResultUtil;
+import com.enagic.modules.enagic.entity.dos.OperationPlan;
+import com.enagic.modules.enagic.entity.dos.OperationRecord;
+import com.enagic.modules.enagic.service.OperationPlanService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+@Api(tags = "Enagic - 买家端运维计划")
+@RestController
+@RequestMapping("/enagic/buyer/operation")
+public class OperationBuyerController {
+
+    @Autowired
+    private OperationPlanService operationPlanService;
+
+    @ApiOperation("我的运维计划列表")
+    @GetMapping("/my-plans")
+    public ResultMessage<Page<OperationPlan>> myPlans(
+            @RequestParam Long memberId,
+            @RequestParam(required = false) String status,
+            @RequestParam(defaultValue = "1") int pageNum,
+            @RequestParam(defaultValue = "10") int pageSize) {
+        return ResultUtil.data(operationPlanService.pageMyPlans(memberId, status, pageNum, pageSize));
+    }
+
+    @ApiOperation("运维计划详情")
+    @GetMapping("/detail/{id}")
+    public ResultMessage<OperationPlan> planDetail(@PathVariable Long id) {
+        return ResultUtil.data(operationPlanService.getPlanById(id));
+    }
+
+    @ApiOperation("运维记录")
+    @GetMapping("/records/{planId}")
+    public ResultMessage<Page<OperationRecord>> planRecords(
+            @PathVariable Long planId,
+            @RequestParam(defaultValue = "1") int pageNum,
+            @RequestParam(defaultValue = "10") int pageSize) {
+        return ResultUtil.data(operationPlanService.pageRecord(planId, pageNum, pageSize));
+    }
+
+    @ApiOperation("我的运维计划数量")
+    @GetMapping("/count")
+    public ResultMessage<Map<String, Object>> planCount(@RequestParam Long memberId) {
+        Page<OperationPlan> inProgress = operationPlanService.pageMyPlans(memberId, "IN_PROGRESS", 1, 1);
+        Page<OperationPlan> completed = operationPlanService.pageMyPlans(memberId, "COMPLETED", 1, 1);
+        Page<OperationPlan> transferred = operationPlanService.pageMyPlans(memberId, "TRANSFERRED", 1, 1);
+        return ResultUtil.data(Map.of(
+                "inProgress", inProgress.getTotal(),
+                "completed", completed.getTotal(),
+                "transferred", transferred.getTotal()
+        ));
+    }
+}

+ 67 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/controller/manager/AiKnowledgeManagerController.java

@@ -0,0 +1,67 @@
+package com.enagic.modules.enagic.controller.manager;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.dan.common.enums.ResultCode;
+import com.dan.common.vo.ResultMessage;
+import com.enagic.modules.enagic.common.ResultUtil;
+import com.enagic.modules.enagic.entity.dos.AiKnowledge;
+import com.enagic.modules.enagic.entity.dos.AiConversation;
+import com.enagic.modules.enagic.service.AiChatService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@Api(tags = "Enagic - AI 知识库管理")
+@RestController
+@RequestMapping("/enagic/manager/ai")
+public class AiKnowledgeManagerController {
+
+    @Autowired
+    private AiChatService aiChatService;
+
+    @ApiOperation("知识库分页")
+    @GetMapping("/knowledge/page")
+    public ResultMessage<Page<AiKnowledge>> knowledgePage(
+            @RequestParam(required = false) String keyword,
+            @RequestParam(required = false) String category,
+            @RequestParam(required = false) String status,
+            @RequestParam(defaultValue = "1") int pageNum,
+            @RequestParam(defaultValue = "10") int pageSize) {
+        return ResultUtil.data(aiChatService.pageKnowledge(keyword, category, status, pageNum, pageSize));
+    }
+
+    @ApiOperation("知识库详情")
+    @GetMapping("/knowledge/{id}")
+    public ResultMessage<AiKnowledge> knowledgeDetail(@PathVariable Long id) {
+        AiKnowledge knowledge = aiChatService.getKnowledgeById(id);
+        if (knowledge == null) {
+            return ResultUtil.error(ResultCode.PARAM_IMPROPER);
+        }
+        return ResultUtil.data(knowledge);
+    }
+
+    @ApiOperation("保存知识库")
+    @PostMapping("/knowledge/save")
+    public ResultMessage<Void> knowledgeSave(@RequestBody AiKnowledge knowledge) {
+        aiChatService.saveKnowledge(knowledge);
+        return ResultUtil.success();
+    }
+
+    @ApiOperation("删除知识库")
+    @DeleteMapping("/knowledge/{id}")
+    public ResultMessage<Void> knowledgeDelete(@PathVariable Long id) {
+        aiChatService.deleteKnowledge(id);
+        return ResultUtil.success();
+    }
+
+    @ApiOperation("对话记录分页")
+    @GetMapping("/conversation-log")
+    public ResultMessage<Page<AiConversation>> conversationLog(
+            @RequestParam(required = false) Long memberId,
+            @RequestParam(required = false) String sessionId,
+            @RequestParam(defaultValue = "1") int pageNum,
+            @RequestParam(defaultValue = "10") int pageSize) {
+        return ResultUtil.data(aiChatService.pageConversationLog(memberId, sessionId, pageNum, pageSize));
+    }
+}

+ 68 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/controller/manager/DeductionManagerController.java

@@ -0,0 +1,68 @@
+package com.enagic.modules.enagic.controller.manager;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.dan.common.vo.ResultMessage;
+import com.enagic.modules.enagic.common.ResultUtil;
+import com.enagic.modules.enagic.entity.dos.DeductionLog;
+import com.enagic.modules.enagic.entity.dos.MemberDeduction;
+import com.enagic.modules.enagic.mapper.DeductionLogMapper;
+import com.enagic.modules.enagic.mapper.MemberDeductionMapper;
+import com.enagic.modules.enagic.service.DeductionService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+@Api(tags = "Enagic - 抵扣金管理")
+@RestController
+@RequestMapping("/enagic/manager/deduction")
+public class DeductionManagerController {
+
+    @Autowired
+    private MemberDeductionMapper memberDeductionMapper;
+
+    @Autowired
+    private DeductionLogMapper deductionLogMapper;
+
+    @Autowired
+    private DeductionService deductionService;
+
+    @ApiOperation("抵扣金账户分页列表")
+    @GetMapping("/page")
+    public ResultMessage<Page<MemberDeduction>> page(
+            @RequestParam(required = false) Integer pageNum,
+            @RequestParam(required = false) Integer pageSize,
+            @RequestParam(required = false) String keyword) {
+        if (pageNum == null || pageNum < 1) pageNum = 1;
+        if (pageSize == null || pageSize < 1) pageSize = 10;
+
+        LambdaQueryWrapper<MemberDeduction> wrapper = new LambdaQueryWrapper<MemberDeduction>()
+                .like(keyword != null, MemberDeduction::getMemberName, keyword)
+                .orderByDesc(MemberDeduction::getUpdateTime);
+
+        Page<MemberDeduction> result = memberDeductionMapper.selectPage(
+                new Page<>(pageNum, pageSize), wrapper);
+        return ResultUtil.data(result);
+    }
+
+    @ApiOperation("抵扣金账户详情")
+    @GetMapping("/{id}")
+    public ResultMessage<MemberDeduction> detail(@PathVariable Long id) {
+        MemberDeduction deduction = memberDeductionMapper.selectById(id);
+        if (deduction == null) {
+            return ResultUtil.error("抵扣金账户不存在");
+        }
+        return ResultUtil.data(deduction);
+    }
+
+    @ApiOperation("抵扣金流水查询")
+    @GetMapping("/log")
+    public ResultMessage<Page<DeductionLog>> log(
+            @RequestParam Long memberId,
+            @RequestParam(required = false, defaultValue = "1") int pageNum,
+            @RequestParam(required = false, defaultValue = "10") int pageSize) {
+        Page<DeductionLog> result = deductionService.getLogPage(memberId, pageNum, pageSize);
+        return ResultUtil.data(result);
+    }
+}

+ 101 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/controller/manager/HealthAdvisorManagerController.java

@@ -0,0 +1,101 @@
+package com.enagic.modules.enagic.controller.manager;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.dan.common.enums.ResultCode;
+import com.dan.common.security.context.UserContext;
+import com.dan.common.security.entity.AdminUser;
+import com.dan.common.vo.ResultMessage;
+import com.enagic.modules.enagic.common.ResultUtil;
+import com.enagic.modules.enagic.entity.dos.*;
+import com.enagic.modules.enagic.mapper.*;
+import com.enagic.modules.enagic.service.HealthAdvisorService;
+import com.enagic.modules.enagic.service.VipService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 健康布施者管理 - 管理端 API
+ * 路径前缀:/enagic/manager/advisor/*
+ */
+@Api(tags = "Enagic - 健康布施者管理")
+@RestController
+@RequestMapping("/enagic/manager/advisor")
+public class HealthAdvisorManagerController {
+
+    @Autowired
+    private HealthAdvisorMapper healthAdvisorMapper;
+
+    @Autowired
+    private AdvisorMedalMapper advisorMedalMapper;
+
+    @Autowired
+    private HealthAdvisorService healthAdvisorService;
+
+    @ApiOperation("健康布施者分页列表")
+    @GetMapping("/page")
+    public ResultMessage<Page<HealthAdvisor>> page(
+            @RequestParam(required = false) Integer pageNum,
+            @RequestParam(required = false) Integer pageSize,
+            @RequestParam(required = false) String keyword,
+            @RequestParam(required = false) String status) {
+
+        Page<HealthAdvisor> result = healthAdvisorService.page(keyword, status, pageNum, pageSize);
+        return ResultUtil.data(result);
+    }
+
+    @ApiOperation("发放勋章")
+    @PostMapping("/medal/grant")
+    public ResultMessage<Void> grantMedal(@RequestBody Map<String, Object> params) {
+        Long advisorId = Long.valueOf(params.get("advisorId").toString());
+        String medalType = params.get("medalType").toString();
+        String reason = params.getOrDefault("reason", "").toString();
+
+        healthAdvisorService.grantMedal(advisorId, medalType, reason);
+        return ResultUtil.success();
+    }
+
+    @ApiOperation("健康布施者详情")
+    @GetMapping("/{id}")
+    public ResultMessage<Map<String, Object>> detail(@PathVariable Long id) {
+        HealthAdvisor advisor = healthAdvisorMapper.selectById(id);
+        if (advisor == null) {
+            return ResultUtil.error(ResultCode.PARAM_IMPROPER);
+        }
+
+        java.util.List<AdvisorMedal> medals = advisorMedalMapper.selectList(
+                new LambdaQueryWrapper<AdvisorMedal>()
+                        .eq(AdvisorMedal::getAdvisorId, id)
+                        .orderByDesc(AdvisorMedal::getGrantTime));
+
+        java.util.List<MemberTransfer> transfers = null; // TODO
+
+        Map<String, Object> result = new HashMap<>();
+        result.put("advisor", advisor);
+        result.put("medals", medals);
+        return ResultUtil.data(result);
+    }
+
+    @ApiOperation("统计数据")
+    @GetMapping("/statistics")
+    public ResultMessage<Map<String, Object>> statistics() {
+        long total = healthAdvisorMapper.selectCount(null);
+        long active = healthAdvisorMapper.selectCount(
+                new LambdaQueryWrapper<HealthAdvisor>().eq(HealthAdvisor::getStatus, "ACTIVE"));
+        long masterCount = healthAdvisorMapper.selectCount(
+                new LambdaQueryWrapper<HealthAdvisor>().eq(HealthAdvisor::getMedalLevel, "MASTER"));
+
+        Map<String, Object> stats = new HashMap<>();
+        stats.put("total", total);
+        stats.put("active", active);
+        stats.put("masterCount", masterCount);
+        stats.put("todayNew", 0L); // TODO: 需要根据日期查询
+        return ResultUtil.data(stats);
+    }
+}

+ 110 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/controller/manager/OperationManagerController.java

@@ -0,0 +1,110 @@
+package com.enagic.modules.enagic.controller.manager;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.dan.common.enums.ResultCode;
+import com.dan.common.vo.ResultMessage;
+import com.enagic.modules.enagic.common.ResultUtil;
+import com.enagic.modules.enagic.entity.dos.*;
+import com.enagic.modules.enagic.service.OperationPlanService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+@Api(tags = "Enagic - 客户运维管理")
+@RestController
+@RequestMapping("/enagic/manager/operation")
+public class OperationManagerController {
+
+    @Autowired
+    private OperationPlanService operationPlanService;
+
+    @ApiOperation("运维流程模板分页")
+    @GetMapping("/flow/page")
+    public ResultMessage<Page<OperationFlow>> flowPage(
+            @RequestParam(required = false) String flowName,
+            @RequestParam(required = false) String status,
+            @RequestParam(defaultValue = "1") int pageNum,
+            @RequestParam(defaultValue = "10") int pageSize) {
+        return ResultUtil.data(operationPlanService.pageFlow(flowName, status, pageNum, pageSize));
+    }
+
+    @ApiOperation("保存运维流程模板")
+    @PostMapping("/flow/save")
+    public ResultMessage<Void> flowSave(@RequestBody OperationFlow flow) {
+        operationPlanService.saveFlow(flow);
+        return ResultUtil.success();
+    }
+
+    @ApiOperation("删除运维流程模板")
+    @DeleteMapping("/flow/{id}")
+    public ResultMessage<Void> flowDelete(@PathVariable Long id) {
+        operationPlanService.deleteFlow(id);
+        return ResultUtil.success();
+    }
+
+    @ApiOperation("切换运维流程模板状态")
+    @PutMapping("/flow/status")
+    public ResultMessage<Void> flowStatus(@RequestBody Map<String, Object> params) {
+        Long id = Long.valueOf(params.get("id").toString());
+        OperationFlow flow = operationPlanService.pageFlow(null, null, 1, 1)
+                .getRecords().stream()
+                .filter(f -> f.getId().equals(id))
+                .findFirst().orElse(null);
+        if (flow == null) {
+            return ResultUtil.error(ResultCode.PARAM_IMPROPER);
+        }
+        String newStatus = "OPEN".equals(flow.getStatus()) ? "CLOSE" : "OPEN";
+        flow.setStatus(newStatus);
+        operationPlanService.saveFlow(flow);
+        return ResultUtil.success();
+    }
+
+    @ApiOperation("运维计划执行分页")
+    @GetMapping("/plan/page")
+    public ResultMessage<Page<OperationPlan>> planPage(
+            @RequestParam(required = false) String status,
+            @RequestParam(required = false) String memberName,
+            @RequestParam(required = false) String flowName,
+            @RequestParam(defaultValue = "1") int pageNum,
+            @RequestParam(defaultValue = "10") int pageSize) {
+        return ResultUtil.data(operationPlanService.pagePlan(status, memberName, pageNum, pageSize));
+    }
+
+    @ApiOperation("运维计划详情")
+    @GetMapping("/plan/{id}")
+    public ResultMessage<OperationPlan> planDetail(@PathVariable Long id) {
+        OperationPlan plan = operationPlanService.getPlanById(id);
+        if (plan == null) {
+            return ResultUtil.error(ResultCode.PARAM_IMPROPER);
+        }
+        return ResultUtil.data(plan);
+    }
+
+    @ApiOperation("手动触发运维提醒")
+    @PostMapping("/plan/remind")
+    public ResultMessage<Void> planRemind(@RequestBody Map<String, Object> params) {
+        Long id = Long.valueOf(params.get("id").toString());
+        operationPlanService.remindPlan(id);
+        return ResultUtil.success();
+    }
+
+    @ApiOperation("标记运维计划完成")
+    @PostMapping("/plan/complete")
+    public ResultMessage<Void> planComplete(@RequestBody Map<String, Object> params) {
+        Long id = Long.valueOf(params.get("id").toString());
+        operationPlanService.completePlan(id);
+        return ResultUtil.success();
+    }
+
+    @ApiOperation("运维记录分页")
+    @GetMapping("/record/page")
+    public ResultMessage<Page<OperationRecord>> recordPage(
+            @RequestParam Long planId,
+            @RequestParam(defaultValue = "1") int pageNum,
+            @RequestParam(defaultValue = "10") int pageSize) {
+        return ResultUtil.data(operationPlanService.pageRecord(planId, pageNum, pageSize));
+    }
+}

+ 106 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/controller/manager/TransferManagerController.java

@@ -0,0 +1,106 @@
+package com.enagic.modules.enagic.controller.manager;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.dan.common.enums.ResultCode;
+import com.dan.common.vo.ResultMessage;
+import com.enagic.modules.enagic.common.ResultUtil;
+import com.enagic.modules.enagic.entity.dos.MemberTransfer;
+import com.enagic.modules.enagic.entity.dos.HealthAdvisor;
+import com.enagic.modules.enagic.mapper.MemberTransferMapper;
+import com.enagic.modules.enagic.mapper.HealthAdvisorMapper;
+import com.enagic.modules.enagic.service.OperationPlanService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.time.LocalDateTime;
+import java.util.Map;
+
+@Api(tags = "Enagic - 客户移交管理")
+@RestController
+@RequestMapping("/enagic/manager/transfer")
+public class TransferManagerController {
+
+    @Autowired
+    private MemberTransferMapper memberTransferMapper;
+
+    @Autowired
+    private HealthAdvisorMapper healthAdvisorMapper;
+
+    @Autowired
+    private OperationPlanService operationPlanService;
+
+    @ApiOperation("移交记录分页")
+    @GetMapping("/page")
+    public ResultMessage<Page<MemberTransfer>> transferPage(
+            @RequestParam(required = false) Long originalAdvisorId,
+            @RequestParam(required = false) Long newAdvisorId,
+            @RequestParam(required = false) String triggerType,
+            @RequestParam(defaultValue = "1") int pageNum,
+            @RequestParam(defaultValue = "10") int pageSize) {
+        Page<MemberTransfer> page = new Page<>(pageNum, pageSize);
+        LambdaQueryWrapper<MemberTransfer> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(originalAdvisorId != null, MemberTransfer::getOriginalAdvisorId, originalAdvisorId);
+        wrapper.eq(newAdvisorId != null, MemberTransfer::getNewAdvisorId, newAdvisorId);
+        wrapper.eq(triggerType != null, MemberTransfer::getTriggerType, triggerType);
+        wrapper.orderByDesc(MemberTransfer::getTransferTime);
+        return ResultUtil.data(memberTransferMapper.selectPage(page, wrapper));
+    }
+
+    @ApiOperation("健康布施者列表(用于选择移交目标)")
+    @GetMapping("/advisor/list")
+    public ResultMessage<Page<HealthAdvisor>> advisorList(
+            @RequestParam(required = false) String keyword,
+            @RequestParam(defaultValue = "1") int pageNum,
+            @RequestParam(defaultValue = "100") int pageSize) {
+        Page<HealthAdvisor> page = new Page<>(pageNum, pageSize);
+        LambdaQueryWrapper<HealthAdvisor> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(HealthAdvisor::getStatus, "ACTIVE");
+        wrapper.like(keyword != null, HealthAdvisor::getMemberName, keyword);
+        wrapper.orderByDesc(HealthAdvisor::getTotalInvites);
+        return ResultUtil.data(healthAdvisorMapper.selectPage(page, wrapper));
+    }
+
+    @ApiOperation("手动转移客户")
+    @PostMapping("/process")
+    public ResultMessage<Void> processTransfer(@RequestBody Map<String, Object> params) {
+        Long memberId = Long.valueOf(params.get("memberId").toString());
+        Long originalAdvisorId = Long.valueOf(params.get("originalAdvisorId").toString());
+        Long newAdvisorId = Long.valueOf(params.get("newAdvisorId").toString());
+        String reason = (String) params.get("reason");
+
+        if (memberId == null || newAdvisorId == null) {
+            return ResultUtil.error(ResultCode.PARAM_IMPROPER);
+        }
+
+        HealthAdvisor originalAdvisor = healthAdvisorMapper.selectById(originalAdvisorId);
+        HealthAdvisor newAdvisor = healthAdvisorMapper.selectById(newAdvisorId);
+
+        MemberTransfer transfer = new MemberTransfer()
+                .setMemberId(memberId)
+                .setOriginalAdvisorId(originalAdvisorId)
+                .setOriginalAdvisorName(originalAdvisor != null ? originalAdvisor.getMemberName() : null)
+                .setNewAdvisorId(newAdvisorId)
+                .setNewAdvisorName(newAdvisor != null ? newAdvisor.getMemberName() : null)
+                .setTransferReason(reason != null ? reason : "管理员手动转移")
+                .setTriggerType("MANUAL")
+                .setStatus("COMPLETED")
+                .setTransferTime(LocalDateTime.now())
+                .setCreateTime(LocalDateTime.now());
+        memberTransferMapper.insert(transfer);
+
+        return ResultUtil.success();
+    }
+
+    @ApiOperation("转移记录详情")
+    @GetMapping("/{id}")
+    public ResultMessage<MemberTransfer> transferDetail(@PathVariable Long id) {
+        MemberTransfer transfer = memberTransferMapper.selectById(id);
+        if (transfer == null) {
+            return ResultUtil.error(ResultCode.PARAM_IMPROPER);
+        }
+        return ResultUtil.data(transfer);
+    }
+}

+ 97 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/controller/manager/VipManagerController.java

@@ -0,0 +1,97 @@
+package com.enagic.modules.enagic.controller.manager;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.dan.common.vo.ResultMessage;
+import com.enagic.modules.enagic.common.ResultUtil;
+import com.enagic.modules.enagic.entity.dos.EnagicVipConfig;
+import com.enagic.modules.enagic.entity.dos.MemberVip;
+import com.enagic.modules.enagic.mapper.EnagicVipConfigMapper;
+import com.enagic.modules.enagic.mapper.MemberVipMapper;
+import com.enagic.modules.enagic.service.VipService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.time.LocalDateTime;
+
+@Api(tags = "Enagic - VIP管理")
+@RestController
+@RequestMapping("/enagic/manager/vip")
+public class VipManagerController {
+
+    @Autowired
+    private EnagicVipConfigMapper vipConfigMapper;
+
+    @Autowired
+    private MemberVipMapper memberVipMapper;
+
+    @Autowired
+    private VipService vipService;
+
+    @ApiOperation("VIP配置分页列表")
+    @GetMapping("/config/page")
+    public ResultMessage<Page<EnagicVipConfig>> configPage(
+            @RequestParam(required = false) Integer pageNum,
+            @RequestParam(required = false) Integer pageSize) {
+        if (pageNum == null || pageNum < 1) pageNum = 1;
+        if (pageSize == null || pageSize < 1) pageSize = 10;
+
+        LambdaQueryWrapper<EnagicVipConfig> wrapper = new LambdaQueryWrapper<EnagicVipConfig>()
+                .orderByAsc(EnagicVipConfig::getSort)
+                .orderByDesc(EnagicVipConfig::getCreateTime);
+
+        Page<EnagicVipConfig> result = vipConfigMapper.selectPage(
+                new Page<>(pageNum, pageSize), wrapper);
+        return ResultUtil.data(result);
+    }
+
+    @ApiOperation("保存VIP配置")
+    @PostMapping("/config/save")
+    public ResultMessage<Void> saveConfig(@RequestBody EnagicVipConfig config) {
+        LocalDateTime now = LocalDateTime.now();
+        if (config.getId() == null) {
+            config.setCreateTime(now);
+            config.setUpdateTime(now);
+            vipConfigMapper.insert(config);
+        } else {
+            config.setUpdateTime(now);
+            vipConfigMapper.updateById(config);
+        }
+        return ResultUtil.success();
+    }
+
+    @ApiOperation("删除VIP配置")
+    @DeleteMapping("/config/{id}")
+    public ResultMessage<Void> deleteConfig(@PathVariable Long id) {
+        vipConfigMapper.deleteById(id);
+        return ResultUtil.success();
+    }
+
+    @ApiOperation("会员VIP记录分页列表")
+    @GetMapping("/member-vip/page")
+    public ResultMessage<Page<MemberVip>> memberVipPage(
+            @RequestParam(required = false) Integer pageNum,
+            @RequestParam(required = false) Integer pageSize) {
+        if (pageNum == null || pageNum < 1) pageNum = 1;
+        if (pageSize == null || pageSize < 1) pageSize = 10;
+
+        LambdaQueryWrapper<MemberVip> wrapper = new LambdaQueryWrapper<MemberVip>()
+                .orderByDesc(MemberVip::getCreateTime);
+
+        Page<MemberVip> result = memberVipMapper.selectPage(
+                new Page<>(pageNum, pageSize), wrapper);
+        return ResultUtil.data(result);
+    }
+
+    @ApiOperation("会员VIP详情")
+    @GetMapping("/member-vip/{id}")
+    public ResultMessage<MemberVip> memberVipDetail(@PathVariable Long id) {
+        MemberVip memberVip = memberVipMapper.selectById(id);
+        if (memberVip == null) {
+            return ResultUtil.error("VIP记录不存在");
+        }
+        return ResultUtil.data(memberVip);
+    }
+}

+ 9 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/AdvisorMedalMapper.java

@@ -0,0 +1,9 @@
+package com.enagic.modules.enagic.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.enagic.modules.enagic.entity.dos.AdvisorMedal;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface AdvisorMedalMapper extends BaseMapper<AdvisorMedal> {
+}

+ 9 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/AiConversationMapper.java

@@ -0,0 +1,9 @@
+package com.enagic.modules.enagic.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.enagic.modules.enagic.entity.dos.AiConversation;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface AiConversationMapper extends BaseMapper<AiConversation> {
+}

+ 9 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/AiKnowledgeMapper.java

@@ -0,0 +1,9 @@
+package com.enagic.modules.enagic.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.enagic.modules.enagic.entity.dos.AiKnowledge;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface AiKnowledgeMapper extends BaseMapper<AiKnowledge> {
+}

+ 9 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/DeductionLogMapper.java

@@ -0,0 +1,9 @@
+package com.enagic.modules.enagic.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.enagic.modules.enagic.entity.dos.DeductionLog;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface DeductionLogMapper extends BaseMapper<DeductionLog> {
+}

+ 9 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/EnagicVipConfigMapper.java

@@ -0,0 +1,9 @@
+package com.enagic.modules.enagic.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.enagic.modules.enagic.entity.dos.EnagicVipConfig;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface EnagicVipConfigMapper extends BaseMapper<EnagicVipConfig> {
+}

+ 9 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/HealthAdvisorMapper.java

@@ -0,0 +1,9 @@
+package com.enagic.modules.enagic.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.enagic.modules.enagic.entity.dos.HealthAdvisor;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface HealthAdvisorMapper extends BaseMapper<HealthAdvisor> {
+}

+ 9 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/MemberDeductionMapper.java

@@ -0,0 +1,9 @@
+package com.enagic.modules.enagic.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.enagic.modules.enagic.entity.dos.MemberDeduction;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface MemberDeductionMapper extends BaseMapper<MemberDeduction> {
+}

+ 9 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/MemberTransferMapper.java

@@ -0,0 +1,9 @@
+package com.enagic.modules.enagic.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.enagic.modules.enagic.entity.dos.MemberTransfer;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface MemberTransferMapper extends BaseMapper<MemberTransfer> {
+}

+ 9 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/MemberVipMapper.java

@@ -0,0 +1,9 @@
+package com.enagic.modules.enagic.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.enagic.modules.enagic.entity.dos.MemberVip;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface MemberVipMapper extends BaseMapper<MemberVip> {
+}

+ 9 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/OperationFlowMapper.java

@@ -0,0 +1,9 @@
+package com.enagic.modules.enagic.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.enagic.modules.enagic.entity.dos.OperationFlow;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface OperationFlowMapper extends BaseMapper<OperationFlow> {
+}

+ 9 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/OperationPlanMapper.java

@@ -0,0 +1,9 @@
+package com.enagic.modules.enagic.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.enagic.modules.enagic.entity.dos.OperationPlan;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface OperationPlanMapper extends BaseMapper<OperationPlan> {
+}

+ 9 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/mapper/OperationRecordMapper.java

@@ -0,0 +1,9 @@
+package com.enagic.modules.enagic.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.enagic.modules.enagic.entity.dos.OperationRecord;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface OperationRecordMapper extends BaseMapper<OperationRecord> {
+}

+ 243 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/service/AiChatService.java

@@ -0,0 +1,243 @@
+package com.enagic.modules.enagic.config;
+
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.dan.common.util.CurrencyUtil;
+import com.dan.modules.member.entity.dos.Member;
+import com.dan.modules.member.service.MemberService;
+import com.enagic.modules.enagic.entity.dos.AiConversation;
+import com.enagic.modules.enagic.entity.dos.AiKnowledge;
+import com.enagic.modules.enagic.mapper.AiConversationMapper;
+import com.enagic.modules.enagic.mapper.AiKnowledgeMapper;
+import com.enagic.modules.system.service.SettingService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+/**
+ * AI 数字人服务
+ * 对接硅基流动 / 阿里云百炼等 AI 大模型
+ */
+@Service
+public class AiChatService {
+
+    @Value("${enagic.ai.provider:siliconflow}")
+    private String provider;
+
+    @Value("${enagic.ai.api-key:}")
+    private String apiKey;
+
+    @Value("${enagic.ai.model:Qwen/Qwen2.5-7B-Instruct}")
+    private String model;
+
+    @Value("${enagic.ai.base-url:https://api.siliconflow.cn/v1}")
+    private String baseUrl;
+
+    @Autowired
+    private AiKnowledgeMapper aiKnowledgeMapper;
+
+    @Autowired
+    private AiConversationMapper aiConversationMapper;
+
+    @Autowired(required = false)
+    private MemberService memberService;
+
+    @Autowired
+    private RedisTemplate<String, String> redisTemplate;
+
+    private static final String SENSITIVE_WORDS_KEY = "enagic:ai:sensitive";
+
+    public String chat(Long memberId, String question, String sessionId) {
+        if (memberId != null && memberService != null) {
+            Member member = memberService.getById(memberId);
+            if (member != null) {
+                question = "【用户" + member.getNickName() + "】" + question;
+            }
+        }
+
+        if (containsSensitive(question)) {
+            return "抱歉,您的问题中包含敏感词汇,请重新描述。";
+        }
+
+        List<AiKnowledge> knowledgeList = searchKnowledge(question);
+        String context = buildContext(knowledgeList);
+        String fullPrompt = context + "\n\n用户问题: " + question;
+
+        String answer;
+        if ("siliconflow".equals(provider)) {
+            answer = callSiliconFlow(fullPrompt);
+        } else if ("aliyun".equals(provider)) {
+            answer = callAliYun(fullPrompt);
+        } else {
+            answer = "AI 服务暂未配置,请联系管理员。";
+        }
+
+        if (containsSensitive(answer)) {
+            answer = "抱歉,AI 暂时无法回答这个问题,建议您联系人工客服获取帮助。";
+        }
+
+        AiConversation conversation = new AiConversation()
+                .setMemberId(memberId)
+                .setSessionId(sessionId)
+                .setQuestion(question)
+                .setAnswer(answer)
+                .setModel(model)
+                .setQuestionType(determineQuestionType(question, knowledgeList))
+                .setHasProductRecommend(answer.contains("推荐"))
+                .setCreateTime(LocalDateTime.now());
+        aiConversationMapper.insert(conversation);
+
+        return answer;
+    }
+
+    private String callSiliconFlow(String prompt) {
+        try {
+            JSONObject body = new JSONObject()
+                    .set("model", model)
+                    .set("messages", new JSONObject[]
+                            {new JSONObject().set("role", "user").set("content", prompt)})
+                    .set("temperature", 0.7)
+                    .set("max_tokens", 1000);
+
+            HttpResponse response = HttpRequest.post(baseUrl + "/chat/completions")
+                    .header("Authorization", "Bearer " + apiKey)
+                    .header("Content-Type", "application/json")
+                    .body(body.toString())
+                    .timeout(30000)
+                    .execute();
+
+            JSONObject result = JSONUtil.parseObj(response.body());
+            return result.getJSONArray("choices")
+                    .getJSONObject(0)
+                    .getJSONObject("message")
+                    .getStr("content");
+        } catch (Exception e) {
+            return "AI 服务暂时不可用,请稍后再试。";
+        }
+    }
+
+    private String callAliYun(String prompt) {
+        return callSiliconFlow(prompt);
+    }
+
+    private List<AiKnowledge> searchKnowledge(String question) {
+        String[] keywords = question.length() > 5
+                ? question.substring(0, 10).split("")
+                : new String[0];
+
+        return aiKnowledgeMapper.selectList(
+                new LambdaQueryWrapper<AiKnowledge>()
+                        .eq(AiKnowledge::getStatus, "ACTIVE")
+                        .orderByDesc(AiKnowledge::getUseCount)
+                        .last("LIMIT 5")
+        );
+    }
+
+    private String buildContext(List<AiKnowledge> knowledgeList) {
+        if (knowledgeList == null || knowledgeList.isEmpty()) {
+            return "请根据你的产品知识和健康知识回答问题。如果不确定,请明确告知用户咨询人工客服。";
+        }
+
+        StringBuilder sb = new StringBuilder("参考知识:\n");
+        for (int i = 0; i < knowledgeList.size(); i++) {
+            AiKnowledge k = knowledgeList.get(i);
+            sb.append("[").append(i + 1).append("] ").append(k.getCategory())
+              .append(" - ").append(k.getTitle()).append("\n")
+              .append(k.getContent()).append("\n\n");
+        }
+        return sb.toString();
+    }
+
+    private String determineQuestionType(String question, List<AiKnowledge> knowledgeList) {
+        if (knowledgeList == null || knowledgeList.isEmpty()) {
+            if (question.contains("怎么用") || question.contains("使用方法")) {
+                return "PRODUCT";
+            } else if (question.contains("健康") || question.contains("身体")) {
+                return "HEALTH";
+            }
+            return "OTHER";
+        }
+        return knowledgeList.get(0).getCategory();
+    }
+
+    private boolean containsSensitive(String text) {
+        try {
+            String words = redisTemplate.opsForValue().get(SENSITIVE_WORDS_KEY);
+            if (words == null || words.isEmpty()) {
+                return false;
+            }
+            for (String word : words.split(",")) {
+                if (text.contains(word.trim())) {
+                    return true;
+                }
+            }
+        } catch (Exception e) {
+            // Redis 未配置时跳过敏感词检查
+        }
+        return false;
+    }
+
+    public List<AiConversation> getHistory(Long memberId, String sessionId, int page, int pageSize) {
+        LambdaQueryWrapper<AiConversation> wrapper = new LambdaQueryWrapper<AiConversation>()
+                .eq(memberId != null, AiConversation::getMemberId, memberId)
+                .eq(sessionId != null, AiConversation::getSessionId, sessionId)
+                .orderByDesc(AiConversation::getCreateTime)
+                .last("LIMIT " + (page - 1) * pageSize + "," + pageSize);
+
+        List<AiConversation> list = aiConversationMapper.selectList(wrapper);
+        return list != null ? list : Collections.emptyList();
+    }
+
+    public com.baomidou.mybatisplus.extension.plugins.pagination.Page<AiKnowledge> pageKnowledge(
+            String keyword, String category, String status, int pageNum, int pageSize) {
+        com.baomidou.mybatisplus.extension.plugins.pagination.Page<AiKnowledge> page =
+                new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(pageNum, pageSize);
+        LambdaQueryWrapper<AiKnowledge> wrapper = new LambdaQueryWrapper<>();
+        wrapper.like(keyword != null, AiKnowledge::getTitle, keyword)
+                .eq(category != null, AiKnowledge::getCategory, category)
+                .eq(status != null, AiKnowledge::getStatus, status)
+                .orderByDesc(AiKnowledge::getCreateTime);
+        return aiKnowledgeMapper.selectPage(page, wrapper);
+    }
+
+    public AiKnowledge getKnowledgeById(Long id) {
+        return aiKnowledgeMapper.selectById(id);
+    }
+
+    @org.springframework.transaction.annotation.Transactional
+    public void saveKnowledge(AiKnowledge knowledge) {
+        if (knowledge.getId() == null) {
+            knowledge.setUseCount(0);
+            knowledge.setCreateTime(LocalDateTime.now());
+            aiKnowledgeMapper.insert(knowledge);
+        } else {
+            aiKnowledgeMapper.updateById(knowledge);
+        }
+    }
+
+    @org.springframework.transaction.annotation.Transactional
+    public void deleteKnowledge(Long id) {
+        aiKnowledgeMapper.deleteById(id);
+    }
+
+    public com.baomidou.mybatisplus.extension.plugins.pagination.Page<AiConversation> pageConversationLog(
+            Long memberId, String sessionId, int pageNum, int pageSize) {
+        com.baomidou.mybatisplus.extension.plugins.pagination.Page<AiConversation> page =
+                new com.baomidou.mybatisplus.extension.plugins.pagination.Page<>(pageNum, pageSize);
+        LambdaQueryWrapper<AiConversation> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(memberId != null, AiConversation::getMemberId, memberId)
+                .eq(sessionId != null, AiConversation::getSessionId, sessionId)
+                .orderByDesc(AiConversation::getCreateTime);
+        return aiConversationMapper.selectPage(page, wrapper);
+    }
+}

+ 190 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/service/DeductionService.java

@@ -0,0 +1,190 @@
+package com.enagic.modules.enagic.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.enagic.modules.enagic.entity.dos.DeductionLog;
+import com.enagic.modules.enagic.entity.dos.MemberDeduction;
+import com.enagic.modules.enagic.mapper.DeductionLogMapper;
+import com.enagic.modules.enagic.mapper.MemberDeductionMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+@Service
+public class DeductionService {
+
+    @Autowired
+    private MemberDeductionMapper memberDeductionMapper;
+
+    @Autowired
+    private DeductionLogMapper deductionLogMapper;
+
+    public MemberDeduction getByMemberId(Long memberId) {
+        MemberDeduction deduction = memberDeductionMapper.selectOne(
+                new LambdaQueryWrapper<MemberDeduction>()
+                        .eq(MemberDeduction::getMemberId, memberId)
+                        .last("LIMIT 1"));
+        
+        if (deduction == null) {
+            deduction = new MemberDeduction()
+                    .setMemberId(memberId)
+                    .setDeductionBalance(BigDecimal.ZERO)
+                    .setFrozenBalance(BigDecimal.ZERO)
+                    .setCreateTime(LocalDateTime.now())
+                    .setUpdateTime(LocalDateTime.now());
+            memberDeductionMapper.insert(deduction);
+        }
+        return deduction;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void recharge(Long memberId, BigDecimal amount, String orderSn) {
+        MemberDeduction deduction = getByMemberId(memberId);
+        
+        BigDecimal beforeBalance = deduction.getDeductionBalance();
+        BigDecimal afterBalance = beforeBalance.add(amount);
+        
+        deduction.setDeductionBalance(afterBalance);
+        deduction.setUpdateTime(LocalDateTime.now());
+        memberDeductionMapper.updateById(deduction);
+        
+        DeductionLog log = new DeductionLog()
+                .setDeductionId(deduction.getId())
+                .setMemberId(memberId)
+                .setAmount(amount)
+                .setBeforeBalance(beforeBalance)
+                .setAfterBalance(afterBalance)
+                .setType("RECHARGE")
+                .setOrderSn(orderSn)
+                .setRemark("充值赠送")
+                .setCreateTime(LocalDateTime.now());
+        deductionLogMapper.insert(log);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public boolean deduct(Long memberId, BigDecimal amount, String orderSn) {
+        MemberDeduction deduction = getByMemberId(memberId);
+        
+        if (deduction.getDeductionBalance().compareTo(amount) < 0) {
+            return false;
+        }
+        
+        BigDecimal beforeBalance = deduction.getDeductionBalance();
+        BigDecimal afterBalance = beforeBalance.subtract(amount);
+        
+        deduction.setDeductionBalance(afterBalance);
+        deduction.setUpdateTime(LocalDateTime.now());
+        memberDeductionMapper.updateById(deduction);
+        
+        DeductionLog log = new DeductionLog()
+                .setDeductionId(deduction.getId())
+                .setMemberId(memberId)
+                .setAmount(amount.negate())
+                .setBeforeBalance(beforeBalance)
+                .setAfterBalance(afterBalance)
+                .setType("ORDER_DEDUCT")
+                .setOrderSn(orderSn)
+                .setRemark("订单抵扣")
+                .setCreateTime(LocalDateTime.now());
+        deductionLogMapper.insert(log);
+        
+        return true;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void freeze(Long memberId, BigDecimal amount, String orderSn) {
+        MemberDeduction deduction = getByMemberId(memberId);
+        
+        if (deduction.getDeductionBalance().compareTo(amount) < 0) {
+            throw new RuntimeException("抵扣金余额不足");
+        }
+        
+        BigDecimal beforeBalance = deduction.getDeductionBalance();
+        BigDecimal afterBalance = beforeBalance.subtract(amount);
+        BigDecimal frozenBalance = deduction.getFrozenBalance().add(amount);
+        
+        deduction.setDeductionBalance(afterBalance);
+        deduction.setFrozenBalance(frozenBalance);
+        deduction.setUpdateTime(LocalDateTime.now());
+        memberDeductionMapper.updateById(deduction);
+        
+        DeductionLog log = new DeductionLog()
+                .setDeductionId(deduction.getId())
+                .setMemberId(memberId)
+                .setAmount(amount.negate())
+                .setBeforeBalance(beforeBalance)
+                .setAfterBalance(afterBalance)
+                .setType("FROZEN")
+                .setOrderSn(orderSn)
+                .setRemark("订单冻结")
+                .setCreateTime(LocalDateTime.now());
+        deductionLogMapper.insert(log);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void unfreeze(Long memberId, BigDecimal amount, String orderSn) {
+        MemberDeduction deduction = getByMemberId(memberId);
+        
+        BigDecimal beforeBalance = deduction.getDeductionBalance();
+        BigDecimal afterBalance = beforeBalance.add(amount);
+        BigDecimal frozenBalance = deduction.getFrozenBalance().subtract(amount);
+        
+        if (frozenBalance.compareTo(BigDecimal.ZERO) < 0) {
+            frozenBalance = BigDecimal.ZERO;
+        }
+        
+        deduction.setDeductionBalance(afterBalance);
+        deduction.setFrozenBalance(frozenBalance);
+        deduction.setUpdateTime(LocalDateTime.now());
+        memberDeductionMapper.updateById(deduction);
+        
+        DeductionLog log = new DeductionLog()
+                .setDeductionId(deduction.getId())
+                .setMemberId(memberId)
+                .setAmount(amount)
+                .setBeforeBalance(beforeBalance)
+                .setAfterBalance(afterBalance)
+                .setType("UNFREEZE")
+                .setOrderSn(orderSn)
+                .setRemark("订单取消解冻")
+                .setCreateTime(LocalDateTime.now());
+        deductionLogMapper.insert(log);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void confirmDeduct(Long memberId, BigDecimal amount, String orderSn) {
+        MemberDeduction deduction = getByMemberId(memberId);
+        
+        BigDecimal frozenBalance = deduction.getFrozenBalance().subtract(amount);
+        if (frozenBalance.compareTo(BigDecimal.ZERO) < 0) {
+            frozenBalance = BigDecimal.ZERO;
+        }
+        
+        deduction.setFrozenBalance(frozenBalance);
+        deduction.setUpdateTime(LocalDateTime.now());
+        memberDeductionMapper.updateById(deduction);
+        
+        DeductionLog log = new DeductionLog()
+                .setDeductionId(deduction.getId())
+                .setMemberId(memberId)
+                .setAmount(amount.negate())
+                .setBeforeBalance(deduction.getDeductionBalance())
+                .setAfterBalance(deduction.getDeductionBalance())
+                .setType("ORDER_DEDUCT")
+                .setOrderSn(orderSn)
+                .setRemark("订单完成确认扣款")
+                .setCreateTime(LocalDateTime.now());
+        deductionLogMapper.insert(log);
+    }
+
+    public Page<DeductionLog> getLogPage(Long memberId, int page, int pageSize) {
+        LambdaQueryWrapper<DeductionLog> wrapper = new LambdaQueryWrapper<DeductionLog>()
+                .eq(DeductionLog::getMemberId, memberId)
+                .orderByDesc(DeductionLog::getCreateTime);
+        
+        return deductionLogMapper.selectPage(new Page<>(page, pageSize), wrapper);
+    }
+}

+ 169 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/service/HealthAdvisorService.java

@@ -0,0 +1,169 @@
+package com.enagic.modules.enagic.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.dan.modules.member.entity.dos.Member;
+import com.dan.modules.member.service.MemberService;
+import com.enagic.modules.enagic.entity.dos.AdvisorMedal;
+import com.enagic.modules.enagic.entity.dos.HealthAdvisor;
+import com.enagic.modules.enagic.mapper.AdvisorMedalMapper;
+import com.enagic.modules.enagic.mapper.HealthAdvisorMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Service
+public class HealthAdvisorService {
+
+    @Autowired
+    private HealthAdvisorMapper healthAdvisorMapper;
+
+    @Autowired
+    private AdvisorMedalMapper advisorMedalMapper;
+
+    @Autowired(required = false)
+    private MemberService memberService;
+
+    public HealthAdvisor getByMemberId(Long memberId) {
+        return healthAdvisorMapper.selectOne(
+                new LambdaQueryWrapper<HealthAdvisor>()
+                        .eq(HealthAdvisor::getMemberId, memberId)
+                        .eq(HealthAdvisor::getStatus, "ACTIVE")
+                        .last("LIMIT 1"));
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void apply(Long memberId, String name, String idNumber) {
+        Member member = memberService.getById(memberId);
+
+        HealthAdvisor existing = getByMemberId(memberId);
+        if (existing != null) {
+            return;
+        }
+
+        HealthAdvisor advisor = new HealthAdvisor()
+                .setMemberId(memberId)
+                .setMemberName(member.getNickName())
+                .setName(name)
+                .setIdNumber(idNumber)
+                .setTotalInvites(0)
+                .setTotalCommission(java.math.BigDecimal.ZERO)
+                .setAvailableCommission(java.math.BigDecimal.ZERO)
+                .setFrozenCommission(java.math.BigDecimal.ZERO)
+                .setAdvisorCredits(0)
+                .setMedalLevel("STAR_1")
+                .setStatus("ACTIVE")
+                .setPermanentBind(true)
+                .setApproveTime(LocalDateTime.now())
+                .setCreateTime(LocalDateTime.now())
+                .setUpdateTime(LocalDateTime.now());
+        healthAdvisorMapper.insert(advisor);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void grantMedal(Long advisorId, String medalType, String reason) {
+        HealthAdvisor advisor = healthAdvisorMapper.selectById(advisorId);
+        if (advisor == null) {
+            return;
+        }
+
+        int level = switch (medalType) {
+            case "STAR_1" -> 1;
+            case "STAR_2" -> 2;
+            case "STAR_3" -> 3;
+            case "MASTER" -> 4;
+            default -> 1;
+        };
+
+        AdvisorMedal medal = new AdvisorMedal()
+                .setAdvisorId(advisorId)
+                .setMedalType(medalType)
+                .setMedalLevel(level)
+                .setGrantReason(reason)
+                .setGrantTime(LocalDateTime.now())
+                .setDisplayed(false)
+                .setCreateTime(LocalDateTime.now());
+        advisorMedalMapper.insert(medal);
+
+        advisor.setMedalLevel(medalType);
+        advisor.setAdvisorCredits(advisor.getAdvisorCredits() + level * 10);
+        healthAdvisorMapper.updateById(advisor);
+    }
+
+    public void onNewCustomerInvited(Long advisorId, Long newMemberId) {
+        if (advisorId == null) {
+            return;
+        }
+
+        HealthAdvisor advisor = healthAdvisorMapper.selectById(advisorId);
+        if (advisor == null) {
+            return;
+        }
+
+        advisor.setTotalInvites(advisor.getTotalInvites() + 1);
+        healthAdvisorMapper.updateById(advisor);
+
+        int newLevel = calculateMedalLevel(advisor.getTotalInvites());
+        String currentLevel = advisor.getMedalLevel();
+        if (newLevel > getMedalLevelValue(currentLevel)) {
+            String newMedalType = getMedalType(newLevel);
+            grantMedal(advisorId, newMedalType, "邀请人数达到" + advisor.getTotalInvites() + "人");
+        }
+    }
+
+    private int calculateMedalLevel(int inviteCount) {
+        if (inviteCount >= 50) return 4;
+        if (inviteCount >= 20) return 3;
+        if (inviteCount >= 5) return 2;
+        return 1;
+    }
+
+    private int getMedalLevelValue(String medalType) {
+        return switch (medalType) {
+            case "STAR_1" -> 1;
+            case "STAR_2" -> 2;
+            case "STAR_3" -> 3;
+            case "MASTER" -> 4;
+            default -> 0;
+        };
+    }
+
+    private String getMedalType(int level) {
+        return switch (level) {
+            case 1 -> "STAR_1";
+            case 2 -> "STAR_2";
+            case 3 -> "STAR_3";
+            default -> "MASTER";
+        };
+    }
+
+    public Page<Member> getMyCustomers(Long advisorId, Integer page, Integer pageSize) {
+        if (page == null || page < 1) page = 1;
+        if (pageSize == null || pageSize < 1) pageSize = 10;
+
+        if (memberService == null) {
+            return new Page<>(page, pageSize);
+        }
+
+        LambdaQueryWrapper<Member> wrapper = new LambdaQueryWrapper<Member>()
+                .eq(Member::getHealthAdviserId, advisorId)
+                .orderByDesc(Member::getCreateTime);
+
+        return memberService.page(new Page<>(page, pageSize), wrapper);
+    }
+
+    public Page<HealthAdvisor> page(String keyword, String status, Integer pageNum, Integer pageSize) {
+        if (pageNum == null || pageNum < 1) pageNum = 1;
+        if (pageSize == null || pageSize < 1) pageSize = 10;
+
+        LambdaQueryWrapper<HealthAdvisor> wrapper = new LambdaQueryWrapper<HealthAdvisor>()
+                .like(keyword != null, HealthAdvisor::getMemberName, keyword)
+                .eq(status != null, HealthAdvisor::getStatus, status)
+                .orderByDesc(HealthAdvisor::getCreateTime);
+
+        return healthAdvisorMapper.selectPage(new Page<>(pageNum, pageSize), wrapper);
+    }
+}

+ 60 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/service/OperationFlowService.java

@@ -0,0 +1,60 @@
+package com.enagic.modules.enagic.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.enagic.modules.enagic.entity.dos.OperationFlow;
+import com.enagic.modules.enagic.mapper.OperationFlowMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.time.LocalDateTime;
+
+@Service
+public class OperationFlowService {
+
+    @Autowired
+    private OperationFlowMapper operationFlowMapper;
+
+    public Page<OperationFlow> page(String flowName, String status, int pageNum, int pageSize) {
+        LambdaQueryWrapper<OperationFlow> wrapper = new LambdaQueryWrapper<OperationFlow>()
+                .like(flowName != null, OperationFlow::getFlowName, flowName)
+                .eq(status != null, OperationFlow::getStatus, status)
+                .orderByDesc(OperationFlow::getCreateTime);
+
+        return operationFlowMapper.selectPage(new Page<>(pageNum, pageSize), wrapper);
+    }
+
+    public OperationFlow getById(Long id) {
+        return operationFlowMapper.selectById(id);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void save(OperationFlow flow) {
+        LocalDateTime now = LocalDateTime.now();
+        if (flow.getId() == null) {
+            flow.setCreateTime(now);
+            flow.setUpdateTime(now);
+            operationFlowMapper.insert(flow);
+        } else {
+            flow.setUpdateTime(now);
+            operationFlowMapper.updateById(flow);
+        }
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void delete(Long id) {
+        operationFlowMapper.deleteById(id);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void toggleStatus(Long id, String status) {
+        OperationFlow flow = operationFlowMapper.selectById(id);
+        if (flow == null) {
+            return;
+        }
+        flow.setStatus(status);
+        flow.setUpdateTime(LocalDateTime.now());
+        operationFlowMapper.updateById(flow);
+    }
+}

+ 218 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/service/OperationPlanService.java

@@ -0,0 +1,218 @@
+package com.enagic.modules.enagic.service;
+
+import cn.hutool.json.JSONArray;
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.dan.modules.message.service.MemberMessageService;
+import com.enagic.modules.enagic.entity.dos.*;
+import com.enagic.modules.enagic.mapper.*;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.Map;
+
+@Service
+public class OperationPlanService {
+
+    @Autowired
+    private OperationPlanMapper operationPlanMapper;
+
+    @Autowired
+    private OperationFlowMapper operationFlowMapper;
+
+    @Autowired
+    private OperationRecordMapper operationRecordMapper;
+
+    @Autowired
+    private HealthAdvisorMapper healthAdvisorMapper;
+
+    @Autowired
+    private MemberTransferMapper memberTransferMapper;
+
+    @Autowired(required = false)
+    private MemberMessageService memberMessageService;
+
+    @Transactional(rollbackFor = Exception.class)
+    public void createPlan(Long flowId, Long memberId, Long goodsId, String orderSn) {
+        OperationFlow flow = operationFlowMapper.selectById(flowId);
+        if (flow == null || !"OPEN".equals(flow.getStatus())) {
+            return;
+        }
+
+        JSONArray nodes = JSONUtil.parseArray(flow.getNodes());
+        if (nodes == null || nodes.isEmpty()) {
+            return;
+        }
+
+        JSONObject firstNode = nodes.getJSONObject(0);
+
+        OperationPlan plan = new OperationPlan()
+                .setFlowId(flowId)
+                .setMemberId(memberId)
+                .setProductId(goodsId)
+                .setOrderSn(orderSn)
+                .setCurrentNodeIndex(0)
+                .setCurrentNodeName(firstNode.getStr("name"))
+                .setNextNodeTime(LocalDateTime.now().plusDays(firstNode.getInt("day")))
+                .setSkipCount(0)
+                .setStatus("IN_PROGRESS")
+                .setCreateTime(LocalDateTime.now())
+                .setUpdateTime(LocalDateTime.now());
+        operationPlanMapper.insert(plan);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void transferToPlatform(Long planId) {
+        OperationPlan plan = operationPlanMapper.selectById(planId);
+        if (plan == null) {
+            return;
+        }
+
+        HealthAdvisor originalAdvisor = healthAdvisorMapper.selectOne(
+                new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<HealthAdvisor>()
+                        .eq(HealthAdvisor::getMemberId, plan.getMemberId())
+                        .last("LIMIT 1"));
+
+        // 平台客服接收(advisorId = 0 表示平台)
+        MemberTransfer transfer = new MemberTransfer()
+                .setMemberId(plan.getMemberId())
+                .setOriginalAdvisorId(originalAdvisor != null ? originalAdvisor.getId() : null)
+                .setOriginalAdvisorName(originalAdvisor != null ? originalAdvisor.getMemberName() : null)
+                .setNewAdvisorId(0L)
+                .setNewAdvisorName("平台客服")
+                .setTransferReason("连续3次未提供运维服务,自动转移")
+                .setTriggerType("AUTO")
+                .setStatus("COMPLETED")
+                .setTransferTime(LocalDateTime.now())
+                .setCreateTime(LocalDateTime.now());
+        memberTransferMapper.insert(transfer);
+
+        plan.setStatus("TRANSFERRED");
+        plan.setUpdateTime(LocalDateTime.now());
+        operationPlanMapper.updateById(plan);
+    }
+
+    public Page<OperationPlan> pagePlan(String status, String memberName, int pageNum, int pageSize) {
+        Page<OperationPlan> page = new Page<>(pageNum, pageSize);
+        LambdaQueryWrapper<OperationPlan> wrapper = new LambdaQueryWrapper<>();
+
+        if (StringUtils.isNotBlank(status)) {
+            wrapper.eq(OperationPlan::getStatus, status);
+        }
+        if (StringUtils.isNotBlank(memberName)) {
+            wrapper.like(OperationPlan::getMemberName, memberName);
+        }
+        wrapper.orderByDesc(OperationPlan::getCreateTime);
+
+        return operationPlanMapper.selectPage(page, wrapper);
+    }
+
+    public OperationPlan getPlanById(Long id) {
+        return operationPlanMapper.selectById(id);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void remindPlan(Long planId) {
+        OperationPlan plan = operationPlanMapper.selectById(planId);
+        if (plan == null || !"IN_PROGRESS".equals(plan.getStatus())) {
+            return;
+        }
+
+        if (memberMessageService != null) {
+            memberMessageService.saveMemberMessage(
+                    plan.getMemberId(),
+                    "运维提醒",
+                    plan.getCurrentNodeName(),
+                    "您的专属健康布施者为您发送了一条运维提醒"
+            );
+        }
+
+        OperationRecord record = new OperationRecord()
+                .setPlanId(planId)
+                .setNodeName(plan.getCurrentNodeName())
+                .setContent("手动触发提醒")
+                .setResult("已发送")
+                .setOperateTime(LocalDateTime.now())
+                .setCreateTime(LocalDateTime.now());
+        operationRecordMapper.insert(record);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void completePlan(Long planId) {
+        OperationPlan plan = operationPlanMapper.selectById(planId);
+        if (plan == null) {
+            return;
+        }
+
+        plan.setStatus("COMPLETED");
+        plan.setUpdateTime(LocalDateTime.now());
+        operationPlanMapper.updateById(plan);
+
+        OperationRecord record = new OperationRecord()
+                .setPlanId(planId)
+                .setNodeName(plan.getCurrentNodeName())
+                .setContent("人工完成计划")
+                .setResult("已完成")
+                .setOperateTime(LocalDateTime.now())
+                .setCreateTime(LocalDateTime.now());
+        operationRecordMapper.insert(record);
+    }
+
+    public Page<OperationRecord> pageRecord(Long planId, int pageNum, int pageSize) {
+        Page<OperationRecord> page = new Page<>(pageNum, pageSize);
+        LambdaQueryWrapper<OperationRecord> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(OperationRecord::getPlanId, planId);
+        wrapper.orderByDesc(OperationRecord::getOperateTime);
+        return operationRecordMapper.selectPage(page, wrapper);
+    }
+
+    public Page<OperationPlan> pageMyPlans(Long memberId, String status, int pageNum, int pageSize) {
+        Page<OperationPlan> page = new Page<>(pageNum, pageSize);
+        LambdaQueryWrapper<OperationPlan> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(memberId != null, OperationPlan::getMemberId, memberId);
+        wrapper.eq(status != null, OperationPlan::getStatus, status);
+        wrapper.orderByDesc(OperationPlan::getCreateTime);
+        return operationPlanMapper.selectPage(page, wrapper);
+    }
+
+    public Page<OperationFlow> pageFlow(String flowName, String status, int pageNum, int pageSize) {
+        Page<OperationFlow> page = new Page<>(pageNum, pageSize);
+        LambdaQueryWrapper<OperationFlow> wrapper = new LambdaQueryWrapper<>();
+
+        if (StringUtils.isNotBlank(flowName)) {
+            wrapper.like(OperationFlow::getFlowName, flowName);
+        }
+        if (StringUtils.isNotBlank(status)) {
+            wrapper.eq(OperationFlow::getStatus, status);
+        }
+        wrapper.orderByDesc(OperationFlow::getCreateTime);
+
+        return operationFlowMapper.selectPage(page, wrapper);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void saveFlow(OperationFlow flow) {
+        if (flow.getId() == null) {
+            flow.setCreateTime(LocalDateTime.now());
+            flow.setUpdateTime(LocalDateTime.now());
+            if (flow.getStatus() == null) {
+                flow.setStatus("OPEN");
+            }
+            operationFlowMapper.insert(flow);
+        } else {
+            flow.setUpdateTime(LocalDateTime.now());
+            operationFlowMapper.updateById(flow);
+        }
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    public void deleteFlow(Long id) {
+        operationFlowMapper.deleteById(id);
+    }
+}

+ 56 - 0
代码/enagic-lilishop/enagic-plugin/enagic-api/src/main/java/com/enagic/modules/enagic/service/VipService.java

@@ -0,0 +1,56 @@
+package com.enagic.modules.enagic.service;
+
+import com.enagic.modules.enagic.entity.dos.*;
+import com.enagic.modules.enagic.mapper.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.time.LocalDateTime;
+
+@Service
+public class VipService {
+
+    @Autowired
+    private com.enagic.modules.enagic.mapper.MemberVipMapper memberVipMapper;
+
+    @Autowired
+    private com.enagic.modules.enagic.mapper.EnagicVipConfigMapper vipConfigMapper;
+
+    public MemberVip getMemberVip(Long memberId) {
+        return memberVipMapper.selectOne(
+                new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<MemberVip>()
+                        .eq(MemberVip::getMemberId, memberId)
+                        .eq(MemberVip::getStatus, "ACTIVE")
+                        .last("LIMIT 1"));
+    }
+
+    public void openVip(Long memberId, Long vipConfigId) {
+        EnagicVipConfig config = vipConfigMapper.selectById(vipConfigId);
+        if (config == null) {
+            throw new RuntimeException("VIP配置不存在");
+        }
+
+        LocalDateTime now = LocalDateTime.now();
+        int remindDays = config.getGratitudeRemindDays() != null ? config.getGratitudeRemindDays() : 30;
+
+        MemberVip existing = getMemberVip(memberId);
+        if (existing != null) {
+            existing.setVipConfigId(vipConfigId);
+            existing.setVipName(config.getVipName());
+            existing.setUpdateTime(now);
+            memberVipMapper.updateById(existing);
+        } else {
+            MemberVip vip = new MemberVip()
+                    .setMemberId(memberId)
+                    .setVipConfigId(vipConfigId)
+                    .setVipName(config.getVipName())
+                    .setOpenTime(now)
+                    .setLastGratitudeRemindTime(now)
+                    .setNextGratitudeRemindTime(now.plusDays(remindDays))
+                    .setStatus("ACTIVE")
+                    .setCreateTime(now)
+                    .setUpdateTime(now);
+            memberVipMapper.insert(vip);
+        }
+    }
+}

+ 48 - 0
代码/enagic-lilishop/enagic-plugin/enagic-consumer/pom.xml

@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>com.enagic</groupId>
+        <artifactId>enagic-plugin</artifactId>
+        <version>1.0.0</version>
+    </parent>
+
+    <artifactId>enagic-consumer</artifactId>
+    <packaging>jar</packaging>
+    <name>Enagic Consumer</name>
+    <description>Enagic 事件消费者 - RocketMQ 监听 + 定时任务</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.enagic</groupId>
+            <artifactId>enagic-entity</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>com.enagic</groupId>
+            <artifactId>enagic-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.dan</groupId>
+            <artifactId>dan-shop-consumer</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.rocketmq</groupId>
+            <artifactId>rocketmq-spring-boot-starter</artifactId>
+            <version>2.2.2</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.xuxueli</groupId>
+            <artifactId>xxl-job-core</artifactId>
+            <version>2.3.0</version>
+        </dependency>
+    </dependencies>
+
+</project>

+ 115 - 0
代码/enagic-lilishop/enagic-plugin/enagic-consumer/src/main/java/com/enagic/modules/enagic/consumer/OperationRemindJob.java

@@ -0,0 +1,115 @@
+package com.enagic.modules.enagic.consumer;
+
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.dan.modules.member.entity.dos.Member;
+import com.dan.modules.member.service.MemberService;
+import com.enagic.modules.enagic.entity.dos.OperationPlan;
+import com.enagic.modules.enagic.entity.dos.OperationRecord;
+import com.enagic.modules.enagic.mapper.OperationPlanMapper;
+import com.enagic.modules.enagic.mapper.OperationRecordMapper;
+import com.enagic.modules.enagic.service.HealthAdvisorService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
+import java.util.List;
+
+/**
+ * 运维计划定时任务
+ * 扫描待执行的运维节点,发送提醒
+ */
+@Component
+public class OperationRemindJob {
+
+    private static final Logger log = LoggerFactory.getLogger(OperationRemindJob.class);
+
+    @Autowired
+    private OperationPlanMapper operationPlanMapper;
+
+    @Autowired
+    private OperationRecordMapper operationRecordMapper;
+
+    @Autowired
+    private com.dan.modules.message.service.MemberMessageService memberMessageService;
+
+    /**
+     * 每天 9:00 扫描运维提醒
+     * cron: 0 0 9 * * ?
+     */
+    // @XxlJob("enagic-operation-remind")
+    public void scanAndRemind() {
+        log.info("Enagic 运维提醒任务开始执行");
+
+        LocalDateTime now = LocalDateTime.now();
+        List<OperationPlan> pendingPlans = operationPlanMapper.selectList(
+                new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<OperationPlan>()
+                        .eq(OperationPlan::getStatus, "IN_PROGRESS")
+                        .le(OperationPlan::getNextNodeTime, now)
+                        .last("LIMIT 100")
+        );
+
+        for (OperationPlan plan : pendingPlans) {
+            try {
+                sendReminder(plan);
+            } catch (Exception e) {
+                log.error("发送运维提醒失败, planId={}", plan.getId(), e);
+            }
+        }
+
+        log.info("Enagic 运维提醒任务执行完成, 处理 {} 条", pendingPlans.size());
+    }
+
+    /**
+     * 每天 12:00 检查客户自动转移
+     * cron: 0 0 12 * * ?
+     */
+    // @XxlJob("enagic-transfer-check")
+    public void checkAutoTransfer() {
+        log.info("Enagic 客户自动转移检查任务开始执行");
+
+        List<OperationPlan> plansToTransfer = operationPlanMapper.selectList(
+                new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<OperationPlan>()
+                        .eq(OperationPlan::getStatus, "IN_PROGRESS")
+                        .ge(OperationPlan::getSkipCount, 3)
+        );
+
+        for (OperationPlan plan : plansToTransfer) {
+            try {
+                operationPlanService.transferToPlatform(plan.getId());
+            } catch (Exception e) {
+                log.error("客户自动转移失败, planId={}", plan.getId(), e);
+            }
+        }
+
+        log.info("Enagic 客户自动转移检查任务执行完成");
+    }
+
+    private void sendReminder(OperationPlan plan) {
+        String content = "亲爱的用户,您的运维任务 [" + plan.getCurrentNodeName() + "] 已到执行时间,请及时处理。";
+
+        // 通过 Lilishop 消息中心发送微信通知
+        try {
+            memberMessageService.sendMsg(plan.getMemberId(), "运维提醒", content);
+        } catch (Exception e) {
+            log.warn("发送微信消息失败, planId={}", plan.getId());
+        }
+
+        OperationRecord record = new OperationRecord()
+                .setPlanId(plan.getId())
+                .setNodeName(plan.getCurrentNodeName())
+                .setContent("系统自动提醒")
+                .setResult("已发送提醒")
+                .setOperateTime(LocalDateTime.now())
+                .setCreateTime(LocalDateTime.now());
+        operationRecordMapper.insert(record);
+
+        // 更新下一次节点时间(需要根据 flow 的 nodes 计算)
+        plan.setUpdateTime(LocalDateTime.now());
+        operationPlanMapper.updateById(plan);
+    }
+}

+ 157 - 0
代码/enagic-lilishop/enagic-plugin/enagic-consumer/src/main/java/com/enagic/modules/enagic/consumer/OrderEventConsumer.java

@@ -0,0 +1,157 @@
+package com.enagic.modules.enagic.consumer;
+
+import cn.hutool.json.JSONObject;
+import cn.hutool.json.JSONUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.dan.modules.order.order.entity.dos.Order;
+import com.enagic.modules.enagic.entity.dos.*;
+import com.enagic.modules.enagic.mapper.*;
+import com.enagic.modules.enagic.service.HealthAdvisorService;
+import com.enagic.modules.enagic.service.OperationPlanService;
+import org.apache.rocketmq.common.message.MessageExt;
+import org.apache.rocketmq.spring.annotation.RocketMQMessageListener;
+import org.apache.rocketmq.spring.core.RocketMQListener;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+/**
+ * 订单事件监听器
+ * 监听 Lilishop 订单状态变更,触发:
+ * 1. 客户运维计划自动生成(订单发货时)
+ * 2. 健康布施者邀请关系建立(用户注册时)
+ * 3. 抵扣金冻结/解冻(订单创建/取消时)
+ */
+@Component
+@RocketMQMessageListener(
+        topic = "order_topic",
+        consumerGroup = "enagic-order-consumer-group"
+)
+public class OrderEventConsumer implements RocketMQListener<MessageExt> {
+
+    private static final Logger log = LoggerFactory.getLogger(OrderEventConsumer.class);
+
+    @Autowired
+    private OperationPlanMapper operationPlanMapper;
+
+    @Autowired
+    private OperationFlowMapper operationFlowMapper;
+
+    @Autowired
+    private HealthAdvisorService healthAdvisorService;
+
+    @Autowired
+    private OperationPlanService operationPlanService;
+
+    @Override
+    public void onMessage(MessageExt message) {
+        try {
+            String body = new String(message.getBody());
+            JSONObject msg = JSONUtil.parseObj(body);
+
+            String eventType = msg.getStr("eventType");
+            String orderSn = msg.getStr("orderSn");
+
+            if (orderSn == null) {
+                return;
+            }
+
+            switch (eventType) {
+                case "ORDER_CREATED":
+                    onOrderCreated(orderSn, msg);
+                    break;
+                case "ORDER_DELIVERED":
+                    onOrderDelivered(orderSn, msg);
+                    break;
+                case "ORDER_COMPLETED":
+                    onOrderCompleted(orderSn, msg);
+                    break;
+                case "ORDER_CANCELLED":
+                    onOrderCancelled(orderSn, msg);
+                    break;
+            }
+        } catch (Exception e) {
+            log.error("处理订单事件失败", e);
+        }
+    }
+
+    /**
+     * 订单创建时:
+     * - 如果使用了抵扣金,冻结对应金额
+     */
+    private void onOrderCreated(String orderSn, JSONObject msg) {
+        log.info("Enagic 收到订单创建事件: {}", orderSn);
+    }
+
+    /**
+     * 订单发货时:
+     * - 自动创建运维计划(使用客户所属健康布施者关联的运维流程)
+     * - 若无对应流程,则使用系统第一个 OPEN 状态的默认流程
+     */
+    private void onOrderDelivered(String orderSn, JSONObject msg) {
+        log.info("Enagic 收到订单发货事件: {}", orderSn);
+        try {
+            Long memberId = msg.getLong("memberId");
+            Long goodsId = msg.getLong("goodsId");
+
+            if (memberId == null) {
+                return;
+            }
+
+            // 查找会员所属的健康布施者
+            HealthAdvisor advisor = healthAdvisorService.getByMemberId(memberId);
+            Long flowId = null;
+
+            if (advisor != null && advisor.getId() != null) {
+                // 使用健康布施者关联的运维流程(通过查找该顾问的第一个活跃流程)
+                List<OperationFlow> flows = operationFlowMapper.selectList(
+                        new LambdaQueryWrapper<OperationFlow>()
+                                .eq(OperationFlow::getStatus, "OPEN")
+                                .last("LIMIT 1"));
+                if (!flows.isEmpty()) {
+                    flowId = flows.get(0).getId();
+                }
+            }
+
+            // 如果仍找不到,使用系统默认流程
+            if (flowId == null) {
+                List<OperationFlow> defaultFlows = operationFlowMapper.selectList(
+                        new LambdaQueryWrapper<OperationFlow>()
+                                .eq(OperationFlow::getStatus, "OPEN")
+                                .orderByAsc(OperationFlow::getId)
+                                .last("LIMIT 1"));
+                if (!defaultFlows.isEmpty()) {
+                    flowId = defaultFlows.get(0).getId();
+                }
+            }
+
+            if (flowId != null) {
+                operationPlanService.createPlan(flowId, memberId, goodsId, orderSn);
+                log.info("运维计划创建成功, orderSn={}, flowId={}", orderSn, flowId);
+            } else {
+                log.warn("未找到可用的运维流程模板, orderSn={}", orderSn);
+            }
+        } catch (Exception e) {
+            log.error("创建运维计划失败, orderSn={}", orderSn, e);
+        }
+    }
+
+    /**
+     * 订单完成时:
+     * - 解冻抵扣金
+     */
+    private void onOrderCompleted(String orderSn, JSONObject msg) {
+        log.info("Enagic 收到订单完成事件: {}", orderSn);
+    }
+
+    /**
+     * 订单取消时:
+     * - 解冻抵扣金
+     */
+    private void onOrderCancelled(String orderSn, JSONObject msg) {
+        log.info("Enagic 收到订单取消事件: {}", orderSn);
+    }
+}

+ 22 - 0
代码/enagic-lilishop/enagic-plugin/enagic-entity/pom.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>com.enagic</groupId>
+        <artifactId>enagic-plugin</artifactId>
+        <version>1.0.0</version>
+    </parent>
+
+    <artifactId>enagic-entity</artifactId>
+    <packaging>jar</packaging>
+    <name>Enagic Entity</name>
+    <description>Enagic 实体层 - 数据库表映射</description>
+
+    <dependencies>
+        <!-- 继承父模块的通用依赖 -->
+    </dependencies>
+
+</project>

+ 65 - 0
代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/AdvisorMedal.java

@@ -0,0 +1,65 @@
+package com.enagic.modules.enagic.entity.dos;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 荣誉勋章表
+ * 对应需求:健康布施者荣誉勋章
+ */
+@Data
+@TableName("li_enagic_advisor_medal")
+@Accessors(chain = true)
+public class AdvisorMedal implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 健康布施者ID
+     */
+    private Long advisorId;
+
+    /**
+     * 勋章类型:STAR_1/STAR_2/STAR_3/MASTER
+     */
+    private String medalType;
+
+    /**
+     * 勋章等级(数字 1-4)
+     */
+    private Integer medalLevel;
+
+    /**
+     * 授予原因
+     */
+    private String grantReason;
+
+    /**
+     * 授予时间
+     */
+    private LocalDateTime grantTime;
+
+    /**
+     * 关联的被邀请人ID(触发勋章的那个客户)
+     */
+    private Long triggerMemberId;
+
+    /**
+     * 是否已展示过(用于新勋章小红点提醒)
+     */
+    private Boolean displayed;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+}

+ 65 - 0
代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/AiConversation.java

@@ -0,0 +1,65 @@
+package com.enagic.modules.enagic.entity.dos;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * AI 对话记录表
+ * 对应需求:AI 数字人
+ */
+@Data
+@TableName("li_enagic_ai_conversation")
+@Accessors(chain = true)
+public class AiConversation implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 会员ID(可为null表示未登录用户)
+     */
+    private Long memberId;
+
+    /**
+     * 会话ID(一次对话的标识)
+     */
+    private String sessionId;
+
+    /**
+     * 提问
+     */
+    private String question;
+
+    /**
+     * 回答
+     */
+    private String answer;
+
+    /**
+     * 使用的 AI 模型
+     */
+    private String model;
+
+    /**
+     * 问题类型:PRODUCT(产品咨询)/ HEALTH(健康咨询)/ OTHER
+     */
+    private String questionType;
+
+    /**
+     * 是否包含产品推荐
+     */
+    private Boolean hasProductRecommend;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+}

+ 75 - 0
代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/AiKnowledge.java

@@ -0,0 +1,75 @@
+package com.enagic.modules.enagic.entity.dos;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * AI 知识库表
+ * 对应需求:产品知识库、健康知识库
+ */
+@Data
+@TableName("li_enagic_ai_knowledge")
+@Accessors(chain = true)
+public class AiKnowledge implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 分类:PRODUCT / HEALTH / FAQ / COMPANY
+     */
+    private String category;
+
+    /**
+     * 标题/问题
+     */
+    private String title;
+
+    /**
+     * 答案内容
+     */
+    private String content;
+
+    /**
+     * 关联商品ID(可null)
+     */
+    private Long goodsId;
+
+    /**
+     * 关联商品名称
+     */
+    private String goodsName;
+
+    /**
+     * 关键词(逗号分隔)
+     */
+    private String keywords;
+
+    /**
+     * 状态:ACTIVE / INACTIVE
+     */
+    private String status;
+
+    /**
+     * 使用次数
+     */
+    private Integer useCount;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+}

+ 35 - 0
代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/ArticleQr.java

@@ -0,0 +1,35 @@
+package com.enagic.modules.enagic.entity.dos;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+@Data
+@TableName("li_enagic_article_qr")
+@Accessors(chain = true)
+public class ArticleQr implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    private Long articleId;
+
+    private String qrUrl;
+
+    private String qrContent;
+
+    private Long bindMemberId;
+
+    private String bindMemberName;
+
+    private LocalDateTime expireTime;
+
+    private LocalDateTime createTime;
+}

+ 37 - 0
代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/BehaviorLog.java

@@ -0,0 +1,37 @@
+package com.enagic.modules.enagic.entity.dos;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+@Data
+@TableName("li_enagic_behavior_log")
+@Accessors(chain = true)
+public class BehaviorLog implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    private Long memberId;
+
+    private String memberName;
+
+    private String eventType;
+
+    private String eventData;
+
+    private String pageUrl;
+
+    private String deviceInfo;
+
+    private String ip;
+
+    private LocalDateTime createTime;
+}

+ 71 - 0
代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/DeductionLog.java

@@ -0,0 +1,71 @@
+package com.enagic.modules.enagic.entity.dos;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 抵扣金流水表
+ */
+@Data
+@TableName("li_enagic_deduction_log")
+@Accessors(chain = true)
+public class DeductionLog implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 抵扣金账户ID
+     */
+    private Long deductionId;
+
+    /**
+     * 会员ID
+     */
+    private Long memberId;
+
+    /**
+     * 变动金额(正数=收入,负数=支出)
+     */
+    private BigDecimal amount;
+
+    /**
+     * 变动前余额
+     */
+    private BigDecimal beforeBalance;
+
+    /**
+     * 变动后余额
+     */
+    private BigDecimal afterBalance;
+
+    /**
+     * 类型:RECHARGE(充值赠送)/ ORDER_DEDUCT(订单抵扣)/
+     *       REFUND(退款返还)/ FROZEN(冻结)/ UNFREEZE(解冻)
+     */
+    private String type;
+
+    /**
+     * 关联订单号
+     */
+    private String orderSn;
+
+    /**
+     * 备注
+     */
+    private String remark;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+}

+ 84 - 0
代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/EnagicVipConfig.java

@@ -0,0 +1,84 @@
+package com.enagic.modules.enagic.entity.dos;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * VIP 配置表
+ * 对应需求:自定义会员等级条件、VIP无到期时间
+ */
+@Data
+@TableName("li_enagic_vip_config")
+@Accessors(chain = true)
+public class EnagicVipConfig implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * VIP 名称
+     */
+    private String vipName;
+
+    /**
+     * VIP 图标
+     */
+    private String vipImage;
+
+    /**
+     * 价格(分购买价格)
+     */
+    private BigDecimal price;
+
+    /**
+     * 升级条件(JSON格式)
+     * 格式:[{"type": "CONSUME_AMOUNT", "value": 1000}, {"type": "INVITE_COUNT", "value": 5}]
+     * type 可选值:CONSUME_AMOUNT / POINTS / INVITE_COUNT / PURCHASE_COUNT
+     */
+    private String upgradeConditions;
+
+    /**
+     * 会员权益(JSON格式)
+     * 格式:[{"type": "DISCOUNT_RATE", "value": 0.9}, {"type": "EXCLUSIVE_SERVICE", "value": true}]
+     */
+    private String benefits;
+
+    /**
+     * 是否无到期时间(true则不设有效期)
+     */
+    private Boolean noExpiry;
+
+    /**
+     * 感恩提醒周期(天)- 每多少天无分享行为触发感恩提醒
+     */
+    private Integer gratitudeRemindDays;
+
+    /**
+     * 排序
+     */
+    private Integer sort;
+
+    /**
+     * 状态:OPEN/CLOSE
+     */
+    private String status;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+}

+ 111 - 0
代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/HealthAdvisor.java

@@ -0,0 +1,111 @@
+package com.enagic.modules.enagic.entity.dos;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 健康布施者表
+ * 对应需求:永久邀请关系 + 荣誉勋章
+ */
+@Data
+@TableName("li_enagic_health_advisor")
+@Accessors(chain = true)
+public class HealthAdvisor implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 关联的会员ID
+     */
+    private Long memberId;
+
+    /**
+     * 会员名称
+     */
+    private String memberName;
+
+    /**
+     * 真实姓名
+     */
+    private String name;
+
+    /**
+     * 身份证号
+     */
+    private String idNumber;
+
+    /**
+     * 勋章等级:STAR_1(一星)/STAR_2(二星)/STAR_3(三星)/MASTER(宗师)
+     * 触发条件:
+     *   STAR_1 - 首次成功邀请
+     *   STAR_2 - 邀请 5 人
+     *   STAR_3 - 邀请 20 人
+     *   MASTER - 邀请 50 人
+     */
+    private String medalLevel;
+
+    /**
+     * 累计邀请人数
+     */
+    private Integer totalInvites;
+
+    /**
+     * 累计佣金总额
+     */
+    private BigDecimal totalCommission;
+
+    /**
+     * 可用佣金
+     */
+    private BigDecimal availableCommission;
+
+    /**
+     * 冻结佣金
+     */
+    private BigDecimal frozenCommission;
+
+    /**
+     * 顾问积分(用于荣誉排名)
+     */
+    private Integer advisorCredits;
+
+    /**
+     * 健康布施者状态:ACTIVE/INACTIVE
+     */
+    private String status;
+
+    /**
+     * 是否永久绑定(即使注销也不解除邀请关系)
+     */
+    private Boolean permanentBind;
+
+    /**
+     * 审核时间
+     */
+    private LocalDateTime approveTime;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+
+    /**
+     * 删除标记
+     */
+    private Integer deleteFlag;
+}

+ 61 - 0
代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/MemberDeduction.java

@@ -0,0 +1,61 @@
+package com.enagic.modules.enagic.entity.dos;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 抵扣金账户表
+ * 对应需求:独立于余额/积分的抵扣金账户
+ */
+@Data
+@TableName("li_enagic_deduction")
+@Accessors(chain = true)
+public class MemberDeduction implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 会员ID
+     */
+    private Long memberId;
+
+    /**
+     * 会员名称
+     */
+    private String memberName;
+
+    /**
+     * 可用抵扣金余额
+     */
+    private BigDecimal deductionBalance;
+
+    /**
+     * 冻结中的抵扣金(下单时冻结)
+     */
+    private BigDecimal frozenBalance;
+
+    /**
+     * 支付密码
+     */
+    private String payPassword;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+}

+ 80 - 0
代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/MemberTransfer.java

@@ -0,0 +1,80 @@
+package com.enagic.modules.enagic.entity.dos;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 客户移交记录表
+ * 对应需求:三次未服务自动转移客户
+ */
+@Data
+@TableName("li_enagic_member_transfer")
+@Accessors(chain = true)
+public class MemberTransfer implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 客户ID
+     */
+    private Long memberId;
+
+    /**
+     * 客户名称
+     */
+    private String memberName;
+
+    /**
+     * 原健康布施者ID
+     */
+    private Long originalAdvisorId;
+
+    /**
+     * 原健康布施者名称
+     */
+    private String originalAdvisorName;
+
+    /**
+     * 接收方健康布施者ID(平台客服)
+     */
+    private Long newAdvisorId;
+
+    /**
+     * 接收方名称
+     */
+    private String newAdvisorName;
+
+    /**
+     * 移交原因
+     */
+    private String transferReason;
+
+    /**
+     * 触发类型:MANUAL(手动)/AUTO(自动)
+     */
+    private String triggerType;
+
+    /**
+     * 状态:PENDING / CONFIRMED / REJECTED / COMPLETED
+     */
+    private String status;
+
+    /**
+     * 转移时间
+     */
+    private LocalDateTime transferTime;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+}

+ 81 - 0
代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/MemberVip.java

@@ -0,0 +1,81 @@
+package com.enagic.modules.enagic.entity.dos;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 会员 VIP 记录表
+ * 对应需求:VIP 无到期时间改造
+ */
+@Data
+@TableName("li_enagic_member_vip")
+@Accessors(chain = true)
+public class MemberVip implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 会员ID
+     */
+    private Long memberId;
+
+    /**
+     * 会员名称
+     */
+    private String memberName;
+
+    /**
+     * VIP 配置ID
+     */
+    private Long vipConfigId;
+
+    /**
+     * VIP 名称(冗余存储)
+     */
+    private String vipName;
+
+    /**
+     * 开通时间
+     */
+    private LocalDateTime openTime;
+
+    /**
+     * 上次感恩提醒时间
+     */
+    private LocalDateTime lastGratitudeRemindTime;
+
+    /**
+     * 下次感恩提醒时间
+     */
+    private LocalDateTime nextGratitudeRemindTime;
+
+    /**
+     * 累计消费金额
+     */
+    private BigDecimal totalConsumeAmount;
+
+    /**
+     * 状态:ACTIVE(激活)/ FROZEN(冻结)
+     */
+    private String status;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+}

+ 63 - 0
代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/OperationFlow.java

@@ -0,0 +1,63 @@
+package com.enagic.modules.enagic.entity.dos;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 运维流程模板表
+ * 对应需求:客户运维流程引擎
+ */
+@Data
+@TableName("li_enagic_operation_flow")
+@Accessors(chain = true)
+public class OperationFlow implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 流程名称
+     */
+    private String flowName;
+
+    /**
+     * 关联商品ID(null表示通用流程)
+     */
+    private Long productId;
+
+    /**
+     * 流程节点(JSON格式)
+     * 格式:
+     * [{"day": 1, "name": "发货提醒", "content": "您的订单已发货",
+     *   "remindType": "WECHAT_MSG", "autoHandle": false},
+     *  {"day": 7, "name": "使用指导", "content": "开始使用产品",
+     *   "remindType": "AI_REMINDER", "autoHandle": true}]
+     * day: 相对发货的天数
+     * remindType: WECHAT_MSG / AI_REMINDER / SMS
+     * autoHandle: 是否自动处理(无需人工介入)
+     */
+    private String nodes;
+
+    /**
+     * 状态:OPEN / CLOSE
+     */
+    private String status;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+}

+ 87 - 0
代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/OperationPlan.java

@@ -0,0 +1,87 @@
+package com.enagic.modules.enagic.entity.dos;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 运维计划表
+ * 对应需求:购买后自动生成运维计划
+ */
+@Data
+@TableName("li_enagic_operation_plan")
+@Accessors(chain = true)
+public class OperationPlan implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 运维流程模板ID
+     */
+    private Long flowId;
+
+    /**
+     * 客户ID(购买者)
+     */
+    private Long memberId;
+
+    /**
+     * 客户名称
+     */
+    private String memberName;
+
+    /**
+     * 关联商品ID
+     */
+    private Long productId;
+
+    /**
+     * 关联订单号
+     */
+    private String orderSn;
+
+    /**
+     * 当前节点索引
+     */
+    private Integer currentNodeIndex;
+
+    /**
+     * 当前节点名称
+     */
+    private String currentNodeName;
+
+    /**
+     * 下一个节点计划时间
+     */
+    private LocalDateTime nextNodeTime;
+
+    /**
+     * 连续跳过次数(用于触发自动转移)
+     */
+    private Integer skipCount;
+
+    /**
+     * 状态:PENDING(待执行)/ IN_PROGRESS(执行中)/
+     *       COMPLETED(已完成)/ CANCELLED(已取消)/
+     *       TRANSFERRED(已转移)
+     */
+    private String status;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    private LocalDateTime updateTime;
+}

+ 74 - 0
代码/enagic-lilishop/enagic-plugin/enagic-entity/src/main/java/com/enagic/modules/enagic/entity/dos/OperationRecord.java

@@ -0,0 +1,74 @@
+package com.enagic.modules.enagic.entity.dos;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 运维记录表
+ */
+@Data
+@TableName("li_enagic_operation_record")
+@Accessors(chain = true)
+public class OperationRecord implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 运维计划ID
+     */
+    private Long planId;
+
+    /**
+     * 运维节点名称
+     */
+    private String nodeName;
+
+    /**
+     * 操作人ID
+     */
+    private Long operatorId;
+
+    /**
+     * 操作人名称
+     */
+    private String operatorName;
+
+    /**
+     * 操作内容
+     */
+    private String content;
+
+    /**
+     * 执行结果
+     */
+    private String result;
+
+    /**
+     * 客户确认状态:PENDING / CONFIRMED / REJECTED
+     */
+    private String confirmStatus;
+
+    /**
+     * 执行时间
+     */
+    private LocalDateTime operateTime;
+
+    /**
+     * 确认时间
+     */
+    private LocalDateTime confirmTime;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+}

+ 102 - 0
代码/enagic-lilishop/enagic-plugin/pom.xml

@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.enagic</groupId>
+    <artifactId>enagic-plugin</artifactId>
+    <version>1.0.0</version>
+    <packaging>pom</packaging>
+
+    <name>Enagic Plugin</name>
+    <description>Enagic 本希甄选小程序插件模块 - 基于 Lilishop B2B2C</description>
+
+    <modules>
+        <module>enagic-entity</module>
+        <module>enagic-api</module>
+        <module>enagic-admin</module>
+        <module>enagic-consumer</module>
+    </modules>
+
+    <properties>
+        <java.version>1.8</java.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <lilishop.version>4.3</lilishop.version>
+        <mybatis-plus.version>3.5.5</mybatis-plus.version>
+        <spring-boot.version>2.4.13</spring-boot.version>
+        <hutool.version>5.8.24</hutool.version>
+    </properties>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>com.dan</groupId>
+                <artifactId>dan-shop-framework</artifactId>
+                <version>${lilishop.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.dan</groupId>
+                <artifactId>dan-shop-buyer-api</artifactId>
+                <version>${lilishop.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.dan</groupId>
+                <artifactId>dan-shop-manager-api</artifactId>
+                <version>${lilishop.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.dan</groupId>
+                <artifactId>dan-shop-consumer</artifactId>
+                <version>${lilishop.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.dan</groupId>
+                <artifactId>dan-shop-admin</artifactId>
+                <version>${lilishop.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>${spring-boot.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+    <dependencies>
+        <!-- Lilishop Framework - 实体和工具类 -->
+        <dependency>
+            <groupId>com.dan</groupId>
+            <artifactId>dan-shop-framework</artifactId>
+        </dependency>
+
+        <!-- 通用依赖 -->
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>${hutool.version}</version>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 58 - 0
代码/enagic-lilishop/pom.xml

@@ -0,0 +1,58 @@
+-- ============================================================
+-- Enagic Lilishop 集成项目 - Maven 聚合 POM
+--
+-- 使用方式:
+-- 1. 将 Lilishop 源码 (从 /mnt/e/workspace/iwt/lilishop) 链接到本项目
+-- 2. 在 Lilishop 的 pom.xml 中添加 <module>enagic-plugin</module>
+-- 3. 执行 mvn clean install -DskipTests
+--
+-- Lilishop 源码路径: /mnt/e/workspace/iwt/lilishop
+-- ============================================================
+
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <!-- Lilishop 主 POM 参考路径(本地工作树) -->
+    <!-- 实际路径由环境变量 LILISHOP_HOME 或工作树配置决定 -->
+
+    <groupId>com.enagic</groupId>
+    <artifactId>enagic-lilishop</artifactId>
+    <version>1.0.0</version>
+    <packaging>pom</packaging>
+
+    <name>Enagic Lilishop Integration</name>
+    <description>Enagic 本希甄选小程序 - 基于 Lilishop B2B2C 集成项目</description>
+
+    <!--
+      本 POM 的作用是作为开发时的便利聚合。
+      实际部署时,enagic-plugin 各子模块会作为 Maven 依赖加入 Lilishop 主项目。
+    -->
+
+    <modules>
+        <module>enagic-plugin</module>
+    </modules>
+
+    <properties>
+        <java.version>1.8</java.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+    </properties>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

+ 135 - 0
代码/enagic-uniapp/README.md

@@ -0,0 +1,135 @@
+# Enagic UniApp 小程序
+
+基于 Lilishop UniApp fork 的小程序扩展项目。
+
+## 项目状态
+
+本项目需要从 Lilishop UniApp fork 过来:
+```bash
+# 从 Lilishop fork
+cp -r /mnt/e/workspace/uniapp/lilishop/* ./
+
+# 然后添加 Enagic 页面
+```
+
+## 已创建的页面
+
+```
+pages/enagic/
+├── ai-chat/index.vue           # AI 数字人对话
+├── health-advisor/
+│   ├── home.vue                 # 健康布施者中心
+│   ├── customers.vue            # 我的客户
+│   └── medals.vue               # 荣誉勋章
+├── vip/
+│   ├── index.vue                # VIP 首页
+│   └── my-vip.vue               # 我的 VIP
+├── deduction/index.vue          # 抵扣金账户
+└── operation/my-plans.vue       # 我的运维计划
+```
+
+## API 层
+
+`api/enagic.js` - 包含所有 Enagic 扩展 API 调用函数
+
+## 集成步骤
+
+### 1. Fork Lilishop UniApp
+
+```bash
+# 方式一:直接从源码复制
+cp -r /mnt/e/workspace/uniapp/lilishop/* ./
+
+# 方式二:Git fork
+git clone https://github.com/pickmall/lilishop-uniapp.git enagic-uniapp
+cd enagic-uniapp
+git remote rename origin lilishop
+git remote add origin http://git.iwintrue.com/liaoxg/enagic-uniapp.git
+```
+
+### 2. 修改 pages.json
+
+在 `pages.json` 的 `subPackages` 中添加:
+
+```json
+{
+  "root": "pages/enagic",
+  "name": "Enagic",
+  "pages": [
+    {
+      "path": "ai-chat/index",
+      "style": { "navigationBarTitleText": "AI 健康顾问" }
+    },
+    {
+      "path": "health-advisor/home",
+      "style": { "navigationBarTitleText": "健康布施者" }
+    },
+    {
+      "path": "health-advisor/customers",
+      "style": { "navigationBarTitleText": "我的客户" }
+    },
+    {
+      "path": "health-advisor/medals",
+      "style": { "navigationBarTitleText": "荣誉勋章" }
+    },
+    {
+      "path": "vip/index",
+      "style": { "navigationBarTitleText": "VIP 会员" }
+    },
+    {
+      "path": "vip/my-vip",
+      "style": { "navigationBarTitleText": "我的 VIP" }
+    },
+    {
+      "path": "deduction/index",
+      "style": { "navigationBarTitleText": "抵扣金" }
+    },
+    {
+      "path": "operation/my-plans",
+      "style": { "navigationBarTitleText": "我的运维计划" }
+    }
+  ]
+}
+```
+
+### 3. 修改 manifest.json
+
+在 `manifest.json` 的 `uniStatistics` 中添加:
+```json
+"enagic": true
+```
+
+### 4. 配置 API 基础路径
+
+在 `utils/api.js` 或 `utils/request.js` 中确保 API 基础路径正确。
+
+### 5. 运行
+
+```bash
+# 在 HBuilderX 中打开
+# 运行 → 运行到小程序模拟器 → 微信开发者工具
+```
+
+## 页面功能对照表
+
+| 页面 | 功能 | API |
+|------|------|-----|
+| ai-chat/index | AI 对话 | `/enagic/buyer/ai/chat` |
+| health-advisor/home | 布施者中心 | `/enagic/buyer/advisor/info` |
+| health-advisor/customers | 客户列表 | `/enagic/buyer/advisor/my-customers` |
+| health-advisor/medals | 勋章展示 | 从 home 获取 |
+| vip/index | VIP 介绍 | `/enagic/buyer/vip/config-list` |
+| vip/my-vip | 我的 VIP | `/enagic/buyer/vip/info` |
+| deduction/index | 抵扣金 | `/enagic/buyer/deduction/info` |
+| operation/my-plans | 运维计划 | `/enagic/buyer/operation/my-plans` |
+
+## 注意事项
+
+1. 使用 Vue 2 + uView v1(不是 Vue 3)
+2. 所有 API 调用使用 `api/enagic.js` 中封装的函数
+3. 页面路径在 subpackages 中配置,不是主包
+
+## 相关文档
+
+- [SPEC.md](../SPEC.md) - 完整技术规格
+- [代码 README](../代码/README.md) - 项目整体说明

+ 61 - 0
代码/enagic-uniapp/api/enagic.js

@@ -0,0 +1,61 @@
+/**
+ * Enagic 小程序 API 调用层
+ * 对接 enagic-lilishop 后台的 /enagic/buyer/* API
+ */
+
+const BASE_URL = 'https://your-domain.com/enagic/buyer'
+
+const request = (options) => {
+  return new Promise((resolve, reject) => {
+    uni.request({
+      url: BASE_URL + options.url,
+      method: options.method || 'GET',
+      data: options.data,
+      header: {
+        'Content-Type': 'application/json',
+        'Authorization': uni.getStorageSync('token') || ''
+      },
+      success: (res) => {
+        if (res.data.success) {
+          resolve(res.data.data)
+        } else {
+          uni.showToast({ title: res.data.message, icon: 'none' })
+          reject(res.data)
+        }
+      },
+      fail: (err) => {
+        uni.showToast({ title: '网络请求失败', icon: 'none' })
+        reject(err)
+      }
+    })
+  })
+}
+
+// AI 数字人
+export const aiChat = (data) => request({ url: '/ai/chat', method: 'POST', data })
+export const aiHistory = (params) => request({ url: '/ai/history', method: 'GET', params })
+export const aiHotQuestions = () => request({ url: '/ai/hot-questions', method: 'GET' })
+
+// 健康布施者
+export const getAdvisorInfo = () => request({ url: '/advisor/info', method: 'GET' })
+export const getMyCustomers = (params) => request({ url: '/advisor/my-customers', method: 'GET', params })
+export const getInviteQr = () => request({ url: '/advisor/invite-qr', method: 'GET' })
+export const applyAsAdvisor = (data) => request({ url: '/advisor/apply', method: 'POST', data })
+export const getAdvisorMedals = () => request({ url: '/advisor/medals', method: 'GET' })
+export const getAdvisorAchievement = () => request({ url: '/advisor/achievement', method: 'GET' })
+
+// VIP
+export const getVipInfo = () => request({ url: '/vip/info', method: 'GET' })
+export const openVip = (data) => request({ url: '/vip/open', method: 'POST', data })
+export const getVipConfigList = () => request({ url: '/vip/config/list', method: 'GET' })
+
+// 抵扣金
+export const getDeductionInfo = () => request({ url: '/deduction/info', method: 'GET' })
+export const getDeductionLog = (params) => request({ url: '/deduction/log', method: 'GET', params })
+
+// 运维计划
+export const getMyOperationPlans = (params) => request({ url: '/operation/my-plans', method: 'GET', params })
+export const getOperationRecord = (params) => request({ url: '/operation/record', method: 'GET', params })
+
+// 素材二维码
+export const getArticleQr = (articleId) => request({ url: `/article/qr/${articleId}`, method: 'GET' })

+ 310 - 0
代码/enagic-uniapp/pages/enagic/ai-chat/index.vue

@@ -0,0 +1,310 @@
+<template>
+  <view class="ai-chat-container">
+    <view class="chat-header">
+      <view class="ai-avatar">
+        <image src="/static/enagic/ai-avatar.png" mode="aspectFill" />
+      </view>
+      <view class="ai-info">
+        <text class="ai-name">AI 健康顾问</text>
+        <text class="ai-desc">专业产品与健康知识咨询</text>
+      </view>
+    </view>
+
+    <scroll-view
+      class="chat-messages"
+      scroll-y
+      :scroll-top="scrollTop"
+      :scroll-with-animation="true"
+    >
+      <view
+        v-for="(msg, index) in messages"
+        :key="index"
+        :class="['message-item', msg.role === 'user' ? 'user' : 'ai']"
+      >
+        <view v-if="msg.role === 'ai'" class="ai-avatar-small">
+          <image src="/static/enagic/ai-avatar.png" mode="aspectFill" />
+        </view>
+        <view class="message-bubble">
+          <text>{{ msg.content }}</text>
+        </view>
+        <view v-if="msg.role === 'user'" class="user-avatar-small">
+          <image :src="userInfo.face || '/static/missing-face.png'" mode="aspectFill" />
+        </view>
+      </view>
+
+      <view v-if="loading" class="message-item ai">
+        <view class="ai-avatar-small">
+          <image src="/static/enagic/ai-avatar.png" mode="aspectFill" />
+        </view>
+        <view class="message-bubble loading">
+          <text>思考中...</text>
+        </view>
+      </view>
+    </scroll-view>
+
+    <view class="hot-questions" v-if="messages.length === 0">
+      <view class="hot-title">猜你想问</view>
+      <view class="hot-list">
+        <view
+          v-for="q in hotQuestions"
+          :key="q"
+          class="hot-item"
+          @tap="sendQuestion(q)"
+        >{{ q }}</view>
+      </view>
+    </view>
+
+    <view class="chat-input">
+      <input
+        v-model="inputText"
+        placeholder="请输入您的问题..."
+        confirm-type="send"
+        @confirm="sendMessage"
+      />
+      <button @tap="sendMessage" :disabled="!inputText || loading">发送</button>
+    </view>
+  </view>
+</template>
+
+<script>
+import { aiChat, aiHistory, aiHotQuestions } from '@/api/enagic.js'
+
+export default {
+  data() {
+    return {
+      messages: [],
+      inputText: '',
+      loading: false,
+      scrollTop: 0,
+      sessionId: '',
+      hotQuestions: [],
+      userInfo: {}
+    }
+  },
+
+  onLoad() {
+    this.userInfo = uni.getStorageSync('userInfo') || {}
+    this.loadHistory()
+    this.loadHotQuestions()
+  },
+
+  methods: {
+    async sendMessage() {
+      if (!this.inputText.trim() || this.loading) return
+
+      const question = this.inputText.trim()
+      this.messages.push({ role: 'user', content: question })
+      this.inputText = ''
+      this.loading = true
+      this.scrollToBottom()
+
+      try {
+        const res = await aiChat({
+          question,
+          sessionId: this.sessionId,
+          memberId: this.userInfo.id
+        })
+        this.sessionId = res.sessionId
+        this.messages.push({ role: 'ai', content: res.answer })
+      } catch (e) {
+        this.messages.push({
+          role: 'ai',
+          content: '抱歉,AI 服务暂时不可用,请稍后再试。'
+        })
+      } finally {
+        this.loading = false
+        this.scrollToBottom()
+      }
+    },
+
+    async sendQuestion(q) {
+      this.inputText = q
+      this.sendMessage()
+    },
+
+    async loadHistory() {
+      if (!this.userInfo.id) return
+      try {
+        const history = await aiHistory({
+          memberId: this.userInfo.id,
+          page: 1,
+          pageSize: 20
+        })
+        this.messages = history.map(h => [
+          { role: 'user', content: h.question },
+          { role: 'ai', content: h.answer }
+        ]).flat()
+      } catch (e) {
+        // ignore
+      }
+    },
+
+    async loadHotQuestions() {
+      try {
+        this.hotQuestions = await aiHotQuestions()
+      } catch (e) {
+        this.hotQuestions = [
+          '这个产品适合什么人群使用?',
+          '如何正确使用这款产品?'
+        ]
+      }
+    },
+
+    scrollToBottom() {
+      this.$nextTick(() => {
+        this.scrollTop = this.scrollTop === 0 ? 1 : 0
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.ai-chat-container {
+  display: flex;
+  flex-direction: column;
+  height: 100vh;
+  background: #f5f5f5;
+}
+
+.chat-header {
+  display: flex;
+  align-items: center;
+  padding: 20rpx 30rpx;
+  background: #fff;
+  border-bottom: 1rpx solid #eee;
+
+  .ai-avatar image {
+    width: 80rpx;
+    height: 80rpx;
+    border-radius: 50%;
+  }
+
+  .ai-info {
+    margin-left: 20rpx;
+    display: flex;
+    flex-direction: column;
+
+    .ai-name {
+      font-size: 32rpx;
+      font-weight: bold;
+      color: #333;
+    }
+
+    .ai-desc {
+      font-size: 24rpx;
+      color: #999;
+      margin-top: 8rpx;
+    }
+  }
+}
+
+.chat-messages {
+  flex: 1;
+  padding: 20rpx;
+
+  .message-item {
+    display: flex;
+    margin-bottom: 30rpx;
+    align-items: flex-start;
+
+    &.user {
+      flex-direction: row-reverse;
+
+      .message-bubble {
+        background: #ff6b35;
+        color: #fff;
+        margin-right: 16rpx;
+      }
+    }
+
+    &.ai {
+      .message-bubble {
+        background: #fff;
+        color: #333;
+        margin-left: 16rpx;
+      }
+    }
+
+    .message-bubble {
+      max-width: 500rpx;
+      padding: 20rpx 24rpx;
+      border-radius: 16rpx;
+      font-size: 28rpx;
+      line-height: 1.5;
+      word-break: break-all;
+
+      &.loading {
+        color: #999;
+        font-style: italic;
+      }
+    }
+
+    .ai-avatar-small image,
+    .user-avatar-small image {
+      width: 64rpx;
+      height: 64rpx;
+      border-radius: 50%;
+    }
+  }
+}
+
+.hot-questions {
+  padding: 30rpx;
+  background: #fff;
+  margin: 20rpx;
+  border-radius: 16rpx;
+
+  .hot-title {
+    font-size: 26rpx;
+    color: #999;
+    margin-bottom: 20rpx;
+  }
+
+  .hot-list {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 20rpx;
+
+    .hot-item {
+      padding: 16rpx 24rpx;
+      background: #fff0eb;
+      color: #ff6b35;
+      border-radius: 30rpx;
+      font-size: 26rpx;
+    }
+  }
+}
+
+.chat-input {
+  display: flex;
+  padding: 20rpx 30rpx;
+  background: #fff;
+  border-top: 1rpx solid #eee;
+  align-items: center;
+
+  input {
+    flex: 1;
+    height: 72rpx;
+    padding: 0 24rpx;
+    background: #f5f5f5;
+    border-radius: 36rpx;
+    font-size: 28rpx;
+  }
+
+  button {
+    margin-left: 20rpx;
+    width: 120rpx;
+    height: 72rpx;
+    line-height: 72rpx;
+    background: #ff6b35;
+    color: #fff;
+    border-radius: 36rpx;
+    font-size: 28rpx;
+
+    &[disabled] {
+      background: #ccc;
+    }
+  }
+}
+</style>

+ 291 - 0
代码/enagic-uniapp/pages/enagic/deduction/index.vue

@@ -0,0 +1,291 @@
+<template>
+  <view class="deduction-page">
+    <view class="balance-card">
+      <view class="balance-item">
+        <text class="label">可用余额</text>
+        <text class="value">¥{{ deductionInfo.availableBalance || 0 }}</text>
+      </view>
+      <view class="balance-divider"></view>
+      <view class="balance-item">
+        <text class="label">冻结金额</text>
+        <text class="value frozen">¥{{ deductionInfo.frozenBalance || 0 }}</text>
+      </view>
+    </view>
+
+    <view class="action-row">
+      <u-button type="primary" size="medium" @click="recharge">充值</u-button>
+      <u-button type="default" size="medium" @click="goDetail">明细</u-button>
+    </view>
+
+    <u-tabs :list="tabs" :current="currentTab" @change="tabChange" />
+
+    <view class="log-list" v-if="logs.length > 0">
+      <view class="log-item" v-for="item in logs" :key="item.id">
+        <view class="log-icon" :class="item.type">
+          <text>{{ item.type === 'income' ? '↓' : '↑' }}</text>
+        </view>
+        <view class="log-info">
+          <text class="log-name">{{ item.typeName }}</text>
+          <text class="log-time">{{ item.createTime }}</text>
+          <text class="log-order" v-if="item.orderSn">订单号: {{ item.orderSn }}</text>
+        </view>
+        <text class="log-amount" :class="item.type">
+          {{ item.type === 'income' ? '+' : '-' }}¥{{ item.amount }}
+        </text>
+      </view>
+    </view>
+
+    <u-empty v-else text="暂无记录" />
+
+    <uni-load-more :status="loadStatus" @clickLoadMore="loadMore" />
+  </view>
+</template>
+
+<script>
+import { getDeductionInfo, getDeductionLog } from '@/api/enagic.js'
+
+export default {
+  data() {
+    return {
+      deductionInfo: {},
+      tabs: [
+        { name: '全部' },
+        { name: '收入' },
+        { name: '支出' }
+      ],
+      currentTab: 0,
+      logs: [],
+      page: 1,
+      pageSize: 20,
+      loadStatus: 'more'
+    }
+  },
+
+  onLoad() {
+    this.loadData()
+  },
+
+  onPullDownRefresh() {
+    this.page = 1
+    this.logs = []
+    this.loadData().finally(() => {
+      uni.stopPullDownRefresh()
+    })
+  },
+
+  onReachBottom() {
+    if (this.loadStatus === 'more') {
+      this.loadMore()
+    }
+  },
+
+  methods: {
+    async loadData() {
+      if (this.loadStatus === 'loading') return
+      this.loadStatus = 'loading'
+
+      uni.showLoading({ title: '加载中' })
+      try {
+        const [info, logRes] = await Promise.all([
+          getDeductionInfo(),
+          this.fetchLogs()
+        ])
+        this.deductionInfo = info || {}
+        const records = (logRes && logRes.records) || []
+
+        if (this.page === 1) {
+          this.logs = records
+        } else {
+          this.logs = [...this.logs, ...records]
+        }
+
+        if (records.length < this.pageSize) {
+          this.loadStatus = 'noMore'
+        } else {
+          this.loadStatus = 'more'
+        }
+      } catch (e) {
+        this.$u.toast('加载失败')
+        this.loadStatus = 'more'
+      } finally {
+        uni.hideLoading()
+      }
+    },
+
+    async fetchLogs() {
+      const params = {
+        page: this.page,
+        pageSize: this.pageSize
+      }
+
+      if (this.currentTab === 1) {
+        params.type = 'income'
+      } else if (this.currentTab === 2) {
+        params.type = 'expend'
+      }
+
+      return getDeductionLog(params)
+    },
+
+    tabChange(index) {
+      this.currentTab = index
+      this.page = 1
+      this.logs = []
+      this.loadData()
+    },
+
+    loadMore() {
+      this.page++
+      this.loadData()
+    },
+
+    recharge() {
+      uni.showModal({
+        title: '充值',
+        content: '请联系客服进行充值',
+        showCancel: false
+      })
+    },
+
+    goDetail() {
+      uni.showToast({
+        title: '明细列表已在下方显示',
+        icon: 'none'
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.deduction-page {
+  min-height: 100vh;
+  background: #f5f5f5;
+}
+
+.balance-card {
+  display: flex;
+  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
+  padding: 40rpx 30rpx;
+  margin: 20rpx;
+  border-radius: 16rpx;
+  align-items: center;
+
+  .balance-item {
+    flex: 1;
+    text-align: center;
+    color: #fff;
+
+    .label {
+      display: block;
+      font-size: 26rpx;
+      opacity: 0.8;
+      margin-bottom: 12rpx;
+    }
+
+    .value {
+      display: block;
+      font-size: 40rpx;
+      font-weight: bold;
+
+      &.frozen {
+        font-size: 32rpx;
+        opacity: 0.8;
+      }
+    }
+  }
+
+  .balance-divider {
+    width: 1rpx;
+    height: 80rpx;
+    background: rgba(255, 255, 255, 0.3);
+  }
+}
+
+.action-row {
+  display: flex;
+  justify-content: center;
+  padding: 20rpx;
+  background: #fff;
+  margin: 0 20rpx 20rpx;
+  border-radius: 16rpx;
+
+  button {
+    margin: 0 20rpx;
+    min-width: 160rpx;
+  }
+}
+
+.log-list {
+  padding: 0 20rpx;
+
+  .log-item {
+    display: flex;
+    align-items: center;
+    background: #fff;
+    padding: 24rpx;
+    margin-bottom: 20rpx;
+    border-radius: 16rpx;
+
+    .log-icon {
+      width: 64rpx;
+      height: 64rpx;
+      border-radius: 50%;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      
+      text {
+        font-size: 32rpx;
+        color: #fff;
+      }
+
+      &.income {
+        background: #52c41a;
+      }
+
+      &.expend {
+        background: #ff4d4f;
+      }
+    }
+
+    .log-info {
+      flex: 1;
+      margin-left: 20rpx;
+
+      .log-name {
+        display: block;
+        font-size: 28rpx;
+        color: #333;
+        margin-bottom: 8rpx;
+      }
+
+      .log-time {
+        display: block;
+        font-size: 24rpx;
+        color: #999;
+        margin-bottom: 4rpx;
+      }
+
+      .log-order {
+        display: block;
+        font-size: 22rpx;
+        color: #999;
+      }
+    }
+
+    .log-amount {
+      font-size: 32rpx;
+      font-weight: bold;
+
+      &.income {
+        color: #52c41a;
+      }
+
+      &.expend {
+        color: #ff4d4f;
+      }
+    }
+  }
+}
+</style>

+ 214 - 0
代码/enagic-uniapp/pages/enagic/health-advisor/customers.vue

@@ -0,0 +1,214 @@
+<template>
+  <view class="customers-page">
+    <u-tabs :list="tabs" :current="currentTab" @change="tabChange" />
+
+    <view class="search-bar">
+      <input v-model="keyword" placeholder="搜索客户昵称" @confirm="search" />
+      <u-button size="mini" type="primary" @click="search">搜索</u-button>
+    </view>
+
+    <view class="customer-list" v-if="customers.length > 0">
+      <view class="customer-card" v-for="item in customers" :key="item.id">
+        <image class="avatar" :src="item.face || '/static/missing-face.png'" mode="aspectFill" />
+        <view class="info">
+          <view class="name-row">
+            <text class="name">{{ item.nickName || '未设置昵称' }}</text>
+            <text class="level-tag" v-if="item.vipLevel">VIP{{ item.vipLevel }}</text>
+            <text class="type-tag" v-if="item.isDistribution">消费商</text>
+          </view>
+          <text class="time">注册时间: {{ item.createTime }}</text>
+        </view>
+      </view>
+    </view>
+
+    <u-empty v-else text="暂无客户数据" />
+
+    <uni-load-more :status="loadStatus" @clickLoadMore="loadMore" />
+  </view>
+</template>
+
+<script>
+import { getMyCustomers } from '@/api/enagic.js'
+
+export default {
+  data() {
+    return {
+      tabs: [
+        { name: '全部' },
+        { name: '消费商' },
+        { name: '纯客户' }
+      ],
+      currentTab: 0,
+      keyword: '',
+      customers: [],
+      page: 1,
+      pageSize: 20,
+      loadStatus: 'more'
+    }
+  },
+
+  onLoad() {
+    this.loadData()
+  },
+
+  onPullDownRefresh() {
+    this.page = 1
+    this.customers = []
+    this.loadData().finally(() => {
+      uni.stopPullDownRefresh()
+    })
+  },
+
+  onReachBottom() {
+    if (this.loadStatus === 'more') {
+      this.loadMore()
+    }
+  },
+
+  methods: {
+    async loadData() {
+      if (this.loadStatus === 'loading') return
+      this.loadStatus = 'loading'
+
+      uni.showLoading({ title: '加载中' })
+      try {
+        const params = {
+          page: this.page,
+          pageSize: this.pageSize,
+          keyword: this.keyword
+        }
+
+        if (this.currentTab === 1) {
+          params.isDistribution = true
+        } else if (this.currentTab === 2) {
+          params.isDistribution = false
+        }
+
+        const res = await getMyCustomers(params)
+        const records = (res && res.records) || []
+
+        if (this.page === 1) {
+          this.customers = records
+        } else {
+          this.customers = [...this.customers, ...records]
+        }
+
+        if (records.length < this.pageSize) {
+          this.loadStatus = 'noMore'
+        } else {
+          this.loadStatus = 'more'
+        }
+      } catch (e) {
+        this.$u.toast('加载失败')
+        this.loadStatus = 'more'
+      } finally {
+        uni.hideLoading()
+      }
+    },
+
+    tabChange(index) {
+      this.currentTab = index
+      this.page = 1
+      this.customers = []
+      this.loadData()
+    },
+
+    search() {
+      this.page = 1
+      this.customers = []
+      this.loadData()
+    },
+
+    loadMore() {
+      this.page++
+      this.loadData()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.customers-page {
+  min-height: 100vh;
+  background: #f5f5f5;
+}
+
+.search-bar {
+  display: flex;
+  align-items: center;
+  padding: 20rpx 30rpx;
+  background: #fff;
+
+  input {
+    flex: 1;
+    height: 64rpx;
+    padding: 0 20rpx;
+    background: #f5f5f5;
+    border-radius: 32rpx;
+    font-size: 26rpx;
+  }
+
+  button {
+    margin-left: 20rpx;
+  }
+}
+
+.customer-list {
+  padding: 20rpx;
+
+  .customer-card {
+    display: flex;
+    align-items: center;
+    background: #fff;
+    padding: 24rpx;
+    margin-bottom: 20rpx;
+    border-radius: 16rpx;
+
+    .avatar {
+      width: 100rpx;
+      height: 100rpx;
+      border-radius: 50%;
+    }
+
+    .info {
+      margin-left: 24rpx;
+      flex: 1;
+
+      .name-row {
+        display: flex;
+        align-items: center;
+        margin-bottom: 10rpx;
+
+        .name {
+          font-size: 30rpx;
+          color: #333;
+          font-weight: bold;
+        }
+
+        .level-tag {
+          margin-left: 16rpx;
+          padding: 4rpx 12rpx;
+          background: linear-gradient(135deg, #ffd700 0%, #ffb700 100%);
+          color: #fff;
+          font-size: 22rpx;
+          border-radius: 16rpx;
+        }
+
+        .type-tag {
+          margin-left: 16rpx;
+          padding: 4rpx 12rpx;
+          background: #ff6b35;
+          color: #fff;
+          font-size: 22rpx;
+          border-radius: 16rpx;
+        }
+      }
+
+      .time {
+        font-size: 24rpx;
+        color: #999;
+      }
+    }
+  }
+}
+</style>

+ 326 - 0
代码/enagic-uniapp/pages/enagic/health-advisor/home.vue

@@ -0,0 +1,326 @@
+<template>
+  <view class="advisor-home">
+    <view class="header-card">
+      <image class="avatar" :src="advisorInfo.face || '/static/missing-face.png'" mode="aspectFill" />
+      <view class="info">
+        <text class="name">{{ advisorInfo.name || '未设置' }}</text>
+        <view class="tag">健康布施者</view>
+      </view>
+    </view>
+
+    <view class="stats-row">
+      <view class="stat-item">
+        <text class="stat-value">{{ achievement.totalInvite || 0 }}</text>
+        <text class="stat-label">累计邀请</text>
+      </view>
+      <view class="stat-item">
+        <text class="stat-value">{{ achievement.availableCommission || 0 }}</text>
+        <text class="stat-label">可用佣金</text>
+      </view>
+      <view class="stat-item">
+        <text class="stat-value">{{ achievement.credits || 0 }}</text>
+        <text class="stat-label">顾问积分</text>
+      </view>
+    </view>
+
+    <view class="medal-section">
+      <view class="medal-title">当前勋章</view>
+      <view class="medal-display">
+        <text class="medal-stars">{{ medalStars }}</text>
+        <text class="medal-name">{{ achievement.medalName || '暂无勋章' }}</text>
+      </view>
+    </view>
+
+    <view class="action-row">
+      <view class="action-btn" @tap="goToInvite">
+        <image src="/static/enagic/icon-invite.png" mode="aspectFit" />
+        <text>邀请客户</text>
+      </view>
+      <view class="action-btn" @tap="goToCustomers">
+        <image src="/static/enagic/icon-customers.png" mode="aspectFit" />
+        <text>我的客户</text>
+      </view>
+      <view class="action-btn" @tap="goToMedals">
+        <image src="/static/enagic/icon-medal.png" mode="aspectFit" />
+        <text>我的勋章</text>
+      </view>
+    </view>
+
+    <view class="section-title">最近客户</view>
+    <view class="customer-list" v-if="recentCustomers.length > 0">
+      <view class="customer-item" v-for="item in recentCustomers" :key="item.id">
+        <image class="customer-avatar" :src="item.face || '/static/missing-face.png'" mode="aspectFill" />
+        <view class="customer-info">
+          <text class="customer-name">{{ item.nickName || '未设置昵称' }}</text>
+          <text class="customer-time">{{ item.createTime }}</text>
+        </view>
+      </view>
+    </view>
+    <u-empty v-else text="暂无客户" />
+
+    <view class="bottom-btn">
+      <u-button type="primary" @click="contactService">联系客服</u-button>
+    </view>
+  </view>
+</template>
+
+<script>
+import { getAdvisorInfo, getAdvisorAchievement, getMyCustomers } from '@/api/enagic.js'
+
+export default {
+  data() {
+    return {
+      advisorInfo: {},
+      achievement: {},
+      recentCustomers: []
+    }
+  },
+
+  computed: {
+    medalStars() {
+      const level = this.achievement.medalLevel || 0
+      return '⭐'.repeat(level)
+    }
+  },
+
+  onLoad() {
+    this.loadData()
+  },
+
+  onPullDownRefresh() {
+    this.loadData().finally(() => {
+      uni.stopPullDownRefresh()
+    })
+  },
+
+  methods: {
+    async loadData() {
+      uni.showLoading({ title: '加载中' })
+      try {
+        const [info, achievement, customers] = await Promise.all([
+          getAdvisorInfo(),
+          getAdvisorAchievement(),
+          getMyCustomers({ page: 1, pageSize: 5 })
+        ])
+        this.advisorInfo = info || {}
+        this.achievement = achievement || {}
+        this.recentCustomers = (customers && customers.records) || []
+      } catch (e) {
+        this.$u.toast('加载失败')
+      } finally {
+        uni.hideLoading()
+      }
+    },
+
+    goToInvite() {
+      uni.navigateTo({
+        url: '/pages/enagic/invite/index'
+      })
+    },
+
+    goToCustomers() {
+      uni.navigateTo({
+        url: '/pages/enagic/health-advisor/customers'
+      })
+    },
+
+    goToMedals() {
+      uni.navigateTo({
+        url: '/pages/enagic/health-advisor/medals'
+      })
+    },
+
+    contactService() {
+      uni.makePhoneCall({
+        phoneNumber: '400-xxx-xxxx'
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.advisor-home {
+  min-height: 100vh;
+  background: #f5f5f5;
+  padding-bottom: 120rpx;
+}
+
+.header-card {
+  display: flex;
+  align-items: center;
+  padding: 40rpx 30rpx;
+  background: linear-gradient(135deg, #ff6b35 0%, #ff8f5a 100%);
+
+  .avatar {
+    width: 120rpx;
+    height: 120rpx;
+    border-radius: 50%;
+    border: 4rpx solid #fff;
+  }
+
+  .info {
+    margin-left: 30rpx;
+    color: #fff;
+
+    .name {
+      font-size: 36rpx;
+      font-weight: bold;
+    }
+
+    .tag {
+      display: inline-block;
+      margin-top: 10rpx;
+      padding: 4rpx 16rpx;
+      background: rgba(255, 255, 255, 0.3);
+      border-radius: 20rpx;
+      font-size: 24rpx;
+    }
+  }
+}
+
+.stats-row {
+  display: flex;
+  background: #fff;
+  padding: 30rpx 0;
+  margin: -20rpx 20rpx 20rpx;
+  border-radius: 16rpx;
+  box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
+
+  .stat-item {
+    flex: 1;
+    text-align: center;
+    border-right: 1rpx solid #f0f0f0;
+
+    &:last-child {
+      border-right: none;
+    }
+
+    .stat-value {
+      display: block;
+      font-size: 40rpx;
+      font-weight: bold;
+      color: #ff6b35;
+    }
+
+    .stat-label {
+      display: block;
+      margin-top: 8rpx;
+      font-size: 24rpx;
+      color: #999;
+    }
+  }
+}
+
+.medal-section {
+  background: #fff;
+  padding: 30rpx;
+  margin: 20rpx;
+  border-radius: 16rpx;
+
+  .medal-title {
+    font-size: 28rpx;
+    color: #333;
+    margin-bottom: 20rpx;
+  }
+
+  .medal-display {
+    display: flex;
+    align-items: center;
+
+    .medal-stars {
+      font-size: 40rpx;
+      margin-right: 20rpx;
+    }
+
+    .medal-name {
+      font-size: 28rpx;
+      color: #666;
+    }
+  }
+}
+
+.action-row {
+  display: flex;
+  background: #fff;
+  padding: 30rpx 20rpx;
+  margin: 20rpx;
+  border-radius: 16rpx;
+
+  .action-btn {
+    flex: 1;
+    display: flex;
+    flex-direction: column;
+    align-items: center;
+
+    image {
+      width: 64rpx;
+      height: 64rpx;
+      margin-bottom: 16rpx;
+    }
+
+    text {
+      font-size: 26rpx;
+      color: #333;
+    }
+  }
+}
+
+.section-title {
+  padding: 20rpx 30rpx;
+  font-size: 28rpx;
+  color: #333;
+  font-weight: bold;
+}
+
+.customer-list {
+  background: #fff;
+  margin: 0 20rpx;
+  border-radius: 16rpx;
+
+  .customer-item {
+    display: flex;
+    align-items: center;
+    padding: 20rpx 30rpx;
+    border-bottom: 1rpx solid #f0f0f0;
+
+    &:last-child {
+      border-bottom: none;
+    }
+
+    .customer-avatar {
+      width: 80rpx;
+      height: 80rpx;
+      border-radius: 50%;
+    }
+
+    .customer-info {
+      margin-left: 20rpx;
+      flex: 1;
+
+      .customer-name {
+        display: block;
+        font-size: 28rpx;
+        color: #333;
+      }
+
+      .customer-time {
+        display: block;
+        margin-top: 8rpx;
+        font-size: 24rpx;
+        color: #999;
+      }
+    }
+  }
+}
+
+.bottom-btn {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  padding: 20rpx 30rpx;
+  background: #fff;
+  box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.05);
+}
+</style>

+ 167 - 0
代码/enagic-uniapp/pages/enagic/health-advisor/medals.vue

@@ -0,0 +1,167 @@
+<template>
+  <view class="medals-page">
+    <view class="medal-wall" v-if="medals.length > 0">
+      <view class="medal-card" v-for="item in medals" :key="item.id">
+        <image class="medal-icon" :src="item.iconUrl || '/static/enagic/medal-default.png'" mode="aspectFit" />
+        <view class="medal-info">
+          <text class="medal-name">{{ item.name }}</text>
+          <text class="medal-time">获得时间: {{ item.getTime }}</text>
+          <text class="medal-reason">{{ item.reason }}</text>
+        </view>
+      </view>
+    </view>
+
+    <u-empty v-else text="暂无勋章" />
+
+    <view class="medal-levels">
+      <view class="level-title">勋章等级说明</view>
+      <view class="level-list">
+        <view class="level-item" v-for="(level, index) in levels" :key="index">
+          <text class="level-star">{{ level.star }}</text>
+          <text class="level-name">{{ level.name }}</text>
+          <text class="level-desc">{{ level.desc }}</text>
+        </view>
+      </view>
+    </view>
+  </view>
+</template>
+
+<script>
+import { getAdvisorMedals } from '@/api/enagic.js'
+
+export default {
+  data() {
+    return {
+      medals: [],
+      levels: [
+        { star: '⭐', name: '新星', desc: '邀请1-10人' },
+        { star: '⭐⭐', name: '达人', desc: '邀请11-50人' },
+        { star: '⭐⭐⭐', name: '导师', desc: '邀请51-200人' },
+        { star: '⭐⭐⭐⭐', name: '宗师', desc: '邀请200人以上' }
+      ]
+    }
+  },
+
+  onLoad() {
+    this.loadData()
+  },
+
+  onPullDownRefresh() {
+    this.loadData().finally(() => {
+      uni.stopPullDownRefresh()
+    })
+  },
+
+  methods: {
+    async loadData() {
+      uni.showLoading({ title: '加载中' })
+      try {
+        const res = await getAdvisorMedals()
+        this.medals = res || []
+      } catch (e) {
+        this.$u.toast('加载失败')
+      } finally {
+        uni.hideLoading()
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.medals-page {
+  min-height: 100vh;
+  background: #f5f5f5;
+  padding-bottom: 40rpx;
+}
+
+.medal-wall {
+  padding: 20rpx;
+
+  .medal-card {
+    display: flex;
+    background: #fff;
+    padding: 24rpx;
+    margin-bottom: 20rpx;
+    border-radius: 16rpx;
+    box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
+
+    .medal-icon {
+      width: 120rpx;
+      height: 120rpx;
+    }
+
+    .medal-info {
+      margin-left: 24rpx;
+      flex: 1;
+
+      .medal-name {
+        display: block;
+        font-size: 32rpx;
+        color: #333;
+        font-weight: bold;
+        margin-bottom: 10rpx;
+      }
+
+      .medal-time {
+        display: block;
+        font-size: 24rpx;
+        color: #999;
+        margin-bottom: 10rpx;
+      }
+
+      .medal-reason {
+        display: block;
+        font-size: 26rpx;
+        color: #666;
+        line-height: 1.5;
+      }
+    }
+  }
+}
+
+.medal-levels {
+  margin: 0 20rpx;
+  background: #fff;
+  padding: 24rpx;
+  border-radius: 16rpx;
+
+  .level-title {
+    font-size: 28rpx;
+    color: #333;
+    font-weight: bold;
+    margin-bottom: 20rpx;
+  }
+
+  .level-list {
+    .level-item {
+      display: flex;
+      align-items: center;
+      padding: 20rpx 0;
+      border-bottom: 1rpx solid #f0f0f0;
+
+      &:last-child {
+        border-bottom: none;
+      }
+
+      .level-star {
+        font-size: 32rpx;
+        margin-right: 16rpx;
+      }
+
+      .level-name {
+        font-size: 28rpx;
+        color: #333;
+        font-weight: bold;
+        margin-right: 20rpx;
+        min-width: 80rpx;
+      }
+
+      .level-desc {
+        font-size: 24rpx;
+        color: #999;
+      }
+    }
+  }
+}
+</style>

+ 318 - 0
代码/enagic-uniapp/pages/enagic/operation/my-plans.vue

@@ -0,0 +1,318 @@
+<template>
+  <view class="my-plans-page">
+    <u-tabs :list="tabs" :current="currentTab" @change="tabChange" />
+
+    <view class="plan-list" v-if="plans.length > 0">
+      <view class="plan-card" v-for="item in plans" :key="item.id">
+        <view class="plan-header">
+          <view class="product-info">
+            <image class="product-img" :src="item.goodsImage || '/static/missing-face.png'" mode="aspectFill" />
+            <text class="product-name">{{ item.goodsName }}</text>
+          </view>
+          <view class="status-tag" :class="item.status">{{ statusText(item.status) }}</view>
+        </view>
+
+        <view class="plan-body">
+          <text class="current-node">当前节点: {{ item.currentNodeName || '待开始' }}</text>
+
+          <view class="timeline">
+            <view 
+              class="timeline-item" 
+              :class="{ completed: node.status === 'completed', current: node.status === 'current' }"
+              v-for="(node, nIndex) in item.nodes"
+              :key="nIndex"
+            >
+              <view class="timeline-dot">
+                <text v-if="node.status === 'completed'">✓</text>
+                <text v-else-if="node.status === 'current'">→</text>
+                <text v-else>○</text>
+              </view>
+              <view class="timeline-content">
+                <text class="node-name">{{ node.name }}</text>
+                <text class="node-time" v-if="node.finishTime">{{ node.finishTime }}</text>
+              </view>
+            </view>
+          </view>
+
+          <text class="remind-time" v-if="item.nextRemindTime">
+            下次提醒: {{ item.nextRemindTime }}
+          </text>
+        </view>
+      </view>
+    </view>
+
+    <u-empty v-else text="暂无运维计划" />
+
+    <uni-load-more :status="loadStatus" @clickLoadMore="loadMore" />
+  </view>
+</template>
+
+<script>
+import { getMyOperationPlans, getOperationRecord } from '@/api/enagic.js'
+
+export default {
+  data() {
+    return {
+      tabs: [
+        { name: '全部' },
+        { name: '进行中' },
+        { name: '已完成' },
+        { name: '已转移' }
+      ],
+      currentTab: 0,
+      plans: [],
+      page: 1,
+      pageSize: 10,
+      loadStatus: 'more'
+    }
+  },
+
+  onLoad() {
+    this.loadData()
+  },
+
+  onPullDownRefresh() {
+    this.page = 1
+    this.plans = []
+    this.loadData().finally(() => {
+      uni.stopPullDownRefresh()
+    })
+  },
+
+  onReachBottom() {
+    if (this.loadStatus === 'more') {
+      this.loadMore()
+    }
+  },
+
+  methods: {
+    async loadData() {
+      if (this.loadStatus === 'loading') return
+      this.loadStatus = 'loading'
+
+      uni.showLoading({ title: '加载中' })
+      try {
+        const params = {
+          page: this.page,
+          pageSize: this.pageSize
+        }
+
+        if (this.currentTab === 1) {
+          params.status = 'active'
+        } else if (this.currentTab === 2) {
+          params.status = 'completed'
+        } else if (this.currentTab === 3) {
+          params.status = 'transferred'
+        }
+
+        const res = await getMyOperationPlans(params)
+        const records = (res && res.records) || []
+
+        if (this.page === 1) {
+          this.plans = records
+        } else {
+          this.plans = [...this.plans, ...records]
+        }
+
+        for (let i = 0; i < this.plans.length; i++) {
+          if (this.plans[i].planId && !this.plans[i].nodes) {
+            try {
+              const recordRes = await getOperationRecord({ planId: this.plans[i].planId })
+              this.$set(this.plans[i], 'nodes', recordRes || [])
+            } catch (e) {
+              this.$set(this.plans[i], 'nodes', [])
+            }
+          }
+        }
+
+        if (records.length < this.pageSize) {
+          this.loadStatus = 'noMore'
+        } else {
+          this.loadStatus = 'more'
+        }
+      } catch (e) {
+        this.$u.toast('加载失败')
+        this.loadStatus = 'more'
+      } finally {
+        uni.hideLoading()
+      }
+    },
+
+    tabChange(index) {
+      this.currentTab = index
+      this.page = 1
+      this.plans = []
+      this.loadData()
+    },
+
+    loadMore() {
+      this.page++
+      this.loadData()
+    },
+
+    statusText(status) {
+      const map = {
+        active: '进行中',
+        completed: '已完成',
+        transferred: '已转移'
+      }
+      return map[status] || '未知'
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.my-plans-page {
+  min-height: 100vh;
+  background: #f5f5f5;
+}
+
+.plan-list {
+  padding: 20rpx;
+
+  .plan-card {
+    background: #fff;
+    border-radius: 16rpx;
+    margin-bottom: 20rpx;
+    overflow: hidden;
+
+    .plan-header {
+      display: flex;
+      align-items: center;
+      justify-content: space-between;
+      padding: 24rpx;
+      border-bottom: 1rpx solid #f0f0f0;
+
+      .product-info {
+        display: flex;
+        align-items: center;
+        flex: 1;
+
+        .product-img {
+          width: 80rpx;
+          height: 80rpx;
+          border-radius: 8rpx;
+        }
+
+        .product-name {
+          margin-left: 20rpx;
+          font-size: 28rpx;
+          color: #333;
+          font-weight: bold;
+        }
+      }
+
+      .status-tag {
+        padding: 4rpx 16rpx;
+        border-radius: 16rpx;
+        font-size: 22rpx;
+
+        &.active {
+          background: #e6f7ff;
+          color: #1890ff;
+        }
+
+        &.completed {
+          background: #f6ffed;
+          color: #52c41a;
+        }
+
+        &.transferred {
+          background: #fff7e6;
+          color: #fa8c16;
+        }
+      }
+    }
+
+    .plan-body {
+      padding: 24rpx;
+
+      .current-node {
+        display: block;
+        font-size: 26rpx;
+        color: #666;
+        margin-bottom: 20rpx;
+      }
+
+      .timeline {
+        padding-left: 20rpx;
+
+        .timeline-item {
+          display: flex;
+          align-items: flex-start;
+          padding-bottom: 20rpx;
+          position: relative;
+
+          &:last-child {
+            padding-bottom: 0;
+          }
+
+          &::before {
+            content: '';
+            position: absolute;
+            left: 14rpx;
+            top: 36rpx;
+            bottom: 0;
+            width: 2rpx;
+            background: #e8e8e8;
+          }
+
+          &:last-child::before {
+            display: none;
+          }
+
+          &.completed .timeline-dot text {
+            color: #52c41a;
+          }
+
+          &.current .timeline-dot text {
+            color: #ff6b35;
+            font-weight: bold;
+          }
+
+          .timeline-dot {
+            width: 32rpx;
+            height: 32rpx;
+            display: flex;
+            align-items: center;
+            justify-content: center;
+            margin-right: 16rpx;
+            flex-shrink: 0;
+            z-index: 1;
+
+            text {
+              font-size: 24rpx;
+              color: #d9d9d9;
+            }
+          }
+
+          .timeline-content {
+            .node-name {
+              display: block;
+              font-size: 26rpx;
+              color: #333;
+            }
+
+            .node-time {
+              display: block;
+              font-size: 22rpx;
+              color: #999;
+              margin-top: 4rpx;
+            }
+          }
+        }
+      }
+
+      .remind-time {
+        display: block;
+        margin-top: 16rpx;
+        font-size: 24rpx;
+        color: #ff6b35;
+        padding-top: 16rpx;
+        border-top: 1rpx solid #f0f0f0;
+      }
+    }
+  }
+}
+</style>

+ 215 - 0
代码/enagic-uniapp/pages/enagic/vip/index.vue

@@ -0,0 +1,215 @@
+<template>
+  <view class="vip-page">
+    <view class="banner">
+      <image src="/static/enagic/vip-banner.png" mode="aspectFill" />
+      <view class="benefits">
+        <text class="benefit-item">✓ 专属折扣</text>
+        <text class="benefit-item">✓ 优先发货</text>
+        <text class="benefit-item">✓ 专属客服</text>
+        <text class="benefit-item">✓ 积分加成</text>
+      </view>
+    </view>
+
+    <scroll-view class="vip-cards" scroll-x="true">
+      <view 
+        class="vip-card" 
+        :class="{ active: selectedIndex === index }"
+        v-for="(item, index) in vipList"
+        :key="item.id"
+        @tap="selectCard(index)"
+      >
+        <text class="vip-name">{{ item.name }}</text>
+        <text class="vip-price">¥{{ item.price }}</text>
+        <view class="vip-benefits">
+          <text v-for="benefit in item.benefits" :key="benefit">{{ benefit }}</text>
+        </view>
+        <u-button type="primary" size="mini" @click.stop="openVip(item)">开通</u-button>
+      </view>
+    </scroll-view>
+
+    <view class="vip-desc">
+      <text class="title">VIP 权益说明</text>
+      <text class="desc">开通VIP后,您将享受专属优惠权益,无时间限制,长期有效。</text>
+    </view>
+  </view>
+</template>
+
+<script>
+import { getVipConfigList, openVip } from '@/api/enagic.js'
+
+export default {
+  data() {
+    return {
+      vipList: [],
+      selectedIndex: 0
+    }
+  },
+
+  onLoad() {
+    this.loadData()
+  },
+
+  methods: {
+    async loadData() {
+      uni.showLoading({ title: '加载中' })
+      try {
+        const res = await getVipConfigList()
+        this.vipList = res || []
+        if (this.vipList.length > 0) {
+          this.selectedIndex = 0
+        }
+      } catch (e) {
+        this.$u.toast('加载失败')
+      } finally {
+        uni.hideLoading()
+      }
+    },
+
+    selectCard(index) {
+      this.selectedIndex = index
+    },
+
+    async openVip(vip) {
+      uni.showModal({
+        title: '确认开通',
+        content: `确认开通${vip.name},支付金额¥${vip.price}`,
+        success: async (res) => {
+          if (res.confirm) {
+            uni.showLoading({ title: '处理中' })
+            try {
+              const result = await openVip({ vipId: vip.id })
+              uni.hideLoading()
+              
+              if (result.paySign) {
+                uni.requestPayment({
+                  provider: 'wxpay',
+                  ...result,
+                  success: () => {
+                    this.$u.toast('开通成功')
+                    uni.navigateTo({ url: '/pages/enagic/vip/my-vip' })
+                  },
+                  fail: (err) => {
+                    this.$u.toast('支付失败')
+                  }
+                })
+              } else {
+                this.$u.toast('开通成功')
+                uni.navigateTo({ url: '/pages/enagic/vip/my-vip' })
+              }
+            } catch (e) {
+              uni.hideLoading()
+              this.$u.toast('开通失败')
+            }
+          }
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.vip-page {
+  min-height: 100vh;
+  background: #f5f5f5;
+}
+
+.banner {
+  position: relative;
+
+  image {
+    width: 100%;
+    height: 300rpx;
+  }
+
+  .benefits {
+    position: absolute;
+    bottom: 40rpx;
+    left: 30rpx;
+    right: 30rpx;
+    display: flex;
+    justify-content: space-around;
+
+    .benefit-item {
+      color: #fff;
+      font-size: 24rpx;
+    }
+  }
+}
+
+.vip-cards {
+  white-space: nowrap;
+  padding: 20rpx 0;
+
+  .vip-card {
+    display: inline-block;
+    width: 280rpx;
+    margin: 0 20rpx;
+    padding: 30rpx;
+    background: #fff;
+    border-radius: 16rpx;
+    text-align: center;
+    box-shadow: 0 4rpx 20rpx rgba(0, 0, 0, 0.05);
+    vertical-align: top;
+
+    &.active {
+      border: 4rpx solid #ff6b35;
+    }
+
+    .vip-name {
+      display: block;
+      font-size: 32rpx;
+      color: #333;
+      font-weight: bold;
+      margin-bottom: 20rpx;
+    }
+
+    .vip-price {
+      display: block;
+      font-size: 40rpx;
+      color: #ff6b35;
+      font-weight: bold;
+      margin-bottom: 20rpx;
+
+      &::before {
+        content: '¥';
+        font-size: 28rpx;
+      }
+    }
+
+    .vip-benefits {
+      text-align: left;
+      margin-bottom: 20rpx;
+
+      text {
+        display: block;
+        font-size: 24rpx;
+        color: #666;
+        margin-bottom: 8rpx;
+      }
+    }
+  }
+}
+
+.vip-desc {
+  margin: 20rpx;
+  padding: 24rpx;
+  background: #fff;
+  border-radius: 16rpx;
+
+  .title {
+    display: block;
+    font-size: 28rpx;
+    color: #333;
+    font-weight: bold;
+    margin-bottom: 16rpx;
+  }
+
+  .desc {
+    display: block;
+    font-size: 26rpx;
+    color: #666;
+    line-height: 1.6;
+  }
+}
+</style>

+ 249 - 0
代码/enagic-uniapp/pages/enagic/vip/my-vip.vue

@@ -0,0 +1,249 @@
+<template>
+  <view class="my-vip-page">
+    <view class="vip-card">
+      <image class="vip-icon" :src="vipInfo.iconUrl || '/static/enagic/vip-icon.png'" mode="aspectFit" />
+      <view class="vip-info">
+        <text class="vip-level">{{ vipInfo.vipName || '暂未开通' }}</text>
+        <text class="vip-time" v-if="vipInfo.openTime">开通时间: {{ vipInfo.openTime }}</text>
+      </view>
+    </view>
+
+    <view class="benefits-section" v-if="vipInfo.benefits && vipInfo.benefits.length > 0">
+      <text class="section-title">我的权益</text>
+      <view class="benefits-list">
+        <view class="benefit-item" v-for="(item, index) in vipInfo.benefits" :key="index">
+          <text class="check">✓</text>
+          <text class="benefit-name">{{ item }}</text>
+        </view>
+      </view>
+    </view>
+
+    <view class="progress-section" v-if="vipInfo.level && vipInfo.hasNextLevel">
+      <text class="section-title">升级进度</text>
+      <view class="progress-item" v-if="vipInfo.needInvite">
+        <text class="progress-label">还需邀请</text>
+        <progress class="progress-bar" :percent="invitePercent" activeColor="#ff6b35" />
+        <text class="progress-value">{{ vipInfo.invitedCount || 0 }}/{{ vipInfo.needInvite }}</text>
+      </view>
+      <view class="progress-item" v-if="vipInfo.needConsume">
+        <text class="progress-label">还需消费</text>
+        <progress class="progress-bar" :percent="consumePercent" activeColor="#ff6b35" />
+        <text class="progress-value">¥{{ vipInfo.consumedAmount || 0 }}/¥{{ vipInfo.needConsume }}</text>
+      </view>
+    </view>
+
+    <view class="action-row">
+      <u-button type="primary" @click="renewVip">续费</u-button>
+      <u-button type="default" @click="shareInvite">分享邀请</u-button>
+    </view>
+  </view>
+</template>
+
+<script>
+import { getVipInfo } from '@/api/enagic.js'
+
+export default {
+  data() {
+    return {
+      vipInfo: {}
+    }
+  },
+
+  computed: {
+    invitePercent() {
+      if (!this.vipInfo.needInvite) return 0
+      return Math.min(100, ((this.vipInfo.invitedCount || 0) / this.vipInfo.needInvite) * 100)
+    },
+
+    consumePercent() {
+      if (!this.vipInfo.needConsume) return 0
+      return Math.min(100, ((this.vipInfo.consumedAmount || 0) / this.vipInfo.needConsume) * 100)
+    }
+  },
+
+  onLoad() {
+    this.loadData()
+  },
+
+  onShow() {
+    this.loadData()
+  },
+
+  onPullDownRefresh() {
+    this.loadData().finally(() => {
+      uni.stopPullDownRefresh()
+    })
+  },
+
+  methods: {
+    async loadData() {
+      uni.showLoading({ title: '加载中' })
+      try {
+        const res = await getVipInfo()
+        this.vipInfo = res || {}
+        
+        if (!this.vipInfo.level) {
+          uni.showModal({
+            title: '提示',
+            content: '您还未开通VIP,是否前往开通?',
+            success: (modalRes) => {
+              if (modalRes.confirm) {
+                uni.navigateTo({ url: '/pages/enagic/vip/index' })
+              } else {
+                uni.navigateBack()
+              }
+            }
+          })
+        }
+      } catch (e) {
+        this.$u.toast('加载失败')
+      } finally {
+        uni.hideLoading()
+      }
+    },
+
+    renewVip() {
+      uni.navigateTo({ url: '/pages/enagic/vip/index' })
+    },
+
+    shareInvite() {
+      uni.share({
+        provider: 'weixin',
+        scene: 'WXSceneSession',
+        type: 0,
+        title: '邀请你开通VIP',
+        summary: '加入VIP,享受更多权益',
+        imageUrl: '/static/enagic/vip-share.png',
+        success: () => {
+          this.$u.toast('分享成功')
+        },
+        fail: () => {
+          this.$u.toast('分享失败')
+        }
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.my-vip-page {
+  min-height: 100vh;
+  background: #f5f5f5;
+  padding-bottom: 140rpx;
+}
+
+.vip-card {
+  display: flex;
+  align-items: center;
+  padding: 40rpx 30rpx;
+  background: linear-gradient(135deg, #ffd700 0%, #ffb700 100%);
+  margin: 20rpx;
+  border-radius: 16rpx;
+
+  .vip-icon {
+    width: 100rpx;
+    height: 100rpx;
+  }
+
+  .vip-info {
+    margin-left: 24rpx;
+    color: #fff;
+
+    .vip-level {
+      display: block;
+      font-size: 36rpx;
+      font-weight: bold;
+      margin-bottom: 12rpx;
+    }
+
+    .vip-time {
+      display: block;
+      font-size: 24rpx;
+      opacity: 0.8;
+    }
+  }
+}
+
+.benefits-section, .progress-section {
+  margin: 0 20rpx 20rpx;
+  padding: 24rpx;
+  background: #fff;
+  border-radius: 16rpx;
+
+  .section-title {
+    display: block;
+    font-size: 28rpx;
+    color: #333;
+    font-weight: bold;
+    margin-bottom: 20rpx;
+  }
+}
+
+.benefits-list {
+  .benefit-item {
+    display: flex;
+    align-items: center;
+    padding: 16rpx 0;
+    border-bottom: 1rpx solid #f0f0f0;
+
+    &:last-child {
+      border-bottom: none;
+    }
+
+    .check {
+      color: #52c41a;
+      font-size: 28rpx;
+      margin-right: 16rpx;
+    }
+
+    .benefit-name {
+      font-size: 26rpx;
+      color: #333;
+    }
+  }
+}
+
+.progress-item {
+  margin-bottom: 30rpx;
+
+  &:last-child {
+    margin-bottom: 0;
+  }
+
+  .progress-label {
+    display: block;
+    font-size: 26rpx;
+    color: #666;
+    margin-bottom: 10rpx;
+  }
+
+  .progress-bar {
+    display: block;
+    margin-bottom: 10rpx;
+  }
+
+  .progress-value {
+    display: block;
+    font-size: 24rpx;
+    color: #999;
+    text-align: right;
+  }
+}
+
+.action-row {
+  position: fixed;
+  bottom: 0;
+  left: 0;
+  right: 0;
+  display: flex;
+  padding: 20rpx 30rpx;
+  background: #fff;
+  box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.05);
+
+  button {
+    flex: 1;
+    margin: 0 10rpx;
+  }
+}
+</style>

BIN
需求文档/本希甄选小程序0212.pdf


BIN
需求文档/本希甄选小程序0225.xlsx


+ 623 - 0
需求文档/本希甄选小程序需求文档.md

@@ -0,0 +1,623 @@
+# 本希甄选小程序 需求文档
+
+> **文档版本:** V1.0
+>
+> **编制日期:** 2025-02-25
+>
+> **项目报价:** ¥100,000
+>
+> **工作量估算:** 90 人天(4 人月)
+
+---
+
+## 一、项目概述
+
+### 1.1 项目背景
+
+本希甄选小程序是一个集商品销售、素材共享、用户管理、客户服务于一体的微信小程序平台。系统包含 **PC 后台管理端** 和 **微信小程序端** 两大部分,支持多角色运营(平台管理员、商家、消费者/消费商)。
+
+### 1.2 系统架构
+
+```
+┌─────────────────────────────────────────────────────┐
+│                    微信小程序端                        │
+│  (用户注册 / 商品浏览 / 购物结算 / 素材中心 / 客服 / AI数字人) │
+└─────────────────────────────────────────────────────┘
+                          │
+                          ▼
+┌─────────────────────────────────────────────────────┐
+│                    PC 后台管理端                      │
+│  (用户管理 / 商家管理 / 商品管理 / 订单处理 / 素材管理 / 客服 / AI接口 / 客户管理) │
+└─────────────────────────────────────────────────────┘
+```
+
+---
+
+## 二、PC 后台管理端
+
+### 2.1 首页设置
+
+#### 2.1.1 页面模板设置
+
+- 提供小程序端界面风格设置工具,支持多模板管理
+- 提供自定义拖拽组件功能,包含:轮播图、图片、广告魔方、标题栏、宫格导航、搜索、商品分类、公告、促销活动等组件
+- 用户可自定义设置组件显示内容和链接内容
+
+#### 2.1.2 模板切换
+
+根据用户需求实时切换展示移动端首页内容
+
+---
+
+### 2.2 用户管理
+
+#### 2.2.1 用户基础信息
+
+- 存储用户微信 openid、unionid、昵称、头像、手机号、用户ID、注册时间
+- 提供接口查询用户完整个人信息(级别、资产、订单统计)
+- 支持修改用户昵称、头像、手机号等基础信息,记录修改日志
+- **消费商可使用手机号自设密码登录后台,填写补充个人信息**
+- 小程序负责大数据统计,为消费商服务跟进提供具体指引,直至订单完成
+
+#### 2.2.2 邀请人管理
+
+- 为每个用户生成唯一邀请二维码,扫码注册后建立邀请关系
+- 新用户注册时记录邀请人ID,建立"健康布施者"关联关系,**永久保存**
+- 查询用户的邀请人信息(健康布施者)和被邀请人列表
+- 统计用户邀请人数、邀请奖励、下级消费贡献等数据
+
+#### 2.2.3 用户等级管理
+
+- 后台配置用户等级体系(普通、银牌、金牌、钻石),设置升级条件(消费金额、积分、邀请人数)
+- 积分未来可用于积分区兑换客户需求产品
+- 为各等级配置对应权益(专属服务、超值产品、优先发货等)
+- 配置 VIP 等级(以销售金额、会员身份彰显、会员级别)、价格、会员权益内容
+- **VIP 不设到期时间,只设分享激励感恩提醒**
+
+#### 2.2.4 资产中心管理
+
+**VIP会员管理:**
+
+- 配置 VIP 等级、价格、权益内容、有效期
+- 处理 VIP 购买订单,支付成功后激活 VIP 身份
+- 查询用户当前 VIP 状态、等级
+
+**优惠券管理:**
+
+- 根据用户行为(注册、消费、邀请、活动)自动发放优惠券到用户账户
+- 查询用户全部优惠券,按状态(未使用、已使用、已过期)分类统计数量
+- 用户下单时选择使用优惠券,校验有效期和使用门槛
+
+**积分管理:**
+
+- 配置积分获取途径(消费返积分、签到、分享、邀请),设置积分比例
+- 记录每笔积分收入和支出明细
+- 查询用户当前积分总额和积分明细列表
+
+**会员卡管理:**
+
+- 配置会员卡等级、权益、升级条件、降级规则
+- 满足条件自动发放电子会员卡
+
+**抵扣金管理:**
+
+- 配置抵扣金获取方式、使用规则
+- 记录抵扣金收入和支出明细,支持冻结和解冻
+
+**余额管理:**
+
+- 处理用户余额充值订单(微信支付)
+- 用户下单选择余额支付时,冻结并扣减余额
+- 处理用户提现申请
+
+---
+
+### 2.3 商家管理
+
+#### 2.3.1 商家入驻
+
+- 第三方商家提交入驻申请,填写企业/个人信息(营业执照、法人身份证、联系方式、经营范围)
+- 管理员审核商家提交的资质材料,审核通过开通商家账号,审核不通过反馈原因
+- **第三方商家合作合同线上签署功能和合作规则法律法规文件,交合作保证金收款链接**
+
+#### 2.3.2 商家账号管理
+
+- 商家通过独立后台地址登录,使用分配的账号密码或绑定微信扫码登录
+
+#### 2.3.3 商家商品管理
+
+- 商家填写商品信息(名称、描述、图片、价格、库存、型号、分类),提交后进入待审核状态
+- 修改已提交或已驳回的商品信息,重新提交审核
+- 商家查看自己发布的全部商品,按状态筛选
+- 商家主动下架在售商品;删除草稿或已驳回的商品
+- 查看商品审核进度和审核结果
+
+#### 2.3.4 商家订单管理
+
+- 查看用户购买的自家商品订单,按状态筛选
+- 选择物流发货时,填写物流公司、运单号,确认发货
+- 选择用户自提时,确认用户已提货
+
+#### 2.3.5 售后处理
+
+处理用户退款/退货申请,审核售后请求,确认退款或驳回并说明原因
+
+---
+
+### 2.4 商品管理
+
+#### 2.4.1 商品分类管理
+
+- 配置商品分类结构,支持一级、二级分类的增删改查
+- 设置分类名称、排序、图标、启用/禁用状态
+- 设置商品所属分类(支持多选),分类删除时校验是否关联商品,防止误删
+
+#### 2.4.2 商品管理
+
+**基础功能:**
+
+- 商品列表查询:后台分页展示全部商品,支持按分类、名称、状态、价格区间筛选,支持批量操作
+- 商品新增:填写商品基础信息、设置所属分类、初始销量、上下架状态
+- 新增商品提供文本编辑器工具,支持图片、链接、视频等媒体文件上传
+- 提供商品编辑、删除、上下架等功能
+
+**型号管理:**
+
+- 为商品配置多规格/型号,设置各型号的独立价格、库存、SKU编码、专属图片
+
+**库存管理:**
+
+- 查看和修改各型号商品库存,设置库存预警值
+
+**价格管理:**
+
+- 设置商品基础价格和型号差价,支持限时特价、会员价等营销价格配置
+
+#### 2.4.3 商品审核(第三方商家商品)
+
+- 查看所有商家提交的待审核商品
+- 查看商品完整信息,预览前端展示效果
+- 审核通过商品,商品立即在小程序前端展示
+- 审核不通过时填写驳回原因
+- 查看历史审核记录
+- 对已上架商品进行巡查,发现违规立即强制下架,记录下架原因并通知商家
+- **情节严重扣除合作保证金,发解除合作法律文件**
+- 配置商品审核的自动规则(如敏感词过滤、图片合规检测),设置必审类目
+
+---
+
+### 2.5 订单处理
+
+- 根据选中商品生成预订单,计算商品总价、运费,锁定库存
+- 管理用户收货地址库
+- 配置支持的配送方式(物流发货、用户自提)
+- 配置用户自提点信息(名称、地址、营业时间、联系电话)
+- 根据收货地址、商品重量/体积、运费模板计算物流费用
+- **调用微信支付统一下单接口,设实体店自提功能**
+- 接收微信支付结果通知,验证签名,更新订单支付状态
+- 支付成功后生成正式订单
+- 支付成功后扣减对应商品型号库存,支持库存回滚
+- 管理订单状态(待支付、已支付/待发货、已发货/待收货、已完成、已取消)
+
+---
+
+### 2.6 素材管理
+
+#### 2.6.1 素材分类管理
+
+- 配置素材分类体系,支持一级、二级分类的增删改查
+- 设置分类可见范围(全部用户/指定角色)
+- 控制分类在前端的展示状态
+
+#### 2.6.2 素材上传
+
+- 支持批量上传,选择素材类型和所属分类
+- 上传图片素材(支持 JPG、PNG、GIF 格式)
+- 上传视频素材(支持 MP4 格式)
+- 上传海报素材,设置海报尺寸规格
+- 填写素材名称、详细描述、关键词标签、适用场景、版权说明
+- **每张素材自动生成关联二维码,便于客户和消费商分享邀请新客户,省去关联流程**
+
+#### 2.6.3 素材基础管理
+
+- 查看全部素材,支持筛选和批量操作
+- 修改素材基础信息
+- 删除素材(逻辑删除或物理删除)
+- 控制素材在前端的展示状态
+
+---
+
+### 2.7 客服
+
+#### 2.7.1 客服账号配置
+
+配置客服坐席账号,设置客服工作时间、自动回复语、转接规则
+
+#### 2.7.2 消息路由分配
+
+将用户消息分配给在线客服,支持按负载均衡或指定客服分配
+
+#### 2.7.3 客服会话记录
+
+存储全部客服对话记录,支持按用户、时间、客服筛选查询
+
+---
+
+### 2.8 会员权益管理
+
+#### 2.8.1 权益规则配置
+
+记录用户权益获取和使用明细,支持权益补发和回收
+
+#### 2.8.2 权益发放记录
+
+存储用户全部收货地址,标记默认地址,关联用户ID
+
+---
+
+### 2.9 消息中心管理
+
+- 配置各类消息的通知模板(标题、内容、跳转链接),支持变量替换
+- 调用微信小程序订阅消息或公众号模板消息接口,触达用户
+- 存储用户消息记录,支持按用户、类型、时间查询,标记已读状态
+
+---
+
+### 2.10 AI接口
+
+#### 2.10.1 AI数字人
+
+- 对接 AI 大模型接口,配置 API 密钥和参数
+- 配置产品知识库、健康知识库,设置 AI 回答的范围和话术规范
+- 存储用户与 AI 的全部对话记录
+- 配置敏感词库,过滤用户输入和 AI 输出的违规内容
+
+---
+
+### 2.11 客户管理
+
+#### 2.11.1 客户绑定关系
+
+- 记录客户与负责人的绑定关系,支持一个客户多个产品分别归属不同人
+- 为每个产品配置标准运维流程
+
+#### 2.11.2 运维流程管理
+
+- 客户购买产品后,根据产品运维流程自动生成运维计划时间表
+- 到达运维节点时自动提醒负责人
+- 存储每次运维工作的记录
+
+#### 2.11.3 客户状态管理
+
+- 管理客户状态:未处理提醒 → 已处理提醒,记录状态变更时间和操作人
+- **处理客户无人服务时,客户服务提醒直接通知,后台指定客服,客户归属权收益权不变**
+- **三次未能给客户提供对应的服务,客户自动转移到平台客服,终止原来关联销售的归属权和收益权**
+
+#### 2.11.4 客户移交
+
+- 移交申请,接收人确认接收或拒绝
+- 存储客户全部移交历史
+
+#### 2.11.5 客户追踪
+
+- 采集用户在小程序的全部操作事件(页面浏览、点击、分享、搜索)
+- 根据邀请关系链查询全部下级用户,构建用户层级树
+- 追踪分享内容的后续传播路径,统计二级、三级分享带来的查看和转化
+- 重要客户行为触发时,向邀请人推送微信通知或站内消息
+
+---
+
+## 三、微信小程序端
+
+### 3.1 用户注册
+
+#### 3.1.1 微信注册
+
+- 用户首次进入小程序时,若未登录,展示"微信一键登录"按钮
+- 授权成功后,系统自动获取用户微信头像、昵称等基础公开信息,创建用户账号记录
+- 此前已授权用户直接完成静默登录
+
+#### 3.1.2 绑定手机号
+
+- 微信授权登录完成后,系统强制用户进行手机号绑定
+- 用户点击"绑定手机号"按钮,通过微信快速验证组件一键授权
+- 后端使用 session_key 解密获取真实手机号,与用户账号建立绑定关系
+- 用户拒绝绑定手机号返回注册界面
+
+---
+
+### 3.2 首页
+
+#### 3.2.1 轮播图
+
+- 显示商品轮播图,显示内容由后台管理自定义设置,最多显示10张
+- 支持点击进入商品详情页
+- 每三秒自动切换图片,可手动向前后查询
+
+#### 3.2.2 宫格导航
+
+- 展示功能图表和名称
+- 点击图标进入功能或详情界面
+
+#### 3.2.3 图片链接
+
+- 展示标题、描述
+- 展示图片超链接,点击进入功能界面或详情页面
+
+#### 3.2.4 商品分类
+
+- 可设置商品分类名称,通过商品分类过滤商品信息
+- 商品详情卡片展示:图片、名称、价格、购买按钮
+- 点击卡片或购买可进入商品详情界面
+
+#### 3.2.5 搜索功能
+
+点击搜索按钮进入商品搜索界面
+
+---
+
+### 3.3 商品分类与浏览
+
+#### 3.3.1 分类菜单
+
+- 左侧一级分类垂直展示,点击切换,当前选中分类高亮显示
+- 点击一级分类后展开对应的二级分类
+- 记录用户当前选中的分类状态
+
+#### 3.3.2 商品展示
+
+- 根据选中的分类展示对应商品,以卡片形式平铺展示
+- 商品卡片展示:商品主图、商品名称、价格
+- 支持上拉加载更多、下拉刷新
+
+#### 3.3.3 商品搜索
+
+- 搜索入口在商品页面顶部,占位符提示"请输入名称或型号"
+- 支持模糊搜索
+- 搜索结果支持按销量排序、按价格排序(从低到高/从高到低)
+
+#### 3.3.4 商品详情
+
+- 展示商品轮播图、完整名称、详细描述、规格参数、价格、库存状态、累计销量
+- 型号选择:如商品存在多规格(颜色、尺寸),先弹出选择窗口
+- 若商品仅有一个型号或无型号,点击"加入购物车"直接加入
+- 加入购物车按钮:点击触发加购逻辑
+
+---
+
+### 3.4 购物与结算功能
+
+#### 3.4.1 购物车
+
+- 购物车入口显示当前商品数量角标,点击进入购物车页面
+- 购物车列表展示已加购商品(缩略图、名称、型号、单价、数量)
+- 支持数量增减、删除商品
+
+#### 3.4.2 结算功能
+
+**订单确认页面:**
+
+- 展示订单商品清单(图片、名称、型号、单价、数量、小计)
+- 显示订单总金额,支持返回修改
+
+**收货地址选择:**
+
+- 选择或新增收货地址,展示收件人姓名、手机号、详细地址
+- 支持设为默认地址
+
+**物流方式选择:**
+
+- 物流发货:展示收货地址信息,根据地址计算运费,显示预计送达时间
+- 用户自提:展示自提点信息(地址、营业时间、联系电话),通过核销码进行核销
+
+---
+
+### 3.5 素材中心(商学院)
+
+#### 3.5.1 数据权限
+
+- 商学院内容分为:发圈素材、海报
+- 消费商角色可查看全部内容,用户只可查看海报内容
+- 产品宣传相关内容、公司快讯等
+
+#### 3.5.2 素材分类展示
+
+- 左侧垂直展示素材分类列表,点击切换
+- 点击一级分类后展开二级分类,点击二级分类筛选对应素材
+- 根据选中分类展示对应素材,支持上拉加载更多、下拉刷新
+- 图片素材卡片展示缩略图、素材名称、上传时间
+- 视频素材卡片展示封面图、播放时长、素材名称
+- 海报素材卡片展示海报缩略图、适用场景、素材名称
+
+#### 3.5.3 素材搜索
+
+- 页面顶部设置搜索栏,占位符提示"请输入素材名称或关键词"
+- 展示用户近期搜索关键词历史,支持删除或清空
+- 输入关键词进行模糊匹配,支持按素材类型筛选
+- 搜索结果支持按上传时间、浏览量/下载量排序
+
+#### 3.5.4 素材详情
+
+- 图片素材支持手势缩放、左右滑动浏览;支持长按保存到相册
+- 视频素材支持全屏播放、进度拖动、倍速播放
+- 海报素材支持长按保存或分享
+- 支持转发素材给微信好友或生成分享海报
+- 详情页底部展示同分类或同标签的相关素材
+
+---
+
+### 3.6 文章管理
+
+- 配置文章分类(健康知识、产品介绍、使用教程等),支持二级分类
+- 富文本编辑器发布文章,设置分类、标签、发布时间
+- 定时推送客户感兴趣内容给客户
+- 控制文章展示状态,设置定时发布和自动下架
+- 统计文章阅读量、分享量、点赞数、收藏数,生成热门文章排行
+
+---
+
+### 3.7 用户中心
+
+#### 3.7.1 用户中心页面
+
+- 展示用户微信头像(圆形裁剪),点击进入头像设置页面
+- 展示用户微信昵称或自定义昵称,点击修改
+- 展示系统分配的唯一用户ID,支持点击复制
+- 根据用户等级展示级别名称及对应等级图标
+
+#### 3.7.2 健康布施者
+
+- 展示邀请人的微信昵称和用户ID,标识"健康布施者"身份
+- 提供说明解释"健康布施者"含义(即邀请注册的人)
+- **给健康布施者荣誉,只要布施关联客户就给发荣誉勋章,从而促进分享动力**
+
+#### 3.7.3 VIP开通
+
+- 醒目展示"开通VIP"按钮或卡片,点击进入VIP权益介绍和开通页面
+- 已是VIP用户展示VIP等级、到期时间、剩余天数,提供续费入口
+
+#### 3.7.4 资产中心
+
+- 展示积分角标,点击进入积分列表,查看可用、已用、未用
+- 展示电子会员卡,点击进入会员卡详情
+- 展示积分兑换金额,点击进入兑换明细
+- 展示账户余额,点击进入余额管理
+
+---
+
+### 3.8 订单中心
+
+#### 3.8.1 订单概览
+
+横向展示待付款、已付款、运送中、售后四个状态的订单数量
+
+#### 3.8.2 订单列表
+
+- 默认展示全部订单,按时间倒序排列,展示订单号、商品缩略图、商品名称、订单金额、订单状态
+- **待付款:** 展示倒计时剩余支付时间,提供立即支付、取消订单按钮
+- **已支付/待发货:** 提供申请退款、联系客服按钮
+- **已发货:** 展示物流公司和运单号,提供查看物流、确认收货按钮
+- **已完成:** 提供再次购买、申请售后、评价按钮
+- 支持按订单号、商品名称搜索历史订单
+
+#### 3.8.3 订单详情
+
+点击订单卡片进入订单详情页,展示完整订单信息、物流轨迹、操作记录
+
+---
+
+### 3.9 个人中心
+
+#### 3.9.1 客服
+
+- 点击进入客服对话窗口,支持文字、图片、语音消息
+- 展示常见问题快捷入口
+- 查看历史客服对话记录,支持继续会话或评价客服
+
+#### 3.9.2 会员权益
+
+- 展示当前会员等级全部权益(图标+文字形式)
+- 查看各项权益的使用历史和剩余次数
+- 展示下一等级升级条件(还需消费金额/积分/布施人数)和进度条
+
+#### 3.9.3 我的地址管理
+
+- 展示全部收货地址,默认地址置顶高亮显示
+- 新增地址:填写收件人姓名、手机号、省市区选择、详细地址
+- 支持修改、删除地址
+- 删除前校验是否有进行中的订单使用该地址
+- 下单时自动将订单中的收货地址保存到地址管理列表(去重判断)
+
+#### 3.9.4 文章管理
+
+- 顶部展示文章分类,点击切换分类
+- 按分类展示文章列表(封面图、标题、摘要、阅读量、发布时间)
+- 支持按关键词搜索文章
+- 点击进入文章详情页,支持收藏、分享、点赞
+- **分享海报时要加入账号二维码**
+
+---
+
+### 3.10 消息中心
+
+- 按类型展示系统通知、订单通知、活动通知、客服消息
+- 未读消息数字角标提示
+- 展示消息标题、摘要、时间,未读消息高亮显示
+- 查看消息完整内容,支持跳转相关页面
+- 标记消息已读,支持批量删除或清空
+- 设置各类型消息是否接收推送通知
+
+---
+
+### 3.11 AI数字人
+
+- 展示AI数字人形象和产品介绍文案,点击进入对话界面
+- 接入AI接口,支持文字或语音与数字人对话,咨询产品信息、健康知识、使用建议
+- 界面展示热门问题快捷按钮,点击直接发送问题
+- 保存用户与数字人的对话记录,支持查看历史会话
+
+---
+
+### 3.12 客户追踪(消费商功能)
+
+- 展示当前用户邀请的全部直接关联用户(健康布施者的反向视角)
+- 展示头像、昵称、注册时间、会员等级
+- 身份区分:纯客户 / 消费商
+- **消费商需按要求填写个人购买信息,按照产品公司要求填写**
+
+---
+
+## 四、非功能性需求
+
+### 4.1 性能需求
+
+- 页面加载时间不超过 3 秒
+- 接口响应时间不超过 500ms
+- 支持高并发访问
+
+### 4.2 安全需求
+
+- 用户密码加密存储
+- 接口需进行签名验证
+- 敏感数据需加密传输
+- 防范 SQL 注入、XSS 等常见攻击
+
+### 4.3 兼容性需求
+
+- 微信小程序需适配最新版本微信
+- 后台管理系统需支持主流浏览器(Chrome、Firefox、Safari、Edge)
+
+### 4.4 数据备份
+
+- 定期进行数据备份
+- 备份数据需异地存储
+
+---
+
+## 五、工作量估算汇总
+
+| 序号 | 模块 | 主要功能点 | 估算人天 |
+|------|------|-----------|---------|
+| 1 | 首页设置 | 页面模板设置、模板切换 | 9 |
+| 2 | 用户管理 | 基础信息、邀请人、等级、资产中心 | 13 |
+| 3 | 商家管理 | 入驻、账号、商品、订单、售后 | 7+ |
+| 4 | 商品管理 | 分类、管理、型号、审核 | 5+ |
+| 5 | 订单处理 | 预订单、支付、库存、状态管理 | 5 |
+| 6 | 素材管理 | 分类、上传、基础管理 | 5+ |
+| 7 | 客服 | 账号配置、消息路由、会话记录 | 5 |
+| 8 | 会员权益 | 权益规则、发放记录 | 3 |
+| 9 | 消息中心 | 消息模板、订阅/推送 | 3 |
+| 10 | AI接口 | AI数字人对接 | 5 |
+| 11 | 客户管理 | 绑定、运维、状态、移交、追踪 | 5+ |
+| 12 | 移动端 | 用户注册、首页、商品、购物、素材、用户中心、AI等 | — |
+| **合计** | | | **90 人天** |
+
+> 注:带 "+" 的模块包含更多细节功能,实际工作量可能根据详细设计有所调整。
+
+---
+
+## 六、备注
+
+1. 本文档基于 `本希甄选小程序0212.pdf` 和 `本希甄选小程序0225.xlsx` 两份原始需求文档整合编写
+2. 如有功能细节与原始文档不符,以原始文档为准
+3. 实际开发中如遇需求变更,需另行评估工作量