CLAUDE.md
此文件为 Claude Code (claude.ai/code) 在此代码库中工作时提供指导。
项目概述
美乐爱觉 (mlaj) - 基于 Vue 3 的教育平台,深度集成微信生态,服务于教师和学生。
-
框架: Vue 3 (Composition API +
<script setup>) - 构建工具: Vite 6.2.0
-
包管理器: pnpm (项目使用
.nvm管理 Node.js 18.19.1) - UI 框架: Vant 4.9.22 (移动端优先)
- 样式: TailwindCSS + Less (分层)
-
状态管理: Context API (
/src/contexts/) + localStorage - 路由: Vue Router 4.5.0,支持懒加载和路由守卫
- HTTP: Axios 1.8.4,集中式拦截器
常用开发命令
核心开发
pnpm dev # 启动开发服务器 (使用 Node.js 18.19.1)
pnpm build # 生产环境构建
pnpm preview # 本地预览生产构建
pnpm test # 使用 Vitest 运行测试
部署
pnpm dev_upload # 部署到开发服务器
pnpm behalo_upload # 部署到 behalo 环境
pnpm oa_upload # 部署到 OA 服务器
开发流程
- 每个部署命令都会:构建、归档(tar.gz)、通过 scp 上传、在服务器上解压、清理归档文件。
目录结构
src/
├── api/ # API 接口层 - 按领域模块化
│ ├── auth.js # 认证相关接口
│ ├── course.js # 课程相关接口
│ ├── teacher.js # 教师端接口
│ └── ...
├── assets/ # 静态资源 (图片、CSS、模拟数据)
├── components/ # 可复用的 Vue 组件
│ ├── ui/ # 通用 UI 组件 (VideoPlayer, AudioPlayer, CheckInDialog 等)
│ ├── checkin/ # 打卡相关组件
│ ├── courses/ # 课程相关组件
│ └── studyDetail/ # 学习详情页组件
├── composables/ # Vue 组合式函数,用于逻辑复用 (useStudyComments, useStudyRecordTracker 等)
├── contexts/ # 全局状态提供者 (auth, cart)
├── common/ # 共享常量和工具
├── router/ # Vue Router 配置
│ ├── index.js # 路由实例与守卫
│ ├── routes.js # 路由定义(懒加载)
│ └── guards.js # 认证守卫辅助函数
├── utils/ # 工具函数
│ ├── axios.js # Axios 实例与拦截器 (认证头、401 处理)
│ ├── tools.js # 通用工具 (wxInfo, 文件处理等)
│ └── auth_user_info.js # 用户信息存储辅助函数
└── views/ # 页面组件,按功能组织
├── auth/ # 登录/认证页面
├── courses/ # 课程浏览、详情、购买
├── profile/ # 用户资料、设置、课程历史
├── recall/ # 提醒/回忆系统
├── study/ # 学习资料和内容
└── teacher/ # 教师端仪表板、任务、班级管理
路径别名
在 vite.config.js 和 jsconfig.json 中配置:
-
@/→src/ -
@components/→src/components/ -
@composables/→src/composables/ -
@utils/→src/utils/ -
@api/→src/api/ -
@images/→src/assets/images/ -
@css/→src/assets/css/ -
@mock/→src/assets/mock/ -
common/→src/common/ -
@root/→ 项目根目录
核心架构模式
API 接口层架构
位置: /src/api/
所有接口遵循统一的响应结构:
{
code: 1, // 1 = 成功,其他 = 失败
data: any, // 响应数据
msg: string // 消息(成功时为空,失败时为错误信息)
}
重要: 检查成功时使用 if (res.code === 1) 而不是 if (res.code),避免将 401/403 误判为成功。
认证头 通过 axios 拦截器自动添加 (/src/utils/axios.js):
- 每次请求读取
localStorage.user_info - 设置
User-Id和User-Token请求头 - 401 响应处理:仅当当前路由需要认证时才重定向到登录页 (见 guards.js 中的
checkAuth)
组件分层
视图页面 (/src/views/): 页面级组件,负责编排:
- 通过 API 获取数据
- 通过 refs/composables 管理状态
- 路由和导航
- 集成更小的组件
UI 组件 (/src/components/ui/): 可复用、无状态或自包含:
- VideoPlayer, AudioPlayer, CheckInDialog, SharePoster, SearchBar 等
- 应尽可能避免直接调用 API
- 通过 emit 事件向父组件传递操作
组合式函数 (/src/composables/): 可复用逻辑:
-
useStudyComments: 评论获取、提交、分页 -
useStudyRecordTracker: 学习时长追踪和分析 -
useCheckin: 打卡流程和提交 - 返回响应式 refs 和函数,内部处理副作用
路由与认证
路由 使用懒加载进行代码分割:
{
path: '/courses/:id',
component: () => import('@/views/courses/CourseDetailPage.vue')
}
认证守卫 (/src/router/guards.js):
-
checkAuth(route)- 返回true或重定向对象 - 不再自动触发微信认证;仅通过登录页手动触发
- 路由可标记
meta: { requireAuth: false }以公开访问
样式策略
TailwindCSS 是主要样式方案:
- 用于布局、间距、排版、颜色
- 自定义颜色定义在
tailwind.config.js中 (primary: #4caf50)
Less 用于组件特定样式:
- 组件边界内的嵌套选择器
- 使用
<style lang="less" scoped>限制作用域到组件 - 使用
:deep()修改 Vant/VideoJS 内部样式
自动导入:
- Vant 组件自动导入(无需手动导入)
- Vue 组合式函数自动导入 (ref, computed, onMounted 等)
状态管理模式
用户认证状态:
- 运行时:
contexts/auth.js→currentUserref - 持久化:
localStorage.currentUser和localStorage.user_info - Axios 请求头: 从 localStorage 派生(在拦截器中)
- 辅助函数:
getUserInfoFromStorage(),removeUserInfoFromStorage()
购物车/订单状态:
- 运行时:
contexts/cart.js - 通过 provide/inject 在页面间保持
微信集成
微信 JS SDK 初始化在 App.vue 中:
- 仅在浏览器环境中
- 通过
wxInfo()工具检测环境 -
wxInfo().isWeiXin- 在微信浏览器中运行 -
wxInfo().isPc- 在 PC 上运行
微信认证流程:
- 用户在登录页点击微信图标
- 重定向到微信 OAuth
- 回调 →
getUserIsLoginAPI()→ 写入用户信息到存储 - 重定向到原页面或首页
微信支付:
- 集成在结账流程中
- 生产环境: 需要微信浏览器环境 (
wxInfo().isWeiXin) - 免费课程: 跳过环境验证
文件预览系统
PDF 预览:
- 组件:
@sunsetglow/vue-pdf-viewer - 专用路由:
/pdfPreview用于浏览器内预览
Office 文档 (Word, Excel, PPT):
-
@vue-office/docx,@vue-office/excel,@vue-office/pptx - 弹窗预览组件,带错误处理
图片:
- 使用 Vant 的
van-image-preview
视频播放器:
- 基于
@videojs-player/vue(Video.js 7.21.7 的封装) - 自定义
VideoPlayer.vue组件添加错误处理、自动重试和播放速率控制
重要注意事项
视频播放器问题
VideoPlayer 使用 v-show vs v-if:
- Video.js 在
v-show(display: none) 下无法正常工作 - 使用
v-if确保视频元素在初始化前完全挂载 - 参考
StudyDetailPage.vue中的正确模式:设置isPlaying = true,然后setTimeout再调用play()
401 响应处理
src/utils/axios.js 中的 axios 响应拦截器:
- 仅当
checkAuth(to)返回重定向时才跳转到登录页 - 公开页面(如课程详情)即使在 401 时也保持当前页
- 页面组件应为自己的用户操作处理 401
API 响应安全性
始终检查 res.code === 1(而不仅仅是 res.code):
// 正确
const { code, data } = await getCourseDetailAPI({ i: courseId })
if (code === 1) { ... }
// 错误 - 将 401/403 当作成功
if (code) { ... }
组件自动导入
Vant 组件通过 unplugin-vue-components 自动导入:
-
不要导入
import { Button } from 'vant' - 直接使用
<van-button> - 参见
src/components.d.ts查看所有可用组件
打卡系统
统一组件: CheckInDialog.vue 处理所有打卡流程:
- 接收
items_today和items_historyprops - 每项包含
id,name,task_type('checkin'/'upload'),is_gray - 完成时触发
check-in-success事件
可复用列表组件: CheckInList.vue
- 用于首页和 CheckInDialog
- 对话框使用紧凑模式,页面使用正常模式
-
submit-success事件向上冒泡
环境配置
使用 .env.development, .env.production 等:
-
VITE_PORT- 开发服务器端口 -
VITE_BASE- 基础路径 -
VITE_PROXY_PREFIX- API 代理前缀 -
VITE_PROXY_TARGET- 后端 API 目标 -
VITE_OUTDIR- 构建输出目录
Speckit 框架命令
位于 .cursor/commands/:
-
/speckit.specify- 从需求生成规范 -
/speckit.plan- 创建实现计划 -
/speckit.tasks- 生成任务分解 -
/speckit.analyze- 跨文件一致性分析 -
/speckit.implement- 执行实现计划 -
/speckit.checklist- 验证检查清单 -
/speckit.clarify- 需求澄清 -
/speckit.constitution- 项目原则和约束
代码风格说明 (来自 VUE_CODE_STYLE_GUIDE.md)
当前实践:
- 新组件使用
<script setup>和 Composition API - API 函数应始终返回
{ code, data, msg }- 永不返回false - 尽可能将逻辑提取到 composables (
/src/composables/useXxx.js) - 本地状态使用 refs,派生状态使用 computed
- 除非必要避免 JSX;大多数页面使用 Vue 模板
已知不一致性 (需注意):
- 文件中混合使用分号/无分号
- 混合使用 2 空格/4 空格缩进
- 混合使用 function/箭头函数
- 混合使用中文/英文注释
特殊功能
分享海报生成
- 基于 Canvas 的海报生成,带二维码 (
qrcode包) - 自动优化
cdn.ipadbiz.cnURL 的图片 - 使用
crossorigin="anonymous"处理跨域 Canvas 污染 - 组件:
SharePoster.vue(可复用)
动态 Open Graph 元标签
- 课程详情页动态添加
og:title,og:description,og:image,og:url - 页面卸载时移除标签以避免冲突
标签指示器动画
- 基于 ResizeObserver 的指示器定位
- 处理异步加载第三列而不错位
- 参考
StudyCoursePage.vue的实现
测试
- 测试运行器: Vitest
-
命令:
pnpm test - 测试文件位于
/test/(当前可能测试覆盖较少)