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

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: PascalCase for class, UPPER_CASE for 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: