feat: 完善项目开发规范和测试文档体系

📝 主要改进:
• Cursor配置模块化:拆分为前端、后端、移动端、文档、API测试5个专门规范文件
• API文档重新组织:按业务模块拆分到docs/开发文档/API/目录下
• 新增维修分类功能完整测试方案和自动化测试脚本
• 后端热启动脚本完善,支持Linux/Windows双平台
• 强化文档同步更新规范,确保代码与文档一致性

🔧 技术改进:
• 优化Cursor AI工作流程和代码生成质量
• 完善API测试规范(AES+RSA双重加密登录方法)
• 提升开发效率和代码质量标准化程度

�� 测试覆盖:
• 维修分类管理功能端到端测试验证通过
• 包含页面加载、CRUD操作、搜索功能等核心测试用例

更新时间:2025-07-01
This commit is contained in:
zlwu committed 2025-07-01 17:53:05 +08:00
1 parent 7a5b9d1bea
commit 249b1dfeb4
44 files changed
+14027 -2852

No files matched your search

+129
View File
@@ -0,0 +1,129 @@
# Cursor 规范文件拆分说明
## 🎯 拆分目的
为了提升 Cursor 编辑器的运行效率和规范管理的便利性,我们将原本的大型`.cursorrules`文件(2359 行)拆分为多个专门的规范文件。
## 📁 文件结构
```
.cursor/
├── README.md # 本说明文件
├── cursorrules-docs.md # 文档管理规范
├── cursorrules-frontend.md # 前端开发规范 (Vue 3 + TypeScript)
├── cursorrules-backend.md # 后端开发规范 (Spring Boot + MyBatis)
├── cursorrules-mobile.md # 移动端开发规范 (uniapp + uView UI)
└── cursorrules-api-test.md # API测试和登录方法
```
## 📋 文件说明
### 1. cursorrules-docs.md
- **项目文档管理规范**
- 文档目录组织结构
- 强制性文档同步更新规则
- 变更记录管理规范
- 业务模块文档管理
- API 文档管理规范
- 测试文档管理规范
### 2. cursorrules-frontend.md
- **Web 前端开发规范**
- Vue 3 + TypeScript 技术栈
- Art Design Pro UI 规范
- 组件开发标准
- API 接口定义规范
- 状态管理和路由配置
- 项目架构和性能优化
### 3. cursorrules-backend.md
- **后端开发规范**
- Spring Boot 技术栈
- 数据库设计规范(强制性)
- API 接口规范(强制性)
- 菜单界面和权限配置
- 标准代码模板
### 4. cursorrules-mobile.md
- **移动端开发规范**
- uni-app + uView UI 技术栈
- 页面和组件开发规范
- API 对接规范
- 状态管理和配置
- 性能优化和测试
### 5. cursorrules-api-test.md
- **API 测试和登录方法**
- AES+RSA 双重加密登录
- API 测试最佳实践
- 自动化测试脚本
- 性能测试方法
## 🔄 使用方式
### Cursor 编辑器自动加载
Cursor 编辑器会自动扫描项目中的规范文件,包括`.cursor/`目录下的所有规范文件。拆分后的文件仍然能够被 Cursor 正常识别和使用。
### 手动引用
如果需要明确引用特定规范,可以在对话中提及:
- "请按照前端开发规范..."
- "遵循后端 API 接口规范..."
- "参考文档管理规范..."
### 模块化开发
现在可以针对不同技术栈进行专门的开发:
- 前端开发人员主要关注 `cursorrules-frontend.md`
- 后端开发人员主要关注 `cursorrules-backend.md`
- 移动端开发人员主要关注 `cursorrules-mobile.md`
- 测试人员主要关注 `cursorrules-api-test.md`
## 🚀 性能优势
1. **加载速度提升**: 每个文件体积更小,加载更快
2. **内容精准**: 根据开发场景加载相关规范
3. **维护便利**: 不同技术栈的规范独立维护
4. **版本管理**: 便于跟踪不同模块的规范变更
## 🔧 维护说明
### 规范更新原则
1. **技术栈专门化**: 每个文件只包含相关技术栈的规范
2. **内容完整性**: 确保每个文件内容自包含,可独立使用
3. **交叉引用**: 在需要时明确说明与其他规范文件的关联
### 文件同步
- 当项目架构或通用规范发生变化时,需要同步更新相关文件
- 重要的跨模块规范变更需要在多个文件中保持一致
## 📝 更新记录
- **2025-07-01**: 完成.cursorrules 文件拆分,创建 5 个专门规范文件
- **拆分原因**: 提升 Cursor 运行效率,便于规范管理
- **文件保留**: 所有原有内容完整保留,无任何删除
## 🎯 使用建议
1. **日常开发**: Cursor 会自动应用相关规范
2. **规范查阅**: 可直接打开对应的规范文件查看详细内容
3. **团队协作**: 不同角色的开发者可专注相关规范文件
4. **规范更新**: 按技术栈分别维护和更新规范内容
---
**维护人员**: wuzilong
**创建时间**: 2025-07-01 16:15:00
**文件总数**: 5 个专门规范文件
**原文件行数**: 2359 行
**内容完整性**: 100%保留
+682
View File
@@ -0,0 +1,682 @@
# Cursor Rules - API 测试和登录方法
## 适用范围
- **测试环境**: http://localhost/dev-api
- **登录认证**: AES+RSA 双重加密
- **Token 管理**: JWT 认证体系
---
# API 测试和登录方法
## 1. 🔐 登录方法配置
### 系统登录接口分析
**接口地址**: `POST http://localhost/dev-api/auth/login`
**当前状态**:
- ✅ **接口技术实现**: 登录接口正常工作,能够正确处理请求
- ✅ **接口地址确认**: 接口地址 http://localhost/dev-api/auth/login 可正常访问
- ✅ **权限配置问题**: 已解决,admin 用户可以正常登录获取 Token
- ✅ **加密登录问题**: 已解决,AES+RSA 双重加密登录正常工作
- ✅ **Token 验证**: Token 有效期 7 天,可正常用于 API 调用
- ✅ **用户权限**: admin 用户具有超级管理员权限 (_:_:\*)
### 🔧 可用的登录方法
#### 方法 1:AES+RSA 加密登录(推荐)
```javascript
// 完整的AES+RSA双重加密登录方法
async function encryptedLogin() {
const axios = require('axios');
const CryptoJS = require('crypto-js');
const NodeRSA = require('node-rsa');
// 配置信息
const CONFIG = {
url: 'http://localhost/dev-api/auth/login',
clientId: 'e5cd7e4891bf95d1d19206ce24a7b32e',
tenantId: '000000',
referer: 'http://localhost/login?redirect=%252Findex',
rsaKey: 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==',
};
// 生成32位随机AES密钥
function generateAESKey() {
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < 32; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return result;
}
// AES加密
function aesEncrypt(data, key) {
const keyUtf8 = CryptoJS.enc.Utf8.parse(key);
return CryptoJS.AES.encrypt(data, keyUtf8, {
mode: CryptoJS.mode.ECB,
padding: CryptoJS.pad.Pkcs7,
}).toString();
}
// RSA加密AES密钥
function rsaEncrypt(aesKey) {
const pemKey = `-----BEGIN PUBLIC KEY-----\n${CONFIG.rsaKey}\n-----END PUBLIC KEY-----`;
const rsaKey = new NodeRSA(pemKey);
rsaKey.setOptions({ encryptionScheme: 'pkcs1' });
const aesKeyBase64 = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(aesKey));
return rsaKey.encrypt(aesKeyBase64, 'base64');
}
// 生成AES密钥并加密登录数据
const aesKey = generateAESKey();
const loginData = {
tenantId: CONFIG.tenantId,
username: 'admin',
password: 'admin123',
clientId: CONFIG.clientId,
grantType: 'password',
};
const encryptedData = aesEncrypt(JSON.stringify(loginData), aesKey);
const encryptedKey = rsaEncrypt(aesKey);
// 设置请求头(按照系统要求的格式)
const headers = {
'Content-Type': 'application/json;charset=utf-8',
clientid: CONFIG.clientId, // 必需:客户端ID
'encrypt-key': encryptedKey, // 必需:RSA加密的AES密钥
referer: CONFIG.referer, // 必需:来源页面
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
isToken: 'false',
isEncrypt: 'true',
repeatSubmit: 'false',
};
// 发送登录请求
const response = await axios.post(CONFIG.url, encryptedData, {
headers: headers,
timeout: 10000,
});
// 返回Token
if (response.data.code === 200 && response.data.data?.access_token) {
return response.data.data.access_token;
} else {
throw new Error(response.data.msg || 'Login failed');
}
}
```
#### 方法 2:快速 Token 获取(简化版)
```javascript
// 快速获取Token的简化版本
async function getToken(username = 'admin', password = 'admin123') {
const { getToken } = require('./test/quick-token-getter');
return await getToken(username, password);
}
```
### 🔧 快速测试工具
#### 使用 test 目录下的测试脚本
```bash
# 在test目录下运行测试
cd test
npm install # 安装依赖(axios, crypto-js, node-rsa, colors)
# 完整功能版登录测试(推荐)
node custom-login-script.js
# 快速Token获取测试
node quick-token-getter.js
```
#### 可用的登录脚本
- **`custom-login-script.js`** - 完整功能版,支持 AES+RSA 双重加密
- **`quick-token-getter.js`** - 快速获取版,代码简洁易懂
#### 依赖安装
```json
{
"dependencies": {
"axios": "^1.7.2",
"crypto-js": "^4.2.0",
"node-rsa": "^1.1.1",
"colors": "^1.4.0"
}
}
```
#### 🎯 成功获取的 Token 示例
```
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOiJzeXNfdXNlcjoxIiwicm5TdHIiOiJ5MlhvbHRnd1Y2YjUzRnRMVzF4SFR1anRSUERjeGdmYyIsImNsaWVudGlkIjoiZTVjZDdlNDg5MWJmOTVkMWQxOTIwNmNlMjRhN2IzMmUiLCJ0ZW5hbnRJZCI6IjAwMDAwMCIsInVzZXJJZCI6MSwidXNlck5hbWUiOiJhZG1pbiIsImRlcHRJZCI6MTAzLCJkZXB0TmFtZSI6IuaZuuiDveaOp-WItuWtpumZoiIsImRlcHRDYXRlZ29yeSI6IiIsIm5pY2tOYW1lIjoi55ax54uC55qE54uu5a2QTGkifQ.WI6iY3AgwPz7ceI8WDsVy-GaTXZnU-JKUYUTjhQdoKM
```
**Token 解析信息**:
- **用户 ID**: 1
- **用户名**: admin
- **昵称**: 疯狂狮子 Li
- **部门**: 智胜技术开发团队
- **权限**: _:_:\* (超级管理员)
- **有效期**: 7 天
- **租户**: 000000
## 2. ✅ 已解决的问题和解决方案
### 已解决问题 1:国际化语言头格式问题
- **原问题**: ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 1
- **原因**: 服务器端国际化解析器无法正确处理 `'Content-Language': 'zh-cn'` 格式
- **解决方案**:
- 使用 `'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8'` 格式
- 或使用标准的 `'Content-Language': 'zh-CN'` 格式
- **状态**: ✅ 已完全解决
### 已解决问题 2:加密登录技术问题
- **原问题**: AES+RSA 双重加密登录存在技术错误
- **原因**: 加密密钥生成和请求头格式不正确
- **解决方案**:
- 使用正确的 32 位随机 AES 密钥生成
- 按照系统要求设置三个关键 Header:clientid、encrypt-key、referer
- 使用正确的 RSA-PKCS1 加密方案
- **状态**: ✅ 已完全解决
### 核心成功要素
1. **必需的 Header 格式**:
```javascript
{
'clientid': 'e5cd7e4891bf95d1d19206ce24a7b32e',
'encrypt-key': '[RSA加密的AES密钥]',
'referer': 'http://localhost/login?redirect=%252Findex'
}
```
2. **正确的加密流程**:
- 生成 32 位随机 AES 密钥
- 使用 AES-ECB 模式加密登录数据
- 使用 RSA-PKCS1 加密 AES 密钥
- 设置正确的请求头格式
## 3. 🔍 API 测试最佳实践
### 测试环境配置
```javascript
const config = {
baseURL: 'http://localhost/dev-api',
timeout: 10000,
headers: {
'Content-Type': 'application/json;charset=utf-8',
clientid: 'e5cd7e4891bf95d1d19206ce24a7b32e',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
referer: 'http://localhost/login?redirect=%252Findex',
},
};
```
### 通用 API 测试方法
```javascript
// 通用API测试方法
async function testAPI(endpoint, data, options = {}) {
const axios = require('axios');
try {
const response = await axios({
method: options.method || 'POST',
url: `http://localhost/dev-api${endpoint}`,
data: data,
headers: {
'Content-Type': 'application/json;charset=utf-8',
clientid: 'e5cd7e4891bf95d1d19206ce24a7b32e',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
referer: 'http://localhost/login?redirect=%252Findex',
Authorization: options.token ? `Bearer ${options.token}` : undefined,
...options.headers,
},
timeout: 10000,
});
return {
success: true,
data: response.data,
status: response.status,
};
} catch (error) {
return {
success: false,
error: error.response?.data || error.message,
status: error.response?.status,
};
}
}
```
### 带 Token 的 API 调用
```javascript
// 带Token的API调用示例
async function callAPIWithToken(token, endpoint, data, method = 'GET') {
return await testAPI(endpoint, data, {
method: method,
token: token,
headers: {
clientid: 'e5cd7e4891bf95d1d19206ce24a7b32e',
referer: 'http://localhost/login?redirect=%252Findex',
},
});
}
// 使用示例
async function getUserInfo(token) {
const result = await callAPIWithToken(token, '/system/user/getInfo', null, 'GET');
return result;
}
// 调用带参数的API
async function getUserList(token, params) {
const result = await callAPIWithToken(token, '/system/user/list', params, 'GET');
return result;
}
```
### 分页接口测试
```javascript
// 分页接口测试模板
async function testPaginationAPI(token, endpoint, params = {}) {
const defaultParams = {
pageNum: 1,
pageSize: 10,
...params,
};
const result = await callAPIWithToken(token, endpoint, defaultParams, 'GET');
if (result.success) {
console.log('分页接口测试成功:');
console.log(`总记录数: ${result.data.total}`);
console.log(`当前页数据: ${result.data.rows?.length || 0} 条`);
console.log('响应格式正确 ✅');
} else {
console.log('分页接口测试失败:', result.error);
}
return result;
}
// 使用示例
async function testUserListAPI(token) {
return await testPaginationAPI(token, '/system/user/list', {
userName: 'admin',
status: '0',
});
}
```
### CRUD 接口测试套件
```javascript
// CRUD接口完整测试套件
async function testCRUDAPIs(token, baseEndpoint, testData) {
const results = {
create: null,
read: null,
update: null,
delete: null,
};
try {
// 1. 测试创建 (CREATE)
console.log('测试创建接口...');
results.create = await callAPIWithToken(token, baseEndpoint, testData, 'POST');
if (results.create.success) {
console.log('✅ 创建接口测试通过');
const createdId = results.create.data.data?.id;
// 2. 测试读取 (READ)
if (createdId) {
console.log('测试读取接口...');
results.read = await callAPIWithToken(
token,
`${baseEndpoint}/${createdId}`,
null,
'GET',
);
if (results.read.success) {
console.log('✅ 读取接口测试通过');
// 3. 测试更新 (UPDATE)
console.log('测试更新接口...');
const updateData = {
...testData,
id: createdId,
name: testData.name + '_updated',
};
results.update = await callAPIWithToken(token, baseEndpoint, updateData, 'PUT');
if (results.update.success) {
console.log('✅ 更新接口测试通过');
}
// 4. 测试删除 (DELETE)
console.log('测试删除接口...');
results.delete = await callAPIWithToken(
token,
`${baseEndpoint}/${createdId}`,
null,
'DELETE',
);
if (results.delete.success) {
console.log('✅ 删除接口测试通过');
}
}
}
}
} catch (error) {
console.error('CRUD测试出现异常:', error);
}
return results;
}
```
## 4. 📝 API 测试记录模板
### 测试结果记录格式
```markdown
## API 测试记录 - YYYY-MM-DD
**测试环境**: http://localhost/dev-api
**测试时间**: YYYY-MM-DD HH:mm:ss
**测试人员**: [测试人员]
### 登录测试
- **方法**: AES+RSA 双重加密登录
- **结果**: ✅ 登录成功
- **Token**: eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...
- **用户信息**: admin / 疯狂狮子 Li / 超级管理员
- **权限**: _:_:\* (完全权限)
- **有效期**: 7 天
### 业务 API 测试
- **接口**: [接口地址]
- **方法**: [HTTP 方法]
- **权限**: [需要的权限]
- **结果**: [测试结果]
- **响应时间**: [响应时间 ms]
- **状态码**: [HTTP 状态码]
### 成功要素记录
1. **Header 配置**: 正确设置 clientid、encrypt-key、referer
2. **加密机制**: AES+RSA 双重加密正常工作
3. **语言头格式**: 使用 Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
### 验证结果
- ✅ 登录接口正常工作
- ✅ Token 有效可用于 API 调用
- ✅ 用户权限验证通过
- ✅ 加密解密机制正常
```
### 详细测试报告模板
```markdown
# API 接口测试报告
## 🎯 测试概览
**测试时间**: YYYY-MM-DD HH:mm:ss
**测试范围**: [具体测试的 API 模块]
**测试环境**: http://localhost/dev-api
**测试工具**: Node.js + Axios + 自定义脚本
## 📁 测试脚本路径
**登录脚本**: `test/custom-login-script.js`
**API 测试脚本**: `test/[功能]-api-test.js`
## 🔐 认证测试
### 登录接口测试
- **接口地址**: POST /auth/login
- **加密方式**: AES+RSA 双重加密
- **测试结果**: ✅ 成功
- **Token 获取**: ✅ 正常
- **Token 有效期**: 7 天
### Token 验证测试
- **Authorization 格式**: Bearer {token}
- **必需 Header**: clientid, referer, Accept-Language
- **权限验证**: ✅ admin 用户完全权限
## 🔍 业务接口测试
### [模块名称]接口测试
#### 列表查询接口
- **接口**: GET /[module]/list
- **参数**: pageNum, pageSize, [查询条件]
- **响应格式**: {total, rows, code, msg}
- **测试结果**: ✅ 通过
- **响应时间**: [x]ms
#### 详情查询接口
- **接口**: GET /[module]/{id}
- **响应格式**: {code, msg, data}
- **测试结果**: ✅ 通过
- **响应时间**: [x]ms
#### 新增接口
- **接口**: POST /[module]
- **请求格式**: JSON 对象
- **响应格式**: {code, msg, data}
- **测试结果**: ✅ 通过
- **响应时间**: [x]ms
#### 修改接口
- **接口**: PUT /[module]
- **请求格式**: JSON 对象(包含 id)
- **响应格式**: {code, msg, data}
- **测试结果**: ✅ 通过
- **响应时间**: [x]ms
#### 删除接口
- **接口**: DELETE /[module]/{id}
- **响应格式**: {code, msg, data}
- **测试结果**: ✅ 通过
- **响应时间**: [x]ms
## 📊 测试统计
- **总接口数**: [数量]
- **测试通过**: [数量]
- **测试失败**: [数量]
- **通过率**: [百分比]%
## ⚠️ 问题记录
[记录测试中发现的问题]
## 🎯 结论
[测试结论和建议]
---
**测试执行**: 基于 `test/` 目录下的测试脚本
**文档路径**: `docs/测试文档/[模块]/[功能]/[报告名称]-YYYY-MM-DD.md`
```
## 5. 🎯 开发和测试建议
### ✅ 已完成的核心功能
1. **登录认证**: AES+RSA 双重加密登录机制完全正常
2. **Token 获取**: 可稳定获取 7 天有效期的 JWT Token
3. **权限验证**: admin 用户具有完全权限 (_:_:\*)
4. **API 调用**: Token 可正常用于所有业务 API 调用
### 🔧 开发最佳实践
1. **使用标准脚本**: 优先使用 `test/custom-login-script.js` 获取 Token
2. **Header 规范**: 始终包含 clientid、encrypt-key、referer 三个关键 Header
3. **语言头格式**: 使用 `Accept-Language: zh-CN,zh;q=0.9,en;q=0.8`
4. **错误处理**: 实现 Token 过期自动重新获取机制
### 🚀 后续优化建议
1. **Token 管理**: 实现 Token 自动刷新和缓存机制
2. **环境配置**: 支持开发、测试、生产环境的灵活切换
3. **自动化测试**: 建立基于 Token 的自动化 API 测试流程
4. **性能监控**: 添加 API 响应时间和成功率监控
### 📚 相关文档和工具
- **成功的登录脚本**: `test/custom-login-script.js` 和 `test/quick-token-getter.js`
- **使用指南**: `test/登录脚本使用说明.md`
- **API 文档**: `docs/开发文档/API.md`
- **变更记录**: `docs/变更管理/code-adjust-record.md`
### 🎯 使用建议
1. **开发阶段**: 使用 `quick-token-getter.js` 快速获取 Token 进行测试
2. **集成测试**: 使用 `custom-login-script.js` 进行完整的登录流程测试
3. **生产环境**: 将加密登录逻辑集成到实际应用中,实现自动 Token 管理
## 6. 🧪 自动化测试脚本
### 完整的 API 测试流程
```javascript
// 完整的API自动化测试脚本示例
async function runCompleteAPITest() {
console.log('🚀 开始API自动化测试...\n');
try {
// 1. 获取Token
console.log('1️⃣ 获取登录Token...');
const token = await encryptedLogin();
console.log('✅ Token获取成功\n');
// 2. 测试用户信息接口
console.log('2️⃣ 测试用户信息接口...');
const userInfo = await getUserInfo(token);
if (userInfo.success) {
console.log('✅ 用户信息接口测试通过');
console.log(`用户: ${userInfo.data.data.user.userName}`);
console.log(`权限: ${userInfo.data.data.permissions}\n`);
}
// 3. 测试分页列表接口
console.log('3️⃣ 测试分页列表接口...');
const userList = await testUserListAPI(token);
if (userList.success) {
console.log('✅ 分页列表接口测试通过\n');
}
// 4. 测试CRUD接口(可选)
console.log('4️⃣ 测试CRUD接口...');
// const crudResults = await testCRUDAPIs(token, '/system/dept', testDeptData);
console.log('🎉 API自动化测试完成!');
} catch (error) {
console.error('❌ 测试失败:', error.message);
}
}
// 执行测试
runCompleteAPITest();
```
### 性能测试脚本
```javascript
// API性能测试脚本
async function performanceTest(token, endpoint, concurrent = 10, iterations = 100) {
console.log(`开始性能测试: ${endpoint}`);
console.log(`并发数: ${concurrent}, 迭代次数: ${iterations}\n`);
const startTime = Date.now();
const results = [];
for (let i = 0; i < concurrent; i++) {
const promises = [];
for (let j = 0; j < iterations / concurrent; j++) {
promises.push(
callAPIWithToken(token, endpoint, null, 'GET')
.then((result) => ({
success: result.success,
time: Date.now(),
}))
.catch((error) => ({
success: false,
error: error.message,
time: Date.now(),
})),
);
}
results.push(...(await Promise.all(promises)));
}
const endTime = Date.now();
const totalTime = endTime - startTime;
const successCount = results.filter((r) => r.success).length;
const failCount = results.length - successCount;
console.log('📊 性能测试结果:');
console.log(`总请求数: ${results.length}`);
console.log(`成功数: ${successCount}`);
console.log(`失败数: ${failCount}`);
console.log(`成功率: ${((successCount / results.length) * 100).toFixed(2)}%`);
console.log(`总耗时: ${totalTime}ms`);
console.log(`平均响应时间: ${(totalTime / results.length).toFixed(2)}ms`);
console.log(`QPS: ${(results.length / (totalTime / 1000)).toFixed(2)} req/s`);
return {
total: results.length,
success: successCount,
fail: failCount,
successRate: successCount / results.length,
totalTime,
avgResponseTime: totalTime / results.length,
qps: results.length / (totalTime / 1000),
};
}
```
---
**🎉 成功状态**: 登录获取 Token 功能已完全实现并正常工作,可以稳定用于 API 开发和测试。
File diff suppressed because it is too large. Load diff
+731
View File
@@ -0,0 +1,731 @@
# Cursor Rules - 项目文档管理规范
## 项目结构说明
- **前端工程**:`web/` (基于 Vue 3 + TypeScript + Element Plus)
- **后端工程**:`backend/` (基于 RuoYi-Vue-Plus + Spring Boot 3.4.6)
- **移动端工程**:`mobile/` (基于 uniapp + uView UI 构建的校园管理移动端应用)
- **文档管理**:`docs/` (项目的需求、设计、开发、测试、部署文档)
---
# 项目文档管理规范
## 1. 文档结构管理 (docs/)
### 🔴 文档目录组织(中文化架构)
```
docs/
├── 项目总览/ # 项目基本信息和架构概览
│ ├── README.md # 项目总览主文档
│ └── 项目总览模板.md # 项目总览标准模板
├── 业务模块/ # 业务模块文档(为AI提供业务上下文)
│ ├── README.md # 业务模块管理总览
│ ├── 业务模块开发模板.md # 业务模块标准开发模板
│ ├── hq-satisfaction-survey/ # 后勤满意度调查模块
│ ├── hall-reservation/ # 报告厅预约模块
│ ├── system-management/ # 系统管理模块
│ └── user-management/ # 用户管理模块
├── 变更管理/ # 变更管理中心
│ ├── README.md # 变更管理流程和规范
│ └── code-adjust-record.md # 代码调整记录
├── 开发文档/ # 开发指南和技术规范
│ ├── README.md # 开发文档总览
│ ├── API.md # API接口完整文档
│ └── API文档模板.md # API文档标准模板
├── 设计文档/ # 设计文档
│ ├── README.md # 设计文档说明
│ └── database/ # 数据库设计
│ ├── hzdyjs_xg.sql # 完整数据库模型
│ ├── 01-workflow-module.sql # 工作流模块SQL
│ ├── 02-code-generator-module.sql # 代码生成模块SQL
│ ├── 03-logistics-module.sql # 后勤管理模块SQL
│ ├── 04-job-scheduler-module.sql # 任务调度模块SQL
│ ├── 05-system-management-module.sql # 系统管理模块SQL
│ ├── 06-test-module.sql # 测试模块SQL
│ ├── SQL文件说明.md # SQL文件拆分说明
│ ├── mysql-database-standard.md # MySQL数据库建设规范
│ ├── database_msg.md # 环境配置信息
│ └── README.md # 数据库设计说明
├── 需求文档/ # 需求文档
│ ├── README.md # 需求管理说明
│ ├── 后勤报告厅预约需求/ # 报告厅预约系统需求
│ └── 后勤满意度调查需求/ # 满意度调查系统需求
├── 测试文档/ # 测试文档(按需求维度组织)
│ ├── README.md # 测试文档管理总览
│ ├── 后勤管理/ # 后勤管理相关测试文档
│ │ ├── 物业报修/ # 物业报修系统测试文档
│ │ ├── 满意度调查/ # 满意度调查系统测试文档
│ │ └── 报告厅预约/ # 报告厅预约系统测试文档
│ ├── 系统管理/ # 系统管理相关测试文档
│ ├── 用户管理/ # 用户管理相关测试文档
│ └── 工作流管理/ # 工作流管理相关测试文档
├── 部署文档/ # 部署文档
│ └── README.md # 部署指南
├── 中间件配置/ # 中间件配置文档
│ ├── README.md # 中间件配置说明
│ └── mysql-config.md # MySQL配置文档
├── 知识库/ # 知识库
├── 报告文档/ # 报告文档
├── structure-optimization-plan.md # 文档结构优化方案
└── README.md # 文档体系总说明
```
### 🔴 重要文档说明
- **工程本地启动指导.md** (项目根目录):包含完整的环境配置和启动指南
- **技术要求更新**:Node.js 20.15.x+, npm 10.7.x+
- **数据库环境**:支持本地安装或使用阿里云测试环境
- **前端访问地址**:http://localhost (非 3000 端口)
## 2. 🚨 强制性文档同步更新规则
### 📋 核心原则:代码与文档必须同步更新
**⚠️ 超级重要:每次使用 Cursor AI 进行代码调整后,必须立即同步更新相应的项目文档!**
### 🔴 强制更新触发条件
每次代码调整必须检查并更新以下文档:
#### 后端代码调整时的强制文档更新:
- **✅ API 接口变更**:
- 必须立即更新 `docs/开发文档/API.md`
- 新增接口:添加完整接口文档(地址、参数、响应、权限、示例)
- 修改接口:更新参数说明、响应格式、错误码
- 删除接口:标记为已废弃,说明替代方案
- 权限变更:更新权限要求说明
- **✅ 数据库变更**:
- 更新 `docs/设计文档/database/` 下的相关文档
- 新增表:添加表结构说明和字段注释
- 修改表:更新字段变更和索引调整
- 数据迁移:记录迁移脚本和注意事项
- **✅ 业务逻辑变更**:
- 更新对应 `docs/业务模块/[模块名称]/` 下的业务文档
- 更新业务流程图和业务规则说明
- 修改用户故事和功能需求
- **✅ 配置变更**:
- 更新 `docs/中间件配置/` 下的配置文档
- 更新 `docs/部署文档/` 下的部署说明
#### 前端代码调整时的强制文档更新:
- **✅ 页面功能变更**:
- 更新对应业务模块的用户操作文档
- 更新 UI 设计规范文档
- **✅ API 调用变更**:
- 检查前端 API 调用是否与后端 API 文档一致
- 更新 API 对接说明文档
- **✅ 组件变更**:
- 更新组件使用说明和属性文档
#### 移动端代码调整时的强制文档更新:
- **✅ 功能变更**:更新移动端功能说明文档
- **✅ API 对接变更**:更新移动端 API 调用文档
- **✅ 用户流程变更**:更新用户操作指南
#### 📚 docs 文档变更时的强制同步更新规则:
**⚠️ 超级重要:每当 docs/目录下的文档结构或重要内容发生变更时,必须立即同步更新.cursorrules 文件!**
- **🔴 文档结构变更**:
- 新增/删除目录:同步更新.cursorrules 中的"文档目录组织"章节
- 重命名目录:更新所有相关路径引用
- 调整文档层级:更新文档结构说明
- **🔴 重要文档变更**:
- 新增标准模板:在"文档模板体系"中添加说明
- 更新开发规范:同步调整.cursorrules 中对应的规范要求
- 修改工作流程:更新"文档更新标准工作流程"
- **🔴 技术环境变更**:
- 环境要求调整:更新.cursorrules 中的技术栈规范
- 配置信息变更:同步更新相关配置说明
- 启动流程调整:更新开发指导相关内容
- **🔴 业务模块变更**:
- 新增业务模块:在.cursorrules 中添加模块说明
- 模块架构调整:更新业务模块文档管理规范
- API 接口变更:确保.cursorrules 中的 API 规范同步
**强制检查清单**:
- [ ] .cursorrules 中的文档目录结构是否与实际一致
- [ ] 重要文档路径引用是否全部更新
- [ ] 新增的开发规范是否已同步到.cursorrules
- [ ] 技术要求和环境配置是否保持一致
### ⏰ 时间填写强制性规范
**🚨 重要:每次记录变更必须填写真实的当前时间!**
#### 强制性时间填写要求:
1. **变更时间**:必须填写变更发生的实际时间,不得使用错误或虚假时间
2. **时间格式**:严格按照 `YYYY-MM-DD HH:mm:ss` 格式填写
3. **时区规范**:使用北京时间(UTC+8)
4. **获取方法**:
- 在 macOS/Linux 系统中使用 `date "+%Y-%m-%d %H:%M:%S"` 命令
- 在 Windows 系统中使用 `Get-Date -Format "yyyy-MM-dd HH:mm:ss"` 命令
- 或使用当前系统显示的时间
5. **验证要求**:变更时间必须与实际代码修改时间相符
#### 错误示例:
- ❌ 使用 1 月份时间但实际是 6 月份
- ❌ 使用固定模板时间不修改
- ❌ 时间格式不正确
#### 正确示例:
- ✅ 2025-06-30 15:43:20 (实际是 6 月 30 日下午 3 点 43 分)
- ✅ 2025-06-30 18:30:00 (实际是 6 月 30 日晚上 6 点 30 分)
### 📝 变更记录排序规范
**🚨 重要:变更记录必须按照倒序排列,最新记录在最上面!**
#### 记录排序要求:
1. **排序原则**:按时间倒序排列,最新的变更记录放在文件最上面
2. **新增记录**:每次新增变更记录都必须插入到文件开头(标题下方)
3. **时间顺序**:确保后面的记录时间早于前面的记录时间
4. **便于查看**:这样安排便于快速查看最近的变更情况
#### 正确的排序示例:
```markdown
# 代码调整记录
## 调整记录 - 2025-06-30 18:30:00 ← 最新记录
## 调整记录 - 2025-06-30 15:43:20 ← 次新记录
## 调整记录 - 2025-06-29 10:20:00 ← 更早记录
## 调整记录 - 2025-06-28 14:15:00 ← 最早记录
```
#### 错误示例:
- ❌ 新记录添加到文件末尾
- ❌ 时间顺序混乱
- ❌ 按正序排列(最早在上面)
### 🔄 文档更新标准工作流程
#### Cursor AI 辅助开发的文档更新流程:
```
1. **AI代码生成/修改完成**
↓
2. **立即检查文档更新需求**
- 是否涉及API变更?
- 是否涉及数据库变更?
- 是否涉及业务逻辑变更?
- 是否涉及配置变更?
- 是否涉及docs文档结构变更?
↓
3. **立即更新相关文档**(不得延后!)
- 使用标准模板格式
- 确保信息准确完整
- 添加真实示例
- ⚠️ 填写真实的当前时间,不得使用模板时间
↓
4. **检查并更新.cursorrules文件**(重要!)
- 如有docs文档结构变更,同步更新.cursorrules
- 如有技术要求变更,同步更新技术栈规范
- 如有开发流程变更,同步更新工作流程
↓
5. **记录变更日志**(按倒序插入到当日文件开头!)
- 检查并创建当日变更记录文件:`code-adjust-record-YYYY-MM-DD-{username}.md`
- 在当日文件开头添加新记录(倒序排列)
- 无需维护索引文件,专注于自己的变更记录
- 标注已同步更新的文档列表
- 标注是否已更新.cursorrules文件
↓
6. **验证文档准确性**
- 确保文档与实际代码一致
- 验证示例可以正常运行
- 验证.cursorrules与实际项目状态一致
- 确认记录时间排序正确
↓
7. **提交代码和文档变更**
```
### 📝 变更记录文件管理规范
**🚨 重要:从 2025-06-30 开始,变更记录按日期和用户分文件管理!**
#### 📁 文件命名规范
- **文件格式**: `code-adjust-record-YYYY-MM-DD-{username}.md`
- **存放位置**: `docs/变更管理/` 目录
- **命名示例**: `code-adjust-record-2025-06-30-zlwu.md`
- **获取用户名**: 使用 `git config --get user.name` 命令获取
- **获取日期**: 使用 `date "+%Y-%m-%d"` 命令获取
#### 🔄 文件创建和使用流程
1. **检查当日文件是否存在**:
```bash
USERNAME=$(git config --get user.name)
TODAY=$(date "+%Y-%m-%d")
FILENAME="docs/变更管理/code-adjust-record-${TODAY}-${USERNAME}.md"
```
2. **文件不存在时创建新文件**:
- 使用标准模板创建当日变更记录文件
- 文件头包含日期、用户名、排序说明
3. **记录变更时**:
- 在当日文件开头插入新记录(倒序排列)
- 无需维护索引文件,每人管理自己的变更记录
#### 👥 多用户协作规范
- **独立管理**: 每个用户有独立的日变更文件,完全避免多人同时编辑冲突
- **无需协调**: 不需要维护共享索引文件,每人管理自己的变更记录
- **用户名一致性**: 确保 git 用户名配置正确,保持文件命名的一致性
- **文件归档**: 历史文件保留,便于追溯和审计
- **查找便利**: 通过文件名快速定位特定日期和用户的变更记录
#### 📋 每日变更文件标准格式
```markdown
# 代码调整记录 - YYYY-MM-DD - {username}
> 📅 **记录日期**: YYYY-MM-DD
> 👤 **记录人员**: {username}
> 📌 **排序说明**: 本文件按照时间倒序排列,最新的变更记录在最上面
## 调整记录 - YYYY-MM-DD HH:mm:ss
**变更 ID**: CHG-YYYYMMDD-001
**变更时间**: YYYY-MM-DD HH:mm:ss (⚠️ 必须填写真实的当前时间!)
**变更人员**: [开发者姓名/Cursor AI 辅助]
**变更类型**: 🆕 新功能/🐛Bug 修复/🔧 重构优化/📚 文档更新/⚙️ 配置调整
**影响级别**: 🔴 重大变更/🟡 中等变更/🟢 小变更
### 📋 变更概述
**变更目的**: [简述变更原因和目标,1-2 句话]
**影响范围**: [列出受影响的模块、功能或文件]
### 📁 涉及文件
**后端文件**:
- backend/[具体文件路径 1]
- backend/[具体文件路径 2]
**前端文件**:
- web/[具体文件路径 1]
- web/[具体文件路径 2]
**配置文件**:
- [配置文件路径]
### 🔧 变更内容详述
**业务逻辑变更**:
1. [具体业务逻辑的变更说明]
2. [新增或修改的业务规则]
**技术实现变更**:
1. [技术方案的调整说明]
2. [代码结构的优化内容]
**接口变更**:
- **新增接口**: [新增接口列表]
- **修改接口**: [修改的接口及变更内容]
- **废弃接口**: [废弃的接口及替代方案]
**数据库变更**:
- **新增表**: [新增表及字段说明]
- **修改表**: [表结构变更内容]
- **数据迁移**: [数据迁移脚本或说明]
### 📖 文档同步更新记录
**API 文档**:
- [ ] ✅ 已更新 docs/开发文档/API.md
- [ ] ✅ 已更新模块 API 接口设计文档
**业务文档**:
- [ ] ✅ 已更新业务模块文档
- [ ] ✅ 已更新用户操作手册
**技术文档**:
- [ ] ✅ 已更新数据库设计文档
- [ ] ✅ 已更新架构设计文档
**其他文档**:
- [ ] ✅ 已更新部署文档
- [ ] ✅ 已更新配置文档
**规范文件**:
- [ ] ✅ 已检查并同步更新.cursorrules 文件
- [ ] ✅ 已确认文档结构与.cursorrules 一致
### 🧪 测试验证
**功能测试**:
- [ ] 单元测试通过
- [ ] 集成测试通过
- [ ] 功能验收测试通过
**文档验证**:
- [ ] 文档内容与代码实现一致
- [ ] 示例代码可以正常运行
- [ ] 接口文档已验证准确性
### 📝 备注
**已知问题**: [如有已知问题需要说明]
**后续计划**: [后续的改进或扩展计划]
**相关链接**: [相关的 Issue、PR 或文档链接]
---
```
## 3. 🔧 业务模块文档管理(为 Cursor AI 提供完整上下文)
### 业务模块文档标准结构
每个业务模块都必须包含以下完整文档:
```
业务模块/[模块名称]/
├── README.md # 模块总览
├── 需求分析/
│ ├── 业务需求说明.md # 详细业务需求
│ ├── 功能需求清单.md # 功能点清单
│ ├── 非功能需求.md # 性能、安全要求
│ └── 用户故事.md # 用户使用场景
├── 技术设计/
│ ├── 数据库设计.md # 表结构设计
│ ├── API接口设计.md # 接口定义
│ ├── 架构设计.md # 模块架构
│ └── 技术选型.md # 技术决策说明
├── 实现文档/
│ ├── 后端实现说明.md # 后端代码结构
│ ├── 前端实现说明.md # 前端代码结构
│ ├── 关键业务逻辑.md # 核心算法逻辑
│ └── 代码规范.md # 编码规范
├── 测试文档/
│ ├── 测试计划.md # 测试策略
│ ├── 测试用例.md # 具体测试用例
│ └── 测试报告.md # 测试结果
└── 运维文档/
├── 部署指南.md # 部署步骤
├── 监控配置.md # 监控指标
└── 故障处理.md # 常见问题
```
### 🤖 Cursor AI 开发提示词模板
#### 新功能开发提示词:
```
基于以下业务模块文档为 [功能名称] 开发代码:
业务上下文:docs/业务模块/[模块名称]/需求分析/
技术规范:docs/业务模块/[模块名称]/技术设计/
代码结构:docs/业务模块/[模块名称]/实现文档/
API规范:docs/开发文档/API.md
请确保:
1. 遵循项目编码规范
2. 使用标准的代码结构
3. 添加完整的注释
4. 生成单元测试代码
5. 立即更新相关文档
开发完成后请同步更新:
- docs/开发文档/API.md(如涉及API)
- docs/业务模块/[模块名称]/相关文档
- docs/变更管理/code-adjust-record.md
```
#### 文档更新提示词:
```
根据刚才的代码变更,请更新以下文档:
变更内容:[具体变更说明]
影响模块:[模块名称]
需要更新的文档:
1. docs/开发文档/API.md - [具体更新内容]
2. docs/业务模块/[模块名称]/[具体文档] - [具体更新内容]
3. docs/设计文档/database/ - [如涉及数据库变更]
请使用标准的文档模板格式,确保信息准确完整。
```
## 4. 📚 API 文档管理规范
### 🔴 强制性 API 文档更新规则
**⚠️ 超级重要:任何 API 接口的新增、修改、删除都必须立即同步更新 `docs/开发文档/API.md` 文档!**
### API 文档标准格式
使用 `docs/开发文档/API/API文档模板.md` 中的标准格式:
````markdown
#### 接口名称
**接口地址**: `HTTP方法 /api/路径`
**接口描述**: 接口功能的详细描述
**权限要求**: 权限代码或"需要登录"
**请求参数**:
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|--------|------|------|------|--------|
| param1 | String | Y | 参数说明 | "example" |
**响应示例**:
```json
{
"code": 200,
"msg": "操作成功",
"data": {}
}
```
````
**错误码**:
| 错误码 | 说明 | 解决方案 |
|--------|------|----------|
| 400001 | 参数错误 | 检查请求参数 |
```
### 🚨 API变更强制检查清单
当进行以下操作时,必须更新 `docs/开发文档/API.md`:
**Controller层变更**:
- [ ] 新增Controller类 → 在API.md中添加新的模块章节
- [ ] 新增@RequestMapping方法 → 添加完整的接口文档
- [ ] 修改@RequestMapping路径 → 更新接口地址
- [ ] 修改HTTP方法 → 更新接口方法
- [ ] 删除接口方法 → 标记为已废弃并说明替代方案
**参数和响应变更**:
- [ ] 新增请求参数 → 更新请求参数表格
- [ ] 修改参数类型或必填属性 → 更新参数说明
- [ ] 修改响应数据结构 → 更新响应示例
- [ ] 新增错误码 → 更新错误码说明表
**权限和安全变更**:
- [ ] 新增@SaCheckPermission注解 → 更新权限要求
- [ ] 修改权限代码 → 更新权限说明
- [ ] 修改接口访问级别 → 更新权限要求说明
## 5. 📊 文档模板体系
### 已创建的标准模板:
- **`docs/项目总览/项目总览模板.md`** - 项目基本信息模板
- **`docs/业务模块/业务模块开发模板.md`** - 业务模块开发标准模板
- **`docs/开发文档/API/API文档模板.md`** - API接口文档标准模板
### 模板使用规范:
1. **新项目或模块开发时**:复制对应模板,替换占位符
2. **文档更新时**:参考模板格式,保持结构一致
3. **Cursor AI生成文档时**:使用模板作为格式参考
## 6. 🔍 文档质量控制
### 文档完整性检查清单:
- [ ] 文档结构符合标准模板
- [ ] 内容与实际代码实现一致
- [ ] API文档包含完整示例
- [ ] 业务逻辑描述清晰准确
- [ ] 技术实现说明详细
- [ ] 变更历史有完整记录
- [ ] 所有占位符已替换为真实内容
### 文档准确性验证:
- [ ] API接口示例可以正常调用
- [ ] 数据库脚本可以成功执行
- [ ] 配置文档与实际配置一致
- [ ] 部署文档可以成功部署
## 7. 🧪 测试文档管理规范
### 🔴 测试文档组织原则
- **按需求维度分类**:测试文档必须按照业务需求模块进行组织,不得混合存放
- **结论性文档独立存放**:测试结论性文档必须存放在 `docs/测试文档/` 目录下
- **测试代码独立存放**:测试相关代码必须只存放在 `test/` 目录下
- **日期标识规范**:每次创建的测试文档必须以日期结尾来区分版本
### 🔴 测试文档目录结构规范
```
docs/测试文档/
├── README.md # 测试文档管理总览
├── [业务模块]/ # 按业务模块分类
│ ├── [具体功能]/ # 具体功能测试
│ │ ├── [功能]接口测试报告-YYYY-MM-DD.md # 接口测试报告
│ │ ├── [功能]功能测试报告-YYYY-MM-DD.md # 功能测试报告
│ │ ├── [功能]性能测试报告-YYYY-MM-DD.md # 性能测试报告
│ │ └── [功能]集成测试报告-YYYY-MM-DD.md # 集成测试报告
│ └── ...
└── ...
test/
├── package.json # 测试依赖配置
├── [功能]-api-test.js # API 接口测试脚本
├── [功能]-detailed-test.js # 详细测试分析脚本
├── [功能]-performance-test.js # 性能测试脚本
└── ...
```
### 🔴 测试文档强制要求
#### 1. 测试结论性文档放置规则
- **强制位置**:必须放置在 `docs/测试文档/` 目录下
- **分类方式**:按照需求维度创建子文件夹存放
- **命名规范**:文档名称必须以日期结尾(格式:YYYY-MM-DD)
- **示例路径**:
```
docs/测试文档/后勤管理/物业报修/物业报修接口测试报告-2025-01-26.md
docs/测试文档/系统管理/用户管理/用户管理功能测试报告-2025-01-26.md
```
#### 2. 测试代码存放规则
- **强制位置**:只能存放在 `test/` 目录下
- **禁止混合**:test目录下不得存放测试结论性文档
- **代码分类**:按功能模块组织测试脚本
- **示例文件**:
```
test/pm-repair-api-test.js # 物业报修 API 测试
test/user-management-test.js # 用户管理测试
test/custom-login-script.js # 登录认证工具
````
#### 3. 测试文档必含信息
每个测试结论性文档必须包含以下信息:
- **📁 测试代码路径**:明确标注对应的测试脚本位置
- **🔧 使用方法**:详细说明如何运行测试脚本
- **📊 测试结果**:完整的测试结果和数据分析
- **🎯 结论建议**:明确的测试结论和改进建议
- **⚠️ 问题记录**:发现的问题和解决方案
#### 测试文档标准模板格式:
```markdown
# [功能模块]测试报告
## 🎯 测试概览
**测试时间**: YYYY-MM-DD HH:mm:ss (⚠️必须填写真实的当前时间!)
**测试范围**: [具体测试范围]
**需求模块**: [所属业务模块]
## 📁 测试代码路径
**测试脚本位置**:
- **主要测试脚本**: `test/[功能]-api-test.js`
- **详细分析脚本**: `test/[功能]-detailed-test.js`
- **辅助工具脚本**: `test/[工具名].js`
**使用方法**:
```bash
cd test
npm install
node [功能]-api-test.js
````
## ✅ 测试结果总结
[测试结果详细内容]
## 🎯 结论
[测试结论和建议]
---
**测试执行**: 基于 `test/` 目录下的测试脚本
**文档路径**: `docs/测试文档/[模块]/[功能]/[报告名称]-YYYY-MM-DD.md`
```
### 🔴 强制工作流程
#### 测试执行流程:
```
1. **编写测试代码**
- 在 test/ 目录下创建测试脚本
- 确保代码可独立运行
↓
2. **执行测试**
- 运行测试脚本获取结果
- 记录详细的测试数据
↓
3. **创建测试报告**
- 在 docs/测试文档/ 按需求维度创建报告
- 文档名称必须包含日期后缀
- 必须包含测试代码路径信息
↓
4. **清理 test 目录**
- 删除 test 目录下的结论性文档
- 只保留测试代码和配置文件
↓
5. **更新文档索引**
- 更新相关 README.md 文件
- 在变更记录中记录测试活动
```
### 🔴 违规检查和纠正
- **检查要点**:
- [ ] test/目录下是否只有代码文件
- [ ] docs/测试文档/下是否按需求维度组织
- [ ] 测试报告是否包含代码路径信息
- [ ] 文档命名是否包含日期后缀
- **纠正措施**:
- 立即移动错误放置的文档到正确位置
- 补充缺失的测试代码路径信息
- 按规范重新组织文档结构
```
+684
View File
@@ -0,0 +1,684 @@
# Cursor Rules - Web 前端开发规范
## 适用范围
- **项目目录**: `web/` (基于 Vue 3 + TypeScript + Element Plus)
- **开发环境**: Node.js 20.15.x+, npm 10.7.x+
- **前端访问**: http://localhost (默认 80 端口)
---
# Web 前端开发规范 (web/)
## 1. 技术栈规范
### 核心技术
- **框架**: Vue 3.5.13 + TypeScript 5.8.3
- **UI 组件库**: Element Plus 2.9.8
- **构建工具**: Vite 7.0.9
- **状态管理**: Pinia
- **路由管理**: Vue Router 4
- **HTTP 客户端**: Axios
- **代码风格**: ESLint + Prettier
- **Node.js**: 20.15.x+ (推荐 20.15.0)
- **npm**: 10.7.x+
### 环境要求
- **开发环境**: 支持本地环境或阿里云测试环境
- **数据库**: MySQL/Redis 支持本机安装或使用阿里云环境
- **前端访问**: http://localhost (默认 80 端口)
- **后端服务**: http://localhost:8080
## 2. Art Design Pro UI 规范
### 设计理念
基于 Art Design Pro 的设计语言,追求现代化、精致、用户友好的界面体验。注重细节、动效和用户交互的流畅性。
### 颜色系统
#### 主色调 (Primary Colors)
```css
--art-primary: 93, 135, 255; /* 主品牌色 - 蓝色 */
--art-secondary: 73, 190, 255; /* 辅助色 - 天蓝色 */
--art-success: 19, 222, 185; /* 成功色 - 绿色 */
--art-warning: 255, 174, 31; /* 警告色 - 橙色 */
--art-error: 250, 137, 107; /* 错误色 - 红色 */
--art-info: 83, 155, 255; /* 信息色 - 蓝色 */
--art-danger: 255, 77, 79; /* 危险色 - 红色 */
```
#### 背景色系统
```css
/* 浅色主题 */
--art-bg-color: #fafbfc; /* 页面底色 */
--art-main-bg-color: #ffffff; /* 主要内容背景 */
--art-bg-primary: 236, 242, 255; /* 主色背景 */
--art-bg-secondary: 232, 247, 255; /* 辅助背景 */
--art-bg-success: 230, 255, 250; /* 成功背景 */
--art-bg-warning: 254, 245, 229; /* 警告背景 */
--art-bg-error: 253, 237, 232; /* 错误背景 */
/* 暗色主题 */
html.dark {
--art-bg-color: #070707; /* 页面底色 */
--art-main-bg-color: #161618; /* 主要内容背景 */
}
```
### 轮廓式按钮设计系统
#### 🎨 设计理念
全面采用轮廓式(Outline)按钮设计,提供更加优雅、现代和一致的用户界面体验。
#### 核心规范
- **Primary 按钮**: 轮廓式主色设计,主色边框和文字,5%透明度主色背景
- **Success 按钮**: 轮廓式成功色设计,成功色边框和文字,5%透明度成功色背景
- **Warning 按钮**: 轮廓式警告色设计,警告色边框和文字,5%透明度警告色背景
- **Danger 按钮**: 轮廓式危险色设计,危险色边框和文字,5%透明度危险色背景
- **Info 按钮**: 轮廓式信息色设计,信息色边框和文字,5%透明度信息色背景
- **Default 按钮**: 白色背景,灰色边框,灰色文字
#### 交互效果
- **悬浮状态**: 上移 1px + 背景透明度变为 10% + 边框透明度变为 80% + 彩色阴影
- **点击状态**: 98%缩放 + 0.1s 快速过渡 + 背景透明度变为 15%
- **禁用状态**: 50%透明度,禁用所有交互和变换
## 3. 组件开发规范
### Vue 组件结构标准
```vue
<template>
<div class="component-container">
<!-- 组件内容 -->
</div>
</template>
<script setup lang="ts" name="ComponentName">
// 1. 引入依赖
import { ref, reactive, computed, onMounted } from 'vue';
import type { ComponentProps, ComponentEmits } from './types';
// 2. 定义Props和Emits
const props = defineProps<ComponentProps>();
const emits = defineEmits<ComponentEmits>();
// 3. 响应式数据
const loading = ref(false);
const formData = reactive({});
// 4. 计算属性
const computedValue = computed(() => {
return /* 计算逻辑 */;
});
// 5. 方法定义
const handleClick = () => {
// 方法实现
};
// 6. 生命周期
onMounted(() => {
// 组件挂载后的逻辑
});
</script>
<style lang="scss" scoped>
.component-container {
// 样式实现
}
</style>
```
### 页面开发规范
#### 列表页面标准模板
```vue
<template>
<div class="p-2 page-container">
<!-- 搜索区域 -->
<transition
:enter-active-class="proxy?.animate.searchAnimate.enter"
:leave-active-class="proxy?.animate.searchAnimate.leave"
>
<div v-show="showSearch" class="mb-[10px]">
<el-card shadow="hover">
<el-form
ref="queryFormRef"
:model="queryParams"
:inline="true"
label-width="100px"
>
<!-- 搜索表单项 -->
<el-form-item>
<el-button type="primary" icon="Search" @click="handleQuery">
搜索
</el-button>
<el-button icon="Refresh" @click="resetQuery">重置</el-button>
</el-form-item>
</el-form>
</el-card>
</div>
</transition>
<!-- 表格区域 -->
<el-card shadow="never" class="button-card table-card">
<template #header>
<el-row :gutter="10" class="mb8">
<el-col :span="1.5">
<el-button type="primary" plain icon="Plus" @click="handleAdd">
新增
</el-button>
</el-col>
<right-toolbar
v-model:showSearch="showSearch"
@queryTable="getList"
></right-toolbar>
</el-row>
</template>
<!-- 数据表格 -->
<el-table v-loading="loading" border :data="dataList" :height="tableHeight">
<el-table-column type="selection" width="55" align="center" />
<!-- 数据列 -->
<el-table-column label="操作" align="center" width="160">
<template #default="scope">
<!-- 操作按钮 -->
</template>
</el-table-column>
</el-table>
<!-- 分页组件 -->
<pagination
v-show="total > 0"
:total="total"
v-model:page="queryParams.pageNum"
v-model:limit="queryParams.pageSize"
@pagination="getList"
/>
</el-card>
</div>
</template>
```
#### 表单页面标准模板
```vue
<template>
<div class="app-container">
<el-form ref="formRef" :model="form" :rules="rules" label-width="120px">
<el-card shadow="never">
<template #header>
<span>基本信息</span>
</template>
<el-row :gutter="20">
<el-col :span="12">
<el-form-item label="名称" prop="name">
<el-input v-model="form.name" placeholder="请输入名称" />
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="状态" prop="status">
<el-select v-model="form.status" placeholder="请选择状态">
<el-option label="启用" value="0" />
<el-option label="禁用" value="1" />
</el-select>
</el-form-item>
</el-col>
</el-row>
<el-form-item>
<el-button type="primary" @click="submitForm">提交</el-button>
<el-button @click="resetForm">重置</el-button>
</el-form-item>
</el-card>
</el-form>
</div>
</template>
<script setup lang="ts">
import { ref, reactive } from 'vue';
import type { FormInstance, FormRules } from 'element-plus';
// 表单引用
const formRef = ref<FormInstance>();
// 表单数据
const form = reactive({
name: '',
status: '0',
});
// 验证规则
const rules = reactive<FormRules>({
name: [{ required: true, message: '请输入名称', trigger: 'blur' }],
status: [{ required: true, message: '请选择状态', trigger: 'change' }],
});
// 提交表单
const submitForm = async () => {
if (!formRef.value) return;
await formRef.value.validate((valid) => {
if (valid) {
// 提交逻辑
console.log('提交表单:', form);
}
});
};
// 重置表单
const resetForm = () => {
if (!formRef.value) return;
formRef.value.resetFields();
};
</script>
```
## 4. API 开发规范
### API 接口定义标准
```typescript
// api/[module]/index.ts
import request from '@/utils/request';
import type { AxiosPromise } from 'axios';
import type { DataVO, DataForm, DataQuery } from './types';
/**
* 查询数据列表
* @param query 查询参数
*/
export const listData = (query?: DataQuery): AxiosPromise<DataVO[]> => {
return request({
url: '/api/data/list',
method: 'get',
params: query,
});
};
/**
* 查询数据详情
* @param id 数据ID
*/
export const getData = (id: string | number): AxiosPromise<DataVO> => {
return request({
url: `/api/data/${id}`,
method: 'get',
});
};
/**
* 新增数据
* @param data 数据信息
*/
export const addData = (data: DataForm): AxiosPromise<void> => {
return request({
url: '/api/data',
method: 'post',
data: data,
});
};
/**
* 修改数据
* @param data 数据信息
*/
export const updateData = (data: DataForm): AxiosPromise<void> => {
return request({
url: '/api/data',
method: 'put',
data: data,
});
};
/**
* 删除数据
* @param ids 数据ID数组
*/
export const delData = (ids: Array<string | number>): AxiosPromise<void> => {
return request({
url: `/api/data/${ids}`,
method: 'delete',
});
};
```
### TypeScript 类型定义
```typescript
// api/[module]/types.ts
// 查询参数
export interface DataQuery extends PageQuery {
name?: string;
status?: string;
createTime?: [DateModelType, DateModelType];
}
// 数据表单
export interface DataForm {
id?: string | number;
name: string;
status: string;
remark?: string;
}
// 数据视图对象
export interface DataVO {
id: string | number;
name: string;
status: string;
createTime: string;
updateTime: string;
remark?: string;
}
```
## 5. 状态管理规范
### Pinia Store 结构
```typescript
// stores/modules/[module].ts
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
import type { DataVO, DataQuery } from '@/api/[module]/types';
import { listData, getData } from '@/api/[module]';
export const useDataStore = defineStore('[module]', () => {
// 状态
const dataList = ref<DataVO[]>([]);
const loading = ref(false);
const total = ref(0);
// 计算属性
const hasData = computed(() => dataList.value.length > 0);
// 方法
const getList = async (query: DataQuery) => {
loading.value = true;
try {
const { data } = await listData(query);
dataList.value = data.rows;
total.value = data.total;
} finally {
loading.value = false;
}
};
const getInfo = async (id: string | number) => {
const { data } = await getData(id);
return data;
};
const reset = () => {
dataList.value = [];
total.value = 0;
};
return {
// 状态
dataList,
loading,
total,
// 计算属性
hasData,
// 方法
getList,
getInfo,
reset,
};
});
```
## 6. 路由管理规范
### 路由定义标准
```typescript
// router/modules/[module].ts
import type { RouteRecordRaw } from 'vue-router';
import Layout from '@/layout/index.vue';
const moduleRouter: RouteRecordRaw = {
path: '/[module]',
component: Layout,
redirect: '/[module]/list',
name: 'Module',
meta: {
title: '模块管理',
icon: 'example',
alwaysShow: true,
},
children: [
{
path: 'list',
component: () => import('@/views/[module]/index.vue'),
name: 'ModuleList',
meta: {
title: '列表管理',
activeMenu: '/[module]/list',
},
},
{
path: 'add',
component: () => import('@/views/[module]/form.vue'),
name: 'ModuleAdd',
meta: {
title: '新增数据',
activeMenu: '/[module]/list',
},
hidden: true,
},
{
path: 'edit/:id(\\d+)',
component: () => import('@/views/[module]/form.vue'),
name: 'ModuleEdit',
meta: {
title: '编辑数据',
activeMenu: '/[module]/list',
},
hidden: true,
},
],
};
export default moduleRouter;
```
## 7. 项目架构规范
### 目录结构标准
```
web/src/
├── api/ # API接口定义
│ ├── [module]/ # 按模块分类
│ │ ├── index.ts # API接口
│ │ └── types.ts # 类型定义
│ └── types.ts # 通用类型定义
├── assets/ # 静态资源
│ ├── icons/ # SVG图标
│ ├── images/ # 图片资源
│ └── styles/ # 全局样式
├── components/ # 通用组件
│ ├── [ComponentName]/ # 组件目录
│ │ ├── index.vue # 组件主文件
│ │ └── types.ts # 组件类型
│ └── index.ts # 组件导出
├── composables/ # 组合式函数
├── directive/ # 自定义指令
├── hooks/ # 自定义钩子
├── layout/ # 布局组件
├── plugins/ # 插件配置
├── router/ # 路由配置
│ ├── modules/ # 路由模块
│ └── index.ts # 路由入口
├── stores/ # 状态管理
│ ├── modules/ # Store模块
│ └── index.ts # Store入口
├── types/ # 全局类型定义
├── utils/ # 工具函数
│ ├── request.ts # HTTP请求封装
│ ├── auth.ts # 认证工具
│ └── index.ts # 工具导出
├── views/ # 页面视图
│ ├── [module]/ # 按模块分类
│ │ ├── index.vue # 列表页面
│ │ ├── form.vue # 表单页面
│ │ └── components/ # 页面组件
│ └── layout/ # 布局页面
├── App.vue # 应用入口
└── main.ts # 主入口文件
```
## 8. 代码规范
### 命名规范
- **文件命名**: 使用 kebab-case (如: user-list.vue)
- **组件命名**: 使用 PascalCase (如: UserList)
- **方法命名**: 使用 camelCase (如: getUserList)
- **常量命名**: 使用 UPPER_SNAKE_CASE (如: API_BASE_URL)
- **CSS 类名**: 使用 kebab-case (如: .user-list-container)
### ESLint 配置
```typescript
// .eslintrc.js
module.exports = {
extends: ['@vue/eslint-config-typescript', '@vue/eslint-config-prettier'],
rules: {
// Vue规则
'vue/multi-word-component-names': 'off',
'vue/no-v-html': 'off',
// TypeScript规则
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/no-explicit-any': 'warn',
// 通用规则
'no-console': 'warn',
'no-debugger': 'error',
},
};
```
### Prettier 配置
```json
{
"semi": true,
"singleQuote": true,
"trailingComma": "none",
"tabWidth": 2,
"useTabs": false,
"printWidth": 100,
"endOfLine": "lf"
}
```
## 9. 性能优化
### 代码分割
```typescript
// 路由懒加载
const Home = () => import('@/views/home/index.vue');
// 组件懒加载
const LazyComponent = defineAsyncComponent(() => import('@/components/LazyComponent.vue'));
```
### 缓存策略
```typescript
// HTTP缓存
import { ElMessage } from 'element-plus';
const request = axios.create({
timeout: 10000,
headers: {
'Cache-Control': 'no-cache'
}
});
// 组件缓存
<router-view v-slot="{ Component }">
<keep-alive :include="cachedViews">
<component :is="Component" :key="route.path" />
</keep-alive>
</router-view>
```
## 10. 错误处理
### 全局错误处理
```typescript
// main.ts
app.config.errorHandler = (err, vm, info) => {
console.error('全局错误:', err);
ElMessage.error('系统异常,请联系管理员');
};
// 请求错误处理
request.interceptors.response.use(
(response) => {
const { code, msg } = response.data;
if (code === 200) {
return response.data;
} else {
ElMessage.error(msg || '请求失败');
return Promise.reject(new Error(msg));
}
},
(error) => {
ElMessage.error('网络异常');
return Promise.reject(error);
},
);
```
## 11. 测试规范
### 单元测试
```typescript
// tests/components/UserList.spec.ts
import { mount } from '@vue/test-utils';
import UserList from '@/components/UserList/index.vue';
describe('UserList', () => {
it('should render correctly', () => {
const wrapper = mount(UserList, {
props: {
users: [],
},
});
expect(wrapper.exists()).toBe(true);
});
});
```
### E2E 测试
```typescript
// e2e/user.spec.ts
import { test, expect } from '@playwright/test';
test('用户列表页面', async ({ page }) => {
await page.goto('/user/list');
await expect(page.locator('.user-list')).toBeVisible();
});
```
+714
View File
@@ -0,0 +1,714 @@
# Cursor Rules - 移动端开发规范
## 适用范围
- **项目目录**: `mobile/` (基于 uniapp + uView UI)
- **开发语言**: JavaScript/TypeScript
- **平台支持**: H5、小程序、APP
---
# 移动端开发规范 (mobile/)
## 1. 技术栈规范
### 核心技术
- **框架**: uni-app
- **UI 组件库**: uView UI
- **开发语言**: JavaScript/TypeScript
- **状态管理**: Vuex
- **HTTP 客户端**: uni.request 封装
## 2. 项目结构规范
### 移动端目录结构
```
mobile/
├── src/
│ ├── api/ # API接口定义
│ ├── components/ # 通用组件
│ ├── pages/ # 页面文件
│ │ ├── index/ # 首页
│ │ ├── login/ # 登录页
│ │ ├── mine/ # 个人中心
│ │ └── workbench/ # 工作台
│ ├── static/ # 静态资源
│ ├── utils/ # 工具函数
│ ├── App.vue # 应用入口
│ ├── config.js # 配置文件
│ └── main.js # 主入口文件
├── pages.json # 页面配置
├── manifest.json # 应用配置
└── uni.scss # 全局样式
```
## 3. 开发规范
### 页面开发规范
- **页面命名**: 使用小写字母和连字符 (如: user-list)
- **组件命名**: 使用 PascalCase (如: UserCard)
- **API 调用**: 统一使用封装的 request 工具
- **样式规范**: 使用 uView UI 组件和样式变量
### 页面模板
```vue
<template>
<view class="page-container">
<u-navbar title="页面标题" @leftClick="handleBack"></u-navbar>
<!-- 页面内容 -->
</view>
</template>
<script>
export default {
data() {
return {
// 页面数据
};
},
onLoad() {
// 页面加载逻辑
},
methods: {
handleBack() {
uni.navigateBack();
},
},
};
</script>
<style lang="scss" scoped>
.page-container {
// 页面样式
}
</style>
```
### 组件开发规范
```vue
<template>
<view class="component-wrapper">
<!-- 组件内容 -->
</view>
</template>
<script>
export default {
name: 'ComponentName',
props: {
// 组件属性
},
data() {
return {
// 组件数据
};
},
methods: {
// 组件方法
},
};
</script>
<style lang="scss" scoped>
.component-wrapper {
// 组件样式
}
</style>
```
## 4. 与后端 API 对接规范
### 请求封装
```javascript
// utils/request.js
const request = (options) => {
return new Promise((resolve, reject) => {
uni.request({
url: getApp().globalData.baseUrl + options.url,
method: options.method || 'GET',
data: options.data || {},
header: {
Authorization: uni.getStorageSync('token'),
'Content-Type': 'application/json',
},
success: (res) => {
if (res.data.code === 200) {
resolve(res.data);
} else {
reject(res.data);
}
},
fail: (err) => {
reject(err);
},
});
});
};
export default request;
```
### API 接口定义
```javascript
// api/user.js
import request from '@/utils/request';
export const userApi = {
// 用户登录
login(data) {
return request({
url: '/auth/login',
method: 'POST',
data,
});
},
// 获取用户信息
getUserInfo() {
return request({
url: '/system/user/getInfo',
method: 'GET',
});
},
// 用户列表
getUserList(params) {
return request({
url: '/system/user/list',
method: 'GET',
data: params,
});
},
};
```
## 5. 状态管理规范
### Vuex Store 结构
```javascript
// store/index.js
import Vue from 'vue';
import Vuex from 'vuex';
import user from './modules/user';
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
user,
},
});
```
### 用户模块示例
```javascript
// store/modules/user.js
const state = {
token: uni.getStorageSync('token') || '',
userInfo: {},
};
const mutations = {
SET_TOKEN(state, token) {
state.token = token;
uni.setStorageSync('token', token);
},
SET_USER_INFO(state, userInfo) {
state.userInfo = userInfo;
},
};
const actions = {
// 用户登录
login({ commit }, loginForm) {
return new Promise((resolve, reject) => {
userApi
.login(loginForm)
.then((res) => {
commit('SET_TOKEN', res.data.access_token);
resolve(res);
})
.catch((error) => {
reject(error);
});
});
},
// 获取用户信息
getUserInfo({ commit }) {
return new Promise((resolve, reject) => {
userApi
.getUserInfo()
.then((res) => {
commit('SET_USER_INFO', res.data);
resolve(res);
})
.catch((error) => {
reject(error);
});
});
},
};
export default {
namespaced: true,
state,
mutations,
actions,
};
```
## 6. 页面配置规范
### pages.json 配置
```json
{
"pages": [
{
"path": "pages/index/index",
"style": {
"navigationBarTitleText": "首页"
}
},
{
"path": "pages/login/login",
"style": {
"navigationBarTitleText": "登录",
"navigationStyle": "custom"
}
}
],
"globalStyle": {
"navigationBarTextStyle": "black",
"navigationBarTitleText": "校园管理",
"navigationBarBackgroundColor": "#F8F8F8",
"backgroundColor": "#F8F8F8"
},
"tabBar": {
"color": "#7A7E83",
"selectedColor": "#3cc51f",
"borderStyle": "black",
"backgroundColor": "#ffffff",
"list": [
{
"pagePath": "pages/index/index",
"iconPath": "static/tabbar/home.png",
"selectedIconPath": "static/tabbar/home-active.png",
"text": "首页"
},
{
"pagePath": "pages/workbench/workbench",
"iconPath": "static/tabbar/workbench.png",
"selectedIconPath": "static/tabbar/workbench-active.png",
"text": "工作台"
},
{
"pagePath": "pages/mine/mine",
"iconPath": "static/tabbar/mine.png",
"selectedIconPath": "static/tabbar/mine-active.png",
"text": "我的"
}
]
}
}
```
## 7. 样式规范
### 全局样式
```scss
// uni.scss
$primary-color: #007aff;
$success-color: #4cd964;
$warning-color: #f0ad4e;
$error-color: #dd524d;
$text-color: #333333;
$text-color-light: #666666;
$text-color-lighter: #999999;
$border-color: #e5e5e5;
$background-color: #f5f5f5;
// 通用样式
.container {
padding: 20rpx;
}
.flex {
display: flex;
}
.flex-center {
display: flex;
align-items: center;
justify-content: center;
}
.text-center {
text-align: center;
}
.text-right {
text-align: right;
}
```
### 组件样式规范
```scss
// 组件样式示例
.user-card {
background: #fff;
border-radius: 10rpx;
padding: 20rpx;
margin-bottom: 20rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
.avatar {
width: 80rpx;
height: 80rpx;
border-radius: 50%;
}
.info {
flex: 1;
margin-left: 20rpx;
.name {
font-size: 32rpx;
color: $text-color;
font-weight: bold;
}
.desc {
font-size: 28rpx;
color: $text-color-light;
margin-top: 10rpx;
}
}
}
```
## 8. 工具函数规范
### 通用工具函数
```javascript
// utils/index.js
// 格式化日期
export function formatDate(date, format = 'YYYY-MM-DD HH:mm:ss') {
// 实现日期格式化逻辑
}
// 防抖函数
export function debounce(func, wait) {
let timeout;
return function executedFunction(...args) {
const later = () => {
clearTimeout(timeout);
func(...args);
};
clearTimeout(timeout);
timeout = setTimeout(later, wait);
};
}
// 节流函数
export function throttle(func, limit) {
let inThrottle;
return function () {
const args = arguments;
const context = this;
if (!inThrottle) {
func.apply(context, args);
inThrottle = true;
setTimeout(() => (inThrottle = false), limit);
}
};
}
// 深拷贝
export function deepClone(obj) {
if (obj === null) return null;
if (typeof obj !== 'object') return obj;
if (obj.constructor === Date) return new Date(obj);
if (obj.constructor === RegExp) return new RegExp(obj);
var newObj = new obj.constructor();
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = deepClone(obj[key]);
}
}
return newObj;
}
```
### 存储工具
```javascript
// utils/storage.js
// 同步存储
export function setStorageSync(key, data) {
try {
uni.setStorageSync(key, data);
} catch (e) {
console.error('存储数据失败', e);
}
}
export function getStorageSync(key) {
try {
return uni.getStorageSync(key);
} catch (e) {
console.error('获取存储数据失败', e);
return null;
}
}
export function removeStorageSync(key) {
try {
uni.removeStorageSync(key);
} catch (e) {
console.error('删除存储数据失败', e);
}
}
// 异步存储
export function setStorage(key, data) {
return new Promise((resolve, reject) => {
uni.setStorage({
key,
data,
success: resolve,
fail: reject,
});
});
}
export function getStorage(key) {
return new Promise((resolve, reject) => {
uni.getStorage({
key,
success: (res) => resolve(res.data),
fail: reject,
});
});
}
```
## 9. 权限管理
### 登录状态检查
```javascript
// utils/auth.js
// 检查登录状态
export function checkLogin() {
const token = uni.getStorageSync('token');
return !!token;
}
// 跳转到登录页
export function toLogin() {
uni.navigateTo({
url: '/pages/login/login',
});
}
// 页面权限检查中间件
export function requireAuth() {
if (!checkLogin()) {
toLogin();
return false;
}
return true;
}
```
### 路由守卫
```javascript
// main.js
import { requireAuth } from '@/utils/auth';
// 页面跳转拦截器
const originalNavigateTo = uni.navigateTo;
uni.navigateTo = function (options) {
// 需要登录的页面列表
const authPages = ['/pages/workbench/workbench', '/pages/mine/mine'];
if (authPages.includes(options.url) && !requireAuth()) {
return;
}
return originalNavigateTo.call(this, options);
};
```
## 10. 错误处理
### 全局错误处理
```javascript
// utils/errorHandler.js
// 统一错误处理
export function handleError(error) {
console.error('Error:', error);
let message = '系统异常,请稍后重试';
if (error.code) {
switch (error.code) {
case 401:
message = '登录已过期,请重新登录';
// 跳转到登录页
toLogin();
break;
case 403:
message = '没有权限访问';
break;
case 404:
message = '请求的资源不存在';
break;
case 500:
message = '服务器内部错误';
break;
default:
message = error.msg || message;
}
}
uni.showToast({
title: message,
icon: 'none',
duration: 2000,
});
}
// 网络错误处理
export function handleNetworkError() {
uni.showToast({
title: '网络连接异常',
icon: 'none',
duration: 2000,
});
}
```
## 11. 性能优化
### 图片优化
```javascript
// 图片懒加载
export function lazyLoadImage(selector) {
const query = uni.createSelectorQuery();
query
.selectAll(selector)
.boundingClientRect((data) => {
data.forEach((item) => {
if (item.top < uni.getSystemInfoSync().windowHeight) {
// 加载图片
}
});
})
.exec();
}
// 图片压缩
export function compressImage(src, quality = 0.8) {
return new Promise((resolve, reject) => {
uni.compressImage({
src,
quality,
success: resolve,
fail: reject,
});
});
}
```
### 数据缓存
```javascript
// 数据缓存管理
class DataCache {
constructor() {
this.cache = new Map();
this.timeout = 5 * 60 * 1000; // 5分钟
}
set(key, data) {
this.cache.set(key, {
data,
timestamp: Date.now(),
});
}
get(key) {
const item = this.cache.get(key);
if (!item) return null;
if (Date.now() - item.timestamp > this.timeout) {
this.cache.delete(key);
return null;
}
return item.data;
}
clear() {
this.cache.clear();
}
}
export const dataCache = new DataCache();
```
## 12. 测试规范
### 单元测试
```javascript
// 使用Jest进行单元测试
describe('utils/index', () => {
test('formatDate should format date correctly', () => {
const date = new Date('2023-01-01 12:00:00');
const result = formatDate(date, 'YYYY-MM-DD');
expect(result).toBe('2023-01-01');
});
});
```
### 页面测试
```javascript
// 页面功能测试
describe('Login Page', () => {
test('should show error when username is empty', async () => {
// 模拟登录表单提交
const wrapper = mount(LoginPage);
await wrapper.find('.login-btn').trigger('tap');
expect(wrapper.find('.error-message').text()).toBe('请输入用户名');
});
});
```
+25
View File
@@ -11,6 +11,20 @@
"cursor.ai.chat.floatingWindow": false,
"cursor.ai.chat.sidePanel": true,
// 🆕 自动接受AI建议设置
"cursor.ai.autoAccept.enabled": true,
"cursor.ai.autoAccept.delay": 1000,
"cursor.ai.suggestions.autoAccept": true,
"cursor.ai.inline.autoAccept": true,
"cursor.ai.tab.autoAccept": true,
"cursor.ai.codeGeneration.autoAccept": true,
"cursor.ai.edit.autoAccept": true,
// Tab补全自动接受
"cursor.tab.autoAccept": true,
"cursor.tab.acceptOnlyFullLine": false,
"cursor.tab.acceptPartialSuggestion": true,
// 禁用多余的AI提示
"cursor.ai.hover.enabled": false,
"cursor.ai.inline.enabled": true,
@@ -47,6 +61,17 @@
"workbench.editor.enablePreviewFromQuickOpen": false,
"workbench.editor.showTabs": "multiple",
// 🆕 VSCode原生自动接受设置
"editor.acceptSuggestionOnCommitCharacter": true,
"editor.acceptSuggestionOnEnter": "on",
"editor.tabCompletion": "on",
"editor.suggestSelection": "recentlyUsed",
"editor.quickSuggestions": {
"other": true,
"comments": true,
"strings": true
},
// 禁用文件关联预览
"files.associations": {
"*.vue": "vue"