hookehuyr

docs: 添加项目文档和本地设置文件

添加 CLAUDE.md 项目文档,包含项目概述、开发命令、目录结构、核心架构模式等重要信息
添加 .claude/settings.local.json 配置文件,设置权限控制
1 +{
2 + "permissions": {
3 + "allow": [
4 + "Bash(tree:*)"
5 + ]
6 + }
7 +}
1 +# CLAUDE.md
2 +
3 +此文件为 Claude Code (claude.ai/code) 在此代码库中工作时提供指导。
4 +
5 +## 项目概述
6 +
7 +**美乐爱觉 (mlaj)** - 基于 Vue 3 的教育平台,深度集成微信生态,服务于教师和学生。
8 +
9 +- **框架**: Vue 3 (Composition API + `<script setup>`)
10 +- **构建工具**: Vite 6.2.0
11 +- **包管理器**: pnpm (项目使用 `.nvm` 管理 Node.js 18.19.1)
12 +- **UI 框架**: Vant 4.9.22 (移动端优先)
13 +- **样式**: TailwindCSS + Less (分层)
14 +- **状态管理**: Context API (`/src/contexts/`) + localStorage
15 +- **路由**: Vue Router 4.5.0,支持懒加载和路由守卫
16 +- **HTTP**: Axios 1.8.4,集中式拦截器
17 +
18 +## 常用开发命令
19 +
20 +### 核心开发
21 +```bash
22 +pnpm dev # 启动开发服务器 (使用 Node.js 18.19.1)
23 +pnpm build # 生产环境构建
24 +pnpm preview # 本地预览生产构建
25 +pnpm test # 使用 Vitest 运行测试
26 +```
27 +
28 +### 部署
29 +```bash
30 +pnpm dev_upload # 部署到开发服务器
31 +pnpm behalo_upload # 部署到 behalo 环境
32 +pnpm oa_upload # 部署到 OA 服务器
33 +```
34 +
35 +### 开发流程
36 +- 每个部署命令都会:构建、归档(tar.gz)、通过 scp 上传、在服务器上解压、清理归档文件。
37 +
38 +## 目录结构
39 +
40 +```
41 +src/
42 +├── api/ # API 接口层 - 按领域模块化
43 +│ ├── auth.js # 认证相关接口
44 +│ ├── course.js # 课程相关接口
45 +│ ├── teacher.js # 教师端接口
46 +│ └── ...
47 +├── assets/ # 静态资源 (图片、CSS、模拟数据)
48 +├── components/ # 可复用的 Vue 组件
49 +│ ├── ui/ # 通用 UI 组件 (VideoPlayer, AudioPlayer, CheckInDialog 等)
50 +│ ├── checkin/ # 打卡相关组件
51 +│ ├── courses/ # 课程相关组件
52 +│ └── studyDetail/ # 学习详情页组件
53 +├── composables/ # Vue 组合式函数,用于逻辑复用 (useStudyComments, useStudyRecordTracker 等)
54 +├── contexts/ # 全局状态提供者 (auth, cart)
55 +├── common/ # 共享常量和工具
56 +├── router/ # Vue Router 配置
57 +│ ├── index.js # 路由实例与守卫
58 +│ ├── routes.js # 路由定义(懒加载)
59 +│ └── guards.js # 认证守卫辅助函数
60 +├── utils/ # 工具函数
61 +│ ├── axios.js # Axios 实例与拦截器 (认证头、401 处理)
62 +│ ├── tools.js # 通用工具 (wxInfo, 文件处理等)
63 +│ └── auth_user_info.js # 用户信息存储辅助函数
64 +└── views/ # 页面组件,按功能组织
65 + ├── auth/ # 登录/认证页面
66 + ├── courses/ # 课程浏览、详情、购买
67 + ├── profile/ # 用户资料、设置、课程历史
68 + ├── recall/ # 提醒/回忆系统
69 + ├── study/ # 学习资料和内容
70 + └── teacher/ # 教师端仪表板、任务、班级管理
71 +```
72 +
73 +## 路径别名
74 +
75 +`vite.config.js``jsconfig.json` 中配置:
76 +- `@/``src/`
77 +- `@components/``src/components/`
78 +- `@composables/``src/composables/`
79 +- `@utils/``src/utils/`
80 +- `@api/``src/api/`
81 +- `@images/``src/assets/images/`
82 +- `@css/``src/assets/css/`
83 +- `@mock/``src/assets/mock/`
84 +- `common/``src/common/`
85 +- `@root/` → 项目根目录
86 +
87 +## 核心架构模式
88 +
89 +### API 接口层架构
90 +
91 +**位置**: `/src/api/`
92 +
93 +所有接口遵循统一的响应结构:
94 +```javascript
95 +{
96 + code: 1, // 1 = 成功,其他 = 失败
97 + data: any, // 响应数据
98 + msg: string // 消息(成功时为空,失败时为错误信息)
99 +}
100 +```
101 +
102 +**重要**: 检查成功时使用 `if (res.code === 1)` 而不是 `if (res.code)`,避免将 401/403 误判为成功。
103 +
104 +**认证头** 通过 axios 拦截器自动添加 (`/src/utils/axios.js`):
105 +- 每次请求读取 `localStorage.user_info`
106 +- 设置 `User-Id``User-Token` 请求头
107 +- 401 响应处理:仅当当前路由需要认证时才重定向到登录页 (见 guards.js 中的 `checkAuth`)
108 +
109 +### 组件分层
110 +
111 +**视图页面** (`/src/views/`): 页面级组件,负责编排:
112 +- 通过 API 获取数据
113 +- 通过 refs/composables 管理状态
114 +- 路由和导航
115 +- 集成更小的组件
116 +
117 +**UI 组件** (`/src/components/ui/`): 可复用、无状态或自包含:
118 +- VideoPlayer, AudioPlayer, CheckInDialog, SharePoster, SearchBar 等
119 +- 应尽可能避免直接调用 API
120 +- 通过 emit 事件向父组件传递操作
121 +
122 +**组合式函数** (`/src/composables/`): 可复用逻辑:
123 +- `useStudyComments`: 评论获取、提交、分页
124 +- `useStudyRecordTracker`: 学习时长追踪和分析
125 +- `useCheckin`: 打卡流程和提交
126 +- 返回响应式 refs 和函数,内部处理副作用
127 +
128 +### 路由与认证
129 +
130 +**路由** 使用懒加载进行代码分割:
131 +```javascript
132 +{
133 + path: '/courses/:id',
134 + component: () => import('@/views/courses/CourseDetailPage.vue')
135 +}
136 +```
137 +
138 +**认证守卫** (`/src/router/guards.js`):
139 +- `checkAuth(route)` - 返回 `true` 或重定向对象
140 +- 不再自动触发微信认证;仅通过登录页手动触发
141 +- 路由可标记 `meta: { requireAuth: false }` 以公开访问
142 +
143 +### 样式策略
144 +
145 +**TailwindCSS** 是主要样式方案:
146 +- 用于布局、间距、排版、颜色
147 +- 自定义颜色定义在 `tailwind.config.js` 中 (primary: #4caf50)
148 +
149 +**Less** 用于组件特定样式:
150 +- 组件边界内的嵌套选择器
151 +- 使用 `<style lang="less" scoped>` 限制作用域到组件
152 +- 使用 `:deep()` 修改 Vant/VideoJS 内部样式
153 +
154 +**自动导入**:
155 +- Vant 组件自动导入(无需手动导入)
156 +- Vue 组合式函数自动导入 (ref, computed, onMounted 等)
157 +
158 +### 状态管理模式
159 +
160 +**用户认证状态**:
161 +- 运行时: `contexts/auth.js``currentUser` ref
162 +- 持久化: `localStorage.currentUser``localStorage.user_info`
163 +- Axios 请求头: 从 localStorage 派生(在拦截器中)
164 +- 辅助函数: `getUserInfoFromStorage()`, `removeUserInfoFromStorage()`
165 +
166 +**购物车/订单状态**:
167 +- 运行时: `contexts/cart.js`
168 +- 通过 provide/inject 在页面间保持
169 +
170 +### 微信集成
171 +
172 +**微信 JS SDK** 初始化在 `App.vue` 中:
173 +- 仅在浏览器环境中
174 +- 通过 `wxInfo()` 工具检测环境
175 +- `wxInfo().isWeiXin` - 在微信浏览器中运行
176 +- `wxInfo().isPc` - 在 PC 上运行
177 +
178 +**微信认证流程**:
179 +1. 用户在登录页点击微信图标
180 +2. 重定向到微信 OAuth
181 +3. 回调 → `getUserIsLoginAPI()` → 写入用户信息到存储
182 +4. 重定向到原页面或首页
183 +
184 +**微信支付**:
185 +- 集成在结账流程中
186 +- 生产环境: 需要微信浏览器环境 (`wxInfo().isWeiXin`)
187 +- 免费课程: 跳过环境验证
188 +
189 +### 文件预览系统
190 +
191 +**PDF 预览**:
192 +- 组件: `@sunsetglow/vue-pdf-viewer`
193 +- 专用路由: `/pdfPreview` 用于浏览器内预览
194 +
195 +**Office 文档** (Word, Excel, PPT):
196 +- `@vue-office/docx`, `@vue-office/excel`, `@vue-office/pptx`
197 +- 弹窗预览组件,带错误处理
198 +
199 +**图片**:
200 +- 使用 Vant 的 `van-image-preview`
201 +
202 +**视频播放器**:
203 +- 基于 `@videojs-player/vue` (Video.js 7.21.7 的封装)
204 +- 自定义 `VideoPlayer.vue` 组件添加错误处理、自动重试和播放速率控制
205 +
206 +## 重要注意事项
207 +
208 +### 视频播放器问题
209 +
210 +**VideoPlayer 使用 `v-show` vs `v-if`**:
211 +- Video.js 在 `v-show` (display: none) 下无法正常工作
212 +- 使用 `v-if` 确保视频元素在初始化前完全挂载
213 +- 参考 `StudyDetailPage.vue` 中的正确模式:设置 `isPlaying = true`,然后 `setTimeout` 再调用 `play()`
214 +
215 +### 401 响应处理
216 +
217 +`src/utils/axios.js` 中的 axios 响应拦截器:
218 +- 仅当 `checkAuth(to)` 返回重定向时才跳转到登录页
219 +- 公开页面(如课程详情)即使在 401 时也保持当前页
220 +- 页面组件应为自己的用户操作处理 401
221 +
222 +### API 响应安全性
223 +
224 +始终检查 `res.code === 1`(而不仅仅是 `res.code`):
225 +```javascript
226 +// 正确
227 +const { code, data } = await getCourseDetailAPI({ i: courseId })
228 +if (code === 1) { ... }
229 +
230 +// 错误 - 将 401/403 当作成功
231 +if (code) { ... }
232 +```
233 +
234 +### 组件自动导入
235 +
236 +Vant 组件通过 `unplugin-vue-components` 自动导入:
237 +- **不要导入** `import { Button } from 'vant'`
238 +- 直接使用 `<van-button>`
239 +- 参见 `src/components.d.ts` 查看所有可用组件
240 +
241 +### 打卡系统
242 +
243 +**统一组件**: `CheckInDialog.vue` 处理所有打卡流程:
244 +- 接收 `items_today``items_history` props
245 +- 每项包含 `id`, `name`, `task_type` ('checkin'/'upload'), `is_gray`
246 +- 完成时触发 `check-in-success` 事件
247 +
248 +**可复用列表组件**: `CheckInList.vue`
249 +- 用于首页和 CheckInDialog
250 +- 对话框使用紧凑模式,页面使用正常模式
251 +- `submit-success` 事件向上冒泡
252 +
253 +### 环境配置
254 +
255 +使用 `.env.development`, `.env.production` 等:
256 +- `VITE_PORT` - 开发服务器端口
257 +- `VITE_BASE` - 基础路径
258 +- `VITE_PROXY_PREFIX` - API 代理前缀
259 +- `VITE_PROXY_TARGET` - 后端 API 目标
260 +- `VITE_OUTDIR` - 构建输出目录
261 +
262 +### Speckit 框架命令
263 +
264 +位于 `.cursor/commands/`:
265 +- `/speckit.specify` - 从需求生成规范
266 +- `/speckit.plan` - 创建实现计划
267 +- `/speckit.tasks` - 生成任务分解
268 +- `/speckit.analyze` - 跨文件一致性分析
269 +- `/speckit.implement` - 执行实现计划
270 +- `/speckit.checklist` - 验证检查清单
271 +- `/speckit.clarify` - 需求澄清
272 +- `/speckit.constitution` - 项目原则和约束
273 +
274 +### 代码风格说明 (来自 VUE_CODE_STYLE_GUIDE.md)
275 +
276 +**当前实践**:
277 +- 新组件使用 `<script setup>` 和 Composition API
278 +- API 函数应始终返回 `{ code, data, msg }` - 永不返回 `false`
279 +- 尽可能将逻辑提取到 composables (`/src/composables/useXxx.js`)
280 +- 本地状态使用 refs,派生状态使用 computed
281 +- 除非必要避免 JSX;大多数页面使用 Vue 模板
282 +
283 +**已知不一致性** (需注意):
284 +- 文件中混合使用分号/无分号
285 +- 混合使用 2 空格/4 空格缩进
286 +- 混合使用 function/箭头函数
287 +- 混合使用中文/英文注释
288 +
289 +## 特殊功能
290 +
291 +### 分享海报生成
292 +- 基于 Canvas 的海报生成,带二维码 (`qrcode` 包)
293 +- 自动优化 `cdn.ipadbiz.cn` URL 的图片
294 +- 使用 `crossorigin="anonymous"` 处理跨域 Canvas 污染
295 +- 组件: `SharePoster.vue` (可复用)
296 +
297 +### 动态 Open Graph 元标签
298 +- 课程详情页动态添加 `og:title`, `og:description`, `og:image`, `og:url`
299 +- 页面卸载时移除标签以避免冲突
300 +
301 +### 标签指示器动画
302 +- 基于 ResizeObserver 的指示器定位
303 +- 处理异步加载第三列而不错位
304 +- 参考 `StudyCoursePage.vue` 的实现
305 +
306 +## 测试
307 +
308 +- **测试运行器**: Vitest
309 +- **命令**: `pnpm test`
310 +- 测试文件位于 `/test/` (当前可能测试覆盖较少)