# QWEN.md - 医院绩效考核管理系统 Context for AI coding agents working in this repository. --- ## Project Overview A **Hospital Performance Management System** (医院绩效考核管理系统) designed for a county-level TCM (Traditional Chinese Medicine) hospital. The system provides comprehensive performance assessment management including: - **Department Management** - Hierarchical department structure - **Staff Management** - Employee information and tracking - **Assessment Indicators** - KPI definition and management - **Performance Evaluation** - Assessment workflow with review process - **Data Analytics** - Reports, statistics, and trend analysis - **Salary Calculation** - Performance-based payroll processing ### Tech Stack | Layer | Technology | |-------|------------| | **Backend** | FastAPI 0.115+ · SQLAlchemy 2.0 (async) · PostgreSQL · Alembic · Pydantic v2 | | **Frontend** | Vue 3 (Composition API) · Element Plus · Pinia · Vite · ECharts | | **Auth** | JWT (python-jose) · bcrypt password hashing | | **Database** | **PostgreSQL 14+** (asyncpg driver) | --- ## Quick Start ### Prerequisites - Python 3.10+ - Node.js 18+ - PostgreSQL 14+ ### Backend Setup ```bash cd backend # Create virtual environment python -m venv venv venv\Scripts\activate # Windows # Install dependencies pip install -r requirements.txt # Configure environment copy .env.example .env # Edit .env with your database credentials # Create database createdb hospital_performance # Run migrations alembic upgrade head # Initialize default data (optional) python init_db.py # Start server uvicorn app.main:app --reload --host 0.0.0.0 --port 8000 ``` ### Frontend Setup ```bash cd frontend # Install dependencies npm install # Start dev server (http://localhost:5173) npm run dev # Build for production npm run build ``` ### Access the Application - **Frontend**: http://localhost:5173 - **API Docs**: http://localhost:8000/api/v1/docs - **Health Check**: http://localhost:8000/health ### Default Credentials - **Username**: `admin` - **Password**: `admin123` --- ## Project Structure ``` hospital-performance/ ├── backend/ # Backend service │ ├── app/ │ │ ├── api/v1/ # API routes │ │ │ ├── auth.py # Authentication │ │ │ ├── departments.py # Department CRUD │ │ │ ├── staff.py # Staff CRUD │ │ │ ├── indicators.py # Indicator CRUD │ │ │ ├── assessments.py # Assessment workflow │ │ │ ├── salary.py # Salary calculation │ │ │ ├── stats.py # Statistics & reports │ │ │ └── finance.py # Finance management │ │ ├── core/ # Core modules │ │ │ ├── config.py # Settings management │ │ │ ├── database.py # DB connection & session │ │ │ ├── security.py # JWT & password hashing │ │ │ └── init_db.py # DB initialization │ │ ├── models/ │ │ │ └── models.py # SQLAlchemy ORM models │ │ ├── schemas/ │ │ │ └── schemas.py # Pydantic v2 schemas │ │ ├── services/ # Business logic layer │ │ │ ├── staff_service.py │ │ │ ├── department_service.py │ │ │ ├── indicator_service.py │ │ │ ├── assessment_service.py │ │ │ ├── salary_service.py │ │ │ └── stats_service.py │ │ ├── utils/ # Utility functions │ │ └── main.py # FastAPI app factory │ ├── alembic/ # Database migrations │ ├── tests/ # Test files (empty) │ ├── requirements.txt │ └── .env.example │ ├── frontend/ # Frontend application │ ├── src/ │ │ ├── api/ # API client (Axios) │ │ │ ├── request.js # Axios instance + interceptors │ │ │ ├── auth.js │ │ │ ├── staff.js │ │ │ ├── department.js │ │ │ ├── indicator.js │ │ │ ├── assessment.js │ │ │ ├── salary.js │ │ │ └── stats.js │ │ ├── stores/ # Pinia stores │ │ │ ├── user.js # User state & auth │ │ │ └── app.js # App-wide state │ │ ├── router/ │ │ │ └── index.js # Vue Router config │ │ ├── views/ # Page components │ │ │ ├── Login.vue │ │ │ ├── Layout.vue # Main layout with sidebar │ │ │ ├── Dashboard.vue │ │ │ ├── basic/ # Basic data management │ │ │ │ ├── Departments.vue │ │ │ │ ├── Staff.vue │ │ │ │ └── Indicators.vue │ │ │ ├── assessment/ # Assessment management │ │ │ │ ├── Assessments.vue │ │ │ │ └── AssessmentDetail.vue │ │ │ ├── salary/ # Salary management │ │ │ │ └── Salary.vue │ │ │ ├── reports/ # Reports & analytics │ │ │ │ └── Reports.vue │ │ │ └── finance/ # Finance management │ │ │ └── Finance.vue │ │ ├── components/ # Reusable components │ │ ├── assets/ # Static assets (SCSS) │ │ ├── App.vue │ │ └── main.js │ ├── dist/ # Production build │ ├── package.json │ └── vite.config.js │ ├── docs/ # Documentation │ ├── index.md │ ├── architecture.md │ ├── database.md │ ├── api.md │ ├── backend.md │ └── frontend.md │ ├── AGENTS.md # AI agent guidelines └── README.md ``` --- ## Database Schema **Database**: PostgreSQL 14+ ### Core Tables | Table | Description | |-------|-------------| | `departments` | Department hierarchy (tree structure with parent_id) | | `staff` | Employee information | | `indicators` | Assessment indicators/KPIs | | `assessments` | Assessment records (header) | | `assessment_details` | Assessment line items (scores per indicator) | | `salary_records` | Monthly salary calculations | | `users` | System users for authentication | ### Key Enums ```python # Department types DeptType: CLINICAL, MEDICAL_TECH, MEDICAL_AUXILIARY, ADMIN, LOGISTICS # Staff status StaffStatus: ACTIVE, LEAVE, RESIGNED, RETIRED # Assessment workflow status AssessmentStatus: DRAFT → SUBMITTED → REVIEWED → FINALIZED (or REJECTED) # Indicator types IndicatorType: QUALITY, QUANTITY, EFFICIENCY, SERVICE, COST ``` ### Assessment Workflow ``` ┌─────────┐ ┌───────────┐ ┌──────────┐ ┌────────────┐ │ DRAFT │ → │ SUBMITTED │ → │ REVIEWED │ → │ FINALIZED │ │ 草稿 │ │ 已提交 │ │ 已审核 │ │ 已确认 │ └─────────┘ └───────────┘ └──────────┘ └────────────┘ ↓ ┌──────────┐ │ REJECTED │ │ 已驳回 │ └──────────┘ ``` --- ## Development Conventions ### Backend (Python/FastAPI) #### Import Order ```python # 1. Standard library from datetime import datetime from typing import Optional, List # 2. Third-party from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.ext.asyncio import AsyncSession # 3. Local imports (absolute paths) from app.core.database import get_db from app.schemas.schemas import StaffCreate 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/Variables**: `snake_case` (e.g., `get_staff_list`) - **Constants**: `UPPER_SNAKE_CASE` #### Pydantic v2 Pattern ```python class StaffResponse(StaffBase): """员工响应""" model_config = ConfigDict(from_attributes=True) # Required for ORM mode id: int status: StaffStatus created_at: datetime ``` #### Async Database Pattern ```python async def get_staff_list(db: AsyncSession, page: int = 1, page_size: int = 20): offset = (page - 1) * page_size result = await db.execute(select(Staff).offset(offset).limit(page_size)) staff_list = result.scalars().all() count_result = await db.execute(select(func.count()).select_from(Staff)) total = count_result.scalar() return staff_list, total ``` #### API Response Format ```python # Standard response return { "code": 200, "message": "success", "data": result, "total": total, # For paginated responses "page": page, "page_size": page_size } # Error response raise HTTPException(status_code=404, detail="员工不存在") ``` #### Service Layer Pattern ```python # API route delegates to service @router.get("/staff") async def get_staff_list( db: AsyncSession = Depends(get_db), page: int = 1, page_size: int = 20 ): staff_list, total = await StaffService.get_list(db, page, page_size) return {"data": staff_list, "total": total, "page": page, "page_size": page_size} ``` ### Frontend (Vue 3/JavaScript) #### Import Order ```javascript // 1. Vue import { ref, reactive, onMounted } from 'vue' // 2. Third-party import { ElMessage, ElMessageBox } from 'element-plus' // 3. Local (use @ alias) import { getStaffList, createStaff } from '@/api/staff' import { useUserStore } from '@/stores/user' ``` #### Component Pattern (` ``` #### Pinia Store Pattern ```javascript // stores/user.js import { defineStore } from 'pinia' export const useUserStore = defineStore('user', () => { const token = ref('') const userInfo = ref(null) async function login(username, password) { const res = await loginApi({ username, password }) token.value = res.access_token localStorage.setItem('token', res.access_token) } function logout() { token.value = '' userInfo.value = null localStorage.removeItem('token') } return { token, userInfo, login, logout } }) ``` #### API Layer Pattern ```javascript // api/staff.js 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 // User confirmation await ElMessageBox.confirm('确定要删除吗?', '提示', { type: 'warning' }) // Feedback ElMessage.success('操作成功') ElMessage.error('操作失败') // Loading state pattern try { await createStaff(form) ElMessage.success('创建成功') } finally { submitting.value = false } ``` --- ## Key API Endpoints | Method | Endpoint | Description | |--------|----------|-------------| | POST | `/auth/login` | User login | | GET | `/auth/me` | Get current user | | GET | `/departments` | List departments | | POST | `/departments` | Create department | | GET | `/staff` | List staff (paginated) | | POST | `/staff` | Create staff | | GET | `/indicators` | List indicators | | POST | `/assessments` | Create assessment | | POST | `/assessments/batch` | Batch create assessments | | POST | `/assessments/{id}/submit` | Submit assessment | | POST | `/assessments/{id}/review` | Review assessment | | POST | `/salary/generate` | Generate salary records | | GET | `/stats/department` | Department statistics | | GET | `/stats/trend` | Trend analysis | --- ## Common Tasks ### Add a New API Endpoint **Backend:** 1. Add route in `backend/app/api/v1/.py` 2. Add service method in `backend/app/services/_service.py` 3. Add Pydantic schemas in `backend/app/schemas/schemas.py` 4. Create Alembic migration if DB changes needed **Frontend:** 1. Add API function in `frontend/src/api/.js` 2. Create/update view component in `frontend/src/views/` 3. Add route in `frontend/src/router/index.js` ### Database Migration ```bash cd backend # Generate new migration alembic revision --autogenerate -m "Description of changes" # Apply migrations alembic upgrade head # Rollback one migration alembic downgrade -1 ``` ### Run Tests (when available) ```bash cd backend pytest pytest tests/test_specific.py -v pytest -k "test_name" -v ``` --- ## Architecture Notes ### Layered Architecture ``` ┌─────────────────────────────────────────┐ │ Frontend (Vue 3) │ │ Views → Components → Stores → API │ └───────────────────┬─────────────────────┘ │ HTTP/JSON ▼ ┌─────────────────────────────────────────┐ │ Backend (FastAPI) │ │ ┌─────────────────────────────────┐ │ │ │ API Layer (routes) │ │ │ └──────────────┬──────────────────┘ │ │ ▼ │ │ ┌─────────────────────────────────┐ │ │ │ Service Layer (business logic) │ │ │ └──────────────┬──────────────────┘ │ │ ▼ │ │ ┌─────────────────────────────────┐ │ │ │ ORM Layer (SQLAlchemy) │ │ │ └──────────────┬──────────────────┘ │ └───────────────────┼─────────────────────┘ ▼ ┌─────────────────────────────────────────┐ │ Database (PostgreSQL) │ └─────────────────────────────────────────┘ ``` ### Authentication Flow 1. Client sends credentials to `/auth/login` 2. Server validates and returns JWT token 3. Client stores token in `localStorage` 4. Client includes `Authorization: Bearer {token}` in subsequent requests 5. Server validates token via `get_current_user` dependency 6. 401 responses trigger redirect to login page ### Salary Calculation Logic ``` Assessment (FINALIZED status) ↓ Read performance score ↓ Apply performance ratio (from staff.perf_ratio) ↓ Calculate: performance_bonus = base_salary × (score/100) × perf_ratio ↓ Generate SalaryRecord with total_salary = base + bonus - deduction + allowance ``` --- ## Troubleshooting ### Backend Issues **Database connection error:** - Ensure PostgreSQL is running - Check `DATABASE_URL` in `.env` - Verify database exists: `createdb hospital_performance` - Check PostgreSQL credentials (username, password, port) **Migration issues:** ```bash # Check migration status alembic current # Show pending migrations alembic history # Clear and re-migrate (dev only) alembic downgrade base alembic upgrade head ``` ### Frontend Issues **API requests failing:** - Ensure backend is running on port 8000 - Check proxy config in `vite.config.js` - Verify token in localStorage is valid **Build errors:** ```bash # Clean and reinstall rm -rf node_modules package-lock.json npm install ``` --- ## Related Documentation - [Architecture](docs/architecture.md) - System architecture overview - [Database](docs/database.md) - ER diagrams and table structures - [API](docs/api.md) - Detailed API documentation - [Backend](docs/backend.md) - Backend development guide - [Frontend](docs/frontend.md) - Frontend development guide