# AGENTS.md - 医院绩效考核管理系统 This document provides essential context for AI coding agents working in this repository. ## Project Overview A hospital performance management system (绩效考核管理系统) for a county-level TCM hospital. Supports department management, staff management, assessment indicators, performance evaluation workflows, data analysis reports, and salary calculation. **Tech Stack:** - **Backend**: FastAPI + SQLAlchemy 2.0 (async) + PostgreSQL/Alembic + Pydantic v2 - **Frontend**: Vue 3 (Composition API) + Element Plus + Pinia + Vite + ECharts --- ## Build/Lint/Test Commands ### Backend (from `backend/` directory) ```bash # Install dependencies pip install -r requirements.txt # Configure environment cp .env.example .env # Edit .env with your database credentials # Run database migrations alembic upgrade head # Start development server uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 # Run tests (when available) pytest pytest tests/test_specific.py -v # Run specific test file pytest -k "test_name" -v # Run tests matching name ``` ### Frontend (from `frontend/` directory) ```bash # Install dependencies npm install # Start development server (http://localhost:5173) npm run dev # Build for production npm run build # Preview production build npm run preview ``` **Note**: No ESLint/Prettier configuration exists. Follow existing code patterns. --- ## Code Style Guidelines ### Backend (Python/FastAPI) #### Imports ```python # Standard library first from datetime import datetime from typing import Optional, List # Third-party next from fastapi import APIRouter, Depends, HTTPException, Query from sqlalchemy.ext.asyncio import AsyncSession from pydantic import BaseModel, Field, ConfigDict # Local imports last (absolute paths) from app.core.database import get_db from app.schemas.schemas import StaffCreate, StaffResponse from app.services.staff_service import StaffService ``` #### Naming Conventions - **Files**: `snake_case.py` (e.g., `staff_service.py`) - **Classes**: `PascalCase` (e.g., `StaffService`, `StaffCreate`) - **Functions/Methods**: `snake_case` (e.g., `get_staff_list`) - **Variables**: `snake_case` (e.g., `staff_list`, `department_id`) - **Constants**: `UPPER_SNAKE_CASE` (e.g., `DATABASE_URL`) - **Enums**: `PascalCase` for class, `UPPER_CASE` for values #### Pydantic Schemas (v2) ```python class StaffResponse(StaffBase): """员工响应""" model_config = ConfigDict(from_attributes=True) # Required for ORM mode id: int status: StaffStatus created_at: datetime ``` #### Async Patterns ```python # Always use async for database operations async def get_staff_list(db: AsyncSession) -> tuple[List[Staff], int]: result = await db.execute(query) return result.scalars().all() # Dependency injection for database sessions @router.get("/staff") async def get_staff(db: AsyncSession = Depends(get_db)): ... ``` #### Error Handling ```python # Use HTTPException for API errors if not staff: raise HTTPException(status_code=404, detail="员工不存在") # Check business constraints if existing: raise HTTPException(status_code=400, detail="工号已存在") ``` #### API Response Format ```python # Standard response structure return { "code": 200, "message": "success", "data": result, "total": total, # For paginated responses "page": page, "page_size": page_size } ``` ### Frontend (Vue 3/JavaScript) #### Imports ```javascript // Vue imports first import { ref, reactive, onMounted } from 'vue' // Third-party next import { ElMessage, ElMessageBox } from 'element-plus' // Local imports last (use @ alias) import { getStaffList, createStaff } from '@/api/staff' import { useUserStore } from '@/stores/user' ``` #### Vue Composition API ```vue ``` #### Naming Conventions - **Components**: `PascalCase.vue` (e.g., `Staff.vue`, `AssessmentDetail.vue`) - **Composables**: `useCamelCase.js` (e.g., `useUserStore`) - **API functions**: `camelCase` (e.g., `getStaffList`, `createStaff`) - **Template refs**: `camelCaseRef` (e.g., `formRef`, `tableRef`) #### Pinia Stores ```javascript // Use composition API style with defineStore export const useUserStore = defineStore('user', () => { const token = ref('') const userInfo = ref(null) async function login(username, password) { ... } function logout() { ... } return { token, userInfo, login, logout } }) ``` #### API Layer ```javascript // Simple wrapper functions around axios instance import request from './request' export function getStaffList(params) { return request.get('/staff', { params }) } export function createStaff(data) { return request.post('/staff', data) } ``` #### Error Handling ```javascript // Use Element Plus messages import { ElMessage, ElMessageBox } from 'element-plus' // User confirmation await ElMessageBox.confirm('确定要删除吗?', '提示', { type: 'warning' }) // Success/error feedback ElMessage.success('操作成功') ElMessage.error('操作失败') // Try-catch with finally for loading states try { await createStaff(form) ElMessage.success('创建成功') dialogVisible.value = false } catch (error) { console.error('创建失败', error) } finally { submitting.value = false } ``` #### Styling ```vue ``` --- ## Project Structure ``` backend/ ├── app/ │ ├── api/v1/ # API routes (auth, staff, departments, etc.) │ ├── core/ # Config, database, security │ ├── models/ # SQLAlchemy ORM models │ ├── schemas/ # Pydantic validation schemas │ ├── services/ # Business logic layer │ └── main.py # FastAPI app factory ├── alembic/ # Database migrations └── requirements.txt frontend/ ├── src/ │ ├── api/ # Axios API functions │ ├── assets/ # Static assets (SCSS, images) │ ├── components/ # Reusable components │ ├── router/ # Vue Router config │ ├── stores/ # Pinia stores │ └── views/ # Page components │ ├── basic/ # Staff, Departments, Indicators │ ├── assessment/ # Assessments │ ├── salary/ # Salary management │ └── reports/ # Statistics & reports └── package.json ``` --- ## Key Patterns ### Backend Service Layer Services encapsulate database operations. Controllers call services, not ORM directly. ```python # API route calls service @router.get("/staff") async def get_staff_list(db: AsyncSession = Depends(get_db)): staff_list, total = await StaffService.get_list(db, ...) return { "data": staff_list, "total": total } ``` ### Frontend API Layer Centralized axios instance with interceptors handles auth tokens and error display. ```javascript // request.js handles: // - Adding Bearer token from localStorage // - Error responses (401 → redirect to login) // - Showing ElMessage for errors ``` ### Database Sessions Uses async sessions with dependency injection. Commits happen automatically in `get_db()`. --- ## Default Credentials - **Username**: admin - **Password**: admin123 ## API Documentation When backend is running: - Swagger UI: http://localhost:8000/api/v1/docs - ReDoc: http://localhost:8000/api/v1/redoc