1372 lines
41 KiB
Markdown
1372 lines
41 KiB
Markdown
# 微信小程序会员绑定系统需求规格说明书
|
||
|
||
## 文档信息
|
||
|
||
**项目名称:** 小智AI微信小程序会员绑定系统
|
||
**文档版本:** v1.0
|
||
**创建日期:** 2025年9月30日
|
||
**项目负责人:** 开发团队
|
||
**文档类型:** 需求规格说明书
|
||
|
||
---
|
||
|
||
## 1. 项目概述
|
||
|
||
### 1.1 项目背景
|
||
小智AI微信小程序需要建立完善的会员体系,通过会员绑定系统实现用户身份验证、会员等级管理和权益分配,提升用户体验和产品价值。
|
||
|
||
### 1.2 项目目标
|
||
1. **无缝对接**:实现微信小程序与会员购买系统的无缝对接
|
||
2. **等级管理**:提供VIP和SVIP两档会员绑定功能
|
||
3. **权益匹配**:确保会员权益与购买等级准确匹配
|
||
4. **用户体验**:提供流畅的会员绑定和管理体验
|
||
|
||
### 1.3 项目范围
|
||
- 微信小程序会员绑定功能开发
|
||
- 会员等级管理系统
|
||
- 会员权益验证机制
|
||
- 相关数据库设计和API接口开发
|
||
|
||
---
|
||
|
||
## 2. 功能需求分析
|
||
|
||
### 2.1 核心功能模块
|
||
|
||
#### 2.1.1 用户授权登录模块
|
||
**功能描述:** 通过微信授权获取用户身份信息
|
||
|
||
**主要功能:**
|
||
- 微信授权登录
|
||
- 获取用户openid
|
||
- 用户信息存储
|
||
- 登录状态管理
|
||
|
||
**业务流程:**
|
||
```
|
||
用户点击登录 → 微信授权 → 获取code → 后端换取openid → 用户信息入库 → 登录成功
|
||
```
|
||
|
||
#### 2.1.2 会员身份验证模块
|
||
**功能描述:** 验证用户会员身份和等级
|
||
|
||
**主要功能:**
|
||
- 会员身份验证
|
||
- 会员等级识别
|
||
- 会员状态查询
|
||
- 会员信息同步
|
||
|
||
**验证逻辑:**
|
||
```
|
||
输入openid → 查询会员表 → 验证会员状态 → 返回会员等级 → 更新绑定状态
|
||
```
|
||
|
||
#### 2.1.3 会员绑定管理模块
|
||
**功能描述:** 管理用户与会员身份的绑定关系
|
||
|
||
**主要功能:**
|
||
- 会员绑定操作
|
||
- 绑定状态更新
|
||
- 绑定历史记录
|
||
- 解绑功能
|
||
|
||
#### 2.1.4 会员等级管理模块
|
||
**功能描述:** 管理不同等级会员的权益和特权
|
||
|
||
**会员等级定义:**
|
||
|
||
| 等级 | 名称 | 权益描述 | 有效期 |
|
||
|------|------|----------|--------|
|
||
| **普通用户** | 免费用户 | 基础功能使用 | 永久 |
|
||
| **VIP** | 基础会员 | 高级功能 + 优先支持 | 按购买周期 |
|
||
| **SVIP** | 高级会员 | 全功能 + 专属服务 | 按购买周期 |
|
||
|
||
### 2.2 功能优先级
|
||
|
||
| 优先级 | 功能模块 | 开发周期 |
|
||
|--------|----------|----------|
|
||
| **P0** | 用户授权登录 | 1周 |
|
||
| **P0** | 会员身份验证 | 1周 |
|
||
| **P1** | 会员绑定管理 | 1周 |
|
||
| **P1** | 会员等级管理 | 1周 |
|
||
| **P2** | 会员权益展示 | 0.5周 |
|
||
|
||
---
|
||
|
||
## 3. 技术架构设计
|
||
|
||
### 3.1 系统架构图
|
||
|
||
```
|
||
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
||
│ 微信小程序 │ │ 后端API服务 │ │ 数据库存储 │
|
||
│ │ │ │ │ │
|
||
│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │
|
||
│ │ 会员绑定页面 │ │◄──►│ │ 会员验证API │ │◄──►│ │ 会员信息表 │ │
|
||
│ └─────────────┘ │ │ └─────────────┘ │ │ └─────────────┘ │
|
||
│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │
|
||
│ │ 会员中心页面 │ │◄──►│ │ 权益查询API │ │◄──►│ │ 绑定关系表 │ │
|
||
│ └─────────────┘ │ │ └─────────────┘ │ │ └─────────────┘ │
|
||
│ ┌─────────────┐ │ │ ┌─────────────┐ │ │ ┌─────────────┐ │
|
||
│ │ 权益说明弹窗 │ │◄──►│ │ 绑定管理API │ │◄──►│ │ 用户信息表 │ │
|
||
│ └─────────────┘ │ │ └─────────────┘ │ │ └─────────────┘ │
|
||
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
||
```
|
||
|
||
### 3.2 技术栈选择
|
||
|
||
**前端技术栈:**
|
||
- 微信小程序原生框架
|
||
- WXML + WXSS + JavaScript
|
||
- 微信小程序API
|
||
|
||
**后端技术栈:**
|
||
- Java Spring Boot
|
||
- MyBatis Plus
|
||
- MySQL 数据库
|
||
- Redis 缓存
|
||
|
||
**第三方服务:**
|
||
- 微信开放平台API
|
||
- 微信支付API
|
||
|
||
---
|
||
|
||
## 4. 数据库设计
|
||
|
||
### 4.1 数据表结构
|
||
|
||
#### 4.1.1 会员信息表 (member_info)
|
||
|
||
```sql
|
||
CREATE TABLE `member_info` (
|
||
`member_id` varchar(64) NOT NULL COMMENT '会员ID,主键',
|
||
`openid` varchar(128) NOT NULL COMMENT '微信用户openid',
|
||
`member_level` varchar(16) NOT NULL DEFAULT 'FREE' COMMENT '会员等级:FREE-免费,VIP-基础会员,SVIP-高级会员',
|
||
`member_status` varchar(16) NOT NULL DEFAULT 'ACTIVE' COMMENT '会员状态:ACTIVE-有效,EXPIRED-过期,SUSPENDED-暂停',
|
||
`start_time` datetime DEFAULT NULL COMMENT '会员开始时间',
|
||
`end_time` datetime DEFAULT NULL COMMENT '会员结束时间',
|
||
`purchase_order_id` varchar(64) DEFAULT NULL COMMENT '购买订单ID',
|
||
`auto_renew` tinyint DEFAULT 0 COMMENT '是否自动续费:0-否,1-是',
|
||
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||
`deleted` tinyint DEFAULT 0 COMMENT '是否删除:0-未删除,1-已删除',
|
||
PRIMARY KEY (`member_id`),
|
||
UNIQUE KEY `uk_openid` (`openid`),
|
||
KEY `idx_member_level` (`member_level`),
|
||
KEY `idx_member_status` (`member_status`),
|
||
KEY `idx_end_time` (`end_time`)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员信息表';
|
||
```
|
||
|
||
#### 4.1.2 会员绑定记录表 (member_bind_log)
|
||
|
||
```sql
|
||
CREATE TABLE `member_bind_log` (
|
||
`log_id` bigint NOT NULL AUTO_INCREMENT COMMENT '日志ID,主键',
|
||
`member_id` varchar(64) NOT NULL COMMENT '会员ID',
|
||
`openid` varchar(128) NOT NULL COMMENT '微信用户openid',
|
||
`bind_type` varchar(16) NOT NULL COMMENT '绑定类型:BIND-绑定,UNBIND-解绑,UPGRADE-升级,DOWNGRADE-降级',
|
||
`old_level` varchar(16) DEFAULT NULL COMMENT '原会员等级',
|
||
`new_level` varchar(16) NOT NULL COMMENT '新会员等级',
|
||
`bind_source` varchar(32) DEFAULT NULL COMMENT '绑定来源:PURCHASE-购买,GIFT-赠送,ADMIN-管理员',
|
||
`related_order_id` varchar(64) DEFAULT NULL COMMENT '关联订单ID',
|
||
`bind_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '绑定时间',
|
||
`remark` varchar(500) DEFAULT NULL COMMENT '备注',
|
||
PRIMARY KEY (`log_id`),
|
||
KEY `idx_member_id` (`member_id`),
|
||
KEY `idx_openid` (`openid`),
|
||
KEY `idx_bind_type` (`bind_type`),
|
||
KEY `idx_bind_time` (`bind_time`)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员绑定记录表';
|
||
```
|
||
|
||
#### 4.1.3 会员权益配置表 (member_benefit_config)
|
||
|
||
```sql
|
||
CREATE TABLE `member_benefit_config` (
|
||
`config_id` int NOT NULL AUTO_INCREMENT COMMENT '配置ID,主键',
|
||
`member_level` varchar(16) NOT NULL COMMENT '会员等级',
|
||
`benefit_code` varchar(32) NOT NULL COMMENT '权益代码',
|
||
`benefit_name` varchar(100) NOT NULL COMMENT '权益名称',
|
||
`benefit_desc` varchar(500) DEFAULT NULL COMMENT '权益描述',
|
||
`benefit_value` varchar(100) DEFAULT NULL COMMENT '权益值',
|
||
`is_enabled` tinyint DEFAULT 1 COMMENT '是否启用:0-禁用,1-启用',
|
||
`sort_order` int DEFAULT 0 COMMENT '排序顺序',
|
||
`create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||
`update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||
PRIMARY KEY (`config_id`),
|
||
UNIQUE KEY `uk_level_code` (`member_level`, `benefit_code`),
|
||
KEY `idx_member_level` (`member_level`),
|
||
KEY `idx_benefit_code` (`benefit_code`)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='会员权益配置表';
|
||
```
|
||
|
||
### 4.2 初始化数据
|
||
|
||
```sql
|
||
-- 插入会员权益配置数据
|
||
INSERT INTO `member_benefit_config` (`member_level`, `benefit_code`, `benefit_name`, `benefit_desc`, `benefit_value`, `sort_order`) VALUES
|
||
('FREE', 'basic_chat', '基础对话', '每日基础AI对话功能', '50', 1),
|
||
('FREE', 'basic_voice', '基础语音', '每日语音识别次数', '20', 2),
|
||
('VIP', 'advanced_chat', '高级对话', '无限制AI对话功能', 'unlimited', 1),
|
||
('VIP', 'advanced_voice', '高级语音', '无限制语音识别', 'unlimited', 2),
|
||
('VIP', 'priority_support', '优先支持', '客服优先响应', 'enabled', 3),
|
||
('VIP', 'custom_model', '自定义模型', '使用自定义AI模型', 'enabled', 4),
|
||
('SVIP', 'premium_chat', '专属对话', '专属AI模型对话', 'unlimited', 1),
|
||
('SVIP', 'premium_voice', '专属语音', '高质量语音合成', 'unlimited', 2),
|
||
('SVIP', 'exclusive_support', '专属服务', '一对一专属客服', 'enabled', 3),
|
||
('SVIP', 'api_access', 'API访问', '开放API接口调用', 'enabled', 4),
|
||
('SVIP', 'data_export', '数据导出', '对话数据导出功能', 'enabled', 5);
|
||
```
|
||
|
||
---
|
||
|
||
## 5. API接口设计
|
||
|
||
### 5.1 会员验证相关接口
|
||
|
||
#### 5.1.1 用户登录接口
|
||
|
||
**接口地址:** `POST /api/member/login`
|
||
|
||
**请求参数:**
|
||
```json
|
||
{
|
||
"code": "微信授权code",
|
||
"userInfo": {
|
||
"nickName": "用户昵称",
|
||
"avatarUrl": "头像URL"
|
||
}
|
||
}
|
||
```
|
||
|
||
**响应数据:**
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "登录成功",
|
||
"data": {
|
||
"openid": "用户openid",
|
||
"sessionKey": "会话密钥",
|
||
"memberInfo": {
|
||
"memberId": "会员ID",
|
||
"memberLevel": "VIP",
|
||
"memberStatus": "ACTIVE",
|
||
"endTime": "2025-12-31 23:59:59"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 5.1.2 会员信息查询接口
|
||
|
||
**接口地址:** `GET /api/member/info`
|
||
|
||
**请求参数:**
|
||
```
|
||
Header: Authorization: Bearer {token}
|
||
```
|
||
|
||
**响应数据:**
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "查询成功",
|
||
"data": {
|
||
"memberId": "会员ID",
|
||
"memberLevel": "VIP",
|
||
"memberStatus": "ACTIVE",
|
||
"startTime": "2025-01-01 00:00:00",
|
||
"endTime": "2025-12-31 23:59:59",
|
||
"autoRenew": true,
|
||
"benefits": [
|
||
{
|
||
"benefitCode": "advanced_chat",
|
||
"benefitName": "高级对话",
|
||
"benefitDesc": "无限制AI对话功能",
|
||
"benefitValue": "unlimited"
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 5.1.3 会员绑定接口
|
||
|
||
**接口地址:** `POST /api/member/bind`
|
||
|
||
**请求参数:**
|
||
```json
|
||
{
|
||
"orderId": "购买订单ID",
|
||
"memberLevel": "VIP",
|
||
"duration": 12,
|
||
"durationUnit": "MONTH"
|
||
}
|
||
```
|
||
|
||
**响应数据:**
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "绑定成功",
|
||
"data": {
|
||
"memberId": "会员ID",
|
||
"memberLevel": "VIP",
|
||
"startTime": "2025-01-01 00:00:00",
|
||
"endTime": "2025-12-31 23:59:59"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5.2 会员权益相关接口
|
||
|
||
#### 5.2.1 权益列表查询接口
|
||
|
||
**接口地址:** `GET /api/member/benefits`
|
||
|
||
**请求参数:**
|
||
```
|
||
Query: memberLevel=VIP (可选,不传则返回当前用户等级权益)
|
||
```
|
||
|
||
**响应数据:**
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "查询成功",
|
||
"data": {
|
||
"memberLevel": "VIP",
|
||
"benefits": [
|
||
{
|
||
"benefitCode": "advanced_chat",
|
||
"benefitName": "高级对话",
|
||
"benefitDesc": "无限制AI对话功能",
|
||
"benefitValue": "unlimited",
|
||
"isEnabled": true
|
||
}
|
||
]
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 5.2.2 权益验证接口
|
||
|
||
**接口地址:** `POST /api/member/verify-benefit`
|
||
|
||
**请求参数:**
|
||
```json
|
||
{
|
||
"benefitCode": "advanced_chat",
|
||
"requestCount": 1
|
||
}
|
||
```
|
||
|
||
**响应数据:**
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"message": "验证成功",
|
||
"data": {
|
||
"hasPermission": true,
|
||
"remainingCount": "unlimited",
|
||
"resetTime": null
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 前端页面设计
|
||
|
||
### 6.1 页面结构
|
||
|
||
```
|
||
pages/
|
||
├── member/
|
||
│ ├── bind/
|
||
│ │ ├── bind.wxml # 会员绑定页面
|
||
│ │ ├── bind.wxss # 样式文件
|
||
│ │ ├── bind.js # 逻辑文件
|
||
│ │ └── bind.json # 配置文件
|
||
│ ├── center/
|
||
│ │ ├── center.wxml # 会员中心页面
|
||
│ │ ├── center.wxss
|
||
│ │ ├── center.js
|
||
│ │ └── center.json
|
||
│ └── benefits/
|
||
│ ├── benefits.wxml # 权益说明页面
|
||
│ ├── benefits.wxss
|
||
│ ├── benefits.js
|
||
│ └── benefits.json
|
||
└── components/
|
||
├── member-card/ # 会员卡片组件
|
||
├── benefit-item/ # 权益项组件
|
||
└── login-modal/ # 登录弹窗组件
|
||
```
|
||
|
||
### 6.2 关键页面设计
|
||
|
||
#### 6.2.1 会员绑定页面 (pages/member/bind/bind.wxml)
|
||
|
||
```xml
|
||
<view class="container">
|
||
<!-- 页面标题 -->
|
||
<view class="header">
|
||
<text class="title">会员绑定</text>
|
||
<text class="subtitle">绑定会员身份,享受专属权益</text>
|
||
</view>
|
||
|
||
<!-- 用户信息卡片 -->
|
||
<view class="user-card">
|
||
<image class="avatar" src="{{userInfo.avatarUrl}}" mode="aspectFill"></image>
|
||
<view class="user-info">
|
||
<text class="nickname">{{userInfo.nickName}}</text>
|
||
<text class="openid">ID: {{userInfo.openid}}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 会员状态 -->
|
||
<view class="member-status">
|
||
<view class="status-item">
|
||
<text class="label">当前状态:</text>
|
||
<text class="value {{memberInfo.memberLevel}}">{{memberLevelText}}</text>
|
||
</view>
|
||
<view class="status-item" wx:if="{{memberInfo.endTime}}">
|
||
<text class="label">到期时间:</text>
|
||
<text class="value">{{memberInfo.endTime}}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 绑定操作区域 -->
|
||
<view class="bind-section">
|
||
<view class="section-title">会员绑定</view>
|
||
|
||
<!-- 订单号输入 -->
|
||
<view class="input-group">
|
||
<text class="input-label">订单号</text>
|
||
<input class="input-field"
|
||
placeholder="请输入购买订单号"
|
||
value="{{orderId}}"
|
||
bindinput="onOrderIdInput" />
|
||
</view>
|
||
|
||
<!-- 绑定按钮 -->
|
||
<button class="bind-btn"
|
||
bindtap="onBindMember"
|
||
disabled="{{!orderId || binding}}">
|
||
{{binding ? '绑定中...' : '绑定会员'}}
|
||
</button>
|
||
</view>
|
||
|
||
<!-- 权益说明 -->
|
||
<view class="benefits-section">
|
||
<view class="section-title">会员权益</view>
|
||
<view class="benefits-list">
|
||
<view class="benefit-item" wx:for="{{benefits}}" wx:key="benefitCode">
|
||
<icon class="benefit-icon" type="success" size="16"></icon>
|
||
<text class="benefit-name">{{item.benefitName}}</text>
|
||
<text class="benefit-desc">{{item.benefitDesc}}</text>
|
||
</view>
|
||
</view>
|
||
<text class="view-more" bindtap="onViewMoreBenefits">查看详细权益说明 ></text>
|
||
</view>
|
||
</view>
|
||
```
|
||
|
||
#### 6.2.2 会员中心页面 (pages/member/center/center.wxml)
|
||
|
||
```xml
|
||
<view class="container">
|
||
<!-- 会员卡片 -->
|
||
<view class="member-card {{memberInfo.memberLevel}}">
|
||
<view class="card-header">
|
||
<image class="avatar" src="{{userInfo.avatarUrl}}" mode="aspectFill"></image>
|
||
<view class="member-info">
|
||
<text class="nickname">{{userInfo.nickName}}</text>
|
||
<view class="member-badge">
|
||
<text class="level-text">{{memberLevelText}}</text>
|
||
</view>
|
||
</view>
|
||
<view class="member-status">
|
||
<text class="status-text">{{memberStatusText}}</text>
|
||
<text class="expire-time" wx:if="{{memberInfo.endTime}}">
|
||
到期:{{memberInfo.endTime}}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
|
||
<view class="card-body">
|
||
<view class="progress-section" wx:if="{{memberInfo.memberLevel !== 'FREE'}}">
|
||
<text class="progress-label">会员有效期</text>
|
||
<view class="progress-bar">
|
||
<view class="progress-fill" style="width: {{memberProgress}}%"></view>
|
||
</view>
|
||
<text class="progress-text">剩余 {{remainingDays}} 天</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 功能菜单 -->
|
||
<view class="menu-section">
|
||
<view class="menu-item" bindtap="onRenewMember">
|
||
<icon class="menu-icon" type="success" size="20"></icon>
|
||
<text class="menu-text">续费会员</text>
|
||
<icon class="arrow-icon" type="arrow" size="16"></icon>
|
||
</view>
|
||
|
||
<view class="menu-item" bindtap="onViewBenefits">
|
||
<icon class="menu-icon" type="info" size="20"></icon>
|
||
<text class="menu-text">权益说明</text>
|
||
<icon class="arrow-icon" type="arrow" size="16"></icon>
|
||
</view>
|
||
|
||
<view class="menu-item" bindtap="onViewBindLog">
|
||
<icon class="menu-icon" type="search" size="20"></icon>
|
||
<text class="menu-text">绑定记录</text>
|
||
<icon class="arrow-icon" type="arrow" size="16"></icon>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 权益快览 -->
|
||
<view class="benefits-preview">
|
||
<view class="section-title">我的权益</view>
|
||
<view class="benefits-grid">
|
||
<view class="benefit-card" wx:for="{{benefits}}" wx:key="benefitCode">
|
||
<icon class="benefit-icon" type="{{item.isEnabled ? 'success' : 'cancel'}}" size="24"></icon>
|
||
<text class="benefit-name">{{item.benefitName}}</text>
|
||
<text class="benefit-value">{{item.benefitValue}}</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
```
|
||
|
||
### 6.3 组件设计
|
||
|
||
#### 6.3.1 会员卡片组件 (components/member-card/member-card.wxml)
|
||
|
||
```xml
|
||
<view class="member-card {{memberLevel}}">
|
||
<view class="card-background">
|
||
<image class="bg-pattern" src="/images/member-bg-{{memberLevel}}.png"></image>
|
||
</view>
|
||
|
||
<view class="card-content">
|
||
<view class="member-level">
|
||
<text class="level-text">{{levelText}}</text>
|
||
<text class="level-desc">{{levelDesc}}</text>
|
||
</view>
|
||
|
||
<view class="member-info">
|
||
<text class="member-id">会员ID: {{memberId}}</text>
|
||
<text class="valid-period" wx:if="{{endTime}}">
|
||
有效期至: {{endTime}}
|
||
</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
```
|
||
|
||
---
|
||
|
||
## 7. 开发脚本
|
||
|
||
### 7.1 小程序端脚本
|
||
|
||
#### 7.1.1 会员绑定页面逻辑 (pages/member/bind/bind.js)
|
||
|
||
```javascript
|
||
// pages/member/bind/bind.js
|
||
const app = getApp()
|
||
const api = require('../../../utils/api')
|
||
|
||
Page({
|
||
data: {
|
||
userInfo: {},
|
||
memberInfo: {},
|
||
orderId: '',
|
||
binding: false,
|
||
benefits: [],
|
||
memberLevelText: '普通用户'
|
||
},
|
||
|
||
onLoad(options) {
|
||
this.initPage()
|
||
this.loadMemberInfo()
|
||
this.loadBenefits()
|
||
},
|
||
|
||
// 初始化页面
|
||
initPage() {
|
||
const userInfo = app.globalData.userInfo
|
||
if (!userInfo) {
|
||
wx.redirectTo({
|
||
url: '/pages/login/login'
|
||
})
|
||
return
|
||
}
|
||
this.setData({ userInfo })
|
||
},
|
||
|
||
// 加载会员信息
|
||
async loadMemberInfo() {
|
||
try {
|
||
wx.showLoading({ title: '加载中...' })
|
||
|
||
const res = await api.getMemberInfo()
|
||
if (res.code === 200) {
|
||
const memberInfo = res.data
|
||
const memberLevelText = this.getMemberLevelText(memberInfo.memberLevel)
|
||
|
||
this.setData({
|
||
memberInfo,
|
||
memberLevelText
|
||
})
|
||
}
|
||
} catch (error) {
|
||
console.error('加载会员信息失败:', error)
|
||
wx.showToast({
|
||
title: '加载失败',
|
||
icon: 'error'
|
||
})
|
||
} finally {
|
||
wx.hideLoading()
|
||
}
|
||
},
|
||
|
||
// 加载权益信息
|
||
async loadBenefits() {
|
||
try {
|
||
const res = await api.getMemberBenefits()
|
||
if (res.code === 200) {
|
||
this.setData({
|
||
benefits: res.data.benefits
|
||
})
|
||
}
|
||
} catch (error) {
|
||
console.error('加载权益信息失败:', error)
|
||
}
|
||
},
|
||
|
||
// 订单号输入
|
||
onOrderIdInput(e) {
|
||
this.setData({
|
||
orderId: e.detail.value.trim()
|
||
})
|
||
},
|
||
|
||
// 绑定会员
|
||
async onBindMember() {
|
||
const { orderId } = this.data
|
||
|
||
if (!orderId) {
|
||
wx.showToast({
|
||
title: '请输入订单号',
|
||
icon: 'error'
|
||
})
|
||
return
|
||
}
|
||
|
||
try {
|
||
this.setData({ binding: true })
|
||
wx.showLoading({ title: '绑定中...' })
|
||
|
||
const res = await api.bindMember({
|
||
orderId: orderId
|
||
})
|
||
|
||
if (res.code === 200) {
|
||
wx.showToast({
|
||
title: '绑定成功',
|
||
icon: 'success'
|
||
})
|
||
|
||
// 刷新会员信息
|
||
setTimeout(() => {
|
||
this.loadMemberInfo()
|
||
}, 1500)
|
||
|
||
// 清空订单号
|
||
this.setData({ orderId: '' })
|
||
} else {
|
||
wx.showToast({
|
||
title: res.message || '绑定失败',
|
||
icon: 'error'
|
||
})
|
||
}
|
||
} catch (error) {
|
||
console.error('绑定会员失败:', error)
|
||
wx.showToast({
|
||
title: '绑定失败',
|
||
icon: 'error'
|
||
})
|
||
} finally {
|
||
this.setData({ binding: false })
|
||
wx.hideLoading()
|
||
}
|
||
},
|
||
|
||
// 查看更多权益
|
||
onViewMoreBenefits() {
|
||
wx.navigateTo({
|
||
url: '/pages/member/benefits/benefits'
|
||
})
|
||
},
|
||
|
||
// 获取会员等级文本
|
||
getMemberLevelText(level) {
|
||
const levelMap = {
|
||
'FREE': '普通用户',
|
||
'VIP': 'VIP会员',
|
||
'SVIP': 'SVIP会员'
|
||
}
|
||
return levelMap[level] || '普通用户'
|
||
}
|
||
})
|
||
```
|
||
|
||
#### 7.1.2 API工具类 (utils/api.js)
|
||
|
||
```javascript
|
||
// utils/api.js
|
||
const config = require('./config')
|
||
|
||
class ApiService {
|
||
constructor() {
|
||
this.baseUrl = config.apiBaseUrl
|
||
this.token = wx.getStorageSync('token') || ''
|
||
}
|
||
|
||
// 通用请求方法
|
||
request(options) {
|
||
return new Promise((resolve, reject) => {
|
||
wx.request({
|
||
url: this.baseUrl + options.url,
|
||
method: options.method || 'GET',
|
||
data: options.data || {},
|
||
header: {
|
||
'Content-Type': 'application/json',
|
||
'Authorization': this.token ? `Bearer ${this.token}` : '',
|
||
...options.header
|
||
},
|
||
success: (res) => {
|
||
if (res.statusCode === 200) {
|
||
resolve(res.data)
|
||
} else if (res.statusCode === 401) {
|
||
// token过期,跳转登录
|
||
wx.removeStorageSync('token')
|
||
wx.redirectTo({
|
||
url: '/pages/login/login'
|
||
})
|
||
reject(new Error('登录已过期'))
|
||
} else {
|
||
reject(new Error(`请求失败: ${res.statusCode}`))
|
||
}
|
||
},
|
||
fail: (error) => {
|
||
reject(error)
|
||
}
|
||
})
|
||
})
|
||
}
|
||
|
||
// 用户登录
|
||
login(data) {
|
||
return this.request({
|
||
url: '/api/member/login',
|
||
method: 'POST',
|
||
data
|
||
})
|
||
}
|
||
|
||
// 获取会员信息
|
||
getMemberInfo() {
|
||
return this.request({
|
||
url: '/api/member/info'
|
||
})
|
||
}
|
||
|
||
// 绑定会员
|
||
bindMember(data) {
|
||
return this.request({
|
||
url: '/api/member/bind',
|
||
method: 'POST',
|
||
data
|
||
})
|
||
}
|
||
|
||
// 获取会员权益
|
||
getMemberBenefits(memberLevel) {
|
||
const url = memberLevel
|
||
? `/api/member/benefits?memberLevel=${memberLevel}`
|
||
: '/api/member/benefits'
|
||
|
||
return this.request({
|
||
url
|
||
})
|
||
}
|
||
|
||
// 验证权益
|
||
verifyBenefit(data) {
|
||
return this.request({
|
||
url: '/api/member/verify-benefit',
|
||
method: 'POST',
|
||
data
|
||
})
|
||
}
|
||
|
||
// 更新token
|
||
setToken(token) {
|
||
this.token = token
|
||
wx.setStorageSync('token', token)
|
||
}
|
||
}
|
||
|
||
module.exports = new ApiService()
|
||
```
|
||
|
||
### 7.2 服务端脚本
|
||
|
||
#### 7.2.1 会员服务类 (MemberService.java)
|
||
|
||
```java
|
||
package com.xiaozhi.plus.service.impl;
|
||
|
||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||
import com.xiaozhi.plus.entity.MemberInfo;
|
||
import com.xiaozhi.plus.entity.MemberBindLog;
|
||
import com.xiaozhi.plus.entity.MemberBenefitConfig;
|
||
import com.xiaozhi.plus.mapper.MemberInfoMapper;
|
||
import com.xiaozhi.plus.mapper.MemberBindLogMapper;
|
||
import com.xiaozhi.plus.mapper.MemberBenefitConfigMapper;
|
||
import com.xiaozhi.plus.service.MemberService;
|
||
import com.xiaozhi.plus.dto.MemberBindRequest;
|
||
import com.xiaozhi.plus.dto.MemberInfoResponse;
|
||
import com.xiaozhi.plus.utils.IdGenerator;
|
||
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 MemberServiceImpl extends ServiceImpl<MemberInfoMapper, MemberInfo> implements MemberService {
|
||
|
||
@Autowired
|
||
private MemberInfoMapper memberInfoMapper;
|
||
|
||
@Autowired
|
||
private MemberBindLogMapper memberBindLogMapper;
|
||
|
||
@Autowired
|
||
private MemberBenefitConfigMapper memberBenefitConfigMapper;
|
||
|
||
@Override
|
||
public MemberInfoResponse getMemberInfo(String openid) {
|
||
MemberInfo memberInfo = memberInfoMapper.selectOne(
|
||
new QueryWrapper<MemberInfo>()
|
||
.eq("openid", openid)
|
||
.eq("deleted", 0)
|
||
);
|
||
|
||
if (memberInfo == null) {
|
||
// 创建免费用户
|
||
memberInfo = createFreeMember(openid);
|
||
}
|
||
|
||
// 检查会员是否过期
|
||
checkMemberExpiry(memberInfo);
|
||
|
||
// 获取会员权益
|
||
List<MemberBenefitConfig> benefits = getMemberBenefits(memberInfo.getMemberLevel());
|
||
|
||
return MemberInfoResponse.builder()
|
||
.memberId(memberInfo.getMemberId())
|
||
.memberLevel(memberInfo.getMemberLevel())
|
||
.memberStatus(memberInfo.getMemberStatus())
|
||
.startTime(memberInfo.getStartTime())
|
||
.endTime(memberInfo.getEndTime())
|
||
.autoRenew(memberInfo.getAutoRenew())
|
||
.benefits(benefits)
|
||
.build();
|
||
}
|
||
|
||
@Override
|
||
@Transactional
|
||
public boolean bindMember(String openid, MemberBindRequest request) {
|
||
// 验证订单有效性
|
||
if (!validateOrder(request.getOrderId())) {
|
||
throw new RuntimeException("订单验证失败");
|
||
}
|
||
|
||
// 获取或创建会员信息
|
||
MemberInfo memberInfo = memberInfoMapper.selectOne(
|
||
new QueryWrapper<MemberInfo>()
|
||
.eq("openid", openid)
|
||
.eq("deleted", 0)
|
||
);
|
||
|
||
String oldLevel = null;
|
||
if (memberInfo == null) {
|
||
memberInfo = new MemberInfo();
|
||
memberInfo.setMemberId(IdGenerator.generateMemberId());
|
||
memberInfo.setOpenid(openid);
|
||
memberInfo.setMemberLevel("FREE");
|
||
memberInfo.setMemberStatus("ACTIVE");
|
||
memberInfo.setCreateTime(LocalDateTime.now());
|
||
} else {
|
||
oldLevel = memberInfo.getMemberLevel();
|
||
}
|
||
|
||
// 更新会员信息
|
||
memberInfo.setMemberLevel(request.getMemberLevel());
|
||
memberInfo.setMemberStatus("ACTIVE");
|
||
memberInfo.setStartTime(LocalDateTime.now());
|
||
memberInfo.setEndTime(calculateEndTime(request.getDuration(), request.getDurationUnit()));
|
||
memberInfo.setPurchaseOrderId(request.getOrderId());
|
||
memberInfo.setUpdateTime(LocalDateTime.now());
|
||
|
||
// 保存会员信息
|
||
if (oldLevel == null) {
|
||
memberInfoMapper.insert(memberInfo);
|
||
} else {
|
||
memberInfoMapper.updateById(memberInfo);
|
||
}
|
||
|
||
// 记录绑定日志
|
||
recordBindLog(memberInfo, oldLevel, "PURCHASE", request.getOrderId());
|
||
|
||
return true;
|
||
}
|
||
|
||
@Override
|
||
public List<MemberBenefitConfig> getMemberBenefits(String memberLevel) {
|
||
return memberBenefitConfigMapper.selectList(
|
||
new QueryWrapper<MemberBenefitConfig>()
|
||
.eq("member_level", memberLevel)
|
||
.eq("is_enabled", 1)
|
||
.orderByAsc("sort_order")
|
||
);
|
||
}
|
||
|
||
@Override
|
||
public boolean verifyBenefit(String openid, String benefitCode, Integer requestCount) {
|
||
MemberInfo memberInfo = memberInfoMapper.selectOne(
|
||
new QueryWrapper<MemberInfo>()
|
||
.eq("openid", openid)
|
||
.eq("deleted", 0)
|
||
);
|
||
|
||
if (memberInfo == null) {
|
||
return false;
|
||
}
|
||
|
||
// 检查会员状态
|
||
if (!"ACTIVE".equals(memberInfo.getMemberStatus())) {
|
||
return false;
|
||
}
|
||
|
||
// 检查是否过期
|
||
if (memberInfo.getEndTime() != null && memberInfo.getEndTime().isBefore(LocalDateTime.now())) {
|
||
return false;
|
||
}
|
||
|
||
// 检查权益配置
|
||
MemberBenefitConfig benefitConfig = memberBenefitConfigMapper.selectOne(
|
||
new QueryWrapper<MemberBenefitConfig>()
|
||
.eq("member_level", memberInfo.getMemberLevel())
|
||
.eq("benefit_code", benefitCode)
|
||
.eq("is_enabled", 1)
|
||
);
|
||
|
||
return benefitConfig != null;
|
||
}
|
||
|
||
private MemberInfo createFreeMember(String openid) {
|
||
MemberInfo memberInfo = new MemberInfo();
|
||
memberInfo.setMemberId(IdGenerator.generateMemberId());
|
||
memberInfo.setOpenid(openid);
|
||
memberInfo.setMemberLevel("FREE");
|
||
memberInfo.setMemberStatus("ACTIVE");
|
||
memberInfo.setCreateTime(LocalDateTime.now());
|
||
|
||
memberInfoMapper.insert(memberInfo);
|
||
return memberInfo;
|
||
}
|
||
|
||
private void checkMemberExpiry(MemberInfo memberInfo) {
|
||
if (memberInfo.getEndTime() != null &&
|
||
memberInfo.getEndTime().isBefore(LocalDateTime.now()) &&
|
||
!"EXPIRED".equals(memberInfo.getMemberStatus())) {
|
||
|
||
memberInfo.setMemberStatus("EXPIRED");
|
||
memberInfoMapper.updateById(memberInfo);
|
||
}
|
||
}
|
||
|
||
private LocalDateTime calculateEndTime(Integer duration, String durationUnit) {
|
||
LocalDateTime now = LocalDateTime.now();
|
||
switch (durationUnit.toUpperCase()) {
|
||
case "DAY":
|
||
return now.plusDays(duration);
|
||
case "MONTH":
|
||
return now.plusMonths(duration);
|
||
case "YEAR":
|
||
return now.plusYears(duration);
|
||
default:
|
||
throw new IllegalArgumentException("不支持的时间单位: " + durationUnit);
|
||
}
|
||
}
|
||
|
||
private void recordBindLog(MemberInfo memberInfo, String oldLevel, String bindSource, String orderId) {
|
||
MemberBindLog bindLog = new MemberBindLog();
|
||
bindLog.setMemberId(memberInfo.getMemberId());
|
||
bindLog.setOpenid(memberInfo.getOpenid());
|
||
bindLog.setBindType(oldLevel == null ? "BIND" : "UPGRADE");
|
||
bindLog.setOldLevel(oldLevel);
|
||
bindLog.setNewLevel(memberInfo.getMemberLevel());
|
||
bindLog.setBindSource(bindSource);
|
||
bindLog.setRelatedOrderId(orderId);
|
||
bindLog.setBindTime(LocalDateTime.now());
|
||
|
||
memberBindLogMapper.insert(bindLog);
|
||
}
|
||
|
||
private boolean validateOrder(String orderId) {
|
||
// TODO: 实现订单验证逻辑
|
||
// 1. 检查订单是否存在
|
||
// 2. 检查订单是否已支付
|
||
// 3. 检查订单是否已绑定
|
||
return true;
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 7.2.2 会员控制器 (MemberController.java)
|
||
|
||
```java
|
||
package com.xiaozhi.plus.controller;
|
||
|
||
import com.xiaozhi.plus.service.MemberService;
|
||
import com.xiaozhi.plus.dto.MemberBindRequest;
|
||
import com.xiaozhi.plus.dto.MemberInfoResponse;
|
||
import com.xiaozhi.plus.dto.BenefitVerifyRequest;
|
||
import com.xiaozhi.plus.entity.MemberBenefitConfig;
|
||
import com.xiaozhi.plus.utils.Result;
|
||
import com.xiaozhi.plus.utils.JwtUtil;
|
||
import org.springframework.beans.factory.annotation.Autowired;
|
||
import org.springframework.web.bind.annotation.*;
|
||
|
||
import javax.servlet.http.HttpServletRequest;
|
||
import java.util.List;
|
||
import java.util.Map;
|
||
|
||
@RestController
|
||
@RequestMapping("/api/member")
|
||
public class MemberController {
|
||
|
||
@Autowired
|
||
private MemberService memberService;
|
||
|
||
@Autowired
|
||
private JwtUtil jwtUtil;
|
||
|
||
/**
|
||
* 获取会员信息
|
||
*/
|
||
@GetMapping("/info")
|
||
public Result<MemberInfoResponse> getMemberInfo(HttpServletRequest request) {
|
||
try {
|
||
String openid = getOpenidFromToken(request);
|
||
MemberInfoResponse memberInfo = memberService.getMemberInfo(openid);
|
||
return Result.success(memberInfo);
|
||
} catch (Exception e) {
|
||
return Result.error("获取会员信息失败: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 绑定会员
|
||
*/
|
||
@PostMapping("/bind")
|
||
public Result<String> bindMember(@RequestBody MemberBindRequest request, HttpServletRequest httpRequest) {
|
||
try {
|
||
String openid = getOpenidFromToken(httpRequest);
|
||
boolean success = memberService.bindMember(openid, request);
|
||
|
||
if (success) {
|
||
return Result.success("绑定成功");
|
||
} else {
|
||
return Result.error("绑定失败");
|
||
}
|
||
} catch (Exception e) {
|
||
return Result.error("绑定失败: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取会员权益
|
||
*/
|
||
@GetMapping("/benefits")
|
||
public Result<Map<String, Object>> getMemberBenefits(
|
||
@RequestParam(required = false) String memberLevel,
|
||
HttpServletRequest request) {
|
||
try {
|
||
String targetLevel = memberLevel;
|
||
if (targetLevel == null) {
|
||
String openid = getOpenidFromToken(request);
|
||
MemberInfoResponse memberInfo = memberService.getMemberInfo(openid);
|
||
targetLevel = memberInfo.getMemberLevel();
|
||
}
|
||
|
||
List<MemberBenefitConfig> benefits = memberService.getMemberBenefits(targetLevel);
|
||
|
||
Map<String, Object> result = Map.of(
|
||
"memberLevel", targetLevel,
|
||
"benefits", benefits
|
||
);
|
||
|
||
return Result.success(result);
|
||
} catch (Exception e) {
|
||
return Result.error("获取权益信息失败: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 验证权益
|
||
*/
|
||
@PostMapping("/verify-benefit")
|
||
public Result<Map<String, Object>> verifyBenefit(
|
||
@RequestBody BenefitVerifyRequest request,
|
||
HttpServletRequest httpRequest) {
|
||
try {
|
||
String openid = getOpenidFromToken(httpRequest);
|
||
boolean hasPermission = memberService.verifyBenefit(
|
||
openid,
|
||
request.getBenefitCode(),
|
||
request.getRequestCount()
|
||
);
|
||
|
||
Map<String, Object> result = Map.of(
|
||
"hasPermission", hasPermission,
|
||
"remainingCount", hasPermission ? "unlimited" : "0",
|
||
"resetTime", null
|
||
);
|
||
|
||
return Result.success(result);
|
||
} catch (Exception e) {
|
||
return Result.error("权益验证失败: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
private String getOpenidFromToken(HttpServletRequest request) {
|
||
String token = request.getHeader("Authorization");
|
||
if (token != null && token.startsWith("Bearer ")) {
|
||
token = token.substring(7);
|
||
return jwtUtil.getOpenidFromToken(token);
|
||
}
|
||
throw new RuntimeException("无效的token");
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 8. 测试用例设计
|
||
|
||
### 8.1 功能测试用例
|
||
|
||
#### 8.1.1 用户登录测试
|
||
|
||
| 测试用例ID | 测试场景 | 测试步骤 | 预期结果 |
|
||
|------------|----------|----------|----------|
|
||
| TC_LOGIN_001 | 正常登录 | 1. 点击登录按钮<br>2. 微信授权成功<br>3. 获取用户信息 | 登录成功,获取到openid和用户信息 |
|
||
| TC_LOGIN_002 | 取消授权 | 1. 点击登录按钮<br>2. 取消微信授权 | 登录失败,提示授权失败 |
|
||
| TC_LOGIN_003 | 网络异常 | 1. 断网状态下登录<br>2. 点击登录按钮 | 登录失败,提示网络异常 |
|
||
|
||
#### 8.1.2 会员绑定测试
|
||
|
||
| 测试用例ID | 测试场景 | 测试步骤 | 预期结果 |
|
||
|------------|----------|----------|----------|
|
||
| TC_BIND_001 | 正常绑定VIP | 1. 输入有效VIP订单号<br>2. 点击绑定按钮 | 绑定成功,会员等级变为VIP |
|
||
| TC_BIND_002 | 正常绑定SVIP | 1. 输入有效SVIP订单号<br>2. 点击绑定按钮 | 绑定成功,会员等级变为SVIP |
|
||
| TC_BIND_003 | 无效订单号 | 1. 输入无效订单号<br>2. 点击绑定按钮 | 绑定失败,提示订单无效 |
|
||
| TC_BIND_004 | 空订单号 | 1. 不输入订单号<br>2. 点击绑定按钮 | 提示请输入订单号 |
|
||
| TC_BIND_005 | 重复绑定 | 1. 输入已绑定的订单号<br>2. 点击绑定按钮 | 绑定失败,提示订单已使用 |
|
||
|
||
#### 8.1.3 权益验证测试
|
||
|
||
| 测试用例ID | 测试场景 | 测试步骤 | 预期结果 |
|
||
|------------|----------|----------|----------|
|
||
| TC_BENEFIT_001 | VIP权益验证 | 1. VIP用户访问高级功能<br>2. 系统验证权益 | 验证通过,允许访问 |
|
||
| TC_BENEFIT_002 | 免费用户权益验证 | 1. 免费用户访问VIP功能<br>2. 系统验证权益 | 验证失败,提示升级会员 |
|
||
| TC_BENEFIT_003 | 过期会员权益验证 | 1. 过期VIP用户访问VIP功能<br>2. 系统验证权益 | 验证失败,提示续费 |
|
||
|
||
### 8.2 接口测试用例
|
||
|
||
#### 8.2.1 会员信息查询接口测试
|
||
|
||
```javascript
|
||
// 测试脚本示例
|
||
describe('会员信息查询接口测试', () => {
|
||
test('正常查询会员信息', async () => {
|
||
const response = await request(app)
|
||
.get('/api/member/info')
|
||
.set('Authorization', 'Bearer valid_token')
|
||
.expect(200);
|
||
|
||
expect(response.body.code).toBe(200);
|
||
expect(response.body.data).toHaveProperty('memberId');
|
||
expect(response.body.data).toHaveProperty('memberLevel');
|
||
});
|
||
|
||
test('无效token查询', async () => {
|
||
const response = await request(app)
|
||
.get('/api/member/info')
|
||
.set('Authorization', 'Bearer invalid_token')
|
||
.expect(401);
|
||
|
||
expect(response.body.code).toBe(401);
|
||
});
|
||
});
|
||
```
|
||
|
||
### 8.3 性能测试用例
|
||
|
||
| 测试项目 | 测试指标 | 预期值 | 测试方法 |
|
||
|----------|----------|--------|----------|
|
||
| 接口响应时间 | 平均响应时间 | <500ms | JMeter压力测试 |
|
||
| 并发处理能力 | 并发用户数 | 1000+ | 并发访问测试 |
|
||
| 数据库查询性能 | 查询响应时间 | <100ms | SQL性能测试 |
|
||
|
||
---
|
||
|
||
## 9. 部署和运维
|
||
|
||
### 9.1 部署环境要求
|
||
|
||
**服务器配置:**
|
||
- CPU: 4核心以上
|
||
- 内存: 8GB以上
|
||
- 存储: 100GB以上SSD
|
||
- 网络: 100Mbps以上带宽
|
||
|
||
**软件环境:**
|
||
- 操作系统: CentOS 7.6+
|
||
- Java: JDK 1.8+
|
||
- 数据库: MySQL 8.0+
|
||
- 缓存: Redis 6.0+
|
||
- Web服务器: Nginx 1.18+
|
||
|
||
### 9.2 部署步骤
|
||
|
||
1. **数据库初始化**
|
||
```bash
|
||
mysql -u root -p < db/member_tables.sql
|
||
```
|
||
|
||
2. **应用部署**
|
||
```bash
|
||
# 构建应用
|
||
mvn clean package -Dmaven.test.skip=true
|
||
|
||
# 部署应用
|
||
java -jar xiaozhi-server.jar --spring.profiles.active=prod
|
||
```
|
||
|
||
3. **Nginx配置**
|
||
```nginx
|
||
server {
|
||
listen 443 ssl;
|
||
server_name api.xiaozhi.com;
|
||
|
||
location /api/member/ {
|
||
proxy_pass http://localhost:8091;
|
||
proxy_set_header Host $host;
|
||
proxy_set_header X-Real-IP $remote_addr;
|
||
}
|
||
}
|
||
```
|
||
|
||
### 9.3 监控和日志
|
||
|
||
**监控指标:**
|
||
- 接口响应时间
|
||
- 错误率统计
|
||
- 数据库连接数
|
||
- 内存使用率
|
||
|
||
**日志配置:**
|
||
```yaml
|
||
logging:
|
||
level:
|
||
com.xiaozhi.plus.service.MemberService: INFO
|
||
file:
|
||
name: /var/log/xiaozhi/member.log
|
||
max-size: 100MB
|
||
max-history: 30
|
||
```
|
||
|
||
---
|
||
|
||
## 10. 风险评估和应对策略
|
||
|
||
### 10.1 技术风险
|
||
|
||
| 风险项目 | 风险等级 | 影响描述 | 应对策略 |
|
||
|----------|----------|----------|----------|
|
||
| 微信API变更 | 中 | 接口不兼容 | 定期检查API文档,及时适配 |
|
||
| 数据库性能 | 中 | 查询缓慢 | 优化索引,使用缓存 |
|
||
| 并发安全 | 高 | 数据不一致 | 使用分布式锁,事务控制 |
|
||
|
||
### 10.2 业务风险
|
||
|
||
| 风险项目 | 风险等级 | 影响描述 | 应对策略 |
|
||
|----------|----------|----------|----------|
|
||
| 恶意绑定 | 高 | 订单被盗用 | 增强订单验证,限制绑定频率 |
|
||
| 权益滥用 | 中 | 超出预期使用 | 设置使用限制,监控异常 |
|
||
| 数据泄露 | 高 | 用户信息泄露 | 数据加密,访问控制 |
|
||
|
||
---
|
||
|
||
## 11. 项目计划和里程碑
|
||
|
||
### 11.1 开发计划
|
||
|
||
| 阶段 | 任务 | 工期 | 负责人 |
|
||
|------|------|------|--------|
|
||
| **第1周** | 数据库设计和API接口开发 | 5天 | 后端开发 |
|
||
| **第2周** | 小程序页面和组件开发 | 5天 | 前端开发 |
|
||
| **第3周** | 功能联调和测试 | 5天 | 全员 |
|
||
| **第4周** | 部署上线和优化 | 5天 | 运维+开发 |
|
||
|
||
### 11.2 里程碑
|
||
|
||
- **M1 (第1周末)**: 后端API开发完成
|
||
- **M2 (第2周末)**: 前端页面开发完成
|
||
- **M3 (第3周末)**: 功能测试通过
|
||
- **M4 (第4周末)**: 正式上线发布
|
||
|
||
---
|
||
|
||
## 12. 附录
|
||
|
||
### 12.1 相关文档
|
||
- [微信小程序开发文档](https://developers.weixin.qq.com/miniprogram/dev/)
|
||
- [微信支付API文档](https://pay.weixin.qq.com/wiki/doc/api/index.html)
|
||
- [Spring Boot官方文档](https://spring.io/projects/spring-boot)
|
||
|
||
### 12.2 联系方式
|
||
- **项目经理**: [姓名] - [邮箱] - [电话]
|
||
- **技术负责人**: [姓名] - [邮箱] - [电话]
|
||
- **测试负责人**: [姓名] - [邮箱] - [电话]
|
||
|
||
---
|
||
|
||
**文档结束**
|
||
|
||
> 📋 本需求规格说明书为微信小程序会员绑定系统的完整技术方案,包含了从需求分析到部署上线的全流程内容。请各相关人员严格按照本文档执行开发和测试工作。 |