feat: 完善项目开发规范和测试文档体系
📝 主要改进: • Cursor配置模块化:拆分为前端、后端、移动端、文档、API测试5个专门规范文件 • API文档重新组织:按业务模块拆分到docs/开发文档/API/目录下 • 新增维修分类功能完整测试方案和自动化测试脚本 • 后端热启动脚本完善,支持Linux/Windows双平台 • 强化文档同步更新规范,确保代码与文档一致性 🔧 技术改进: • 优化Cursor AI工作流程和代码生成质量 • 完善API测试规范(AES+RSA双重加密登录方法) • 提升开发效率和代码质量标准化程度 �� 测试覆盖: • 维修分类管理功能端到端测试验证通过 • 包含页面加载、CRUD操作、搜索功能等核心测试用例 更新时间:2025-07-01
This commit is contained in:
1 parent
7a5b9d1bea
commit
249b1dfeb4
44 files changed
+14027
-2852
No files matched your search
@@ -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%保留
|
||||
@@ -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
@@ -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/测试文档/下是否按需求维度组织
|
||||
- [ ] 测试报告是否包含代码路径信息
|
||||
- [ ] 文档命名是否包含日期后缀
|
||||
|
||||
- **纠正措施**:
|
||||
- 立即移动错误放置的文档到正确位置
|
||||
- 补充缺失的测试代码路径信息
|
||||
- 按规范重新组织文档结构
|
||||
```
|
||||
@@ -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();
|
||||
});
|
||||
```
|
||||
@@ -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('请输入用户名');
|
||||
});
|
||||
});
|
||||
```
|
||||
@@ -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"
|
||||
|
||||
Reference in new issue
Block a user