Files
hospital_performance/AGENTS.md
2026-02-28 15:02:08 +08:00

328 lines
8.0 KiB
Markdown

# 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
<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
```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
<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.
```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