Files
gongxue-base/技术文档.md

288 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 宿舍水电费精准计费系统 - 技术文档
## 一、系统概述
教培公司集训基地宿舍水电费精准计费系统,采用「人天数加权分摊」算法,按每位学生的实际入住天数公平分摊宿舍公共费用。
### 核心功能
| 模块 | 功能说明 |
|------|---------|
| 数据面板 | 统计卡片、费用趋势图、宿舍排行、甘特图 |
| 宿舍总览 | 房态可视化网格,空置/在住/满员颜色区分 |
| 学生管理 | 增删改查 |
| 宿舍管理 | 增删改查,删除前检查在住人员 |
| 入住管理 | 入住登记、退宿、换房、删除已退宿记录 |
| 费用录入 | 宿舍公共费用(水/电/保洁等)+ 个人附加费,支持编辑 |
| 账单管理 | 自动生成、确认、标记已付、删除、批量操作 |
| 账单导出 | Excel汇总+明细双Sheet、单条PDF账单 |
| 操作日志 | 所有涉及钱的操作自动审计留痕 |
| 账号管理 | 用户增删改查、角色区分、启用/禁用、重置密码仅admin可见 |
| 移动端适配 | 手机端Drawer导航、响应式表格和弹窗 |
---
## 二、技术架构
```
前端 (React + Vite) 后端 (NestJS) 数据库
┌─────────────────┐ ┌──────────────────┐ ┌──────────┐
│ React 19 │ │ NestJS 11 │ │ MySQL 8 │
│ Ant Design 6 │────▶│ TypeORM 0.3 │────▶│ │
│ ECharts │ │ JWT + Passport │ │ │
│ Vite 8 │ │ ExcelJS + PDFKit │ │ │
└─────────────────┘ └──────────────────┘ └──────────┘
```
### 前端技术栈
- React 19 + TypeScript
- Vite 8构建打包
- Ant Design 6UI 组件库)
- ECharts图表可视化
- react-router v8路由
- axiosHTTP 客户端)
- dayjs日期处理
- Apple 设计语言:主色 #007AFF,背景 #f5f5f7
### 后端技术栈
- NestJS 11 + TypeScript
- TypeORM 0.3ORM 框架)
- passport-jwtJWT 认证)
- bcryptjs密码加密
- class-validator参数校验
- ExcelJSExcel 导出)
- PDFKitPDF 导出)
- MySQL 8唯一支持的数据库
---
## 三、项目目录结构
```
宿舍水电费/
├── backend/ # 后端NestJS
│ ├── src/
│ │ ├── entities/ # 数据库实体
│ │ │ ├── student.entity.ts
│ │ │ ├── room.entity.ts
│ │ │ ├── occupancy.entity.ts
│ │ │ ├── room-expense.entity.ts
│ │ │ ├── personal-expense.entity.ts
│ │ │ ├── bill.entity.ts
│ │ │ ├── bill-item.entity.ts
│ │ │ ├── user.entity.ts
│ │ │ ├── operation-log.entity.ts
│ │ │ └── index.ts
│ │ ├── auth/ # 认证 & 账号管理
│ │ │ ├── auth.module.ts
│ │ │ ├── auth.service.ts
│ │ │ ├── auth.controller.ts
│ │ │ ├── dto/auth.dto.ts
│ │ │ ├── guards/jwt-auth.guard.ts
│ │ │ └── strategies/jwt.strategy.ts
│ │ ├── students/ # 学生模块
│ │ ├── rooms/ # 宿舍模块
│ │ ├── occupancies/ # 入住模块
│ │ ├── expenses/ # 费用模块
│ │ ├── bills/ # 账单模块
│ │ │ ├── bills.module.ts
│ │ │ ├── bills.service.ts # 核心计费引擎
│ │ │ ├── bills-export.service.ts # Excel/PDF导出
│ │ │ ├── bills.controller.ts
│ │ │ └── dto/bill.dto.ts
│ │ ├── dashboard/ # 数据面板
│ │ ├── operation-logs/ # 操作日志(@Global
│ │ ├── app.module.ts # 根模块
│ │ └── main.ts # 入口
│ ├── .env.example # 环境变量模板
│ ├── package.json
│ └── tsconfig.json
├── frontend/ # 前端React + Vite
│ ├── src/
│ │ ├── api/index.ts # axios 实例自动携带JWT
│ │ ├── layouts/MainLayout.tsx # 主布局(桌面侧边栏/移动端Drawer
│ │ ├── pages/
│ │ │ ├── Login/ # 登录页
│ │ │ ├── Dashboard/ # 数据面板
│ │ │ ├── RoomVisual/ # 宿舍可视化
│ │ │ ├── Students/ # 学生管理
│ │ │ ├── Rooms/ # 宿舍管理
│ │ │ ├── Occupancies/ # 入住管理
│ │ │ ├── Expenses/ # 费用录入
│ │ │ ├── Bills/ # 账单管理(含导出)
│ │ │ ├── OperationLogs/ # 操作日志
│ │ │ └── Users/ # 账号管理
│ │ ├── App.tsx # 路由配置
│ │ ├── index.css # 全局样式 + 移动端媒体查询
│ │ └── main.tsx
│ ├── package.json
│ └── vite.config.ts
└── .gitignore
```
---
## 四、核心算法 —— 人天数加权分摊
```
学生应付 = (该学生计费天数 / 宿舍所有学生计费天数之和) × 宿舍该项总费用
```
**计费天数计算规则:**
- 起始日 = max(学生计费起始日, 账单周期开始日)
- 结束日 = min(学生退宿日 或 周期结束日, 账单周期结束日)
- 天数 = ceil(结束日 - 起始日) + 1不足一天按一天算
**设计亮点:**
- `billing_start_date``check_in_date` 分离,允许灵活调整计费起始日
- 个人附加费独立处理,不参与分摊
- 一次生成所有学生账单,包含分摊明细
---
## 五、数据库表结构
| 表名 | 说明 | 关键字段 |
|------|------|---------|
| students | 学生 | id, name, phone, id_card, status |
| rooms | 宿舍 | id, building, room_number, capacity |
| occupancies | 入住记录 | student_id, room_id, check_in_date, billing_start_date, check_out_date |
| room_expenses | 宿舍费用 | room_id, expense_type, amount, period_start, period_end |
| personal_expenses | 个人费用 | student_id, room_id, expense_type, amount, expense_date |
| bills | 账单 | student_id, period_start, period_end, shared_amount, personal_amount, total_amount, status |
| bill_items | 账单明细 | bill_id, expense_type, days, total_room_days, room_total_amount, student_amount |
| users | 系统用户 | username, password_hash, role(admin/operator), is_active, last_login_at |
| operation_logs | 操作日志 | user_id, username, module, action, target_id, detail, created_at |
---
## 六、API 接口列表
### 认证
| 方法 | 路径 | 说明 |
|------|------|------|
| POST | /api/auth/login | 登录 |
| POST | /api/auth/register | 创建账号需JWT |
| GET | /api/auth/profile | 当前用户信息 |
| GET | /api/auth/users | 用户列表 |
| PUT | /api/auth/users/:id | 编辑用户 |
| PUT | /api/auth/users/:id/password | 重置密码 |
| PUT | /api/rbac/users/:id/archive | 归档用户 |
| PUT | /api/rbac/users/:id/restore | 恢复用户 |
### 业务模块
| 方法 | 路径 | 说明 |
|------|------|------|
| CRUD | /api/students | 学生管理 |
| CRUD | /api/rooms | 宿舍管理 |
| GET | /api/rooms/visual | 宿舍可视化数据 |
| POST | /api/occupancies/check-in | 入住登记 |
| PUT | /api/occupancies/:id/check-out | 退宿 |
| PUT | /api/occupancies/:id/transfer | 换房 |
| CRUD | /api/expenses/room | 宿舍费用 |
| CRUD | /api/expenses/personal | 个人费用 |
| POST | /api/bills/generate | 生成账单 |
| GET | /api/bills | 账单列表 |
| GET | /api/bills/export/excel | 导出Excel |
| GET | /api/bills/export/pdf/:id | 导出单条PDF |
| PUT | /api/bills/:id/status | 更新状态 |
| GET | /api/operation-logs | 操作日志 |
| GET | /api/dashboard/stats | 统计数据 |
---
## 七、环境变量配置
参见 `backend/.env.example`
| 变量 | 说明 | 默认值 |
|------|------|--------|
| DB_TYPE | 数据库类型(仅支持 MySQL | mysql |
| DB_HOST | MySQL 主机 | localhost |
| DB_PORT | MySQL 端口 | 3306 |
| DB_USERNAME | 数据库用户 | root |
| DB_PASSWORD | 数据库密码 | (空) |
| DB_DATABASE | 数据库名 | dorm_billing |
| JWT_SECRET | JWT 签名密钥 | dorm-billing-jwt-secret-key-2024 |
| JWT_EXPIRES_IN | JWT 过期时间 | 24h |
| ADMIN_PASSWORD | 初始管理员密码 | admin123 |
---
## 八、生产部署(宝塔面板)
### 前置条件
- 宝塔面板已安装 Node.js v18+、MySQL 8.0
- 已创建数据库 `dorm_billing`
### 部署步骤
```bash
# 1. 上传代码到服务器
# 2. 配置后端环境变量
cd /www/wwwroot/dorm-billing/backend
cp .env.example .env
vi .env # 填入真实的数据库密码、JWT密钥、管理员密码
# 3. 安装依赖 & 构建
cd backend && npm install && npm run build
cd ../frontend && npm install && npm run build
# 4. PM2 启动后端
cd ../backend
pm2 start dist/main.js --name dorm-billing
pm2 save && pm2 startup
```
### Nginx 配置
```nginx
server {
listen 80;
server_name your-domain.com;
root /www/wwwroot/dorm-billing/frontend/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://127.0.0.1:3000/api/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
}
```
### 首次登录
-`admin` + `.env` 中设置的 `ADMIN_PASSWORD` 登录
- 进入「账号管理」为老师创建操作员账号
---
## 九、角色权限
| 角色 | 权限 |
|------|------|
| admin管理员 | 所有功能 + 账号管理 |
| operator操作员 | 除账号管理外的所有功能 |
---
## 十、常见运维操作
```bash
# 查看后端日志
pm2 logs dorm-billing
# 重启后端
pm2 restart dorm-billing
# 更新代码后重新部署
cd backend && npm install && npm run build && pm2 restart dorm-billing
cd ../frontend && npm install && npm run build
```