mirror of
https://github.com/Cccc-owo/CheckInApp.git
synced 2026-06-17 05:56:29 +00:00
f8dcf6e3d3
BREAKING CHANGE: apps/backend/requirements.txt is no longer the backend dependency source. Use uv sync and uv run python main.py for backend setup and startup.
8.1 KiB
8.1 KiB
开发指南
开发环境设置
后端开发
# 克隆项目
git clone <repository>
cd CheckInApp
# 安装后端依赖
uv sync
uv run python main.py backend
前端开发
cd apps/frontend
# 安装依赖
npm install
# 启动开发服务器
npm run dev
# 代码格式化
npm run lint
npm run format
项目结构
后端目录说明
apps/backend/
├── main.py # FastAPI 应用入口,CORS、路由注册
├── config.py # Pydantic Settings 配置
├── dependencies.py # 依赖注入(认证、权限)
├── exceptions.py # 自定义异常类
│
├── models/ # SQLAlchemy 数据模型
│ ├── database.py # 数据库连接、Session
│ ├── user.py
│ ├── check_in_task.py
│ ├── check_in_record.py
│ └── task_template.py
│
├── schemas/ # Pydantic 请求响应模型
│ ├── user.py
│ ├── task.py
│ ├── auth.py
│ └── response.py # 标准化响应
│
├── api/ # API 路由(按模块划分)
│ ├── auth.py # 认证相关
│ ├── users.py # 用户管理
│ ├── tasks.py # 任务管理
│ ├── check_in.py # 打卡功能
│ ├── admin.py # 管理员功能
│ └── templates.py # 模板管理
│
├── services/ # 业务逻辑层
│ ├── auth_service.py
│ ├── user_service.py
│ ├── task_service.py
│ ├── check_in_service.py
│ ├── scheduler_service.py
│ ├── template_service.py
│ └── registration_manager.py
│
└── workers/ # Selenium 自动化
├── token_refresher.py # QQ 登录
├── check_in_worker.py # 打卡执行
└── email_notifier.py # 邮件发送
前端目录说明
apps/frontend/src/
├── main.js # Vue 应用入口
├── App.vue # 根组件
│
├── api/ # API 封装
│ ├── client.js # Axios 实例、拦截器
│ └── index.js # API 模块(auth, user, task 等)
│
├── views/ # 页面组件
│ ├── LoginView.vue
│ ├── DashboardView.vue
│ ├── TasksView.vue
│ ├── RecordsView.vue
│ └── admin/ # 管理员页面
│
├── components/ # 可复用组件
│ ├── TaskCard.vue
│ ├── RecordTable.vue
│ └── ...
│
├── stores/ # Pinia 状态管理
│ ├── auth.js # 认证状态
│ ├── user.js # 用户信息
│ └── task.js # 任务列表
│
├── router/ # Vue Router
│ └── index.js # 路由配置、导航守卫
│
└── composables/ # 组合式函数
├── useAuth.js
└── useTask.js
开发流程
添加新功能
1. 后端 API 开发
步骤:
- 在
models/定义数据模型 - 在
schemas/定义请求响应模型 - 在
services/实现业务逻辑 - 在
api/创建路由端点 - 在
main.py注册路由
示例: 添加一个新的"任务标签"功能
# models/task_tag.py
class TaskTag(Base):
__tablename__ = "task_tags"
id = Column(Integer, primary_key=True)
task_id = Column(Integer, ForeignKey("check_in_tasks.id"))
tag_name = Column(String(50))
# schemas/tag.py
class TaskTagCreate(BaseModel):
tag_name: str
# services/tag_service.py
def create_tag(db: Session, task_id: int, tag_data: TaskTagCreate):
tag = TaskTag(task_id=task_id, tag_name=tag_data.tag_name)
db.add(tag)
db.commit()
return tag
# api/tags.py
@router.post("/tasks/{task_id}/tags")
def add_tag(task_id: int, tag: TaskTagCreate, db: Session = Depends(get_db)):
return tag_service.create_tag(db, task_id, tag)
# apps/backend/main.py
from backend.api import tags
app.include_router(tags.router, prefix="/api")
2. 前端开发
步骤:
- 在
api/index.js添加 API 调用 - 在
stores/创建或更新状态 - 创建或更新 Vue 组件
- 配置路由(如需要)
示例: 添加标签管理页面
// api/index.js
export const tagApi = {
addTag: (taskId, data) => client.post(`/tasks/${taskId}/tags`, data),
getTags: (taskId) => client.get(`/tasks/${taskId}/tags`)
}
// stores/tag.js
export const useTagStore = defineStore('tag', {
state: () => ({
tags: []
}),
actions: {
async fetchTags(taskId) {
const { data } = await tagApi.getTags(taskId)
this.tags = data
}
}
})
// components/TagManager.vue
<template>
<div>
<a-tag v-for="tag in tags" :key="tag.id">{{ tag.tag_name }}</a-tag>
<a-button @click="addTag">添加标签</a-button>
</div>
</template>
数据库迁移
# 修改模型后生成迁移脚本
# 手动创建脚本在 apps/backend/scripts/migrate_*.py
# 执行迁移
uv run python apps/backend/scripts/migrate_xxx.py
测试
后端测试
# tests/test_task_service.py
import pytest
from backend.services import task_service
def test_create_task():
task = task_service.create_task(db, user_id=1, task_data)
assert task.name == "Test Task"
assert task.is_active == True
# 运行测试
uv run pytest tests/
前端测试
// tests/TaskCard.spec.js
import { mount } from '@vue/test-utils'
import TaskCard from '@/components/TaskCard.vue'
test('displays task name', () => {
const wrapper = mount(TaskCard, {
props: { task: { name: 'Test Task' } }
})
expect(wrapper.text()).toContain('Test Task')
})
// 运行测试
npm run test
代码规范
后端规范
- 使用 Black 格式化:
uv run black apps/backend/ - 遵循 PEP 8
- 函数添加类型注解
- API 路由使用 Pydantic 模型验证
- 使用 dependency injection
# 好的示例
async def create_task(
task_data: TaskCreate,
db: Session = Depends(get_db),
current_user: User = Depends(get_current_user)
) -> TaskResponse:
"""创建新任务"""
return task_service.create_task(db, current_user.id, task_data)
前端规范
- 使用 ESLint + Prettier
- 组件使用 Composition API
- 使用
<script setup>语法 - Props 添加类型验证
- 统一使用 Ant Design Vue 组件
<!-- 好的示例 -->
<script setup>
import { ref, computed } from 'vue'
const props = defineProps({
task: {
type: Object,
required: true
}
})
const isActive = computed(() => props.task.is_active)
</script>
调试技巧
后端调试
# 使用 logging
import logging
logger = logging.getLogger(__name__)
logger.info(f"Creating task for user {user_id}")
# 使用 pdb
import pdb; pdb.set_trace()
# 查看 SQL 查询
import logging
logging.basicConfig()
logging.getLogger('sqlalchemy.engine').setLevel(logging.INFO)
前端调试
// 使用 Vue Devtools
// Chrome 扩展安装
// console 输出
console.log('Task data:', task.value)
// 调试 API 请求
axios.interceptors.request.use(request => {
console.log('Request:', request)
return request
})
常见问题
CORS 错误
在 .env 添加前端地址:
CORS_ORIGINS=http://localhost:3000
数据库锁定
使用 connection pool:
engine = create_engine(
DATABASE_URL,
pool_pre_ping=True,
pool_size=10
)
Selenium 超时
增加等待时间:
WebDriverWait(driver, 30).until(...)
Git 工作流
# 创建功能分支
git checkout -b feature/task-tags
# 提交代码
git add .
git commit -m "feat: add task tag functionality"
# 合并到主分支
git checkout main
git merge feature/task-tags
# 推送
git push origin main
性能优化
后端优化
- 使用 SQLAlchemy 的
joinedload避免 N+1 查询 - 添加数据库索引
- 使用异步任务处理耗时操作
- 启用 gzip 压缩
前端优化
- 使用虚拟滚动处理大列表
- 路由懒加载
- 图片懒加载
- 使用
keep-alive缓存组件