diff --git a/server/.idea/.gitignore b/server/.idea/.gitignore
new file mode 100644
index 0000000..35410ca
--- /dev/null
+++ b/server/.idea/.gitignore
@@ -0,0 +1,8 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/server/.idea/compiler.xml b/server/.idea/compiler.xml
new file mode 100644
index 0000000..f5e9b39
--- /dev/null
+++ b/server/.idea/compiler.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/server/.idea/encodings.xml b/server/.idea/encodings.xml
new file mode 100644
index 0000000..63e9001
--- /dev/null
+++ b/server/.idea/encodings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/server/.idea/jarRepositories.xml b/server/.idea/jarRepositories.xml
new file mode 100644
index 0000000..712ab9d
--- /dev/null
+++ b/server/.idea/jarRepositories.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/server/.idea/misc.xml b/server/.idea/misc.xml
new file mode 100644
index 0000000..76bd8cd
--- /dev/null
+++ b/server/.idea/misc.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/server/.idea/vcs.xml b/server/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/server/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/server/README.md b/server/README.md
new file mode 100644
index 0000000..bf2e3fd
--- /dev/null
+++ b/server/README.md
@@ -0,0 +1,156 @@
+# 校园活动组织与报名系统
+
+基于 Spring Boot 3.x 的校园活动组织与报名系统后端项目。
+
+## 技术栈
+
+- Java 21
+- Spring Boot 3.2.5
+- Spring Security 6.x
+- MyBatis-Plus 3.5.5
+- MySQL 8.0+
+- JWT (jjwt 0.12.5)
+- Knife4j 4.4.0
+- Hutool 5.8.25
+- ZXing 3.5.2 (二维码)
+- iText 8.0.2 (PDF)
+- EasyExcel 3.3.4
+
+## 项目结构
+
+```
+campus-activity-system/
+├── src/main/java/com/campus/activity/
+│ ├── CampusActivityApplication.java # 启动类
+│ ├── config/ # 配置类
+│ ├── controller/ # 控制器层
+│ ├── service/ # 服务层
+│ ├── mapper/ # 数据访问层
+│ ├── entity/ # 实体类
+│ ├── dto/ # 数据传输对象
+│ ├── vo/ # 视图对象
+│ ├── common/ # 公共模块
+│ ├── exception/ # 异常处理
+│ ├── security/ # 安全模块
+│ └── util/ # 工具类
+├── src/main/resources/
+│ ├── application.yml
+│ └── mapper/ # MyBatis XML映射文件
+├── docs/
+│ └── init.sql # 数据库初始化脚本
+└── pom.xml
+```
+
+## 快速开始
+
+### 1. 环境要求
+
+- JDK 21+
+- MySQL 8.0+
+- Maven 3.6+
+
+### 2. 数据库初始化
+
+执行 `docs/init.sql` 脚本创建数据库和表:
+
+```bash
+mysql -u root -p < docs/init.sql
+```
+
+### 3. 配置数据库连接
+
+修改 `src/main/resources/application.yml` 中的数据库配置:
+
+```yaml
+spring:
+ datasource:
+ url: jdbc:mysql://localhost:3306/campus_activity?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
+ username: root
+ password: your_password
+```
+
+### 4. 运行项目
+
+```bash
+mvn spring-boot:run
+```
+
+或者在 IDE 中运行 `CampusActivityApplication.java`。
+
+### 5. 访问 API 文档
+
+启动成功后,访问 Knife4j API 文档:
+
+```
+http://localhost:8080/doc.html
+```
+
+## 默认账号
+
+- 管理员账号:`admin` / `admin123`
+
+## API 接口
+
+### 认证模块
+
+- POST `/api/v1/auth/register` - 用户注册
+- POST `/api/v1/auth/login` - 用户登录
+- POST `/api/v1/auth/refresh` - 刷新Token
+- GET `/api/v1/auth/me` - 获取当前用户信息
+- PUT `/api/v1/auth/password` - 修改密码
+
+### 活动模块
+
+- GET `/api/v1/activities` - 活动列表
+- GET `/api/v1/activities/{id}` - 活动详情
+- POST `/api/v1/activities` - 创建活动(管理员)
+- PUT `/api/v1/activities/{id}` - 更新活动(管理员)
+- DELETE `/api/v1/activities/{id}` - 删除活动(管理员)
+- GET `/api/v1/activities/calendar` - 日历视图
+- POST `/api/v1/activities/check-conflict` - 时间冲突检测
+
+### 报名模块
+
+- POST `/api/v1/registrations` - 报名活动
+- DELETE `/api/v1/registrations/{id}` - 取消报名
+- GET `/api/v1/registrations/my` - 我的报名列表
+- GET `/api/v1/registrations/activity/{activityId}` - 活动报名列表(管理员)
+- GET `/api/v1/registrations/{id}/ticket` - 下载电子票PDF
+
+### 签到模块
+
+- POST `/api/v1/checkin/qrcode/{activityId}` - 生成签到二维码(管理员)
+- POST `/api/v1/checkin/scan` - 学生扫码签到
+- POST `/api/v1/checkin/ticket` - 管理员扫票签到
+- GET `/api/v1/checkin/activity/{activityId}` - 签到列表(管理员)
+
+### 评价模块
+
+- POST `/api/v1/reviews` - 提交评价
+- GET `/api/v1/reviews/activity/{activityId}` - 活动评价列表
+- GET `/api/v1/reviews/my` - 我的评价列表
+
+### 统计模块
+
+- GET `/api/v1/statistics/activity/{activityId}` - 活动统计(管理员)
+- GET `/api/v1/statistics/activity/{activityId}/export` - 导出活动数据(管理员)
+- GET `/api/v1/statistics/overview` - 总体统计(管理员)
+
+## 开发说明
+
+### 代码规范
+
+- 遵循阿里巴巴 Java 开发手册
+- 使用 Lombok 简化代码
+- 统一异常处理
+- 统一响应格式
+
+### 安全说明
+
+- 使用 JWT 进行身份认证
+- 密码使用 BCrypt 加密存储
+- 接口权限控制基于角色
+
+## 许可证
+
+Apache License 2.0
\ No newline at end of file
diff --git a/server/docs/API接口设计.md b/server/docs/API接口设计.md
new file mode 100644
index 0000000..b14ff08
--- /dev/null
+++ b/server/docs/API接口设计.md
@@ -0,0 +1,1208 @@
+# 校园活动系统 - 后端 API 接口文档
+
+## 基本信息
+
+- **基础路径**: `/api/v1`
+- **认证方式**: JWT Token (Bearer Token)
+- **响应格式**: JSON
+
+## 统一响应格式
+
+所有接口返回统一的响应格式:
+
+```json
+{
+ "code": 200,
+ "message": "success",
+ "data": {},
+ "timestamp": 1736620800000
+}
+```
+
+### 状态码说明
+
+| 状态码 | 说明 |
+|--------|------|
+| 200 | 成功 |
+| 400 | 请求参数错误 |
+| 401 | 未认证或Token已过期 |
+| 403 | 无权限访问 |
+| 404 | 资源不存在 |
+| 409 | 业务冲突 |
+| 500 | 服务器内部错误 |
+
+### 业务错误码
+
+| 错误码 | 说明 |
+|--------|------|
+| 1001 | 用户不存在 |
+| 1002 | 用户已存在 |
+| 1003 | 密码错误 |
+| 1004 | 用户名或密码错误 |
+| 1005 | 学号已存在 |
+| 2001 | 活动不存在 |
+| 2002 | 活动已开始,无法取消报名 |
+| 2003 | 活动时间冲突 |
+| 2004 | 活动报名人数已满 |
+| 3001 | 报名记录不存在 |
+| 3002 | 您已报名该活动 |
+| 3003 | 您未报名该活动 |
+| 4001 | 签到失败 |
+| 4002 | 已签到 |
+| 4003 | 签到时间已过期 |
+| 5001 | 您已评价该活动 |
+| 5002 | 评价记录不存在 |
+| 5003 | 您未参加该活动,无法评价 |
+
+---
+
+## 一、认证模块 (`/api/v1/auth`)
+
+### 1.1 用户注册
+
+**接口地址**: `POST /api/v1/auth/register`
+
+**请求权限**: 无需认证
+
+**请求参数**:
+
+| 参数名 | 类型 | 必填 | 说明 | 验证规则 |
+|--------|------|------|------|----------|
+| username | String | 是 | 用户名 | 3-50个字符 |
+| password | String | 是 | 密码 | 6-20个字符 |
+| name | String | 是 | 姓名 | 最多50个字符 |
+| studentId | String | 否 | 学号 | 10-20位数字 |
+| email | String | 否 | 邮箱 | 邮箱格式 |
+| phone | String | 否 | 手机号 | 11位手机号 |
+
+**请求示例**:
+```json
+{
+ "username": "student001",
+ "password": "123456",
+ "name": "张三",
+ "studentId": "2021000001",
+ "email": "zhangsan@example.com",
+ "phone": "13800138000"
+}
+```
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "注册成功",
+ "data": null,
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+### 1.2 用户登录
+
+**接口地址**: `POST /api/v1/auth/login`
+
+**请求权限**: 无需认证
+
+**请求参数**:
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| username | String | 是 | 用户名 |
+| password | String | 是 | 密码 |
+
+**请求示例**:
+```json
+{
+ "username": "student001",
+ "password": "123456"
+}
+```
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "登录成功",
+ "data": {
+ "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
+ "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
+ "expiresIn": 3600,
+ "tokenType": "Bearer",
+ "userInfo": {
+ "id": 1,
+ "username": "student001",
+ "name": "张三",
+ "role": 0,
+ "avatar": null
+ }
+ },
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+### 1.3 刷新Token
+
+**接口地址**: `POST /api/v1/auth/refresh`
+
+**请求权限**: 无需认证
+
+**请求参数**:
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| refreshToken | String | 是 | 刷新Token |
+
+**请求示例**:
+```json
+{
+ "refreshToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
+}
+```
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "success",
+ "data": {
+ "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
+ "expiresIn": 3600
+ },
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+### 1.4 获取当前用户信息
+
+**接口地址**: `GET /api/v1/auth/me`
+
+**请求权限**: 需要认证
+
+**请求头**:
+```
+Authorization: Bearer {accessToken}
+```
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "success",
+ "data": {
+ "id": 1,
+ "username": "student001",
+ "password": "$2a$10$...",
+ "name": "张三",
+ "studentId": "2021000001",
+ "email": "zhangsan@example.com",
+ "phone": "13800138000",
+ "avatar": null,
+ "role": 0,
+ "status": 1,
+ "createdAt": "2026-01-01T00:00:00",
+ "updatedAt": "2026-01-01T00:00:00"
+ },
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+### 1.5 修改密码
+
+**接口地址**: `PUT /api/v1/auth/password`
+
+**请求权限**: 需要认证
+
+**请求参数**:
+
+| 参数名 | 类型 | 必填 | 说明 | 验证规则 |
+|--------|------|------|------|----------|
+| oldPassword | String | 是 | 旧密码 | 不能为空 |
+| newPassword | String | 是 | 新密码 | 6-20个字符 |
+
+**请求示例**:
+```json
+{
+ "oldPassword": "123456",
+ "newPassword": "654321"
+}
+```
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "密码修改成功",
+ "data": null,
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+## 二、活动模块 (`/api/v1/activities`)
+
+### 2.1 获取活动列表
+
+**接口地址**: `GET /api/v1/activities`
+
+**请求权限**: 无需认证
+
+**请求参数**:
+
+| 参数名 | 类型 | 必填 | 说明 | 默认值 |
+|--------|------|------|------|--------|
+| current | Long | 否 | 当前页码 | 1 |
+| size | Long | 否 | 每页数量 | 10 |
+| status | Integer | 否 | 活动状态 | - |
+| keyword | String | 否 | 关键词搜索 | - |
+| category | String | 否 | 活动分类 | - |
+| startDate | LocalDateTime | 否 | 开始时间(yyyy-MM-dd HH:mm:ss) | - |
+| endDate | LocalDateTime | 否 | 结束时间(yyyy-MM-dd HH:mm:ss) | - |
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "success",
+ "data": {
+ "records": [
+ {
+ "id": 1,
+ "title": "校园音乐节",
+ "description": "一年一度的校园音乐盛会",
+ "coverImage": "https://example.com/cover.jpg",
+ "startTime": "2026-01-15T19:00:00",
+ "endTime": "2026-01-15T22:00:00",
+ "registrationDeadline": "2026-01-14T18:00:00",
+ "location": "大礼堂",
+ "maxParticipants": 500,
+ "currentParticipants": 300,
+ "status": 1,
+ "category": "文艺活动",
+ "adminId": 1,
+ "adminName": "管理员",
+ "averageRating": 4.5,
+ "reviewCount": 20,
+ "isRegistered": false,
+ "createdAt": "2026-01-01T00:00:00"
+ }
+ ],
+ "total": 1,
+ "pages": 1,
+ "current": 1,
+ "size": 10
+ },
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+### 2.2 获取活动详情
+
+**接口地址**: `GET /api/v1/activities/{id}`
+
+**请求权限**: 无需认证
+
+**路径参数**:
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| id | Long | 是 | 活动ID |
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "success",
+ "data": {
+ "id": 1,
+ "title": "校园音乐节",
+ "description": "一年一度的校园音乐盛会",
+ "coverImage": "https://example.com/cover.jpg",
+ "startTime": "2026-01-15T19:00:00",
+ "endTime": "2026-01-15T22:00:00",
+ "registrationDeadline": "2026-01-14T18:00:00",
+ "location": "大礼堂",
+ "maxParticipants": 500,
+ "currentParticipants": 300,
+ "status": 1,
+ "category": "文艺活动",
+ "adminId": 1,
+ "adminName": "管理员",
+ "averageRating": 4.5,
+ "reviewCount": 20,
+ "isRegistered": false,
+ "createdAt": "2026-01-01T00:00:00"
+ },
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+### 2.3 创建活动(管理员)
+
+**接口地址**: `POST /api/v1/activities`
+
+**请求权限**: 管理员 (ADMIN)
+
+**请求参数**:
+
+| 参数名 | 类型 | 必填 | 说明 | 验证规则 |
+|--------|------|------|------|----------|
+| title | String | 是 | 活动名称 | 最多100个字符 |
+| description | String | 否 | 活动简介 | 最多2000个字符 |
+| coverImage | String | 否 | 封面图片URL | - |
+| startTime | LocalDateTime | 是 | 开始时间 | 必须是未来时间 |
+| endTime | LocalDateTime | 是 | 结束时间 | - |
+| registrationDeadline | LocalDateTime | 否 | 报名截止时间 | - |
+| location | String | 是 | 活动地点 | 最多200个字符 |
+| maxParticipants | Integer | 是 | 报名人数上限 | 1-10000 |
+| category | String | 否 | 活动分类 | 最多50个字符 |
+
+**请求示例**:
+```json
+{
+ "title": "校园音乐节",
+ "description": "一年一度的校园音乐盛会",
+ "coverImage": "https://example.com/cover.jpg",
+ "startTime": "2026-01-15T19:00:00",
+ "endTime": "2026-01-15T22:00:00",
+ "registrationDeadline": "2026-01-14T18:00:00",
+ "location": "大礼堂",
+ "maxParticipants": 500,
+ "category": "文艺活动"
+}
+```
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "创建成功",
+ "data": 1,
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+### 2.4 更新活动(管理员)
+
+**接口地址**: `PUT /api/v1/activities/{id}`
+
+**请求权限**: 管理员 (ADMIN)
+
+**路径参数**:
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| id | Long | 是 | 活动ID |
+
+**请求参数**:
+
+| 参数名 | 类型 | 必填 | 说明 | 验证规则 |
+|--------|------|------|------|----------|
+| title | String | 是 | 活动名称 | 最多100个字符 |
+| description | String | 否 | 活动简介 | 最多2000个字符 |
+| coverImage | String | 否 | 封面图片URL | - |
+| startTime | LocalDateTime | 是 | 开始时间 | - |
+| endTime | LocalDateTime | 是 | 结束时间 | - |
+| registrationDeadline | LocalDateTime | 否 | 报名截止时间 | - |
+| location | String | 是 | 活动地点 | 最多200个字符 |
+| maxParticipants | Integer | 是 | 报名人数上限 | 1-10000 |
+| status | Integer | 否 | 活动状态 | - |
+| category | String | 否 | 活动分类 | 最多50个字符 |
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "更新成功",
+ "data": null,
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+### 2.5 删除活动(管理员)
+
+**接口地址**: `DELETE /api/v1/activities/{id}`
+
+**请求权限**: 管理员 (ADMIN)
+
+**路径参数**:
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| id | Long | 是 | 活动ID |
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "删除成功",
+ "data": null,
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+### 2.6 获取日历视图活动
+
+**接口地址**: `GET /api/v1/activities/calendar`
+
+**请求权限**: 无需认证
+
+**请求参数**:
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| year | Integer | 是 | 年份 |
+| month | Integer | 是 | 月份 |
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "success",
+ "data": [
+ {
+ "id": 1,
+ "title": "校园音乐节",
+ "description": "一年一度的校园音乐盛会",
+ "coverImage": "https://example.com/cover.jpg",
+ "startTime": "2026-01-15T19:00:00",
+ "endTime": "2026-01-15T22:00:00",
+ "registrationDeadline": "2026-01-14T18:00:00",
+ "location": "大礼堂",
+ "maxParticipants": 500,
+ "currentParticipants": 300,
+ "status": 1,
+ "category": "文艺活动",
+ "adminId": 1,
+ "adminName": "管理员",
+ "averageRating": 4.5,
+ "reviewCount": 20,
+ "isRegistered": false,
+ "createdAt": "2026-01-01T00:00:00"
+ }
+ ],
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+### 2.7 检测时间冲突(管理员)
+
+**接口地址**: `POST /api/v1/activities/check-conflict`
+
+**请求权限**: 管理员 (ADMIN)
+
+**请求参数**:
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| startTime | LocalDateTime | 是 | 开始时间 |
+| endTime | LocalDateTime | 是 | 结束时间 |
+| excludeActivityId | Long | 否 | 排除的活动ID(更新时使用) |
+
+**请求示例**:
+```json
+{
+ "startTime": "2026-01-15T19:00:00",
+ "endTime": "2026-01-15T22:00:00",
+ "excludeActivityId": 1
+}
+```
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "success",
+ "data": {
+ "hasConflict": true,
+ "conflictActivities": [
+ {
+ "id": 2,
+ "title": "校园篮球赛",
+ "startTime": "2026-01-15T18:00:00",
+ "endTime": "2026-01-15T20:00:00"
+ }
+ ]
+ },
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+## 三、报名模块 (`/api/v1/registrations`)
+
+### 3.1 报名活动
+
+**接口地址**: `POST /api/v1/registrations`
+
+**请求权限**: 需要认证
+
+**请求参数**:
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| activityId | Long | 是 | 活动ID |
+
+**请求示例**:
+```json
+{
+ "activityId": 1
+}
+```
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "报名成功",
+ "data": {
+ "id": 1,
+ "activityId": 1,
+ "activityTitle": "校园音乐节",
+ "activityStartTime": "2026-01-15T19:00:00",
+ "activityEndTime": "2026-01-15T22:00:00",
+ "activityLocation": "大礼堂",
+ "ticketCode": "TICKET202601150001",
+ "ticketPdfUrl": "https://example.com/tickets/TICKET202601150001.pdf",
+ "status": 1,
+ "createdAt": "2026-01-10T10:00:00",
+ "canceledAt": null
+ },
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+### 3.2 取消报名
+
+**接口地址**: `DELETE /api/v1/registrations/{id}`
+
+**请求权限**: 需要认证
+
+**路径参数**:
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| id | Long | 是 | 报名记录ID |
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "取消成功",
+ "data": null,
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+### 3.3 获取我的报名列表
+
+**接口地址**: `GET /api/v1/registrations/my`
+
+**请求权限**: 需要认证
+
+**请求参数**:
+
+| 参数名 | 类型 | 必填 | 说明 | 默认值 |
+|--------|------|------|------|--------|
+| current | Long | 否 | 当前页码 | 1 |
+| size | Long | 否 | 每页数量 | 10 |
+| status | Integer | 否 | 报名状态 | - |
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "success",
+ "data": {
+ "records": [
+ {
+ "id": 1,
+ "activityId": 1,
+ "activityTitle": "校园音乐节",
+ "activityStartTime": "2026-01-15T19:00:00",
+ "activityEndTime": "2026-01-15T22:00:00",
+ "activityLocation": "大礼堂",
+ "ticketCode": "TICKET202601150001",
+ "ticketPdfUrl": "https://example.com/tickets/TICKET202601150001.pdf",
+ "status": 1,
+ "createdAt": "2026-01-10T10:00:00",
+ "canceledAt": null
+ }
+ ],
+ "total": 1,
+ "pages": 1,
+ "current": 1,
+ "size": 10
+ },
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+### 3.4 获取活动报名列表(管理员)
+
+**接口地址**: `GET /api/v1/registrations/activity/{activityId}`
+
+**请求权限**: 管理员 (ADMIN)
+
+**路径参数**:
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| activityId | Long | 是 | 活动ID |
+
+**请求参数**:
+
+| 参数名 | 类型 | 必填 | 说明 | 默认值 |
+|--------|------|------|------|--------|
+| current | Long | 否 | 当前页码 | 1 |
+| size | Long | 否 | 每页数量 | 10 |
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "success",
+ "data": {
+ "records": [
+ {
+ "id": 1,
+ "activityId": 1,
+ "activityTitle": "校园音乐节",
+ "activityStartTime": "2026-01-15T19:00:00",
+ "activityEndTime": "2026-01-15T22:00:00",
+ "activityLocation": "大礼堂",
+ "ticketCode": "TICKET202601150001",
+ "ticketPdfUrl": "https://example.com/tickets/TICKET202601150001.pdf",
+ "status": 1,
+ "createdAt": "2026-01-10T10:00:00",
+ "canceledAt": null
+ }
+ ],
+ "total": 1,
+ "pages": 1,
+ "current": 1,
+ "size": 10
+ },
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+### 3.5 下载电子票PDF
+
+**接口地址**: `GET /api/v1/registrations/{id}/ticket`
+
+**请求权限**: 需要认证
+
+**路径参数**:
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| id | Long | 是 | 报名记录ID |
+
+**响应**: PDF文件流
+
+**响应头**:
+```
+Content-Disposition: attachment; filename=ticket.pdf
+Content-Type: application/pdf
+```
+
+---
+
+## 四、签到模块 (`/api/v1/checkin`)
+
+### 4.1 生成签到二维码(管理员)
+
+**接口地址**: `POST /api/v1/checkin/qrcode/{activityId}`
+
+**请求权限**: 管理员 (ADMIN)
+
+**路径参数**:
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| activityId | Long | 是 | 活动ID |
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "success",
+ "data": {
+ "qrCodeUrl": "https://example.com/qrcode/ACTIVITY1.png",
+ "qrCodeContent": "activity:1:2026-01-15T19:00:00",
+ "expiresAt": "2026-01-15T23:00:00"
+ },
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+### 4.2 学生扫码签到
+
+**接口地址**: `POST /api/v1/checkin/scan`
+
+**请求权限**: 需要认证
+
+**请求参数**:
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| qrCodeContent | String | 是 | 二维码内容 |
+
+**请求示例**:
+```json
+{
+ "qrCodeContent": "activity:1:2026-01-15T19:00:00"
+}
+```
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "签到成功",
+ "data": {
+ "id": 1,
+ "userId": 1,
+ "userName": "张三",
+ "studentId": "2021000001",
+ "activityId": 1,
+ "checkInTime": "2026-01-15T19:30:00",
+ "checkInMethod": 1
+ },
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+### 4.3 管理员扫学生票签到
+
+**接口地址**: `POST /api/v1/checkin/ticket`
+
+**请求权限**: 管理员 (ADMIN)
+
+**请求参数**:
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| activityId | Long | 是 | 活动ID |
+| ticketCode | String | 是 | 电子票号 |
+
+**请求示例**:
+```json
+{
+ "activityId": 1,
+ "ticketCode": "TICKET202601150001"
+}
+```
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "签到成功",
+ "data": {
+ "id": 1,
+ "userId": 1,
+ "userName": "张三",
+ "studentId": "2021000001",
+ "activityId": 1,
+ "checkInTime": "2026-01-15T19:30:00",
+ "checkInMethod": 2
+ },
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+### 4.4 获取活动签到列表(管理员)
+
+**接口地址**: `GET /api/v1/checkin/activity/{activityId}`
+
+**请求权限**: 管理员 (ADMIN)
+
+**路径参数**:
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| activityId | Long | 是 | 活动ID |
+
+**请求参数**:
+
+| 参数名 | 类型 | 必填 | 说明 | 默认值 |
+|--------|------|------|------|--------|
+| current | Long | 否 | 当前页码 | 1 |
+| size | Long | 否 | 每页数量 | 10 |
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "success",
+ "data": {
+ "records": [
+ {
+ "id": 1,
+ "userId": 1,
+ "userName": "张三",
+ "studentId": "2021000001",
+ "activityId": 1,
+ "checkInTime": "2026-01-15T19:30:00",
+ "checkInMethod": 1
+ }
+ ],
+ "total": 1,
+ "pages": 1,
+ "current": 1,
+ "size": 10
+ },
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+## 五、评价模块 (`/api/v1/reviews`)
+
+### 5.1 提交评价
+
+**接口地址**: `POST /api/v1/reviews`
+
+**请求权限**: 需要认证
+
+**请求参数**:
+
+| 参数名 | 类型 | 必填 | 说明 | 验证规则 |
+|--------|------|------|------|----------|
+| activityId | Long | 是 | 活动ID | - |
+| rating | Integer | 是 | 评分 | 1-5分 |
+| content | String | 否 | 评论内容 | 最多500个字符 |
+
+**请求示例**:
+```json
+{
+ "activityId": 1,
+ "rating": 5,
+ "content": "非常精彩的活动!"
+}
+```
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "评价成功",
+ "data": {
+ "id": 1,
+ "userId": 1,
+ "userName": "张三",
+ "userAvatar": null,
+ "activityId": 1,
+ "activityTitle": "校园音乐节",
+ "rating": 5,
+ "content": "非常精彩的活动!",
+ "createdAt": "2026-01-16T10:00:00"
+ },
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+### 5.2 获取活动评价列表
+
+**接口地址**: `GET /api/v1/reviews/activity/{activityId}`
+
+**请求权限**: 无需认证
+
+**路径参数**:
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| activityId | Long | 是 | 活动ID |
+
+**请求参数**:
+
+| 参数名 | 类型 | 必填 | 说明 | 默认值 |
+|--------|------|------|------|--------|
+| current | Long | 否 | 当前页码 | 1 |
+| size | Long | 否 | 每页数量 | 10 |
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "success",
+ "data": {
+ "records": [
+ {
+ "id": 1,
+ "userId": 1,
+ "userName": "张三",
+ "userAvatar": null,
+ "activityId": 1,
+ "activityTitle": "校园音乐节",
+ "rating": 5,
+ "content": "非常精彩的活动!",
+ "createdAt": "2026-01-16T10:00:00"
+ }
+ ],
+ "total": 1,
+ "pages": 1,
+ "current": 1,
+ "size": 10
+ },
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+### 5.3 获取我的评价列表
+
+**接口地址**: `GET /api/v1/reviews/my`
+
+**请求权限**: 需要认证
+
+**请求参数**:
+
+| 参数名 | 类型 | 必填 | 说明 | 默认值 |
+|--------|------|------|------|--------|
+| current | Long | 否 | 当前页码 | 1 |
+| size | Long | 否 | 每页数量 | 10 |
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "success",
+ "data": {
+ "records": [
+ {
+ "id": 1,
+ "userId": 1,
+ "userName": "张三",
+ "userAvatar": null,
+ "activityId": 1,
+ "activityTitle": "校园音乐节",
+ "rating": 5,
+ "content": "非常精彩的活动!",
+ "createdAt": "2026-01-16T10:00:00"
+ }
+ ],
+ "total": 1,
+ "pages": 1,
+ "current": 1,
+ "size": 10
+ },
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+## 六、统计模块 (`/api/v1/statistics`)
+
+### 6.1 获取活动统计数据(管理员)
+
+**接口地址**: `GET /api/v1/statistics/activity/{activityId}`
+
+**请求权限**: 管理员 (ADMIN)
+
+**路径参数**:
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| activityId | Long | 是 | 活动ID |
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "success",
+ "data": {
+ "activityId": 1,
+ "activityTitle": "校园音乐节",
+ "registeredCount": 300,
+ "checkedInCount": 250,
+ "checkInRate": 0.8333,
+ "reviewCount": 20,
+ "averageRating": 4.5,
+ "ratingDistribution": {
+ "1": 0,
+ "2": 1,
+ "3": 3,
+ "4": 6,
+ "5": 10
+ }
+ },
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+### 6.2 导出活动数据(管理员)
+
+**接口地址**: `GET /api/v1/statistics/activity/{activityId}/export`
+
+**请求权限**: 管理员 (ADMIN)
+
+**路径参数**:
+
+| 参数名 | 类型 | 必填 | 说明 |
+|--------|------|------|------|
+| activityId | Long | 是 | 活动ID |
+
+**请求参数**:
+
+| 参数名 | 类型 | 必填 | 说明 | 默认值 |
+|--------|------|------|------|--------|
+| format | String | 否 | 导出格式 | excel |
+
+**响应**: 文件流 (Excel或PDF)
+
+---
+
+### 6.3 获取总体统计(管理员)
+
+**接口地址**: `GET /api/v1/statistics/overview`
+
+**请求权限**: 管理员 (ADMIN)
+
+**响应示例**:
+```json
+{
+ "code": 200,
+ "message": "success",
+ "data": {
+ "totalActivities": 50,
+ "totalRegistrations": 1000,
+ "totalCheckIns": 800,
+ "totalReviews": 500,
+ "averageRating": 4.3,
+ "monthlyStats": [
+ {
+ "month": "2026-01",
+ "activityCount": 10,
+ "registrationCount": 200
+ },
+ {
+ "month": "2026-02",
+ "activityCount": 15,
+ "registrationCount": 300
+ }
+ ]
+ },
+ "timestamp": 1736620800000
+}
+```
+
+---
+
+## 附录:数据模型说明
+
+### 用户角色 (role)
+
+| 值 | 说明 |
+|----|------|
+| 0 | 学生 |
+| 1 | 管理员 |
+
+### 用户状态 (status)
+
+| 值 | 说明 |
+|----|------|
+| 0 | 禁用 |
+| 1 | 正常 |
+
+### 活动状态 (status)
+
+| 值 | 说明 |
+|----|------|
+| 0 | 草稿 |
+| 1 | 已发布 |
+| 2 | 进行中 |
+| 3 | 已结束 |
+| 4 | 已取消 |
+
+### 报名状态 (status)
+
+| 值 | 说明 |
+|----|------|
+| 0 | 已取消 |
+| 1 | 已报名 |
+
+### 签到方式 (checkInMethod)
+
+| 值 | 说明 |
+|----|------|
+| 1 | 学生扫码签到 |
+| 2 | 管理员扫票签到 |
+
+---
+
+## 接口权限汇总
+
+| 接口路径 | 方法 | 学生 | 管理员 | 说明 |
+|----------|------|------|--------|------|
+| `/auth/register` | POST | ✓ | ✓ | 公开 |
+| `/auth/login` | POST | ✓ | ✓ | 公开 |
+| `/auth/refresh` | POST | ✓ | ✓ | 公开 |
+| `/auth/me` | GET | ✓ | ✓ | 需要认证 |
+| `/auth/password` | PUT | ✓ | ✓ | 需要认证 |
+| `/activities` | GET | ✓ | ✓ | 公开 |
+| `/activities/{id}` | GET | ✓ | ✓ | 公开 |
+| `/activities` | POST | ✗ | ✓ | 仅管理员 |
+| `/activities/{id}` | PUT | ✗ | ✓ | 仅管理员 |
+| `/activities/{id}` | DELETE | ✗ | ✓ | 仅管理员 |
+| `/activities/calendar` | GET | ✓ | ✓ | 公开 |
+| `/activities/check-conflict` | POST | ✗ | ✓ | 仅管理员 |
+| `/registrations` | POST | ✓ | ✗ | 需要认证 |
+| `/registrations/{id}` | DELETE | ✓ | ✗ | 需要认证 |
+| `/registrations/my` | GET | ✓ | ✗ | 需要认证 |
+| `/registrations/activity/{id}` | GET | ✗ | ✓ | 仅管理员 |
+| `/registrations/{id}/ticket` | GET | ✓ | ✓ | 需要认证 |
+| `/checkin/qrcode/{id}` | POST | ✗ | ✓ | 仅管理员 |
+| `/checkin/scan` | POST | ✓ | ✗ | 需要认证 |
+| `/checkin/ticket` | POST | ✗ | ✓ | 仅管理员 |
+| `/checkin/activity/{id}` | GET | ✗ | ✓ | 仅管理员 |
+| `/reviews` | POST | ✓ | ✗ | 需要认证 |
+| `/reviews/activity/{id}` | GET | ✓ | ✓ | 公开 |
+| `/reviews/my` | GET | ✓ | ✗ | 需要认证 |
+| `/statistics/activity/{id}` | GET | ✗ | ✓ | 仅管理员 |
+| `/statistics/activity/{id}/export` | GET | ✗ | ✓ | 仅管理员 |
+| `/statistics/overview` | GET | ✗ | ✓ | 仅管理员 |
\ No newline at end of file
diff --git a/server/docs/init.sql b/server/docs/init.sql
new file mode 100644
index 0000000..b898e22
--- /dev/null
+++ b/server/docs/init.sql
@@ -0,0 +1,110 @@
+-- 创建数据库
+CREATE DATABASE IF NOT EXISTS `campus_activity`
+DEFAULT CHARACTER SET utf8mb4
+COLLATE utf8mb4_general_ci;
+
+USE `campus_activity`;
+
+-- 创建用户表
+CREATE TABLE `user` (
+ `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '用户ID',
+ `username` VARCHAR(50) NOT NULL COMMENT '登录用户名',
+ `password` VARCHAR(255) NOT NULL COMMENT '密码',
+ `name` VARCHAR(50) NOT NULL COMMENT '真实姓名',
+ `student_id` VARCHAR(20) DEFAULT NULL COMMENT '学号',
+ `email` VARCHAR(100) DEFAULT NULL COMMENT '邮箱',
+ `phone` VARCHAR(20) DEFAULT NULL COMMENT '手机号',
+ `avatar` VARCHAR(255) DEFAULT NULL COMMENT '头像URL',
+ `role` TINYINT NOT NULL DEFAULT 0 COMMENT '角色:0-学生,1-管理员',
+ `status` TINYINT DEFAULT 1 COMMENT '状态:0-禁用,1-正常',
+ `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updated_at` DATETIME DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `deleted` TINYINT DEFAULT 0 COMMENT '逻辑删除',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_username` (`username`),
+ UNIQUE KEY `uk_student_id` (`student_id`),
+ KEY `idx_role` (`role`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='用户表';
+
+-- 创建活动表
+CREATE TABLE `activity` (
+ `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '活动ID',
+ `title` VARCHAR(100) NOT NULL COMMENT '活动名称',
+ `description` TEXT DEFAULT NULL COMMENT '活动简介',
+ `cover_image` VARCHAR(255) DEFAULT NULL COMMENT '封面图片',
+ `start_time` DATETIME NOT NULL COMMENT '开始时间',
+ `end_time` DATETIME NOT NULL COMMENT '结束时间',
+ `registration_deadline` DATETIME DEFAULT NULL COMMENT '报名截止时间',
+ `location` VARCHAR(200) NOT NULL COMMENT '活动地点',
+ `max_participants` INT NOT NULL COMMENT '报名人数上限',
+ `current_participants` INT DEFAULT 0 COMMENT '当前报名人数',
+ `status` TINYINT DEFAULT 0 COMMENT '状态:0-未开始,1-报名中,2-进行中,3-已结束',
+ `category` VARCHAR(50) DEFAULT NULL COMMENT '活动分类',
+ `admin_id` BIGINT NOT NULL COMMENT '创建者ID',
+ `qr_code` VARCHAR(255) DEFAULT NULL COMMENT '签到二维码',
+ `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
+ `updated_at` DATETIME DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `deleted` TINYINT DEFAULT 0 COMMENT '逻辑删除',
+ `version` INT DEFAULT 0 COMMENT '乐观锁版本号',
+ PRIMARY KEY (`id`),
+ KEY `idx_status` (`status`),
+ KEY `idx_start_time` (`start_time`),
+ KEY `idx_admin_id` (`admin_id`),
+ CONSTRAINT `fk_activity_admin` FOREIGN KEY (`admin_id`) REFERENCES `user` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='活动表';
+
+-- 创建报名表
+CREATE TABLE `registration` (
+ `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '报名ID',
+ `user_id` BIGINT NOT NULL COMMENT '用户ID',
+ `activity_id` BIGINT NOT NULL COMMENT '活动ID',
+ `ticket_code` VARCHAR(100) DEFAULT NULL COMMENT '电子票唯一码',
+ `ticket_pdf_url` VARCHAR(255) DEFAULT NULL COMMENT '电子票PDF地址',
+ `status` TINYINT DEFAULT 1 COMMENT '状态:0-已取消,1-已报名,2-已签到',
+ `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '报名时间',
+ `updated_at` DATETIME DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ `canceled_at` DATETIME DEFAULT NULL COMMENT '取消时间',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_user_activity` (`user_id`, `activity_id`),
+ UNIQUE KEY `uk_ticket_code` (`ticket_code`),
+ KEY `idx_activity_id` (`activity_id`),
+ CONSTRAINT `fk_registration_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`),
+ CONSTRAINT `fk_registration_activity` FOREIGN KEY (`activity_id`) REFERENCES `activity` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='报名表';
+
+-- 创建签到表
+CREATE TABLE `check_in` (
+ `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '签到ID',
+ `registration_id` BIGINT NOT NULL COMMENT '报名ID',
+ `user_id` BIGINT NOT NULL COMMENT '用户ID',
+ `activity_id` BIGINT NOT NULL COMMENT '活动ID',
+ `check_in_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '签到时间',
+ `check_in_method` TINYINT DEFAULT 0 COMMENT '签到方式:0-扫码,1-管理员代签',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_registration_id` (`registration_id`),
+ KEY `idx_activity_id` (`activity_id`),
+ KEY `idx_user_id` (`user_id`),
+ CONSTRAINT `fk_checkin_registration` FOREIGN KEY (`registration_id`) REFERENCES `registration` (`id`),
+ CONSTRAINT `fk_checkin_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`),
+ CONSTRAINT `fk_checkin_activity` FOREIGN KEY (`activity_id`) REFERENCES `activity` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='签到表';
+
+-- 创建评价表
+CREATE TABLE `review` (
+ `id` BIGINT NOT NULL AUTO_INCREMENT COMMENT '评价ID',
+ `user_id` BIGINT NOT NULL COMMENT '用户ID',
+ `activity_id` BIGINT NOT NULL COMMENT '活动ID',
+ `rating` TINYINT NOT NULL COMMENT '评分(1-5)',
+ `content` TEXT DEFAULT NULL COMMENT '评论内容',
+ `created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '评价时间',
+ `updated_at` DATETIME DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
+ PRIMARY KEY (`id`),
+ UNIQUE KEY `uk_user_activity` (`user_id`, `activity_id`),
+ KEY `idx_activity_id` (`activity_id`),
+ CONSTRAINT `fk_review_user` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`),
+ CONSTRAINT `fk_review_activity` FOREIGN KEY (`activity_id`) REFERENCES `activity` (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='评价表';
+
+-- 插入测试管理员账号(密码:admin123,BCrypt加密)
+INSERT INTO `user` (`username`, `password`, `name`, `role`) VALUES
+('admin', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iKXP6X3SqmI8Q0WJLoUbWAHZJ.5i', '系统管理员', 1);
\ No newline at end of file
diff --git a/server/docs/sample_data.sql b/server/docs/sample_data.sql
new file mode 100644
index 0000000..a1f3fa2
--- /dev/null
+++ b/server/docs/sample_data.sql
@@ -0,0 +1,105 @@
+-- 校园活动组织与报名系统 - 示例数据
+-- 执行前请确保已运行 init.sql 创建数据库和表结构
+
+USE `campus_activity`;
+
+-- ============================================
+-- 1. 插入示例学生账户(密码:123456)
+-- ============================================
+-- 密码 "123456" 的 BCrypt 加密值
+INSERT INTO `user` (`username`, `password`, `name`, `student_id`, `email`, `phone`, `role`, `status`) VALUES
+('student01', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iKXP6X3SqmI8Q0WJLoUbWAHZJ.5i', '张三', '2024001', 'zhangsan@example.com', '13800138001', 0, 1),
+('student02', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iKXP6X3SqmI8Q0WJLoUbWAHZJ.5i', '李四', '2024002', 'lisi@example.com', '13800138002', 0, 1),
+('student03', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iKXP6X3SqmI8Q0WJLoUbWAHZJ.5i', '王五', '2024003', 'wangwu@example.com', '13800138003', 0, 1),
+('student04', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iKXP6X3SqmI8Q0WJLoUbWAHZJ.5i', '赵六', '2024004', 'zhaoliu@example.com', '13800138004', 0, 1),
+('student05', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iKXP6X3SqmI8Q0WJLoUbWAHZJ.5i', '孙七', '2024005', 'sunqi@example.com', '13800138005', 0, 1),
+('student06', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iKXP6X3SqmI8Q0WJLoUbWAHZJ.5i', '周八', '2024006', 'zhouba@example.com', '13800138006', 0, 1),
+('student07', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iKXP6X3SqmI8Q0WJLoUbWAHZJ.5i', '吴九', '2024007', 'wujiu@example.com', '13800138007', 0, 1),
+('student08', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iKXP6X3SqmI8Q0WJLoUbWAHZJ.5i', '郑十', '2024008', 'zhengshi@example.com', '13800138008', 0, 1),
+('student09', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iKXP6X3SqmI8Q0WJLoUbWAHZJ.5i', '陈十一', '2024009', 'chenshiyi@example.com', '13800138009', 0, 1),
+('student10', '$2a$10$N.zmdr9k7uOCQb376NoUnuTJ8iKXP6X3SqmI8Q0WJLoUbWAHZJ.5i', '刘十二', '2024010', 'liushier@example.com', '13800138010', 0, 1);
+
+-- ============================================
+-- 2. 插入示例活动数据
+-- ============================================
+INSERT INTO `activity` (`title`, `description`, `cover_image`, `start_time`, `end_time`, `registration_deadline`, `location`, `max_participants`, `current_participants`, `status`, `category`, `admin_id`) VALUES
+('科技创新大赛', '校园年度科技创新大赛,展示学生创新成果,激发创新热情', 'https://example.com/images/tech.jpg', '2026-01-15 09:00:00', '2026-01-15 17:00:00', '2026-01-14 23:59:59', '学术报告厅', 100, 0, 1, '科技竞赛', 1),
+('校园歌手大赛', '展示青春风采,唱响校园旋律', 'https://example.com/images/singer.jpg', '2026-01-20 19:00:00', '2026-01-20 22:00:00', '2026-01-19 18:00:00', '大学生活动中心', 300, 0, 1, '文艺娱乐', 1),
+('编程马拉松', '48小时极限编程挑战,团队协作完成创新项目', 'https://example.com/images/code.jpg', '2026-01-25 09:00:00', '2026-01-27 09:00:00', '2026-01-23 23:59:59', '计算机学院实验室', 50, 0, 1, '科技竞赛', 1),
+('读书分享会', '分享阅读心得,交流思想感悟', 'https://example.com/images/book.jpg', '2026-01-18 14:00:00', '2026-01-18 16:30:00', '2026-01-17 12:00:00', '图书馆报告厅', 80, 0, 1, '学术讲座', 1),
+('篮球友谊赛', '增进友谊,强健体魄,展现体育精神', 'https://example.com/images/basketball.jpg', '2026-01-22 16:00:00', '2026-01-22 18:00:00', '2026-01-21 12:00:00', '体育馆', 40, 0, 1, '体育活动', 1),
+('创业讲座', '邀请成功企业家分享创业经验', 'https://example.com/images/business.jpg', '2026-01-28 14:00:00', '2026-01-28 17:00:00', '2026-01-27 12:00:00', '商学院报告厅', 150, 0, 1, '学术讲座', 1),
+('摄影展', '展示校园风光,记录美好瞬间', 'https://example.com/images/photo.jpg', '2026-01-30 09:00:00', '2026-01-31 18:00:00', '2026-01-29 12:00:00', '艺术楼展厅', 200, 0, 1, '文艺娱乐', 1),
+('英语角活动', '提升英语口语能力,结交志同道合的朋友', 'https://example.com/images/english.jpg', '2026-01-16 19:00:00', '2026-01-16 21:00:00', '2026-01-15 18:00:00', '外语学院活动室', 30, 0, 1, '学术讲座', 1);
+
+-- ============================================
+-- 3. 插入示例报名数据
+-- ============================================
+-- 学生报名活动
+INSERT INTO `registration` (`user_id`, `activity_id`, `ticket_code`, `status`) VALUES
+(2, 1, 'TICKET-20260115001', 1), -- 张三报名科技创新大赛
+(3, 1, 'TICKET-20260115002', 1), -- 李四报名科技创新大赛
+(4, 1, 'TICKET-20260115003', 1), -- 王五报名科技创新大赛
+(2, 2, 'TICKET-20260120001', 1), -- 张三报名校园歌手大赛
+(5, 2, 'TICKET-20260120002', 1), -- 赵六报名校园歌手大赛
+(6, 2, 'TICKET-20260120003', 1), -- 孙七报名校园歌手大赛
+(7, 2, 'TICKET-20260120004', 1), -- 周八报名校园歌手大赛
+(3, 3, 'TICKET-20260125001', 1), -- 李四报名编程马拉松
+(4, 3, 'TICKET-20260125002', 1), -- 王五报名编程马拉松
+(8, 3, 'TICKET-20260125003', 1), -- 吴九报名编程马拉松
+(2, 4, 'TICKET-20260118001', 1), -- 张三报名读书分享会
+(5, 4, 'TICKET-20260118002', 1), -- 赵六报名读书分享会
+(9, 4, 'TICKET-20260118003', 1), -- 郑十报名读书分享会
+(3, 5, 'TICKET-20260122001', 1), -- 李四报名篮球友谊赛
+(6, 5, 'TICKET-20260122002', 1), -- 孙七报名篮球友谊赛
+(10, 5, 'TICKET-20260122003', 1), -- 刘十二报名篮球友谊赛
+(4, 6, 'TICKET-20260128001', 1), -- 王五报名创业讲座
+(7, 6, 'TICKET-20260128002', 1), -- 周八报名创业讲座
+(2, 7, 'TICKET-20260130001', 1), -- 张三报名摄影展
+(5, 7, 'TICKET-20260130002', 1), -- 赵六报名摄影展
+(8, 7, 'TICKET-20260130003', 1), -- 吴九报名摄影展
+(3, 8, 'TICKET-20260116001', 1), -- 李四报名英语角
+(9, 8, 'TICKET-20260116002', 1); -- 郑十报名英语角
+
+-- 更新活动的当前报名人数
+UPDATE `activity` SET `current_participants` = 3 WHERE `id` = 1;
+UPDATE `activity` SET `current_participants` = 4 WHERE `id` = 2;
+UPDATE `activity` SET `current_participants` = 3 WHERE `id` = 3;
+UPDATE `activity` SET `current_participants` = 3 WHERE `id` = 4;
+UPDATE `activity` SET `current_participants` = 3 WHERE `id` = 5;
+UPDATE `activity` SET `current_participants` = 2 WHERE `id` = 6;
+UPDATE `activity` SET `current_participants` = 3 WHERE `id` = 7;
+UPDATE `activity` SET `current_participants` = 2 WHERE `id` = 8;
+
+-- ============================================
+-- 4. 插入示例签到数据
+-- ============================================
+INSERT INTO `check_in` (`registration_id`, `user_id`, `activity_id`, `check_in_method`) VALUES
+(1, 2, 1, 0), -- 张三扫码签到科技创新大赛
+(2, 3, 1, 0), -- 李四扫码签到科技创新大赛
+(4, 2, 2, 1), -- 张三管理员代签校园歌手大赛
+(11, 2, 4, 0), -- 张三扫码签到读书分享会
+(15, 3, 5, 0); -- 李四扫码签到篮球友谊赛
+
+-- 更新报名状态为已签到
+UPDATE `registration` SET `status` = 2 WHERE `id` IN (1, 2, 4, 11, 15);
+
+-- ============================================
+-- 5. 插入示例评价数据
+-- ============================================
+INSERT INTO `review` (`user_id`, `activity_id`, `rating`, `content`) VALUES
+(2, 1, 5, '非常有意义的活动,学到了很多新技术!'),
+(3, 1, 4, '组织得很好,希望下次能增加更多互动环节'),
+(2, 2, 5, '歌手们都很棒,现场气氛热烈!'),
+(5, 2, 4, '活动很精彩,就是座位有点紧张'),
+(2, 4, 5, '分享的内容很有深度,受益匪浅'),
+(5, 4, 4, '书籍推荐很实用,期待下次活动'),
+(3, 5, 5, '比赛很激烈,团队合作很重要'),
+(6, 5, 4, '裁判很专业,场地也不错');
+
+-- ============================================
+-- 数据插入完成
+-- ============================================
+SELECT '示例数据插入完成!' AS message;
+SELECT '管理员账号:admin / admin123' AS admin_account;
+SELECT '学生账号:student01-student10 / 123456' AS student_accounts;
\ No newline at end of file
diff --git a/server/docs/前端开发规范.md b/server/docs/前端开发规范.md
new file mode 100644
index 0000000..c300384
--- /dev/null
+++ b/server/docs/前端开发规范.md
@@ -0,0 +1,1343 @@
+# 校园活动组织与报名系统 - 前端开发规范
+
+## 1. 命名规范
+
+### 1.1 文件命名
+
+| 类型 | 规范 | 示例 |
+|------|------|------|
+| Vue 组件 | PascalCase | `ActivityCard.vue`, `NavBar.vue` |
+| TypeScript 文件 | camelCase | `useAuth.ts`, `request.ts` |
+| 样式文件 | kebab-case | `global.scss`, `variables.scss` |
+| 常量文件 | camelCase | `constant.ts` |
+| 类型定义文件 | kebab-case.d.ts | `user.d.ts`, `activity.d.ts` |
+
+### 1.2 变量命名
+
+```typescript
+// 常量:全大写下划线分隔
+const API_BASE_URL = '/api/v1'
+const MAX_FILE_SIZE = 1024 * 1024 * 5
+
+// 变量:小驼峰
+const userName = 'zhangsan'
+const activityList = []
+
+// 布尔值:is/has/can 前缀
+const isLoading = false
+const hasPermission = true
+const canEdit = false
+
+// 私有属性:下划线前缀
+const _privateData = {}
+
+// 组件 props:小驼峰
+const props = defineProps<{
+ activityId: number
+ showDetail: boolean
+}>()
+
+// 事件名:on 前缀
+const emit = defineEmits<{
+ onSubmit: [data: FormData]
+ onCancel: []
+}>()
+```
+
+### 1.3 函数命名
+
+```typescript
+// 获取数据:get 前缀
+function getActivityList() {}
+function getUserInfo() {}
+
+// 设置数据:set 前缀
+function setToken(token: string) {}
+
+// 处理事件:handle 前缀
+function handleSubmit() {}
+function handleClick() {}
+
+// 判断逻辑:is/has/can 前缀
+function isAdmin() {}
+function hasRegistered() {}
+function canCheckIn() {}
+
+// 格式化:format 前缀
+function formatDate(date: Date) {}
+function formatPrice(price: number) {}
+
+// 转换:to 前缀
+function toArray(data: any) {}
+function toString(value: any) {}
+
+// 异步操作:async/await
+async function fetchActivities() {}
+async function submitRegistration() {}
+```
+
+### 1.4 CSS 类命名 (BEM 规范)
+
+```scss
+// Block__Element--Modifier
+
+// 活动卡片
+.activity-card {
+ // Element
+ &__header {}
+ &__title {}
+ &__content {}
+ &__footer {}
+ &__image {}
+
+ // Modifier
+ &--active {}
+ &--disabled {}
+ &--loading {}
+}
+
+// 示例
+
+```
+
+### 1.5 路由命名
+
+```typescript
+// 路由 name:PascalCase
+{
+ path: '/activities',
+ name: 'ActivityList',
+ component: () => import('@/views/activity/List.vue')
+}
+
+// 路由 path:kebab-case
+{
+ path: '/my/registrations',
+ name: 'MyRegistrations',
+ component: () => import('@/views/registration/MyList.vue')
+}
+```
+
+---
+
+## 2. 代码风格规范
+
+### 2.1 Vue 组件结构
+
+```vue
+
+
+
+
+
+
+
+```
+
+### 2.2 TypeScript 规范
+
+```typescript
+// 1. 明确类型声明,避免使用 any
+// Bad
+const data: any = {}
+
+// Good
+interface ActivityData {
+ id: number
+ title: string
+}
+const data: ActivityData = { id: 1, title: '活动' }
+
+// 2. 使用 interface 定义对象类型
+interface User {
+ id: number
+ username: string
+ name: string
+ role: 0 | 1
+}
+
+// 3. 使用 type 定义联合类型
+type ActivityStatus = 0 | 1 | 2 | 3
+type RequestMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'
+
+// 4. 使用枚举定义常量集合
+enum ActivityStatusEnum {
+ PENDING = 0, // 未开始
+ OPEN = 1, // 报名中
+ ONGOING = 2, // 进行中
+ ENDED = 3 // 已结束
+}
+
+// 5. 泛型使用
+interface ApiResponse {
+ code: number
+ message: string
+ data: T
+ timestamp: number
+}
+
+// 6. 可选属性使用 ?
+interface CreateActivityParams {
+ title: string
+ description?: string
+ coverImage?: string
+}
+
+// 7. 只读属性使用 readonly
+interface Config {
+ readonly apiUrl: string
+ readonly timeout: number
+}
+```
+
+### 2.3 API 请求规范
+
+```typescript
+// src/api/activity.ts
+import request from '@/utils/request'
+import type { Activity, ActivityListParams, CreateActivityParams } from '@/types/activity'
+import type { ApiResponse, PageResult } from '@/types/api'
+
+/**
+ * 获取活动列表
+ * @param params 查询参数
+ */
+export function getActivityList(params: ActivityListParams) {
+ return request.get>>('/activities', { params })
+}
+
+/**
+ * 获取活动详情
+ * @param id 活动ID
+ */
+export function getActivityDetail(id: number) {
+ return request.get>(`/activities/${id}`)
+}
+
+/**
+ * 创建活动(管理员)
+ * @param data 活动数据
+ */
+export function createActivity(data: CreateActivityParams) {
+ return request.post>('/activities', data)
+}
+
+/**
+ * 更新活动(管理员)
+ * @param id 活动ID
+ * @param data 更新数据
+ */
+export function updateActivity(id: number, data: Partial) {
+ return request.put>(`/activities/${id}`, data)
+}
+
+/**
+ * 删除活动(管理员)
+ * @param id 活动ID
+ */
+export function deleteActivity(id: number) {
+ return request.delete>(`/activities/${id}`)
+}
+```
+
+### 2.4 Store 规范
+
+```typescript
+// src/stores/user.ts
+import { defineStore } from 'pinia'
+import { ref, computed } from 'vue'
+import type { UserInfo } from '@/types/user'
+import { login, getUserInfo, refreshToken } from '@/api/auth'
+
+export const useUserStore = defineStore('user', () => {
+ // State
+ const token = ref(localStorage.getItem('accessToken'))
+ const refreshTokenValue = ref(localStorage.getItem('refreshToken'))
+ const userInfo = ref(null)
+
+ // Getters
+ const isLoggedIn = computed(() => !!token.value)
+ const isAdmin = computed(() => userInfo.value?.role === 1)
+ const userName = computed(() => userInfo.value?.name || '')
+
+ // Actions
+ async function loginAction(username: string, password: string) {
+ try {
+ const res = await login({ username, password })
+ token.value = res.data.accessToken
+ refreshTokenValue.value = res.data.refreshToken
+ userInfo.value = res.data.userInfo
+
+ localStorage.setItem('accessToken', res.data.accessToken)
+ localStorage.setItem('refreshToken', res.data.refreshToken)
+
+ return true
+ } catch (error) {
+ return false
+ }
+ }
+
+ function logout() {
+ token.value = null
+ refreshTokenValue.value = null
+ userInfo.value = null
+
+ localStorage.removeItem('accessToken')
+ localStorage.removeItem('refreshToken')
+ }
+
+ async function fetchUserInfo() {
+ try {
+ const res = await getUserInfo()
+ userInfo.value = res.data
+ } catch (error) {
+ console.error('获取用户信息失败', error)
+ }
+ }
+
+ return {
+ // State
+ token,
+ userInfo,
+ // Getters
+ isLoggedIn,
+ isAdmin,
+ userName,
+ // Actions
+ loginAction,
+ logout,
+ fetchUserInfo
+ }
+})
+```
+
+### 2.5 Composable 规范
+
+```typescript
+// src/composables/usePagination.ts
+import { ref, computed } from 'vue'
+
+interface PaginationOptions {
+ defaultPage?: number
+ defaultSize?: number
+}
+
+export function usePagination(options: PaginationOptions = {}) {
+ const { defaultPage = 1, defaultSize = 10 } = options
+
+ const currentPage = ref(defaultPage)
+ const pageSize = ref(defaultSize)
+ const total = ref(0)
+
+ const totalPages = computed(() => Math.ceil(total.value / pageSize.value))
+ const hasMore = computed(() => currentPage.value < totalPages.value)
+
+ function setTotal(value: number) {
+ total.value = value
+ }
+
+ function nextPage() {
+ if (hasMore.value) {
+ currentPage.value++
+ }
+ }
+
+ function prevPage() {
+ if (currentPage.value > 1) {
+ currentPage.value--
+ }
+ }
+
+ function reset() {
+ currentPage.value = defaultPage
+ total.value = 0
+ }
+
+ return {
+ currentPage,
+ pageSize,
+ total,
+ totalPages,
+ hasMore,
+ setTotal,
+ nextPage,
+ prevPage,
+ reset
+ }
+}
+```
+
+---
+
+## 3. 组件开发规范
+
+### 3.1 组件分类
+
+| 类型 | 位置 | 说明 |
+|------|------|------|
+| 基础组件 | components/common/ | 通用 UI 组件,如 NavBar、TabBar |
+| 业务组件 | components/[module]/ | 特定业务模块组件 |
+| 页面组件 | views/[module]/ | 路由对应的页面组件 |
+| 布局组件 | layouts/ | 页面布局组件 |
+
+### 3.2 组件设计原则
+
+```vue
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+```
+
+### 3.3 组件 Props 规范
+
+```typescript
+// 1. 使用 TypeScript 定义 Props
+interface Props {
+ // 必填属性
+ activityId: number
+ // 可选属性,带默认值
+ showImage?: boolean
+ // 复杂类型
+ activity: Activity
+}
+
+const props = withDefaults(defineProps(), {
+ showImage: true
+})
+
+// 2. Props 校验(可选,TS 已提供类型检查)
+const props = defineProps({
+ activityId: {
+ type: Number,
+ required: true
+ },
+ status: {
+ type: Number,
+ default: 0,
+ validator: (value: number) => [0, 1, 2, 3].includes(value)
+ }
+})
+```
+
+### 3.4 组件样式规范
+
+```vue
+
+```
+
+---
+
+## 4. 类型定义规范
+
+### 4.1 API 响应类型
+
+```typescript
+// src/types/api.d.ts
+
+// 统一响应格式
+interface ApiResponse {
+ code: number
+ message: string
+ data: T
+ timestamp: number
+}
+
+// 分页响应
+interface PageResult {
+ records: T[]
+ total: number
+ pages: number
+ current: number
+ size: number
+}
+
+// 分页请求参数
+interface PageParams {
+ page?: number
+ size?: number
+}
+```
+
+### 4.2 业务类型定义
+
+```typescript
+// src/types/user.d.ts
+interface UserInfo {
+ id: number
+ username: string
+ name: string
+ studentId: string | null
+ email: string | null
+ phone: string | null
+ avatar: string | null
+ role: 0 | 1 // 0-学生,1-管理员
+}
+
+interface LoginRequest {
+ username: string
+ password: string
+}
+
+interface LoginResponse {
+ accessToken: string
+ refreshToken: string
+ expiresIn: number
+ tokenType: string
+ userInfo: UserInfo
+}
+
+// src/types/activity.d.ts
+interface Activity {
+ id: number
+ title: string
+ description: string
+ coverImage: string | null
+ startTime: string
+ endTime: string
+ registrationDeadline: string | null
+ location: string
+ maxParticipants: number
+ currentParticipants: number
+ status: ActivityStatus
+ category: string | null
+ adminId: number
+ adminName?: string
+ averageRating?: number
+ reviewCount?: number
+ isRegistered?: boolean
+ createdAt: string
+}
+
+type ActivityStatus = 0 | 1 | 2 | 3
+
+interface ActivityListParams extends PageParams {
+ status?: ActivityStatus
+ keyword?: string
+ category?: string
+ startDate?: string
+ endDate?: string
+}
+
+interface CreateActivityParams {
+ title: string
+ description?: string
+ coverImage?: string
+ startTime: string
+ endTime: string
+ registrationDeadline?: string
+ location: string
+ maxParticipants: number
+ category?: string
+}
+
+// src/types/registration.d.ts
+interface Registration {
+ id: number
+ activityId: number
+ activityTitle: string
+ activityStartTime: string
+ activityLocation: string
+ ticketCode: string
+ ticketPdfUrl: string
+ status: RegistrationStatus
+ createdAt: string
+}
+
+type RegistrationStatus = 0 | 1 | 2 // 0-已取消,1-已报名,2-已签到
+
+// src/types/review.d.ts
+interface Review {
+ id: number
+ userId: number
+ userName: string
+ userAvatar: string | null
+ activityId: number
+ rating: 1 | 2 | 3 | 4 | 5
+ content: string
+ createdAt: string
+}
+
+interface CreateReviewParams {
+ activityId: number
+ rating: number
+ content: string
+}
+```
+
+---
+
+## 5. 错误处理规范
+
+### 5.1 API 错误处理
+
+```typescript
+// src/utils/request.ts
+import axios from 'axios'
+import { showToast, showDialog } from 'vant'
+import router from '@/router'
+import { useUserStore } from '@/stores/user'
+
+const instance = axios.create({
+ baseURL: import.meta.env.VITE_API_BASE_URL,
+ timeout: 10000
+})
+
+// 响应拦截器
+instance.interceptors.response.use(
+ response => {
+ const { code, message, data } = response.data
+
+ // 业务成功
+ if (code === 200) {
+ return response.data
+ }
+
+ // 业务错误
+ showToast(message || '操作失败')
+ return Promise.reject(new Error(message))
+ },
+ error => {
+ const { response } = error
+
+ if (response) {
+ const { status, data } = response
+
+ switch (status) {
+ case 400:
+ showToast(data.message || '请求参数错误')
+ break
+ case 401:
+ // Token 过期,清除登录状态,跳转登录页
+ const userStore = useUserStore()
+ userStore.logout()
+ router.push('/login')
+ showToast('登录已过期,请重新登录')
+ break
+ case 403:
+ showToast('无权限访问')
+ break
+ case 404:
+ showToast('请求的资源不存在')
+ break
+ case 409:
+ // 业务冲突,显示具体原因
+ showToast(data.message || '操作冲突')
+ break
+ case 500:
+ showToast('服务器异常,请稍后重试')
+ break
+ default:
+ showToast('网络异常')
+ }
+ } else {
+ showToast('网络连接失败')
+ }
+
+ return Promise.reject(error)
+ }
+)
+```
+
+### 5.2 组件错误处理
+
+```vue
+
+```
+
+### 5.3 表单校验
+
+```vue
+
+
+
+
+
+
+
+
+ 提交
+
+
+
+
+
+
+```
+
+---
+
+## 6. 注释规范
+
+### 6.1 文件头注释
+
+```typescript
+/**
+ * @file 活动相关 API 接口
+ * @author Your Name
+ * @description 包含活动的增删改查、日历视图、冲突检测等接口
+ */
+```
+
+### 6.2 函数注释
+
+```typescript
+/**
+ * 格式化日期时间
+ * @param date - 日期字符串或 Date 对象
+ * @param format - 格式化模板,默认 'YYYY-MM-DD HH:mm'
+ * @returns 格式化后的日期字符串
+ * @example
+ * formatDateTime('2025-06-01T09:00:00') // '2025-06-01 09:00'
+ * formatDateTime(new Date(), 'YYYY年MM月DD日') // '2025年06月01日'
+ */
+export function formatDateTime(
+ date: string | Date,
+ format: string = 'YYYY-MM-DD HH:mm'
+): string {
+ return dayjs(date).format(format)
+}
+```
+
+### 6.3 组件注释
+
+```vue
+
+```
+
+### 6.4 复杂逻辑注释
+
+```typescript
+async function handleRegister() {
+ // 1. 检查是否已登录
+ if (!userStore.isLoggedIn) {
+ router.push('/login')
+ return
+ }
+
+ // 2. 检查报名状态
+ // - 已报名:提示已报名
+ // - 已满员:提示名额已满
+ // - 已截止:提示报名已截止
+ if (activity.value.isRegistered) {
+ showToast('您已报名该活动')
+ return
+ }
+
+ // 3. 发起报名请求
+ // ...
+}
+```
+
+---
+
+## 7. Git 提交规范
+
+### 7.1 提交信息格式
+
+```
+():
+
+
+
+