小程序开发文档
This commit is contained in:
parent
9f8df3061a
commit
501bdcc999
101
uniapp/README.md
Normal file
101
uniapp/README.md
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
# 学业邑规划 - 小程序前端
|
||||
|
||||
## 项目概述
|
||||
|
||||
基于 UniApp + Vue 3 + TypeScript 开发的微信小程序,提供多元智能测评和学业规划服务。
|
||||
|
||||
## 技术栈
|
||||
|
||||
| 技术 | 版本 | 说明 |
|
||||
|------|------|------|
|
||||
| UniApp | 3.x | 跨平台框架 |
|
||||
| Vue | 3.x | 前端框架 |
|
||||
| TypeScript | 5.x | 类型系统 |
|
||||
| Pinia | 2.x | 状态管理 |
|
||||
| uni-ui | latest | UI 组件库 |
|
||||
| Sass | latest | CSS 预处理器 |
|
||||
|
||||
## 快速开始
|
||||
|
||||
```bash
|
||||
# 安装依赖
|
||||
npm install
|
||||
|
||||
# 开发模式(微信小程序)
|
||||
npm run dev:mp-weixin
|
||||
|
||||
# 构建生产版本
|
||||
npm run build:mp-weixin
|
||||
```
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
uniapp/
|
||||
├── src/
|
||||
│ ├── api/ # API 接口
|
||||
│ │ ├── request.ts # 请求封装
|
||||
│ │ ├── user.ts # 用户接口
|
||||
│ │ ├── home.ts # 首页接口
|
||||
│ │ ├── assessment.ts # 测评接口
|
||||
│ │ ├── order.ts # 订单接口
|
||||
│ │ ├── planner.ts # 规划师接口
|
||||
│ │ └── invite.ts # 分销接口
|
||||
│ ├── components/ # 公共组件
|
||||
│ │ ├── common/ # 通用组件
|
||||
│ │ └── business/ # 业务组件
|
||||
│ ├── composables/ # 组合式函数
|
||||
│ │ ├── useAuth.ts # 认证相关
|
||||
│ │ ├── usePayment.ts # 支付相关
|
||||
│ │ └── useShare.ts # 分享相关
|
||||
│ ├── pages/ # 页面
|
||||
│ │ ├── index/ # 首页(TabBar)
|
||||
│ │ ├── team/ # 团队(TabBar)
|
||||
│ │ ├── mine/ # 我的(TabBar)
|
||||
│ │ ├── login/ # 登录
|
||||
│ │ ├── assessment/ # 测评相关
|
||||
│ │ ├── order/ # 订单相关
|
||||
│ │ ├── planner/ # 学业规划
|
||||
│ │ ├── invite/ # 邀请分销
|
||||
│ │ └── about/ # 关于/协议
|
||||
│ ├── static/ # 静态资源
|
||||
│ │ ├── images/ # 图片
|
||||
│ │ └── icons/ # 图标
|
||||
│ ├── stores/ # Pinia 状态管理
|
||||
│ │ ├── user.ts # 用户状态
|
||||
│ │ └── app.ts # 应用状态
|
||||
│ ├── styles/ # 全局样式
|
||||
│ │ ├── variables.scss # 变量定义
|
||||
│ │ ├── mixins.scss # 混入
|
||||
│ │ └── common.scss # 通用样式
|
||||
│ ├── types/ # 类型定义
|
||||
│ │ ├── api.d.ts # API 类型
|
||||
│ │ ├── user.d.ts # 用户类型
|
||||
│ │ └── assessment.d.ts # 测评类型
|
||||
│ ├── utils/ # 工具函数
|
||||
│ │ ├── storage.ts # 本地存储
|
||||
│ │ ├── format.ts # 格式化
|
||||
│ │ └── validate.ts # 验证
|
||||
│ ├── App.vue # 根组件
|
||||
│ ├── main.ts # 入口文件
|
||||
│ ├── manifest.json # 应用配置
|
||||
│ ├── pages.json # 页面配置
|
||||
│ └── uni.scss # uni-app 样式变量
|
||||
├── package.json
|
||||
├── tsconfig.json
|
||||
├── vite.config.ts
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## 相关文档
|
||||
|
||||
- [开发规范](./docs/开发规范.md)
|
||||
- [页面清单](./docs/页面清单.md)
|
||||
- [组件文档](./docs/组件文档.md)
|
||||
- [API 文档](./docs/API文档.md)
|
||||
|
||||
## 设计资源
|
||||
|
||||
- Figma 设计图:https://www.figma.com/design/88edYGASUcyID6afiwILdf/项目?node-id=432-1991
|
||||
- 本地设计图:`docs/设计图/`
|
||||
- 切图资源:`docs/切图/`
|
||||
920
uniapp/docs/API文档.md
Normal file
920
uniapp/docs/API文档.md
Normal file
|
|
@ -0,0 +1,920 @@
|
|||
# 学业邑规划 - 小程序 API 文档
|
||||
|
||||
本文档定义了小程序端调用的所有后端接口。
|
||||
|
||||
---
|
||||
|
||||
## 一、接口规范
|
||||
|
||||
### 1.1 基础信息
|
||||
|
||||
| 项目 | 说明 |
|
||||
|------|------|
|
||||
| 基础地址 | 开发环境:`http://localhost:5000`<br>生产环境:`https://api.example.com` |
|
||||
| 请求方式 | GET / POST |
|
||||
| 数据格式 | JSON |
|
||||
| 认证方式 | Bearer Token |
|
||||
|
||||
### 1.2 请求头
|
||||
|
||||
```
|
||||
Content-Type: application/json
|
||||
Authorization: Bearer {token}
|
||||
```
|
||||
|
||||
### 1.3 响应格式
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "success",
|
||||
"data": {}
|
||||
}
|
||||
```
|
||||
|
||||
### 1.4 错误码
|
||||
|
||||
| 错误码 | 说明 |
|
||||
|--------|------|
|
||||
| 0 | 成功 |
|
||||
| 1001 | 参数错误 |
|
||||
| 1002 | 未登录 |
|
||||
| 1003 | 登录已过期 |
|
||||
| 1004 | 无权限 |
|
||||
| 2001 | 业务错误 |
|
||||
| 5000 | 系统错误 |
|
||||
|
||||
---
|
||||
|
||||
## 二、用户模块
|
||||
|
||||
### 2.1 微信登录
|
||||
|
||||
**接口**:`POST /api/user/login`
|
||||
|
||||
**描述**:微信小程序登录
|
||||
|
||||
**请求参数**:
|
||||
```typescript
|
||||
interface LoginRequest {
|
||||
/** 微信 code */
|
||||
code: string
|
||||
/** 加密手机号数据 */
|
||||
encryptedData: string
|
||||
/** 加密向量 */
|
||||
iv: string
|
||||
/** 邀请人ID(可选) */
|
||||
inviteUserId?: number
|
||||
}
|
||||
```
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface LoginResponse {
|
||||
/** 访问令牌 */
|
||||
token: string
|
||||
/** 刷新令牌 */
|
||||
refreshToken: string
|
||||
/** 用户信息 */
|
||||
userInfo: UserInfo
|
||||
}
|
||||
|
||||
interface UserInfo {
|
||||
id: number
|
||||
uid: string
|
||||
nickname: string
|
||||
avatar: string
|
||||
phone: string
|
||||
userLevel: number // 1普通用户 2合伙人 3渠道合伙人
|
||||
createTime: string
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.2 获取用户信息
|
||||
|
||||
**接口**:`GET /api/user/getProfile`
|
||||
|
||||
**描述**:获取当前登录用户信息
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface UserInfo {
|
||||
id: number
|
||||
uid: string
|
||||
nickname: string
|
||||
avatar: string
|
||||
phone: string
|
||||
userLevel: number
|
||||
balance: number // 可提现余额
|
||||
totalIncome: number // 累计收益
|
||||
createTime: string
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.3 更新用户信息
|
||||
|
||||
**接口**:`POST /api/user/updateProfile`
|
||||
|
||||
**描述**:更新用户昵称
|
||||
|
||||
**请求参数**:
|
||||
```typescript
|
||||
interface UpdateProfileRequest {
|
||||
nickname: string
|
||||
}
|
||||
```
|
||||
|
||||
**响应数据**:`boolean`
|
||||
|
||||
---
|
||||
|
||||
### 2.4 更新头像
|
||||
|
||||
**接口**:`POST /api/user/updateAvatar`
|
||||
|
||||
**描述**:更新用户头像
|
||||
|
||||
**请求参数**:
|
||||
```typescript
|
||||
interface UpdateAvatarRequest {
|
||||
/** 头像文件(Base64 或 URL) */
|
||||
avatar: string
|
||||
}
|
||||
```
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface UpdateAvatarResponse {
|
||||
/** 新头像 URL */
|
||||
avatarUrl: string
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、首页模块
|
||||
|
||||
### 3.1 获取 Banner 列表
|
||||
|
||||
**接口**:`GET /api/home/getBannerList`
|
||||
|
||||
**描述**:获取首页轮播图列表
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface BannerItem {
|
||||
id: number
|
||||
title: string
|
||||
imageUrl: string
|
||||
linkType: number // 0无跳转 1内部页面 2外部链接 3小程序
|
||||
linkUrl: string
|
||||
appId?: string // 小程序 AppId
|
||||
}
|
||||
|
||||
type Response = BannerItem[]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.2 获取测评入口列表
|
||||
|
||||
**接口**:`GET /api/home/getAssessmentList`
|
||||
|
||||
**描述**:获取测评类型列表
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface AssessmentType {
|
||||
id: number
|
||||
name: string
|
||||
code: string
|
||||
imageUrl: string
|
||||
price: number
|
||||
status: number // 0已下线 1已上线 2即将上线
|
||||
}
|
||||
|
||||
type Response = AssessmentType[]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.3 获取宣传图列表
|
||||
|
||||
**接口**:`GET /api/home/getPromotionList`
|
||||
|
||||
**描述**:获取首页底部宣传图
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface PromotionItem {
|
||||
id: number
|
||||
title: string
|
||||
imageUrl: string
|
||||
}
|
||||
|
||||
type Response = PromotionItem[]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、团队模块
|
||||
|
||||
### 4.1 获取团队介绍
|
||||
|
||||
**接口**:`GET /api/team/getInfo`
|
||||
|
||||
**描述**:获取团队介绍图片
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface TeamInfo {
|
||||
images: string[] // 图片列表
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、测评模块
|
||||
|
||||
### 5.1 获取测评介绍
|
||||
|
||||
**接口**:`GET /api/assessment/getIntro`
|
||||
|
||||
**描述**:获取测评介绍内容(基本信息页顶部)
|
||||
|
||||
**请求参数**:
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| typeId | number | 是 | 测评类型ID |
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface AssessmentIntro {
|
||||
/** 介绍内容(富文本或图片URL) */
|
||||
content: string
|
||||
/** 内容类型:text / image */
|
||||
contentType: string
|
||||
/** 测评价格 */
|
||||
price: number
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5.2 获取题目列表
|
||||
|
||||
**接口**:`GET /api/assessment/getQuestionList`
|
||||
|
||||
**描述**:获取测评题目列表
|
||||
|
||||
**请求参数**:
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| typeId | number | 是 | 测评类型ID |
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface Question {
|
||||
id: number
|
||||
questionNo: number
|
||||
content: string
|
||||
}
|
||||
|
||||
type Response = Question[]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5.3 提交测评答案
|
||||
|
||||
**接口**:`POST /api/assessment/submitAnswers`
|
||||
|
||||
**描述**:提交测评答案
|
||||
|
||||
**请求参数**:
|
||||
```typescript
|
||||
interface SubmitAnswersRequest {
|
||||
/** 测评记录ID */
|
||||
recordId: number
|
||||
/** 答案列表 */
|
||||
answers: {
|
||||
questionId: number
|
||||
answerValue: number // 1-10
|
||||
}[]
|
||||
}
|
||||
```
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface SubmitAnswersResponse {
|
||||
/** 是否提交成功 */
|
||||
success: boolean
|
||||
/** 报告预计生成时间(秒) */
|
||||
estimatedTime: number
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5.4 查询报告生成状态
|
||||
|
||||
**接口**:`GET /api/assessment/getResultStatus`
|
||||
|
||||
**描述**:查询测评报告生成状态
|
||||
|
||||
**请求参数**:
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| recordId | number | 是 | 测评记录ID |
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface ResultStatus {
|
||||
/** 状态:1待测评 2测评中 3生成中 4已完成 */
|
||||
status: number
|
||||
/** 是否完成 */
|
||||
isCompleted: boolean
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5.5 获取测评结果
|
||||
|
||||
**接口**:`GET /api/assessment/getResult`
|
||||
|
||||
**描述**:获取测评报告详情
|
||||
|
||||
**请求参数**:
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| recordId | number | 是 | 测评记录ID |
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface AssessmentResult {
|
||||
/** 基本信息 */
|
||||
basicInfo: {
|
||||
name: string
|
||||
age: number
|
||||
educationStage: string
|
||||
testDate: string
|
||||
}
|
||||
/** 八大智能分析 */
|
||||
intelligenceAnalysis: {
|
||||
items: IntelligenceItem[]
|
||||
topTwo: IntelligenceConclusion[]
|
||||
bottomTwo: IntelligenceConclusion[]
|
||||
}
|
||||
/** 个人特质分析 */
|
||||
traitAnalysis: {
|
||||
items: TraitItem[]
|
||||
topConclusion: string
|
||||
}
|
||||
/** 40项细分能力 */
|
||||
abilityAnalysis: {
|
||||
groups: AbilityGroup[]
|
||||
topTen: AbilityItem[]
|
||||
bottomTen: AbilityItem[]
|
||||
}
|
||||
/** 其他分析... */
|
||||
}
|
||||
|
||||
interface IntelligenceItem {
|
||||
name: string
|
||||
code: string
|
||||
score: number
|
||||
maxScore: number
|
||||
percentage: number
|
||||
rank: number
|
||||
}
|
||||
|
||||
interface IntelligenceConclusion {
|
||||
name: string
|
||||
rank: number
|
||||
rankName: string // 最强五星 / 较强五星 / 相对较弱
|
||||
conclusion: string
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5.6 验证邀请码
|
||||
|
||||
**接口**:`POST /api/assessment/verifyInviteCode`
|
||||
|
||||
**描述**:验证测评邀请码
|
||||
|
||||
**请求参数**:
|
||||
```typescript
|
||||
interface VerifyInviteCodeRequest {
|
||||
/** 邀请码(5位大写字母) */
|
||||
code: string
|
||||
}
|
||||
```
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface VerifyInviteCodeResponse {
|
||||
/** 是否有效 */
|
||||
isValid: boolean
|
||||
/** 错误信息(无效时) */
|
||||
errorMessage?: string // "邀请码有误" / "邀请码已被使用"
|
||||
/** 邀请码ID(有效时) */
|
||||
inviteCodeId?: number
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5.7 获取往期测评列表
|
||||
|
||||
**接口**:`GET /api/assessment/getHistoryList`
|
||||
|
||||
**描述**:获取用户的往期测评记录
|
||||
|
||||
**请求参数**:
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| page | number | 否 | 页码,默认1 |
|
||||
| pageSize | number | 否 | 每页数量,默认20 |
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface AssessmentHistory {
|
||||
id: number
|
||||
orderNo: string
|
||||
assessmentName: string
|
||||
status: number // 3生成中 4已完成
|
||||
statusText: string
|
||||
testDate: string
|
||||
}
|
||||
|
||||
interface PageResponse {
|
||||
list: AssessmentHistory[]
|
||||
total: number
|
||||
page: number
|
||||
pageSize: number
|
||||
totalPages: number
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、订单模块
|
||||
|
||||
### 6.1 获取订单列表
|
||||
|
||||
**接口**:`GET /api/order/getList`
|
||||
|
||||
**描述**:获取用户订单列表
|
||||
|
||||
**请求参数**:
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| page | number | 否 | 页码,默认1 |
|
||||
| pageSize | number | 否 | 每页数量,默认20 |
|
||||
| orderType | number | 否 | 订单类型:1测评 2学业规划 |
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface OrderItem {
|
||||
id: number
|
||||
orderNo: string
|
||||
orderType: number
|
||||
productName: string
|
||||
amount: number
|
||||
status: number
|
||||
statusText: string
|
||||
createTime: string
|
||||
/** 测评记录ID(测评订单) */
|
||||
assessmentRecordId?: number
|
||||
}
|
||||
|
||||
interface PageResponse {
|
||||
list: OrderItem[]
|
||||
total: number
|
||||
page: number
|
||||
pageSize: number
|
||||
totalPages: number
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6.2 获取订单详情
|
||||
|
||||
**接口**:`GET /api/order/getDetail`
|
||||
|
||||
**描述**:获取订单详情
|
||||
|
||||
**请求参数**:
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| orderId | number | 是 | 订单ID |
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface OrderDetail {
|
||||
id: number
|
||||
orderNo: string
|
||||
orderType: number
|
||||
productId: number
|
||||
productName: string
|
||||
amount: number
|
||||
payAmount: number
|
||||
payType: number
|
||||
status: number
|
||||
statusText: string
|
||||
payTime?: string
|
||||
createTime: string
|
||||
/** 测评相关 */
|
||||
assessmentRecord?: {
|
||||
id: number
|
||||
status: number
|
||||
name: string
|
||||
phone: string
|
||||
}
|
||||
/** 学业规划相关 */
|
||||
plannerBooking?: {
|
||||
id: number
|
||||
plannerName: string
|
||||
bookingDate: string
|
||||
bookingTime: string
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6.3 创建订单
|
||||
|
||||
**接口**:`POST /api/order/create`
|
||||
|
||||
**描述**:创建订单
|
||||
|
||||
**请求参数**:
|
||||
```typescript
|
||||
interface CreateOrderRequest {
|
||||
/** 订单类型:1测评 2学业规划 */
|
||||
orderType: number
|
||||
/** 商品ID(测评类型ID / 规划师ID) */
|
||||
productId: number
|
||||
/** 测评基本信息(测评订单必填) */
|
||||
assessmentInfo?: {
|
||||
name: string
|
||||
phone: string
|
||||
gender: number
|
||||
age: number
|
||||
educationStage: number
|
||||
province: string
|
||||
city: string
|
||||
district: string
|
||||
}
|
||||
/** 规划预约信息(学业规划订单必填) */
|
||||
plannerInfo?: {
|
||||
bookingDate: string
|
||||
bookingTime: string
|
||||
name: string
|
||||
phone: string
|
||||
gender: number
|
||||
grade: number
|
||||
majorName?: string
|
||||
scoreChinese?: number
|
||||
scoreMath?: number
|
||||
scoreEnglish?: number
|
||||
scorePhysics?: number
|
||||
scoreChemistry?: number
|
||||
scoreBiology?: number
|
||||
scoreGeography?: number
|
||||
scorePolitics?: number
|
||||
}
|
||||
/** 邀请码ID(使用邀请码时) */
|
||||
inviteCodeId?: number
|
||||
}
|
||||
```
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface CreateOrderResponse {
|
||||
/** 订单ID */
|
||||
orderId: number
|
||||
/** 订单编号 */
|
||||
orderNo: string
|
||||
/** 支付金额 */
|
||||
payAmount: number
|
||||
/** 是否需要支付(使用邀请码时为 false) */
|
||||
needPay: boolean
|
||||
/** 测评记录ID(测评订单) */
|
||||
assessmentRecordId?: number
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6.4 发起支付
|
||||
|
||||
**接口**:`POST /api/order/pay`
|
||||
|
||||
**描述**:发起微信支付
|
||||
|
||||
**请求参数**:
|
||||
```typescript
|
||||
interface PayRequest {
|
||||
/** 订单ID */
|
||||
orderId: number
|
||||
}
|
||||
```
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface PayResponse {
|
||||
/** 微信支付参数 */
|
||||
timeStamp: string
|
||||
nonceStr: string
|
||||
package: string
|
||||
signType: string
|
||||
paySign: string
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6.5 查询支付结果
|
||||
|
||||
**接口**:`GET /api/order/getPayResult`
|
||||
|
||||
**描述**:查询订单支付结果
|
||||
|
||||
**请求参数**:
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| orderId | number | 是 | 订单ID |
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface PayResult {
|
||||
/** 是否支付成功 */
|
||||
isPaid: boolean
|
||||
/** 订单状态 */
|
||||
status: number
|
||||
/** 测评记录ID(测评订单) */
|
||||
assessmentRecordId?: number
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、学业规划模块
|
||||
|
||||
### 7.1 获取规划师列表
|
||||
|
||||
**接口**:`GET /api/planner/getList`
|
||||
|
||||
**描述**:获取规划师列表
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface PlannerInfo {
|
||||
id: number
|
||||
name: string
|
||||
avatar: string
|
||||
introduction: string
|
||||
price: number
|
||||
}
|
||||
|
||||
type Response = PlannerInfo[]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 7.2 预约规划
|
||||
|
||||
**接口**:`POST /api/planner/book`
|
||||
|
||||
**描述**:预约学业规划(创建订单并支付)
|
||||
|
||||
**请求参数**:同 `创建订单` 接口的 `plannerInfo`
|
||||
|
||||
**响应数据**:同 `创建订单` 接口
|
||||
|
||||
---
|
||||
|
||||
## 八、分销模块
|
||||
|
||||
### 8.1 获取邀请信息
|
||||
|
||||
**接口**:`GET /api/invite/getInfo`
|
||||
|
||||
**描述**:获取邀请页面信息
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface InviteInfo {
|
||||
/** 邀请链接 */
|
||||
inviteUrl: string
|
||||
/** 邀请码 */
|
||||
inviteCode: string
|
||||
/** 已提现金额 */
|
||||
withdrawnAmount: number
|
||||
/** 待提现金额 */
|
||||
pendingAmount: number
|
||||
/** 邀请人数 */
|
||||
inviteCount: number
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 8.2 生成邀请二维码
|
||||
|
||||
**接口**:`GET /api/invite/getQrcode`
|
||||
|
||||
**描述**:生成邀请二维码图片
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface QrcodeResponse {
|
||||
/** 二维码图片 URL */
|
||||
qrcodeUrl: string
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 8.3 获取邀请记录
|
||||
|
||||
**接口**:`GET /api/invite/getRecordList`
|
||||
|
||||
**描述**:获取邀请记录列表
|
||||
|
||||
**请求参数**:
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| page | number | 否 | 页码 |
|
||||
| pageSize | number | 否 | 每页数量 |
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface InviteRecord {
|
||||
/** 用户ID */
|
||||
userId: number
|
||||
/** 用户昵称 */
|
||||
nickname: string
|
||||
/** 用户头像 */
|
||||
avatar: string
|
||||
/** 用户UID */
|
||||
uid: string
|
||||
/** 注册日期 */
|
||||
registerDate: string
|
||||
/** 贡献佣金 */
|
||||
commission: number
|
||||
}
|
||||
|
||||
interface PageResponse {
|
||||
list: InviteRecord[]
|
||||
total: number
|
||||
page: number
|
||||
pageSize: number
|
||||
totalPages: number
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 8.4 获取佣金信息
|
||||
|
||||
**接口**:`GET /api/invite/getCommission`
|
||||
|
||||
**描述**:获取佣金详情
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface CommissionInfo {
|
||||
/** 累计收益 */
|
||||
totalIncome: number
|
||||
/** 已提现 */
|
||||
withdrawnAmount: number
|
||||
/** 待提现 */
|
||||
pendingAmount: number
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 8.5 申请提现
|
||||
|
||||
**接口**:`POST /api/invite/applyWithdraw`
|
||||
|
||||
**描述**:申请提现
|
||||
|
||||
**请求参数**:
|
||||
```typescript
|
||||
interface ApplyWithdrawRequest {
|
||||
/** 提现金额(整数,最低1元) */
|
||||
amount: number
|
||||
}
|
||||
```
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface ApplyWithdrawResponse {
|
||||
/** 是否成功 */
|
||||
success: boolean
|
||||
/** 错误信息 */
|
||||
errorMessage?: string // "超出待提现金额"
|
||||
/** 提现单号 */
|
||||
withdrawalNo?: string
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 8.6 获取提现记录
|
||||
|
||||
**接口**:`GET /api/invite/getWithdrawList`
|
||||
|
||||
**描述**:获取提现记录列表
|
||||
|
||||
**请求参数**:
|
||||
| 参数 | 类型 | 必填 | 说明 |
|
||||
|------|------|------|------|
|
||||
| page | number | 否 | 页码 |
|
||||
| pageSize | number | 否 | 每页数量 |
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface WithdrawRecord {
|
||||
id: number
|
||||
withdrawalNo: string
|
||||
amount: number
|
||||
status: number // 1申请中 2提现中 3已提现 4已取消
|
||||
statusText: string
|
||||
createTime: string
|
||||
payTime?: string
|
||||
}
|
||||
|
||||
interface PageResponse {
|
||||
list: WithdrawRecord[]
|
||||
total: number
|
||||
page: number
|
||||
pageSize: number
|
||||
totalPages: number
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 九、系统模块
|
||||
|
||||
### 9.1 获取用户协议
|
||||
|
||||
**接口**:`GET /api/system/getAgreement`
|
||||
|
||||
**描述**:获取用户协议内容
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface AgreementResponse {
|
||||
/** 协议内容(富文本) */
|
||||
content: string
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 9.2 获取隐私政策
|
||||
|
||||
**接口**:`GET /api/system/getPrivacy`
|
||||
|
||||
**描述**:获取隐私政策内容
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface PrivacyResponse {
|
||||
/** 政策内容(富文本) */
|
||||
content: string
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 9.3 获取关于我们
|
||||
|
||||
**接口**:`GET /api/system/getAbout`
|
||||
|
||||
**描述**:获取关于我们内容
|
||||
|
||||
**响应数据**:
|
||||
```typescript
|
||||
interface AboutResponse {
|
||||
/** 内容(富文本) */
|
||||
content: string
|
||||
/** 版本号 */
|
||||
version: string
|
||||
}
|
||||
```
|
||||
895
uniapp/docs/开发规范.md
Normal file
895
uniapp/docs/开发规范.md
Normal file
|
|
@ -0,0 +1,895 @@
|
|||
# 学业邑规划 - 小程序开发规范
|
||||
|
||||
本文档定义了小程序前端的开发规范和编码标准,所有开发工作必须遵循这些规范。
|
||||
|
||||
---
|
||||
|
||||
## 一、命名规范
|
||||
|
||||
### 1.1 文件命名
|
||||
|
||||
| 类型 | 规范 | 示例 |
|
||||
|------|------|------|
|
||||
| 页面文件夹 | kebab-case | `assessment-info/`, `order-list/` |
|
||||
| 页面文件 | index.vue | `pages/login/index.vue` |
|
||||
| 组件文件 | PascalCase | `UserAvatar.vue`, `OrderCard.vue` |
|
||||
| 组合式函数 | use + camelCase | `useAuth.ts`, `usePayment.ts` |
|
||||
| 工具函数 | camelCase | `format.ts`, `validate.ts` |
|
||||
| 类型定义 | camelCase + .d.ts | `user.d.ts`, `api.d.ts` |
|
||||
| 样式文件 | kebab-case | `variables.scss`, `common.scss` |
|
||||
|
||||
### 1.2 代码命名
|
||||
|
||||
| 类型 | 规范 | 示例 |
|
||||
|------|------|------|
|
||||
| 组件名 | PascalCase | `UserAvatar`, `OrderCard` |
|
||||
| 变量/函数 | camelCase | `userInfo`, `handleSubmit` |
|
||||
| 常量 | UPPER_SNAKE_CASE | `API_BASE_URL`, `MAX_PAGE_SIZE` |
|
||||
| 类型/接口 | PascalCase | `UserInfo`, `OrderStatus` |
|
||||
| 枚举 | PascalCase | `OrderStatus`, `UserLevel` |
|
||||
| CSS 类名 | kebab-case | `user-avatar`, `order-card` |
|
||||
| 事件名 | on + 动词 | `onClick`, `onSubmit`, `onChange` |
|
||||
| Props | camelCase | `userId`, `showHeader` |
|
||||
| Emits | kebab-case | `@update:value`, `@item-click` |
|
||||
|
||||
### 1.3 命名示例
|
||||
|
||||
```typescript
|
||||
// ✅ 建议
|
||||
const userInfo = ref<UserInfo | null>(null)
|
||||
const isLoading = ref(false)
|
||||
const orderList = ref<OrderItem[]>([])
|
||||
|
||||
function handleLogin() { }
|
||||
function fetchUserInfo() { }
|
||||
function formatPrice(price: number) { }
|
||||
|
||||
// ❌ 不建议
|
||||
const user_info = ref(null) // 不使用下划线
|
||||
const data = ref([]) // 命名太模糊
|
||||
const info = ref(null) // 命名太模糊
|
||||
function login() { } // 缺少动词前缀
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、项目结构规范
|
||||
|
||||
### 2.1 页面结构
|
||||
|
||||
每个页面文件夹包含:
|
||||
|
||||
```
|
||||
pages/assessment/info/
|
||||
├── index.vue # 页面主文件
|
||||
├── components/ # 页面私有组件(可选)
|
||||
│ └── InfoForm.vue
|
||||
└── composables/ # 页面私有组合式函数(可选)
|
||||
└── useInfoForm.ts
|
||||
```
|
||||
|
||||
### 2.2 组件分类
|
||||
|
||||
```
|
||||
components/
|
||||
├── common/ # 通用组件(与业务无关)
|
||||
│ ├── AppButton.vue # 按钮
|
||||
│ ├── AppModal.vue # 弹窗
|
||||
│ ├── AppEmpty.vue # 空状态
|
||||
│ ├── AppLoading.vue # 加载
|
||||
│ └── AppNavbar.vue # 导航栏
|
||||
├── business/ # 业务组件(与业务相关)
|
||||
│ ├── UserAvatar.vue # 用户头像
|
||||
│ ├── OrderCard.vue # 订单卡片
|
||||
│ ├── AssessmentCard.vue # 测评卡片
|
||||
│ └── PlannerCard.vue # 规划师卡片
|
||||
└── layout/ # 布局组件
|
||||
└── TabBar.vue # 底部导航
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、Vue 组件规范
|
||||
|
||||
### 3.1 组件结构
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
/**
|
||||
* 组件名称
|
||||
* @description 组件描述
|
||||
*/
|
||||
|
||||
// 1. 导入
|
||||
import { ref, computed, onMounted } from 'vue'
|
||||
import type { UserInfo } from '@/types/user'
|
||||
import { useUserStore } from '@/stores/user'
|
||||
import { getUserInfo } from '@/api/user'
|
||||
|
||||
// 2. Props 定义
|
||||
interface Props {
|
||||
/** 用户ID */
|
||||
userId: number
|
||||
/** 是否显示头像 */
|
||||
showAvatar?: boolean
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
showAvatar: true
|
||||
})
|
||||
|
||||
// 3. Emits 定义
|
||||
interface Emits {
|
||||
(e: 'click', user: UserInfo): void
|
||||
(e: 'update:value', value: string): void
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
// 4. 响应式状态
|
||||
const loading = ref(false)
|
||||
const userInfo = ref<UserInfo | null>(null)
|
||||
|
||||
// 5. 计算属性
|
||||
const displayName = computed(() => {
|
||||
return userInfo.value?.nickname || '未知用户'
|
||||
})
|
||||
|
||||
// 6. 方法
|
||||
async function fetchData() {
|
||||
loading.value = true
|
||||
try {
|
||||
userInfo.value = await getUserInfo(props.userId)
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
function handleClick() {
|
||||
if (userInfo.value) {
|
||||
emit('click', userInfo.value)
|
||||
}
|
||||
}
|
||||
|
||||
// 7. 生命周期
|
||||
onMounted(() => {
|
||||
fetchData()
|
||||
})
|
||||
|
||||
// 8. 暴露方法(可选)
|
||||
defineExpose({
|
||||
refresh: fetchData
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<view class="user-card" @click="handleClick">
|
||||
<image
|
||||
v-if="showAvatar"
|
||||
class="user-card__avatar"
|
||||
:src="userInfo?.avatar"
|
||||
/>
|
||||
<text class="user-card__name">{{ displayName }}</text>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.user-card {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 24rpx;
|
||||
|
||||
&__avatar {
|
||||
width: 80rpx;
|
||||
height: 80rpx;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
&__name {
|
||||
margin-left: 16rpx;
|
||||
font-size: 28rpx;
|
||||
color: $text-color;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
```
|
||||
|
||||
### 3.2 Props 规范
|
||||
|
||||
```typescript
|
||||
// ✅ 建议:使用 TypeScript 接口定义
|
||||
interface Props {
|
||||
/** 用户ID(必填) */
|
||||
userId: number
|
||||
/** 标题 */
|
||||
title?: string
|
||||
/** 是否显示 */
|
||||
visible?: boolean
|
||||
/** 列表数据 */
|
||||
list?: OrderItem[]
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
title: '默认标题',
|
||||
visible: false,
|
||||
list: () => []
|
||||
})
|
||||
|
||||
// ❌ 不建议:使用运行时声明
|
||||
const props = defineProps({
|
||||
userId: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### 3.3 Emits 规范
|
||||
|
||||
```typescript
|
||||
// ✅ 建议:使用 TypeScript 接口定义
|
||||
interface Emits {
|
||||
(e: 'submit', data: FormData): void
|
||||
(e: 'cancel'): void
|
||||
(e: 'update:visible', value: boolean): void
|
||||
}
|
||||
|
||||
const emit = defineEmits<Emits>()
|
||||
|
||||
// 触发事件
|
||||
emit('submit', formData)
|
||||
emit('update:visible', false)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、TypeScript 规范
|
||||
|
||||
### 4.1 类型定义
|
||||
|
||||
```typescript
|
||||
// types/user.d.ts
|
||||
|
||||
/** 用户等级 */
|
||||
export enum UserLevel {
|
||||
/** 普通用户 */
|
||||
Normal = 1,
|
||||
/** 合伙人 */
|
||||
Partner = 2,
|
||||
/** 渠道合伙人 */
|
||||
ChannelPartner = 3
|
||||
}
|
||||
|
||||
/** 用户信息 */
|
||||
export interface UserInfo {
|
||||
/** 用户ID */
|
||||
id: number
|
||||
/** 用户UID */
|
||||
uid: string
|
||||
/** 昵称 */
|
||||
nickname: string
|
||||
/** 头像 */
|
||||
avatar: string
|
||||
/** 手机号 */
|
||||
phone: string
|
||||
/** 用户等级 */
|
||||
userLevel: UserLevel
|
||||
/** 创建时间 */
|
||||
createTime: string
|
||||
}
|
||||
|
||||
/** 登录请求参数 */
|
||||
export interface LoginRequest {
|
||||
/** 微信 code */
|
||||
code: string
|
||||
/** 加密手机号数据 */
|
||||
encryptedData: string
|
||||
/** 加密向量 */
|
||||
iv: string
|
||||
}
|
||||
|
||||
/** 登录响应 */
|
||||
export interface LoginResponse {
|
||||
/** 访问令牌 */
|
||||
token: string
|
||||
/** 刷新令牌 */
|
||||
refreshToken: string
|
||||
/** 用户信息 */
|
||||
userInfo: UserInfo
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 API 类型
|
||||
|
||||
```typescript
|
||||
// types/api.d.ts
|
||||
|
||||
/** 通用响应结构 */
|
||||
export interface ApiResponse<T = any> {
|
||||
/** 状态码 */
|
||||
code: number
|
||||
/** 提示信息 */
|
||||
message: string
|
||||
/** 业务数据 */
|
||||
data: T
|
||||
}
|
||||
|
||||
/** 分页请求参数 */
|
||||
export interface PageRequest {
|
||||
/** 页码 */
|
||||
page?: number
|
||||
/** 每页数量 */
|
||||
pageSize?: number
|
||||
}
|
||||
|
||||
/** 分页响应 */
|
||||
export interface PageResponse<T> {
|
||||
/** 列表数据 */
|
||||
list: T[]
|
||||
/** 总数 */
|
||||
total: number
|
||||
/** 当前页 */
|
||||
page: number
|
||||
/** 每页数量 */
|
||||
pageSize: number
|
||||
/** 总页数 */
|
||||
totalPages: number
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 类型使用
|
||||
|
||||
```typescript
|
||||
// ✅ 建议:明确类型
|
||||
const userInfo = ref<UserInfo | null>(null)
|
||||
const orderList = ref<OrderItem[]>([])
|
||||
const loading = ref<boolean>(false)
|
||||
|
||||
// ✅ 函数参数和返回值类型
|
||||
function formatPrice(price: number): string {
|
||||
return `¥${price.toFixed(2)}`
|
||||
}
|
||||
|
||||
async function fetchOrders(params: PageRequest): Promise<PageResponse<OrderItem>> {
|
||||
const res = await request.get<PageResponse<OrderItem>>('/api/order/getList', { params })
|
||||
return res.data
|
||||
}
|
||||
|
||||
// ❌ 不建议:使用 any
|
||||
const data: any = {}
|
||||
function handleData(data: any) { }
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、API 请求规范
|
||||
|
||||
### 5.1 请求封装
|
||||
|
||||
```typescript
|
||||
// api/request.ts
|
||||
import type { ApiResponse } from '@/types/api'
|
||||
|
||||
const BASE_URL = import.meta.env.VITE_API_BASE_URL
|
||||
|
||||
interface RequestOptions {
|
||||
url: string
|
||||
method?: 'GET' | 'POST'
|
||||
data?: any
|
||||
params?: any
|
||||
showLoading?: boolean
|
||||
showError?: boolean
|
||||
}
|
||||
|
||||
class Request {
|
||||
private getToken(): string {
|
||||
return uni.getStorageSync('token') || ''
|
||||
}
|
||||
|
||||
async request<T = any>(options: RequestOptions): Promise<ApiResponse<T>> {
|
||||
const { url, method = 'GET', data, params, showLoading = true, showError = true } = options
|
||||
|
||||
if (showLoading) {
|
||||
uni.showLoading({ title: '加载中...' })
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await uni.request({
|
||||
url: BASE_URL + url,
|
||||
method,
|
||||
data: method === 'POST' ? data : undefined,
|
||||
header: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${this.getToken()}`
|
||||
}
|
||||
})
|
||||
|
||||
const result = res.data as ApiResponse<T>
|
||||
|
||||
if (result.code !== 0) {
|
||||
if (showError) {
|
||||
uni.showToast({ title: result.message, icon: 'none' })
|
||||
}
|
||||
throw new Error(result.message)
|
||||
}
|
||||
|
||||
return result
|
||||
} finally {
|
||||
if (showLoading) {
|
||||
uni.hideLoading()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get<T = any>(url: string, options?: Partial<RequestOptions>) {
|
||||
return this.request<T>({ url, method: 'GET', ...options })
|
||||
}
|
||||
|
||||
post<T = any>(url: string, data?: any, options?: Partial<RequestOptions>) {
|
||||
return this.request<T>({ url, method: 'POST', data, ...options })
|
||||
}
|
||||
}
|
||||
|
||||
export const request = new Request()
|
||||
```
|
||||
|
||||
### 5.2 API 模块
|
||||
|
||||
```typescript
|
||||
// api/user.ts
|
||||
import { request } from './request'
|
||||
import type { LoginRequest, LoginResponse, UserInfo } from '@/types/user'
|
||||
|
||||
/**
|
||||
* 微信登录
|
||||
*/
|
||||
export function login(data: LoginRequest) {
|
||||
return request.post<LoginResponse>('/api/user/login', data)
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户信息
|
||||
*/
|
||||
export function getUserProfile() {
|
||||
return request.get<UserInfo>('/api/user/getProfile')
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新用户信息
|
||||
*/
|
||||
export function updateProfile(data: Partial<UserInfo>) {
|
||||
return request.post<boolean>('/api/user/updateProfile', data)
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 API 调用
|
||||
|
||||
```typescript
|
||||
// 在组件中使用
|
||||
import { getUserProfile } from '@/api/user'
|
||||
|
||||
async function fetchUserInfo() {
|
||||
try {
|
||||
const res = await getUserProfile()
|
||||
userInfo.value = res.data
|
||||
} catch (error) {
|
||||
console.error('获取用户信息失败', error)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、状态管理规范
|
||||
|
||||
### 6.1 Store 定义
|
||||
|
||||
```typescript
|
||||
// stores/user.ts
|
||||
import { defineStore } from 'pinia'
|
||||
import { ref, computed } from 'vue'
|
||||
import type { UserInfo } from '@/types/user'
|
||||
import { getUserProfile, login } from '@/api/user'
|
||||
|
||||
export const useUserStore = defineStore('user', () => {
|
||||
// 状态
|
||||
const token = ref<string>('')
|
||||
const userInfo = ref<UserInfo | null>(null)
|
||||
|
||||
// 计算属性
|
||||
const isLoggedIn = computed(() => !!token.value)
|
||||
const isPartner = computed(() => (userInfo.value?.userLevel ?? 0) >= 2)
|
||||
|
||||
// 方法
|
||||
async function loginAction(code: string, encryptedData: string, iv: string) {
|
||||
const res = await login({ code, encryptedData, iv })
|
||||
token.value = res.data.token
|
||||
userInfo.value = res.data.userInfo
|
||||
uni.setStorageSync('token', res.data.token)
|
||||
}
|
||||
|
||||
async function fetchUserInfo() {
|
||||
if (!token.value) return
|
||||
const res = await getUserProfile()
|
||||
userInfo.value = res.data
|
||||
}
|
||||
|
||||
function logout() {
|
||||
token.value = ''
|
||||
userInfo.value = null
|
||||
uni.removeStorageSync('token')
|
||||
}
|
||||
|
||||
// 初始化
|
||||
function init() {
|
||||
token.value = uni.getStorageSync('token') || ''
|
||||
if (token.value) {
|
||||
fetchUserInfo()
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
token,
|
||||
userInfo,
|
||||
isLoggedIn,
|
||||
isPartner,
|
||||
loginAction,
|
||||
fetchUserInfo,
|
||||
logout,
|
||||
init
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### 6.2 Store 使用
|
||||
|
||||
```typescript
|
||||
// 在组件中使用
|
||||
import { useUserStore } from '@/stores/user'
|
||||
|
||||
const userStore = useUserStore()
|
||||
|
||||
// 访问状态
|
||||
const { userInfo, isLoggedIn } = storeToRefs(userStore)
|
||||
|
||||
// 调用方法
|
||||
await userStore.loginAction(code, encryptedData, iv)
|
||||
userStore.logout()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 七、样式规范
|
||||
|
||||
### 7.1 变量定义
|
||||
|
||||
```scss
|
||||
// styles/variables.scss
|
||||
|
||||
// 主题色
|
||||
$primary-color: #4A90E2;
|
||||
$primary-color-light: #6BA3E8;
|
||||
$primary-color-dark: #3A7BC8;
|
||||
|
||||
// 文字颜色
|
||||
$text-color: #333333;
|
||||
$text-color-secondary: #666666;
|
||||
$text-color-placeholder: #999999;
|
||||
$text-color-disabled: #CCCCCC;
|
||||
|
||||
// 背景色
|
||||
$bg-color: #F5F5F5;
|
||||
$bg-color-white: #FFFFFF;
|
||||
$bg-color-gray: #F8F8F8;
|
||||
|
||||
// 边框
|
||||
$border-color: #EEEEEE;
|
||||
$border-radius: 8rpx;
|
||||
$border-radius-lg: 16rpx;
|
||||
|
||||
// 间距
|
||||
$spacing-xs: 8rpx;
|
||||
$spacing-sm: 16rpx;
|
||||
$spacing-md: 24rpx;
|
||||
$spacing-lg: 32rpx;
|
||||
$spacing-xl: 48rpx;
|
||||
|
||||
// 字体大小
|
||||
$font-size-xs: 20rpx;
|
||||
$font-size-sm: 24rpx;
|
||||
$font-size-md: 28rpx;
|
||||
$font-size-lg: 32rpx;
|
||||
$font-size-xl: 36rpx;
|
||||
|
||||
// 安全区域
|
||||
$safe-area-bottom: env(safe-area-inset-bottom);
|
||||
```
|
||||
|
||||
### 7.2 BEM 命名
|
||||
|
||||
```scss
|
||||
// ✅ 建议:使用 BEM 命名
|
||||
.order-card {
|
||||
// Block
|
||||
padding: $spacing-md;
|
||||
background: $bg-color-white;
|
||||
|
||||
// Element
|
||||
&__header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&__title {
|
||||
font-size: $font-size-lg;
|
||||
color: $text-color;
|
||||
}
|
||||
|
||||
&__status {
|
||||
font-size: $font-size-sm;
|
||||
color: $text-color-secondary;
|
||||
}
|
||||
|
||||
&__content {
|
||||
margin-top: $spacing-sm;
|
||||
}
|
||||
|
||||
&__footer {
|
||||
margin-top: $spacing-md;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
// Modifier
|
||||
&--active {
|
||||
border-color: $primary-color;
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 7.3 响应式单位
|
||||
|
||||
```scss
|
||||
// ✅ 使用 rpx 作为主要单位
|
||||
.container {
|
||||
padding: 24rpx;
|
||||
font-size: 28rpx;
|
||||
border-radius: 8rpx;
|
||||
}
|
||||
|
||||
// ✅ 固定尺寸使用 px
|
||||
.icon {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
}
|
||||
|
||||
// ❌ 不建议混用单位
|
||||
.box {
|
||||
padding: 12px 24rpx; // 不要混用
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 八、页面开发流程
|
||||
|
||||
### 8.1 开发步骤
|
||||
|
||||
1. **查看设计图** - 确认页面布局和交互
|
||||
2. **定义类型** - 在 `types/` 下定义相关类型
|
||||
3. **编写 API** - 在 `api/` 下编写接口调用
|
||||
4. **创建页面** - 在 `pages/` 下创建页面文件夹
|
||||
5. **配置路由** - 在 `pages.json` 中添加页面配置
|
||||
6. **编写组件** - 抽取可复用组件
|
||||
7. **编写样式** - 使用 BEM 命名,引用变量
|
||||
8. **测试验证** - 在模拟器和真机测试
|
||||
|
||||
### 8.2 页面配置
|
||||
|
||||
```json
|
||||
// pages.json
|
||||
{
|
||||
"pages": [
|
||||
{
|
||||
"path": "pages/index/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "首页",
|
||||
"navigationStyle": "custom"
|
||||
}
|
||||
},
|
||||
{
|
||||
"path": "pages/assessment/info/index",
|
||||
"style": {
|
||||
"navigationBarTitleText": "填写信息"
|
||||
}
|
||||
}
|
||||
],
|
||||
"tabBar": {
|
||||
"color": "#999999",
|
||||
"selectedColor": "#4A90E2",
|
||||
"backgroundColor": "#FFFFFF",
|
||||
"list": [
|
||||
{
|
||||
"pagePath": "pages/index/index",
|
||||
"text": "首页",
|
||||
"iconPath": "static/icons/tab-home.png",
|
||||
"selectedIconPath": "static/icons/tab-home-active.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/team/index",
|
||||
"text": "团队",
|
||||
"iconPath": "static/icons/tab-team.png",
|
||||
"selectedIconPath": "static/icons/tab-team-active.png"
|
||||
},
|
||||
{
|
||||
"pagePath": "pages/mine/index",
|
||||
"text": "我的",
|
||||
"iconPath": "static/icons/tab-mine.png",
|
||||
"selectedIconPath": "static/icons/tab-mine-active.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 九、常用工具函数
|
||||
|
||||
### 9.1 格式化
|
||||
|
||||
```typescript
|
||||
// utils/format.ts
|
||||
|
||||
/**
|
||||
* 格式化价格
|
||||
*/
|
||||
export function formatPrice(price: number): string {
|
||||
return `¥${price.toFixed(2)}`
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化日期
|
||||
*/
|
||||
export function formatDate(date: string | Date, format = 'YYYY-MM-DD'): string {
|
||||
const d = new Date(date)
|
||||
const year = d.getFullYear()
|
||||
const month = String(d.getMonth() + 1).padStart(2, '0')
|
||||
const day = String(d.getDate()).padStart(2, '0')
|
||||
const hour = String(d.getHours()).padStart(2, '0')
|
||||
const minute = String(d.getMinutes()).padStart(2, '0')
|
||||
|
||||
return format
|
||||
.replace('YYYY', String(year))
|
||||
.replace('MM', month)
|
||||
.replace('DD', day)
|
||||
.replace('HH', hour)
|
||||
.replace('mm', minute)
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化手机号(隐藏中间4位)
|
||||
*/
|
||||
export function formatPhone(phone: string): string {
|
||||
return phone.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')
|
||||
}
|
||||
```
|
||||
|
||||
### 9.2 验证
|
||||
|
||||
```typescript
|
||||
// utils/validate.ts
|
||||
|
||||
/**
|
||||
* 验证手机号
|
||||
*/
|
||||
export function isValidPhone(phone: string): boolean {
|
||||
return /^1[3-9]\d{9}$/.test(phone)
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证邀请码(5位大写字母)
|
||||
*/
|
||||
export function isValidInviteCode(code: string): boolean {
|
||||
return /^[A-Z]{5}$/.test(code)
|
||||
}
|
||||
```
|
||||
|
||||
### 9.3 存储
|
||||
|
||||
```typescript
|
||||
// utils/storage.ts
|
||||
|
||||
const TOKEN_KEY = 'token'
|
||||
const USER_INFO_KEY = 'userInfo'
|
||||
|
||||
export const storage = {
|
||||
getToken(): string {
|
||||
return uni.getStorageSync(TOKEN_KEY) || ''
|
||||
},
|
||||
|
||||
setToken(token: string): void {
|
||||
uni.setStorageSync(TOKEN_KEY, token)
|
||||
},
|
||||
|
||||
removeToken(): void {
|
||||
uni.removeStorageSync(TOKEN_KEY)
|
||||
},
|
||||
|
||||
getUserInfo<T>(): T | null {
|
||||
const data = uni.getStorageSync(USER_INFO_KEY)
|
||||
return data ? JSON.parse(data) : null
|
||||
},
|
||||
|
||||
setUserInfo<T>(info: T): void {
|
||||
uni.setStorageSync(USER_INFO_KEY, JSON.stringify(info))
|
||||
},
|
||||
|
||||
clear(): void {
|
||||
uni.clearStorageSync()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 十、注意事项
|
||||
|
||||
### 10.1 性能优化
|
||||
|
||||
- 图片使用 CDN 地址,避免本地大图
|
||||
- 列表使用虚拟滚动或分页加载
|
||||
- 避免在 `onShow` 中频繁请求数据
|
||||
- 使用 `v-if` 而非 `v-show` 控制大组件显示
|
||||
|
||||
### 10.2 兼容性
|
||||
|
||||
- 使用 `rpx` 作为主要单位
|
||||
- 避免使用不支持的 CSS 属性
|
||||
- 测试 iOS 和 Android 两端表现
|
||||
- 注意安全区域适配
|
||||
|
||||
### 10.3 安全
|
||||
|
||||
- 敏感数据不存储在本地
|
||||
- Token 过期自动刷新或跳转登录
|
||||
- 支付相关操作需二次确认
|
||||
- 用户输入需做 XSS 过滤
|
||||
|
||||
---
|
||||
|
||||
## 十一、Git 提交规范
|
||||
|
||||
### 11.1 提交信息格式
|
||||
|
||||
```
|
||||
<type>(<scope>): <subject>
|
||||
|
||||
<body>
|
||||
```
|
||||
|
||||
### 11.2 Type 类型
|
||||
|
||||
| Type | 说明 |
|
||||
|------|------|
|
||||
| feat | 新功能 |
|
||||
| fix | 修复 bug |
|
||||
| docs | 文档更新 |
|
||||
| style | 代码格式(不影响功能) |
|
||||
| refactor | 重构 |
|
||||
| perf | 性能优化 |
|
||||
| test | 测试 |
|
||||
| chore | 构建/工具 |
|
||||
|
||||
### 11.3 示例
|
||||
|
||||
```
|
||||
feat(assessment): 添加测评答题页面
|
||||
|
||||
- 实现题目列表展示
|
||||
- 实现选项选择交互
|
||||
- 添加提交答案功能
|
||||
```
|
||||
501
uniapp/docs/组件文档.md
Normal file
501
uniapp/docs/组件文档.md
Normal file
|
|
@ -0,0 +1,501 @@
|
|||
# 学业邑规划 - 组件文档
|
||||
|
||||
本文档定义了小程序中需要开发的公共组件和业务组件。
|
||||
|
||||
---
|
||||
|
||||
## 一、组件分类
|
||||
|
||||
```
|
||||
components/
|
||||
├── common/ # 通用组件(与业务无关)
|
||||
├── business/ # 业务组件(与业务相关)
|
||||
└── layout/ # 布局组件
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 二、通用组件
|
||||
|
||||
### 2.1 AppButton 按钮
|
||||
|
||||
**文件**:`components/common/AppButton.vue`
|
||||
|
||||
**功能**:统一的按钮组件,支持多种样式和状态
|
||||
|
||||
**Props**:
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| type | string | 'primary' | 按钮类型:primary / secondary / text |
|
||||
| size | string | 'medium' | 按钮大小:small / medium / large |
|
||||
| disabled | boolean | false | 是否禁用 |
|
||||
| loading | boolean | false | 是否加载中 |
|
||||
| block | boolean | false | 是否块级按钮 |
|
||||
|
||||
**使用示例**:
|
||||
```vue
|
||||
<AppButton type="primary" @click="handleSubmit">提交</AppButton>
|
||||
<AppButton type="secondary" size="small">取消</AppButton>
|
||||
<AppButton :disabled="!isValid" :loading="submitting">
|
||||
支付¥99元 开始测评
|
||||
</AppButton>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.2 AppModal 弹窗
|
||||
|
||||
**文件**:`components/common/AppModal.vue`
|
||||
|
||||
**功能**:统一的弹窗组件
|
||||
|
||||
**Props**:
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| visible | boolean | false | 是否显示 |
|
||||
| title | string | '' | 标题 |
|
||||
| showClose | boolean | true | 是否显示关闭按钮 |
|
||||
| maskClosable | boolean | true | 点击遮罩是否关闭 |
|
||||
|
||||
**Emits**:
|
||||
| 事件 | 参数 | 说明 |
|
||||
|------|------|------|
|
||||
| update:visible | boolean | 显示状态变化 |
|
||||
| close | - | 关闭事件 |
|
||||
|
||||
**使用示例**:
|
||||
```vue
|
||||
<AppModal v-model:visible="showModal" title="提示">
|
||||
<text>确定要退出登录吗?</text>
|
||||
<template #footer>
|
||||
<AppButton type="secondary" @click="showModal = false">取消</AppButton>
|
||||
<AppButton type="primary" @click="handleConfirm">确定</AppButton>
|
||||
</template>
|
||||
</AppModal>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.3 AppEmpty 空状态
|
||||
|
||||
**文件**:`components/common/AppEmpty.vue`
|
||||
|
||||
**功能**:列表为空时的占位组件
|
||||
|
||||
**Props**:
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| image | string | 默认图片 | 空状态图片 |
|
||||
| text | string | '暂无数据' | 提示文字 |
|
||||
| showButton | boolean | false | 是否显示按钮 |
|
||||
| buttonText | string | '' | 按钮文字 |
|
||||
|
||||
**使用示例**:
|
||||
```vue
|
||||
<AppEmpty text="暂无订单" />
|
||||
<AppEmpty
|
||||
text="暂无测评记录"
|
||||
:showButton="true"
|
||||
buttonText="去测评"
|
||||
@click="goAssessment"
|
||||
/>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.4 AppLoading 加载
|
||||
|
||||
**文件**:`components/common/AppLoading.vue`
|
||||
|
||||
**功能**:加载状态组件
|
||||
|
||||
**Props**:
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| loading | boolean | false | 是否加载中 |
|
||||
| text | string | '加载中...' | 加载文字 |
|
||||
| fullscreen | boolean | false | 是否全屏 |
|
||||
|
||||
**使用示例**:
|
||||
```vue
|
||||
<AppLoading :loading="isLoading" />
|
||||
<AppLoading :loading="isLoading" text="报告生成中..." :fullscreen="true" />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.5 AppNavbar 导航栏
|
||||
|
||||
**文件**:`components/common/AppNavbar.vue`
|
||||
|
||||
**功能**:自定义导航栏(用于 navigationStyle: custom 的页面)
|
||||
|
||||
**Props**:
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| title | string | '' | 标题 |
|
||||
| showBack | boolean | true | 是否显示返回按钮 |
|
||||
| showHome | boolean | false | 是否显示首页按钮 |
|
||||
| bgColor | string | '#fff' | 背景色 |
|
||||
| textColor | string | '#333' | 文字颜色 |
|
||||
|
||||
**使用示例**:
|
||||
```vue
|
||||
<AppNavbar title="测评结果" :showBack="true" />
|
||||
<AppNavbar title="首页" :showBack="false" bgColor="transparent" textColor="#fff" />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.6 AppInput 输入框
|
||||
|
||||
**文件**:`components/common/AppInput.vue`
|
||||
|
||||
**功能**:统一的输入框组件
|
||||
|
||||
**Props**:
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| modelValue | string | '' | 输入值 |
|
||||
| type | string | 'text' | 输入类型 |
|
||||
| placeholder | string | '' | 占位文字 |
|
||||
| disabled | boolean | false | 是否禁用 |
|
||||
| maxlength | number | -1 | 最大长度 |
|
||||
| error | string | '' | 错误提示 |
|
||||
|
||||
**使用示例**:
|
||||
```vue
|
||||
<AppInput
|
||||
v-model="form.name"
|
||||
placeholder="请输入姓名"
|
||||
:error="errors.name"
|
||||
/>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.7 AppPicker 选择器
|
||||
|
||||
**文件**:`components/common/AppPicker.vue`
|
||||
|
||||
**功能**:统一的选择器组件
|
||||
|
||||
**Props**:
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| modelValue | any | null | 选中值 |
|
||||
| options | array | [] | 选项列表 |
|
||||
| placeholder | string | '请选择' | 占位文字 |
|
||||
| labelKey | string | 'label' | 显示字段 |
|
||||
| valueKey | string | 'value' | 值字段 |
|
||||
|
||||
**使用示例**:
|
||||
```vue
|
||||
<AppPicker
|
||||
v-model="form.age"
|
||||
:options="ageOptions"
|
||||
placeholder="请选择年龄"
|
||||
/>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2.8 AppRegionPicker 地区选择器
|
||||
|
||||
**文件**:`components/common/AppRegionPicker.vue`
|
||||
|
||||
**功能**:省市区三级联动选择器
|
||||
|
||||
**Props**:
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| province | string | '' | 省份 |
|
||||
| city | string | '' | 城市 |
|
||||
| district | string | '' | 区县 |
|
||||
|
||||
**Emits**:
|
||||
| 事件 | 参数 | 说明 |
|
||||
|------|------|------|
|
||||
| change | { province, city, district } | 选择变化 |
|
||||
|
||||
**使用示例**:
|
||||
```vue
|
||||
<AppRegionPicker
|
||||
:province="form.province"
|
||||
:city="form.city"
|
||||
:district="form.district"
|
||||
@change="handleRegionChange"
|
||||
/>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 三、业务组件
|
||||
|
||||
### 3.1 UserAvatar 用户头像
|
||||
|
||||
**文件**:`components/business/UserAvatar.vue`
|
||||
|
||||
**功能**:用户头像展示组件
|
||||
|
||||
**Props**:
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| src | string | '' | 头像地址 |
|
||||
| size | string | 'medium' | 大小:small / medium / large |
|
||||
| showLevel | boolean | false | 是否显示等级标识 |
|
||||
| level | number | 1 | 用户等级 |
|
||||
|
||||
**使用示例**:
|
||||
```vue
|
||||
<UserAvatar :src="userInfo.avatar" size="large" />
|
||||
<UserAvatar :src="userInfo.avatar" :showLevel="true" :level="userInfo.userLevel" />
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.2 OrderCard 订单卡片
|
||||
|
||||
**文件**:`components/business/OrderCard.vue`
|
||||
|
||||
**功能**:订单列表项组件
|
||||
|
||||
**Props**:
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| order | OrderItem | required | 订单数据 |
|
||||
|
||||
**Emits**:
|
||||
| 事件 | 参数 | 说明 |
|
||||
|------|------|------|
|
||||
| action | { type, order } | 操作按钮点击 |
|
||||
|
||||
**使用示例**:
|
||||
```vue
|
||||
<OrderCard
|
||||
v-for="order in orderList"
|
||||
:key="order.id"
|
||||
:order="order"
|
||||
@action="handleOrderAction"
|
||||
/>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.3 AssessmentCard 测评入口卡片
|
||||
|
||||
**文件**:`components/business/AssessmentCard.vue`
|
||||
|
||||
**功能**:首页测评入口组件
|
||||
|
||||
**Props**:
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| assessment | AssessmentType | required | 测评类型数据 |
|
||||
|
||||
**Emits**:
|
||||
| 事件 | 参数 | 说明 |
|
||||
|------|------|------|
|
||||
| click | AssessmentType | 点击事件 |
|
||||
|
||||
**使用示例**:
|
||||
```vue
|
||||
<AssessmentCard
|
||||
v-for="item in assessmentList"
|
||||
:key="item.id"
|
||||
:assessment="item"
|
||||
@click="handleAssessmentClick"
|
||||
/>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.4 PlannerCard 规划师卡片
|
||||
|
||||
**文件**:`components/business/PlannerCard.vue`
|
||||
|
||||
**功能**:规划师列表项组件
|
||||
|
||||
**Props**:
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| planner | PlannerInfo | required | 规划师数据 |
|
||||
| selected | boolean | false | 是否选中 |
|
||||
|
||||
**Emits**:
|
||||
| 事件 | 参数 | 说明 |
|
||||
|------|------|------|
|
||||
| select | PlannerInfo | 选择事件 |
|
||||
|
||||
**使用示例**:
|
||||
```vue
|
||||
<PlannerCard
|
||||
v-for="planner in plannerList"
|
||||
:key="planner.id"
|
||||
:planner="planner"
|
||||
:selected="selectedId === planner.id"
|
||||
@select="handleSelect"
|
||||
/>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.5 QuestionItem 题目组件
|
||||
|
||||
**文件**:`components/business/QuestionItem.vue`
|
||||
|
||||
**功能**:测评答题页的题目组件
|
||||
|
||||
**Props**:
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| question | Question | required | 题目数据 |
|
||||
| answer | number | null | 当前答案 |
|
||||
| index | number | required | 题目序号 |
|
||||
|
||||
**Emits**:
|
||||
| 事件 | 参数 | 说明 |
|
||||
|------|------|------|
|
||||
| change | { questionId, value } | 答案变化 |
|
||||
|
||||
**使用示例**:
|
||||
```vue
|
||||
<QuestionItem
|
||||
v-for="(question, index) in questionList"
|
||||
:key="question.id"
|
||||
:question="question"
|
||||
:answer="answers[question.id]"
|
||||
:index="index"
|
||||
@change="handleAnswerChange"
|
||||
/>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.6 InviteRecord 邀请记录项
|
||||
|
||||
**文件**:`components/business/InviteRecord.vue`
|
||||
|
||||
**功能**:邀请记录列表项组件
|
||||
|
||||
**Props**:
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| record | InviteRecord | required | 邀请记录数据 |
|
||||
|
||||
**使用示例**:
|
||||
```vue
|
||||
<InviteRecord
|
||||
v-for="record in recordList"
|
||||
:key="record.id"
|
||||
:record="record"
|
||||
/>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3.7 WithdrawRecord 提现记录项
|
||||
|
||||
**文件**:`components/business/WithdrawRecord.vue`
|
||||
|
||||
**功能**:提现记录列表项组件
|
||||
|
||||
**Props**:
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| record | WithdrawRecord | required | 提现记录数据 |
|
||||
|
||||
**使用示例**:
|
||||
```vue
|
||||
<WithdrawRecord
|
||||
v-for="record in withdrawList"
|
||||
:key="record.id"
|
||||
:record="record"
|
||||
/>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 四、布局组件
|
||||
|
||||
### 4.1 PageContainer 页面容器
|
||||
|
||||
**文件**:`components/layout/PageContainer.vue`
|
||||
|
||||
**功能**:统一的页面容器,处理安全区域
|
||||
|
||||
**Props**:
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| safeBottom | boolean | true | 是否适配底部安全区域 |
|
||||
| bgColor | string | '#f5f5f5' | 背景色 |
|
||||
|
||||
**使用示例**:
|
||||
```vue
|
||||
<PageContainer>
|
||||
<!-- 页面内容 -->
|
||||
</PageContainer>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4.2 ListContainer 列表容器
|
||||
|
||||
**文件**:`components/layout/ListContainer.vue`
|
||||
|
||||
**功能**:带下拉刷新和上拉加载的列表容器
|
||||
|
||||
**Props**:
|
||||
| 属性 | 类型 | 默认值 | 说明 |
|
||||
|------|------|--------|------|
|
||||
| loading | boolean | false | 是否加载中 |
|
||||
| finished | boolean | false | 是否加载完成 |
|
||||
| emptyText | string | '暂无数据' | 空状态文字 |
|
||||
|
||||
**Emits**:
|
||||
| 事件 | 参数 | 说明 |
|
||||
|------|------|------|
|
||||
| refresh | - | 下拉刷新 |
|
||||
| loadMore | - | 上拉加载 |
|
||||
|
||||
**使用示例**:
|
||||
```vue
|
||||
<ListContainer
|
||||
:loading="loading"
|
||||
:finished="finished"
|
||||
@refresh="handleRefresh"
|
||||
@loadMore="handleLoadMore"
|
||||
>
|
||||
<OrderCard v-for="order in orderList" :key="order.id" :order="order" />
|
||||
</ListContainer>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 五、组件开发规范
|
||||
|
||||
### 5.1 组件命名
|
||||
|
||||
- 通用组件以 `App` 开头:`AppButton`, `AppModal`
|
||||
- 业务组件使用业务名词:`UserAvatar`, `OrderCard`
|
||||
- 布局组件以 `Container` 结尾:`PageContainer`, `ListContainer`
|
||||
|
||||
### 5.2 Props 规范
|
||||
|
||||
- 使用 TypeScript 接口定义
|
||||
- 必填属性标注 `required`
|
||||
- 提供合理的默认值
|
||||
- 添加 JSDoc 注释
|
||||
|
||||
### 5.3 样式规范
|
||||
|
||||
- 使用 BEM 命名
|
||||
- 使用 `scoped` 限制作用域
|
||||
- 引用全局变量
|
||||
- 避免使用 `!important`
|
||||
|
||||
### 5.4 事件规范
|
||||
|
||||
- 使用 `emit` 定义类型
|
||||
- 事件名使用 kebab-case
|
||||
- 提供完整的事件参数类型
|
||||
474
uniapp/docs/页面清单.md
Normal file
474
uniapp/docs/页面清单.md
Normal file
|
|
@ -0,0 +1,474 @@
|
|||
# 学业邑规划 - 小程序页面清单
|
||||
|
||||
本文档列出所有小程序页面的详细信息,包括路由、功能、状态和开发优先级。
|
||||
|
||||
---
|
||||
|
||||
## 一、页面总览
|
||||
|
||||
| 序号 | 页面名称 | 路由 | 优先级 | 状态 |
|
||||
|------|----------|------|--------|------|
|
||||
| 1 | 首页 | /pages/index/index | P0 | 待开发 |
|
||||
| 2 | 团队页 | /pages/team/index | P0 | 待开发 |
|
||||
| 3 | 我的页 | /pages/mine/index | P0 | 待开发 |
|
||||
| 4 | 登录页 | /pages/login/index | P0 | 待开发 |
|
||||
| 5 | 个人资料页 | /pages/mine/profile/index | P1 | 待开发 |
|
||||
| 6 | 业务详情页 | /pages/business/detail/index | P1 | 待开发 |
|
||||
| 7 | 测评-信息填写 | /pages/assessment/info/index | P0 | 待开发 |
|
||||
| 8 | 测评-答题页 | /pages/assessment/questions/index | P0 | 待开发 |
|
||||
| 9 | 测评-生成中 | /pages/assessment/loading/index | P0 | 待开发 |
|
||||
| 10 | 测评-结果页 | /pages/assessment/result/index | P0 | 待开发 |
|
||||
| 11 | 我的订单 | /pages/order/list/index | P1 | 待开发 |
|
||||
| 12 | 往期测评 | /pages/assessment/history/index | P1 | 待开发 |
|
||||
| 13 | 学业规划-规划师 | /pages/planner/list/index | P2 | 待开发 |
|
||||
| 14 | 学业规划-预约 | /pages/planner/book/index | P2 | 待开发 |
|
||||
| 15 | 邀请新用户 | /pages/invite/index | P2 | 待开发 |
|
||||
| 16 | 关于页 | /pages/about/index | P3 | 待开发 |
|
||||
| 17 | 用户协议 | /pages/agreement/user/index | P3 | 待开发 |
|
||||
| 18 | 隐私政策 | /pages/agreement/privacy/index | P3 | 待开发 |
|
||||
|
||||
**优先级说明**:
|
||||
- P0:核心功能,必须首先完成
|
||||
- P1:重要功能,核心功能完成后开发
|
||||
- P2:扩展功能,可延后开发
|
||||
- P3:辅助功能,最后开发
|
||||
|
||||
---
|
||||
|
||||
## 二、TabBar 页面
|
||||
|
||||
### 2.1 首页 (P0)
|
||||
|
||||
**路由**:`/pages/index/index`
|
||||
|
||||
**设计图**:`docs/设计图/首页.png`
|
||||
|
||||
**功能描述**:
|
||||
- 展示公司介绍性内容
|
||||
- Banner 轮播图(可跳转)
|
||||
- 测评入口列表
|
||||
- 底部宣传长图
|
||||
|
||||
**数据来源**:
|
||||
| 数据 | 接口 | 说明 |
|
||||
|------|------|------|
|
||||
| Banner 列表 | GET /api/home/getBannerList | 轮播图数据 |
|
||||
| 测评入口 | GET /api/home/getAssessmentList | 测评类型列表 |
|
||||
| 宣传图 | GET /api/home/getPromotionList | 底部宣传图 |
|
||||
|
||||
**交互逻辑**:
|
||||
- 点击 Banner → 根据跳转类型跳转
|
||||
- 点击已上线测评 → 进入测评流程
|
||||
- 点击即将上线测评 → 弹出提示"该测评暂未开放"
|
||||
|
||||
---
|
||||
|
||||
### 2.2 团队页 (P0)
|
||||
|
||||
**路由**:`/pages/team/index`
|
||||
|
||||
**设计图**:`docs/设计图/团队.png`
|
||||
|
||||
**功能描述**:
|
||||
- 展示团队介绍图片
|
||||
|
||||
**数据来源**:
|
||||
| 数据 | 接口 | 说明 |
|
||||
|------|------|------|
|
||||
| 团队介绍 | GET /api/team/getInfo | 团队介绍图片 |
|
||||
|
||||
---
|
||||
|
||||
### 2.3 我的页 (P0)
|
||||
|
||||
**路由**:`/pages/mine/index`
|
||||
|
||||
**设计图**:
|
||||
- `docs/设计图/我的-未登录.png`
|
||||
- `docs/设计图/我的-登录页.png`
|
||||
- `docs/设计图/我的-退出登录.png`
|
||||
|
||||
**功能描述**:
|
||||
- 未登录:显示"点击登录"
|
||||
- 已登录:显示头像、昵称、UID
|
||||
- 常用功能:我的订单、往期测评、联系我们、邀请新用户(合伙人可见)
|
||||
- 其他功能:关于、用户协议、隐私政策、退出登录
|
||||
|
||||
**数据来源**:
|
||||
| 数据 | 接口 | 说明 |
|
||||
|------|------|------|
|
||||
| 用户信息 | GET /api/user/getProfile | 用户基本信息 |
|
||||
|
||||
**交互逻辑**:
|
||||
- 未登录点击头像区域 → 跳转登录页
|
||||
- 点击各功能入口 → 跳转对应页面
|
||||
- 点击退出登录 → 弹出二次确认弹窗
|
||||
|
||||
---
|
||||
|
||||
## 三、登录相关
|
||||
|
||||
### 3.1 登录页 (P0)
|
||||
|
||||
**路由**:`/pages/login/index`
|
||||
|
||||
**设计图**:`docs/设计图/登录页.png`
|
||||
|
||||
**功能描述**:
|
||||
- 微信一键登录(获取手机号)
|
||||
- 用户协议和隐私政策勾选
|
||||
|
||||
**数据来源**:
|
||||
| 数据 | 接口 | 说明 |
|
||||
|------|------|------|
|
||||
| 登录 | POST /api/user/login | 微信登录 |
|
||||
|
||||
**交互逻辑**:
|
||||
1. 用户点击登录按钮
|
||||
2. 调用 `wx.login()` 获取 code
|
||||
3. 调用 `wx.getPhoneNumber()` 获取加密手机号
|
||||
4. 调用后端登录接口
|
||||
5. 保存 token,跳转回原页面
|
||||
|
||||
---
|
||||
|
||||
### 3.2 个人资料页 (P1)
|
||||
|
||||
**路由**:`/pages/mine/profile/index`
|
||||
|
||||
**设计图**:`docs/设计图/个人资料.png`
|
||||
|
||||
**功能描述**:
|
||||
- 查看/修改头像
|
||||
- 查看/修改昵称
|
||||
- 查看 UID(不可修改)
|
||||
|
||||
**数据来源**:
|
||||
| 数据 | 接口 | 说明 |
|
||||
|------|------|------|
|
||||
| 用户信息 | GET /api/user/getProfile | 获取用户信息 |
|
||||
| 更新信息 | POST /api/user/updateProfile | 更新昵称 |
|
||||
| 更新头像 | POST /api/user/updateAvatar | 更新头像 |
|
||||
|
||||
---
|
||||
|
||||
## 四、测评相关
|
||||
|
||||
### 4.1 测评-信息填写页 (P0)
|
||||
|
||||
**路由**:`/pages/assessment/info/index`
|
||||
|
||||
**设计图**:
|
||||
- `docs/设计图/测评-个人信息填写.png`
|
||||
- `docs/设计图/测评-个人信息填写2.png`
|
||||
- `docs/设计图/测评-个人信息填写3.png`
|
||||
- `docs/设计图/测评-个人信息填写4.png`
|
||||
|
||||
**功能描述**:
|
||||
- 顶部测评介绍(后台配置)
|
||||
- 填写基本信息:姓名、手机号、性别、年龄、学业阶段、省市区
|
||||
- 两个入口按钮:支付测评、邀请码免费测评
|
||||
|
||||
**表单字段**:
|
||||
| 字段 | 类型 | 必填 | 验证规则 |
|
||||
|------|------|------|----------|
|
||||
| 姓名 | 文本 | 是 | 非空 |
|
||||
| 手机号 | 文本 | 是 | 11位手机号格式 |
|
||||
| 性别 | 单选 | 是 | 男/女 |
|
||||
| 年龄 | 下拉 | 是 | 10-50岁 |
|
||||
| 学业阶段 | 下拉 | 是 | 6个选项 |
|
||||
| 省份 | 下拉 | 是 | 省份列表 |
|
||||
| 城市 | 下拉 | 是 | 城市列表 |
|
||||
| 区县 | 下拉 | 是 | 区县列表 |
|
||||
|
||||
**数据来源**:
|
||||
| 数据 | 接口 | 说明 |
|
||||
|------|------|------|
|
||||
| 测评介绍 | GET /api/assessment/getIntro | 顶部介绍内容 |
|
||||
| 验证邀请码 | POST /api/assessment/verifyInviteCode | 验证邀请码 |
|
||||
| 创建订单 | POST /api/order/create | 创建测评订单 |
|
||||
| 发起支付 | POST /api/order/pay | 拉起微信支付 |
|
||||
|
||||
**交互逻辑**:
|
||||
- 有未填写项 → 按钮灰色不可点击
|
||||
- 点击支付按钮 → 验证信息 → 创建订单 → 拉起支付
|
||||
- 点击邀请码按钮 → 验证信息 → 弹出邀请码输入框 → 验证邀请码
|
||||
|
||||
---
|
||||
|
||||
### 4.2 测评-答题页 (P0)
|
||||
|
||||
**路由**:`/pages/assessment/questions/index`
|
||||
|
||||
**设计图**:
|
||||
- `docs/设计图/测评-题目.png`
|
||||
- `docs/设计图/测评-提交题目检验空题.png`
|
||||
|
||||
**功能描述**:
|
||||
- 展示所有题目(80道)
|
||||
- 每题10个选项
|
||||
- 底部提交按钮
|
||||
- 提交时检测未答题目
|
||||
|
||||
**数据来源**:
|
||||
| 数据 | 接口 | 说明 |
|
||||
|------|------|------|
|
||||
| 题目列表 | GET /api/assessment/getQuestionList | 获取所有题目 |
|
||||
| 提交答案 | POST /api/assessment/submitAnswers | 提交测评答案 |
|
||||
|
||||
**交互逻辑**:
|
||||
- 点击提交 → 检测未答题目
|
||||
- 有未答题 → 弹窗显示未答题号
|
||||
- 全部已答 → 提交答案 → 跳转生成中页面
|
||||
|
||||
---
|
||||
|
||||
### 4.3 测评-生成中页 (P0)
|
||||
|
||||
**路由**:`/pages/assessment/loading/index`
|
||||
|
||||
**设计图**:`docs/设计图/测评-等待测评.png`
|
||||
|
||||
**功能描述**:
|
||||
- 显示加载动画
|
||||
- 提示文字
|
||||
- 轮询查询报告状态
|
||||
- 生成完成自动跳转
|
||||
|
||||
**数据来源**:
|
||||
| 数据 | 接口 | 说明 |
|
||||
|------|------|------|
|
||||
| 报告状态 | GET /api/assessment/getResultStatus | 查询报告生成状态 |
|
||||
|
||||
---
|
||||
|
||||
### 4.4 测评-结果页 (P0)
|
||||
|
||||
**路由**:`/pages/assessment/result/index`
|
||||
|
||||
**设计图**:(需补充)
|
||||
|
||||
**功能描述**:
|
||||
- 展示测评报告
|
||||
- 八大智能分析(雷达图)
|
||||
- 个人特质分析
|
||||
- 40项细分能力
|
||||
- 其他分析报告
|
||||
- 保存到本地(PDF)
|
||||
|
||||
**数据来源**:
|
||||
| 数据 | 接口 | 说明 |
|
||||
|------|------|------|
|
||||
| 测评结果 | GET /api/assessment/getResult | 获取完整测评报告 |
|
||||
|
||||
---
|
||||
|
||||
### 4.5 往期测评页 (P1)
|
||||
|
||||
**路由**:`/pages/assessment/history/index`
|
||||
|
||||
**设计图**:`docs/设计图/往期测评-空状态.png`
|
||||
|
||||
**功能描述**:
|
||||
- 展示已完成的测评列表
|
||||
- 显示测评日期、订单编号、测评项目、报告状态
|
||||
|
||||
**数据来源**:
|
||||
| 数据 | 接口 | 说明 |
|
||||
|------|------|------|
|
||||
| 测评记录 | GET /api/assessment/getHistoryList | 获取往期测评列表 |
|
||||
|
||||
---
|
||||
|
||||
## 五、订单相关
|
||||
|
||||
### 5.1 我的订单页 (P1)
|
||||
|
||||
**路由**:`/pages/order/list/index`
|
||||
|
||||
**设计图**:
|
||||
- `docs/设计图/我的订单.png`
|
||||
- `docs/设计图/我的订单-空状态.png`
|
||||
|
||||
**功能描述**:
|
||||
- 展示所有订单
|
||||
- 显示订单日期、编号、项目、金额、状态
|
||||
- 根据状态显示不同操作按钮
|
||||
|
||||
**订单状态**:
|
||||
| 状态 | 说明 | 操作 |
|
||||
|------|------|------|
|
||||
| 待测评 | 已支付,未答题 | 开始测评 |
|
||||
| 测评生成中 | 已答题,生成中 | - |
|
||||
| 已测评 | 报告已生成 | 查看结果 |
|
||||
| 退款中 | 申请退款中 | - |
|
||||
| 已退款 | 退款完成 | - |
|
||||
| 已支付 | 学业规划订单 | - |
|
||||
|
||||
**数据来源**:
|
||||
| 数据 | 接口 | 说明 |
|
||||
|------|------|------|
|
||||
| 订单列表 | GET /api/order/getList | 获取订单列表 |
|
||||
|
||||
---
|
||||
|
||||
## 六、学业规划
|
||||
|
||||
### 6.1 规划师选择页 (P2)
|
||||
|
||||
**路由**:`/pages/planner/list/index`
|
||||
|
||||
**设计图**:`docs/设计图/学业规划.png`
|
||||
|
||||
**功能描述**:
|
||||
- 展示规划师列表
|
||||
- 显示照片、姓名、介绍、价格
|
||||
|
||||
**数据来源**:
|
||||
| 数据 | 接口 | 说明 |
|
||||
|------|------|------|
|
||||
| 规划师列表 | GET /api/planner/getList | 获取规划师列表 |
|
||||
|
||||
---
|
||||
|
||||
### 6.2 规划预约页 (P2)
|
||||
|
||||
**路由**:`/pages/planner/book/index`
|
||||
|
||||
**设计图**:
|
||||
- `docs/设计图/学业规划2.png`
|
||||
- `docs/设计图/学业规划3.png`
|
||||
- `docs/设计图/学业规划4.png`
|
||||
|
||||
**功能描述**:
|
||||
- 选择预约日期和时间
|
||||
- 填写个人信息
|
||||
- 根据年级动态显示成绩字段
|
||||
- 支付预约费
|
||||
|
||||
**数据来源**:
|
||||
| 数据 | 接口 | 说明 |
|
||||
|------|------|------|
|
||||
| 预约 | POST /api/planner/book | 提交预约信息 |
|
||||
|
||||
---
|
||||
|
||||
## 七、分销相关
|
||||
|
||||
### 7.1 邀请新用户页 (P2)
|
||||
|
||||
**路由**:`/pages/invite/index`
|
||||
|
||||
**设计图**:
|
||||
- `docs/设计图/邀请新用户.png`
|
||||
- `docs/设计图/邀请新用户-二维码.png`
|
||||
- `docs/设计图/邀请新用户-提现金额.png`
|
||||
- `docs/设计图/邀请新用户-提现记录.png`
|
||||
|
||||
**功能描述**:
|
||||
- 邀请规则说明
|
||||
- 生成邀请二维码
|
||||
- 分享邀请链接
|
||||
- 已提现/待提现金额
|
||||
- 申请提现
|
||||
- 提现记录
|
||||
- 邀请记录列表
|
||||
|
||||
**访问权限**:仅合伙人及以上可见
|
||||
|
||||
**数据来源**:
|
||||
| 数据 | 接口 | 说明 |
|
||||
|------|------|------|
|
||||
| 邀请信息 | GET /api/invite/getInfo | 获取邀请信息 |
|
||||
| 生成二维码 | GET /api/invite/getQrcode | 生成邀请二维码 |
|
||||
| 邀请记录 | GET /api/invite/getRecordList | 获取邀请记录 |
|
||||
| 佣金信息 | GET /api/invite/getCommission | 获取佣金信息 |
|
||||
| 申请提现 | POST /api/invite/applyWithdraw | 申请提现 |
|
||||
| 提现记录 | GET /api/invite/getWithdrawList | 获取提现记录 |
|
||||
|
||||
---
|
||||
|
||||
## 八、其他页面
|
||||
|
||||
### 8.1 业务详情页 (P1)
|
||||
|
||||
**路由**:`/pages/business/detail/index`
|
||||
|
||||
**设计图**:`docs/设计图/业务详情页.png`
|
||||
|
||||
**功能描述**:
|
||||
- 展示业务介绍长图
|
||||
- 底部"点击参与"按钮(可选)
|
||||
|
||||
---
|
||||
|
||||
### 8.2 关于页 (P3)
|
||||
|
||||
**路由**:`/pages/about/index`
|
||||
|
||||
**设计图**:`docs/设计图/关于.png`
|
||||
|
||||
**功能描述**:
|
||||
- 显示 LOGO
|
||||
- 显示版本号
|
||||
|
||||
---
|
||||
|
||||
### 8.3 用户协议页 (P3)
|
||||
|
||||
**路由**:`/pages/agreement/user/index`
|
||||
|
||||
**设计图**:`docs/设计图/用户/隐私协议.png`
|
||||
|
||||
**功能描述**:
|
||||
- 显示用户协议内容
|
||||
|
||||
**数据来源**:
|
||||
| 数据 | 接口 | 说明 |
|
||||
|------|------|------|
|
||||
| 用户协议 | GET /api/system/getAgreement | 获取用户协议 |
|
||||
|
||||
---
|
||||
|
||||
### 8.4 隐私政策页 (P3)
|
||||
|
||||
**路由**:`/pages/agreement/privacy/index`
|
||||
|
||||
**设计图**:`docs/设计图/用户/隐私协议.png`
|
||||
|
||||
**功能描述**:
|
||||
- 显示隐私政策内容
|
||||
|
||||
**数据来源**:
|
||||
| 数据 | 接口 | 说明 |
|
||||
|------|------|------|
|
||||
| 隐私政策 | GET /api/system/getPrivacy | 获取隐私政策 |
|
||||
|
||||
---
|
||||
|
||||
## 九、开发顺序建议
|
||||
|
||||
### 第一阶段(P0 核心功能)
|
||||
1. 项目初始化 + 基础框架
|
||||
2. TabBar 框架(首页、团队、我的骨架)
|
||||
3. 登录页 + 登录流程
|
||||
4. 首页完整功能
|
||||
5. 测评流程(信息填写 → 答题 → 生成中 → 结果)
|
||||
|
||||
### 第二阶段(P1 重要功能)
|
||||
6. 我的页完整功能
|
||||
7. 个人资料页
|
||||
8. 我的订单页
|
||||
9. 往期测评页
|
||||
10. 业务详情页
|
||||
11. 团队页
|
||||
|
||||
### 第三阶段(P2 扩展功能)
|
||||
12. 学业规划-规划师选择
|
||||
13. 学业规划-预约
|
||||
14. 邀请新用户(分销功能)
|
||||
|
||||
### 第四阶段(P3 辅助功能)
|
||||
15. 关于页
|
||||
16. 用户协议页
|
||||
17. 隐私政策页
|
||||
Loading…
Reference in New Issue
Block a user