8.0 KiB
8.0 KiB
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)
# 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)
# 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
# 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:
PascalCasefor class,UPPER_CASEfor values
Pydantic Schemas (v2)
class StaffResponse(StaffBase):
"""员工响应"""
model_config = ConfigDict(from_attributes=True) # Required for ORM mode
id: int
status: StaffStatus
created_at: datetime
Async Patterns
# 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
# 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
# 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
// 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
<script setup>
// Use <script setup> syntax (always)
import { ref, reactive, onMounted } from 'vue'
// Reactive state
const loading = ref(false)
const tableData = ref([])
const form = reactive({
name: '',
status: 'active'
})
// Lifecycle
onMounted(() => {
loadData()
})
// Functions (regular, not async in template)
async function loadData() {
loading.value = true
try {
const res = await getStaffList({ ...searchForm })
tableData.value = res.data || []
} finally {
loading.value = false
}
}
</script>
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
// 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
// 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
// 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
<style scoped lang="scss">
// Use scoped styles with SCSS
.search-bar {
display: flex;
gap: 12px;
margin-bottom: 20px;
.el-input {
width: 160px;
}
}
</style>
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.
# 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.
// 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