From 0dda75dbe2ba12d8ea6fc156162d0f337cadd4fc Mon Sep 17 00:00:00 2001 From: my_mir Date: Fri, 30 May 2025 10:27:45 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E6=9B=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cursor/rules/coding-standards.mdc | 221 +++++++++++++++++++++++++- .cursor/rules/project-guide.mdc | 119 +++++++++++++- .cursor/rules/social-login-errors.mdc | 216 ++++++++++++++++++++++++- .cursor/rules/troubleshooting.mdc | 180 ++++++++++++++++++++- 4 files changed, 728 insertions(+), 8 deletions(-) diff --git a/.cursor/rules/coding-standards.mdc b/.cursor/rules/coding-standards.mdc index b93c988..51fc132 100644 --- a/.cursor/rules/coding-standards.mdc +++ b/.cursor/rules/coding-standards.mdc @@ -1,5 +1,222 @@ --- -description: -globs: +description: +globs: alwaysApply: false --- +# 智慧生态项目编码规范 + +## 代码风格 + +### JavaScript/Vue 规范 +1. 使用 ES6+ 语法特性 +2. 变量命名: + - 常量使用 UPPER_SNAKE_CASE + - 变量和函数使用 camelCase + - 组件名使用 PascalCase +3. 缩进使用 Tab 制表符 +4. 字符串优先使用单引号 +5. 语句末尾不加分号(遵循项目现有风格) + +### Vue 组件规范 +```vue + + + + + +``` + +## API 接口规范 + +### 接口定义示例 +参考 [login.js](mdc:api/login.js) 的实现方式: + +```javascript +import request from '@/utils/request' + +// 登录方法 +export function login(username, password, captchaVerification) { + const data = { + username, + password, + captchaVerification + } + return request({ + url: '/system/auth/login', + headers: { + isToken: false + }, + 'method': 'POST', + 'data': data + }) +} +``` + +### 请求响应处理 +1. 使用 [request.js](mdc:utils/request.js) 统一处理请求 +2. 错误码定义在 [errorCode.js](mdc:utils/errorCode.js) +3. 统一的响应拦截和错误处理 + +## 状态管理规范 + +### Vuex Module 示例 +```javascript +const state = { + // 状态定义 +} + +const mutations = { + SET_STATE(state, value) { + state.property = value + } +} + +const actions = { + async fetchData({ commit }) { + const res = await api.getData() + commit('SET_STATE', res.data) + } +} + +export default { + namespaced: true, + state, + mutations, + actions +} +``` + +## 工具函数规范 + +### 工具函数定义 +参考 [common.js](mdc:utils/common.js) 和 [ruoyi.js](mdc:utils/ruoyi.js): +1. 单一职责原则 +2. 函数命名清晰 +3. 添加必要的注释 + +## uni-app 特定规范 + +### 条件编译 +```javascript +// #ifdef MP-WEIXIN +// 微信小程序特有代码 +// #endif + +// #ifdef APP-PLUS +// APP 特有代码 +// #endif +``` + +### 页面跳转 +使用 uni-app 的路由 API: +```javascript +// 保留当前页面,跳转到应用内的某个页面 +uni.navigateTo({ + url: '/pages/detail/detail' +}) + +// 关闭当前页面,跳转到应用内的某个页面 +uni.redirectTo({ + url: '/pages/index/index' +}) + +// 关闭所有页面,打开到应用内的某个页面 +uni.reLaunch({ + url: '/pages/login/login' +}) +``` + +### 数据存储 +使用 [storage.js](mdc:utils/storage.js) 封装的方法: +```javascript +import storage from '@/utils/storage' + +// 存储 +storage.set('key', value) + +// 获取 +const value = storage.get('key') + +// 删除 +storage.remove('key') +``` + +## 权限控制 + +### 路由权限 +参考 [permission.js](mdc:permission.js) 实现: +1. 定义白名单页面 +2. 使用拦截器进行权限验证 +3. 未授权自动跳转登录页 + +### 接口权限 +使用 [auth.js](mdc:utils/auth.js) 管理 Token: +```javascript +import { getAccessToken } from '@/utils/auth' + +// 在请求头中携带 Token +const token = getAccessToken() +``` + +## 错误处理 + +### 统一错误提示 +```javascript +uni.showToast({ + title: '操作失败', + icon: 'none' +}) + +// 或使用封装的提示方法 +this.$modal.msg('操作成功') +this.$modal.msgError('操作失败') +``` + +### 异常捕获 +```javascript +try { + const res = await api.getData() + // 处理成功响应 +} catch (error) { + console.error('请求失败:', error) + this.$modal.msgError('获取数据失败') +} +``` + +## 性能优化 + +### 小程序分包 +1. 主包保持精简,只包含核心页面 +2. 按功能模块进行分包 +3. 在 [pages.json](mdc:pages.json) 中配置 subPackages + +### 图片优化 +1. 使用合适的图片格式 +2. 控制图片大小 +3. 使用懒加载 + +### 数据缓存 +1. 合理使用本地存储 +2. 避免频繁请求相同数据 +3. 设置合理的缓存过期时间 diff --git a/.cursor/rules/project-guide.mdc b/.cursor/rules/project-guide.mdc index b93c988..68f9eff 100644 --- a/.cursor/rules/project-guide.mdc +++ b/.cursor/rules/project-guide.mdc @@ -1,5 +1,120 @@ --- -description: -globs: +description: +globs: alwaysApply: false --- +# 智慧生态小程序项目指南 + +## 项目概述 +这是一个基于 uni-app 开发的跨平台应用,支持微信小程序和移动端 APP。项目采用 Vue 2.x 技术栈,后端使用 RuoYi 框架。 + +## 技术栈 +- **前端框架**: uni-app (Vue 2.x) +- **状态管理**: Vuex +- **后端框架**: RuoYi +- **加密库**: crypto-js +- **支持平台**: 微信小程序、Android/iOS APP、H5 + +## 项目结构 + +### 核心文件 +- [main.js](mdc:main.js) - 应用入口文件 +- [App.vue](mdc:App.vue) - 根组件 +- [manifest.json](mdc:manifest.json) - 应用配置文件 +- [pages.json](mdc:pages.json) - 页面路由配置 +- [config.js](mdc:config.js) - 全局配置(API 地址等) + +### 目录结构 +``` +├── api/ # API 接口模块 +│ ├── system/ # 系统管理接口 +│ ├── task/ # 任务管理接口 +│ ├── enterprise/ # 企业管理接口 +│ ├── inspections/ # 检查管理接口 +│ └── login.js # 登录接口 +├── components/ # 公共组件 +├── pages/ # 主包页面 +│ ├── index.vue # 首页 +│ ├── login.vue # 登录页 +│ ├── task.vue # 任务页 +│ ├── owner.vue # 业主页 +│ └── enterprise.vue # 企业页 +├── sub/ # 分包目录(优化小程序体积) +│ ├── task/ # 任务模块分包 +│ ├── owner/ # 业主模块分包 +│ ├── enterprise/ # 企业模块分包 +│ └── inspection/ # 检查模块分包 +├── store/ # Vuex 状态管理 +│ ├── index.js # Store 入口 +│ ├── getters.js # 全局 getters +│ └── modules/ # 状态模块 +├── utils/ # 工具函数 +│ ├── request.js # 请求封装 +│ ├── auth.js # 认证相关 +│ ├── permission.js # 权限控制 +│ └── storage.js # 本地存储 +└── static/ # 静态资源 +``` + +## 开发规范 + +### API 调用规范 +1. 所有 API 请求都应通过 `utils/request.js` 封装的方法 +2. API 模块按功能领域组织在 `api/` 目录下 +3. 使用统一的错误处理机制 + +### 路由权限控制 +- 使用 [permission.js](mdc:permission.js) 进行路由拦截 +- 白名单页面定义在 `whiteList` 数组中 +- 未登录用户自动跳转到登录页 + +### 状态管理规范 +1. 全局状态使用 Vuex 管理 +2. 模块化组织 store,每个业务模块独立管理 +3. 通过 getters 暴露需要的状态 + +### 组件开发规范 +1. 公共组件放在 `components/` 目录 +2. 页面组件放在 `pages/` 或 `sub/` 目录 +3. 组件命名使用 PascalCase +4. 组件文件名与组件名保持一致 + +### 样式规范 +- 使用 [uni.scss](mdc:uni.scss) 定义的全局样式变量 +- 支持 scss 预处理器 +- 遵循 uni-app 的样式编写规范 + +## 配置说明 + +### 环境配置 +在 [config.js](mdc:config.js) 中配置: +- `baseUrl`: API 服务器地址 +- `baseApi`: API 基础路径 +- `appInfo`: 应用基本信息 + +### 小程序配置 +在 [manifest.json](mdc:manifest.json) 中的 `mp-weixin` 节点配置: +- `appid`: 小程序 AppID +- `permission`: 权限申请说明 +- `requiredPrivateInfos`: 隐私接口声明 + +## 常用功能模块 + +### 登录认证 +- 登录接口: `api/login.js` +- Token 管理: `utils/auth.js` +- 权限验证: `utils/permission.js` + +### 文件上传 +- 上传工具: `utils/upload.js` +- 支持图片、文件上传到服务器 + +### 数据字典 +- 字典工具: `utils/dict.js` +- 统一管理下拉选项等枚举数据 + +## 注意事项 +1. 开发时注意区分平台差异,使用条件编译 +2. 小程序有包大小限制,合理使用分包 +3. 遵循 uni-app 的生命周期和 API 使用规范 +4. 注意处理网络请求的异常情况 diff --git a/.cursor/rules/social-login-errors.mdc b/.cursor/rules/social-login-errors.mdc index b93c988..431aaa8 100644 --- a/.cursor/rules/social-login-errors.mdc +++ b/.cursor/rules/social-login-errors.mdc @@ -1,5 +1,217 @@ --- -description: -globs: +description: +globs: alwaysApply: false --- +# 社交登录错误码映射指南 + +## 错误码说明 + +### 微信小程序登录错误码 +# 社交登录错误码映射指南 + +## 错误码说明 + +### 微信小程序登录错误码 + +| 错误码 | 错误信息 | 前端处理建议 | +|--------|----------|--------------| +| 1002018000 | 社交授权失败,原因是:{} | 显示具体错误原因,引导用户重试 | +| 1002018001 | 社交授权失败,找不到对应的用户 | 提示用户账号未绑定,引导注册或绑定 | +| 1002018002 | 微信授权码已过期,请重新授权 | 自动调用 `uni.login()` 重新获取 code | +| 1002018003 | 微信授权码无效或已被使用 | 清除本地存储的 code,重新获取 | +| 1002018005 | 微信服务器连接失败,请稍后重试 | 提示网络问题,延迟后重试 | +| 1002018006 | 用户身份验证失败,请重新登录 | 清除本地 token,跳转登录页 | + +## 参数验证说明 + +### 使用 @Valid 注解进行参数验证 + +在控制器方法中使用 `@Valid` 注解时,Spring 会自动验证请求对象的字段: + +```java +@PostMapping("/app_login") +public CommonResult AppLogin(@RequestBody @Valid AuthSocialLoginReqVO reqVO) { + // 不需要手动检查 code、type、state 是否为空 + // @Valid 会根据 AuthSocialLoginReqVO 中的注解自动验证 +} +``` + +`AuthSocialLoginReqVO` 中的验证规则: +- `code`: `@NotEmpty(message = "授权码不能为空")` +- `type`: `@NotNull(message = "社交平台的类型不能为空")` +- `state`: `@NotEmpty(message = "state 不能为空")` +- `openid`: 无验证注解(需要手动验证) +- `userType`: 无验证注解 + +**注意**:当参数验证失败时,Spring 会自动返回 400 Bad Request 错误,包含详细的验证错误信息。 + +## 前端错误处理示例 + +```javascript +// 在 store/modules/user.js 中优化错误处理 +Login({ commit }, userInfo) { + return new Promise((resolve, reject) => { + login(userInfo).then(res => { + const { data } = res + setToken(data) + resolve() + }).catch(error => { + // 根据错误码进行不同处理 + const errorCode = error.code + + switch(errorCode) { + case '1002018002': // code 过期 + // 重新获取 code + uni.login({ + success: (res) => { + setOpenId(res.code) + // 重试登录 + this.dispatch('Login', { + ...userInfo, + code: res.code + }) + } + }) + break + + case '1002018003': // code 无效 + // 清除本地 code + removeOpenId() + uni.showModal({ + title: '提示', + content: '授权信息无效,请重新进入小程序', + showCancel: false, + success: () => { + // 可以选择重启小程序 + uni.reLaunch({ + url: '/pages/login' + }) + } + }) + break + + case '1002018005': // 网络错误 + uni.showToast({ + title: '网络连接失败,请稍后重试', + icon: 'none', + duration: 2000 + }) + // 延迟后重试 + setTimeout(() => { + this.dispatch('Login', userInfo) + }, 3000) + break + + default: + // 显示默认错误信息 + uni.showToast({ + title: error.message || '登录失败', + icon: 'none' + }) + } + + reject(error) + }) + }) +} +``` + +## 最佳实践 + +### 1. 避免 code 重复使用 +```javascript +// 错误做法:保存 code 供多次使用 +setOpenId(res.code) // ❌ code 只能用一次 + +// 正确做法:获取后立即使用 +uni.login({ + success: res => { + // 立即调用登录接口 + this.$store.dispatch('Login', { + type: 34, + code: res.code, // ✅ 立即使用 + state: 'default' + }) + } +}) +``` + +### 2. 处理 code 过期 +```javascript +// 设置 code 有效期检查 +const CODE_EXPIRE_TIME = 4 * 60 * 1000 // 4分钟(保守估计) + +// 保存 code 时记录时间 +uni.login({ + success: res => { + const codeData = { + code: res.code, + timestamp: Date.now() + } + uni.setStorageSync('wxCode', codeData) + } +}) + +// 使用时检查是否过期 +const codeData = uni.getStorageSync('wxCode') +if (codeData && (Date.now() - codeData.timestamp < CODE_EXPIRE_TIME)) { + // 使用 code +} else { + // 重新获取 +} +``` + +### 3. 优雅的错误提示 +```javascript +const errorMessages = { + '1002018002': '登录信息已过期,正在重新获取...', + '1002018003': '授权无效,请重新进入小程序', + '1002018005': '网络连接失败,请检查网络设置', + '1002018006': '身份验证失败,请重新登录' +} + +// 统一错误处理 +function handleLoginError(error) { + const message = errorMessages[error.code] || error.message || '登录失败' + + if (error.code === '1002018002') { + // 自动处理,不显示错误 + console.log(message) + } else { + // 显示错误提示 + uni.showToast({ + title: message, + icon: 'none', + duration: 2000 + }) + } +} +``` + +## 后端日志查看 + +当前端遇到登录问题时,可以通过查看后端日志快速定位问题: + +1. **查看请求日志** + ``` + [AppLogin][小程序登录开始,code(xxx) type(34) userType(3)] + ``` + +2. **查看认证过程** + ``` + [getAuthUser][开始请求社交平台,type(34) userType(2) code(xxx)] + [miniAppLogin][获取到用户信息,openId(xxx) nickname(xxx)] + ``` + +3. **查看错误日志** + ``` + [getAuthUser][社交授权失败,type(34) code(xxx) errorMsg(invalid code)] + [AppLogin][小程序登录失败,code(xxx) error(微信授权码无效或已被使用)] + ``` + +通过这些日志可以快速判断: +- code 是否正确传递 +- 微信接口返回的具体错误 +- 用户是新用户还是老用户 +- 绑定过程是否成功 diff --git a/.cursor/rules/troubleshooting.mdc b/.cursor/rules/troubleshooting.mdc index b93c988..4df8d5b 100644 --- a/.cursor/rules/troubleshooting.mdc +++ b/.cursor/rules/troubleshooting.mdc @@ -1,5 +1,181 @@ --- -description: -globs: +description: +globs: alwaysApply: false --- +# 智慧生态项目常见问题排查指南 + +## 登录相关问题 + +### Token 失效处理 +问题:用户 Token 过期后的处理 +解决方案: +1. 在 [request.js](mdc:utils/request.js) 中检测 401 错误 +2. 清除本地 Token:`removeToken()` +3. 跳转到登录页:`uni.reLaunch({ url: '/pages/login' })` + +### 权限拦截不生效 +问题:页面权限拦截失效 +检查点: +1. 确认 [permission.js](mdc:permission.js) 已在 [main.js](mdc:main.js) 中引入 +2. 检查页面路径是否在白名单中 +3. 确认使用了正确的跳转方法(navigateTo、redirectTo 等) + +## API 请求问题 + +### 跨域问题 +在开发环境中遇到跨域: +1. H5 开发:在 [manifest.json](mdc:manifest.json) 配置代理 +2. 小程序:在小程序开发工具中关闭域名校验 +3. 生产环境:确保服务器配置了正确的 CORS 头 + +### 请求超时 +调整请求超时时间: +```javascript +// 在 request.js 中设置 +const service = uni.request({ + timeout: 10000 // 10秒超时 +}) +``` + +## 小程序特定问题 + +### 包体积超限 +解决方案: +1. 使用分包加载,配置在 [pages.json](mdc:pages.json) +2. 压缩图片资源 +3. 移除未使用的代码和依赖 +4. 使用 CDN 加载大型资源 + +### 真机调试问题 +1. 确保 [config.js](mdc:config.js) 中的 baseUrl 使用 HTTPS +2. 在小程序管理后台配置合法域名 +3. 检查 [manifest.json](mdc:manifest.json) 中的权限申请 + +### 小程序授权失败 +检查: +1. `manifest.json` 中的 `permission` 配置 +2. `requiredPrivateInfos` 是否声明了需要的接口 +3. 用户是否拒绝了授权 + +## 样式问题 + +### 样式不生效 +1. 检查是否使用了 `scoped` +2. uni-app 不支持的 CSS 选择器 +3. 使用 `/deep/` 或 `::v-deep` 穿透组件样式 + +### rpx 单位问题 +```scss +// 使用 uni.scss 中的变量 +@import '@/uni.scss'; + +.container { + padding: 20rpx; // 自动适配不同屏幕 +} +``` + +## 状态管理问题 + +### Vuex 数据不更新 +1. 确认使用了 `commit` 提交 mutation +2. 检查是否正确使用了命名空间 +3. 使用 `mapState`、`mapGetters` 辅助函数 + +### 页面刷新数据丢失 +解决方案: +1. 重要数据持久化到 storage +2. 在 `onShow` 生命周期重新获取数据 +3. 使用 Vuex 配合持久化插件 + +## 性能优化 + +### 页面加载慢 +1. 减少首屏加载的数据量 +2. 使用图片懒加载 +3. 分页加载列表数据 +4. 使用骨架屏提升体验 + +### 列表滚动卡顿 +```vue + + + +``` + +## 开发环境问题 + +### HBuilderX 相关 +1. 确保使用最新版本的 HBuilderX +2. 清理项目缓存:工具 -> 清理缓存 +3. 重启 HBuilderX 和开发者工具 + +### 依赖安装问题 +```powershell +# 清理缓存 +Remove-Item -Recurse -Force node_modules +Remove-Item package-lock.json + +# 重新安装 +npm install +``` + +## 调试技巧 + +### 查看网络请求 +1. 小程序:使用开发者工具的 Network 面板 +2. H5:使用浏览器开发者工具 +3. APP:使用 `console.log` 或远程调试 + +### 查看存储数据 +```javascript +// 获取所有存储的键 +const res = uni.getStorageInfoSync() +console.log('keys:', res.keys) + +// 查看特定数据 +const token = uni.getStorageSync('token') +console.log('token:', token) +``` + +### 页面栈信息 +```javascript +// 获取当前页面栈 +const pages = getCurrentPages() +console.log('页面栈:', pages) + +// 获取当前页面实例 +const currentPage = pages[pages.length - 1] +``` + +## 发布部署 + +### 小程序发布前检查 +1. 关闭调试模式 +2. 检查 API 地址是否正确 +3. 压缩代码和资源 +4. 测试各项权限申请 + +### 版本更新提示 +```javascript +// 在 App.vue 中添加 +onShow() { + // #ifdef MP-WEIXIN + const updateManager = uni.getUpdateManager() + updateManager.onUpdateReady(() => { + uni.showModal({ + title: '更新提示', + content: '新版本已经准备好,是否重启应用?', + success: (res) => { + if (res.confirm) { + updateManager.applyUpdate() + } + } + }) + }) + // #endif +}