# 宿舍水电费精准计费系统 - 技术文档 ## 一、系统概述 教培公司集训基地宿舍水电费精准计费系统,采用「人天数加权分摊」算法,按每位学生的实际入住天数公平分摊宿舍公共费用。 ### 核心功能 | 模块 | 功能说明 | |------|---------| | 数据面板 | 统计卡片、费用趋势图、宿舍排行、甘特图 | | 宿舍总览 | 房态可视化网格,空置/在住/满员颜色区分 | | 学生管理 | 增删改查 | | 宿舍管理 | 增删改查,删除前检查在住人员 | | 入住管理 | 入住登记、退宿、换房、删除已退宿记录 | | 费用录入 | 宿舍公共费用(水/电/保洁等)+ 个人附加费,支持编辑 | | 账单管理 | 自动生成、确认、标记已付、删除、批量操作 | | 账单导出 | Excel(汇总+明细双Sheet)、单条PDF账单 | | 操作日志 | 所有涉及钱的操作自动审计留痕 | | 账号管理 | 用户增删改查、角色区分、启用/禁用、重置密码(仅admin可见) | | 移动端适配 | 手机端Drawer导航、响应式表格和弹窗 | --- ## 二、技术架构 ``` 前端 (React + Vite) 后端 (NestJS) 数据库 ┌─────────────────┐ ┌──────────────────┐ ┌──────────┐ │ React 19 │ │ NestJS 11 │ │ SQLite │ │ Ant Design 6 │────▶│ TypeORM 0.3 │────▶│ (开发) │ │ ECharts │ │ JWT + Passport │ │ MySQL 8 │ │ Vite 8 │ │ ExcelJS + PDFKit │ │ (生产) │ └─────────────────┘ └──────────────────┘ └──────────┘ ``` ### 前端技术栈 - React 19 + TypeScript - Vite 8(构建打包) - Ant Design 6(UI 组件库) - ECharts(图表可视化) - react-router-dom v7(路由) - axios(HTTP 客户端) - dayjs(日期处理) - Apple 设计语言:主色 #007AFF,背景 #f5f5f7 ### 后端技术栈 - NestJS 11 + TypeScript - TypeORM 0.3(ORM 框架) - passport-jwt(JWT 认证) - bcryptjs(密码加密) - class-validator(参数校验) - ExcelJS(Excel 导出) - PDFKit(PDF 导出) - SQLite / MySQL(双数据库支持) --- ## 三、项目目录结构 ``` 宿舍水电费/ ├── 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 | 数据库类型 | sqlite | | 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 ```