Files
VolunteerManage-for-byw/.trae/documents/volunteer_system_plan.md
T
Trae Assistant 25b2b8f381 feat: 初始化义工时长管理系统
- 管理台:活动设置、时长登记、用户管理、数据导出(Excel/PNG)
- 用户端:姓名查询个人义工时长与活动记录
- 技术栈:React + Vite + TailwindCSS / Node.js + Express + sql.js (SQLite)
- 支持 Docker 部署,附带 Gitea Actions 自动部署工作流
- 响应式界面,兼容移动端与 PC 端
- 默认管理员账号:admin / admin123
2026-10-04 18:06:24 +08:00

203 lines
12 KiB
Markdown
Raw 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.
# 义工时长管理系统实施计划
## 仓库研究结论
- **Gitea 仓库**:`Henry_Du/VolunteerManage-for-byw`(空仓库,无任何提交)
- **本地工作目录**:`d:\义工时长系统`(空目录)
- **部署目标**:Docker 容器运行于服务器,域名 `volunteer.bzw-hheb.top`(反向代理)
- **CI/CD**:Gitea Actions 自动构建并部署
***
## 技术选型
| 层级 | 技术方案 | 选型理由 |
| ----- | ------------------------------------------ | ------------------------------ |
| 前端框架 | **React 18 + Vite 5 + TypeScript** | 开发效率高,响应式生态成熟 |
| UI 样式 | **TailwindCSS 3** | 快速构建硬边/极简响应式界面,契合用户 UI 偏好 |
| 组件库 | **shadcn/ui**(按需引入) | 轻量无样式组件,易定制硬边风格 |
| 后端框架 | **Node.js + Express + TypeScript** | 与前端同语言,部署简单 |
| 数据库 | **SQLite 3**(better-sqlite3) | 单文件数据库,无需额外容器;中小规模数据完全够用 |
| 认证 | **管理台:账号密码 + JWT**;**用户端:仅按姓名查询(无鉴权)** | 简单实用 |
| 导出 | **xlsx**(Excel 表格)、**html2canvas**(图片 PNG) | 表格+图片两种导出需求全覆盖 |
| 容器化 | **多阶段 Dockerfile**(构建前端 → 打包后端 + 静态资源) | 单容器部署,简单可靠 |
| CI/CD | **Gitea Actions** | 推送 main 分支自动构建镜像,通过 SSH 部署到服务器 |
***
## 文件与模块结构
```
VolunteerManage-for-byw/
├── client/ # 前端 React 项目
│ ├── src/
│ │ ├── components/ # 通用组件
│ │ ├── pages/
│ │ │ ├── admin/ # 管理台页面
│ │ │ │ ├── Login.tsx # 管理员登录
│ │ │ │ ├── Layout.tsx # 管理台布局 + 侧边栏
│ │ │ │ ├── Activities.tsx # ① 活动设置
│ │ │ │ ├── Hours.tsx # ② 义工时长登记 + 单次活动导出
│ │ │ │ ├── Users.tsx # ③ 用户管理(含个人详情)
│ │ │ │ └── Export.tsx # ④ 数据导出(多选导出项)
│ │ │ └── user/
│ │ │ ├── Index.tsx # 姓名输入页
│ │ │ └── Dashboard.tsx # 个人义工时长总览
│ │ ├── api/ # axios 封装与接口定义
│ │ ├── types/ # 共享类型
│ │ ├── App.tsx / main.tsx
│ │ └── index.css
│ ├── index.html
│ ├── vite.config.ts
│ ├── tailwind.config.ts
│ ├── tsconfig.json
│ └── package.json
├── server/ # 后端 Express 项目
│ ├── src/
│ │ ├── index.ts # 入口:挂载静态资源 + API 路由
│ │ ├── db/
│ │ │ ├── index.ts # SQLite 初始化 + 建表
│ │ │ └── schema.sql # 建表 SQL(users, groups, activities, hours)
│ │ ├── middleware/
│ │ │ └── auth.ts # JWT 鉴权中间件
│ │ ├── routes/
│ │ │ ├── auth.ts # POST /api/admin/login
│ │ │ ├── activities.ts # 活动 CRUD
│ │ │ ├── hours.ts # 时长登记 + 按活动查询
│ │ │ ├── users.ts # 部员 CRUD + 个人活动/累计时长
│ │ │ ├── groups.ts # 工作组 CRUD
│ │ │ └── export.ts # 各种导出接口(JSON 数据)
│ │ └── config.ts
│ ├── data/ # SQLite db 文件存放目录(Docker volume 挂载)
│ ├── tsconfig.json
│ └── package.json
├── .gitea/
│ └── workflows/
│ └── deploy.yml # Actions:构建镜像 → SSH 部署
├── Dockerfile # 多阶段构建
├── docker-compose.yml # 本地快速调试用
├── .dockerignore
├── .gitignore
├── .npmrc # 配置 npmmirror 镜像源
└── README.md
```
### 数据库表设计(SQLite)
| 表名 | 关键字段 | 说明 |
| ----------------- | --------------------------------------------------------------- | ------------------------------- |
| `work_groups` | id, name (唯一) | 工作组(如"策划部"、"宣传部") |
| `users` | id, class, name, volunteer\_no, group\_id (FK) | 部员信息;班级+姓名组合唯一 |
| `activities` | id, title, content, start\_time, end\_time, created\_at | 活动 |
| `activity_groups` | activity\_id, group\_id | 活动 ↔ 工作组 多对多关联 |
| `hours` | id, activity\_id, user\_id, hours(decimal), remark, created\_at | 义工时长登记(一人一次活动一条) |
| `admins` | id, username, password\_hash | 管理员账号(初始化一条默认:admin / admin123) |
***
## 实施步骤(按依赖顺序)
### 阶段 1:项目脚手架 & 基础配置
1. 创建根目录结构:`client/`、`server/`、`.gitea/workflows/`
2. 配置 `.npmrc` 使用 npmmirror 国内镜像
3. 初始化前端 Vite + React + TS + TailwindCSS + shadcn 基础依赖
4. 初始化后端 Express + TS + SQLite 基础依赖
5. 编写 `.gitignore`、`.dockerignore`
### 阶段 2:后端 API 实现
1. 编写 SQLite 初始化脚本(建表 + 插入默认管理员)
2. 实现认证路由:管理员登录(返回 JWT) + 鉴权中间件
3. 实现工作组 CRUD
4. 实现部员 CRUD(含所属工作组;查询个人参与活动及累计时长)
5. 实现活动 CRUD(含设置关联工作组)
6. 实现时长登记 CRUD(为某活动某部员设置时长+备注;按活动查询所有人的登记)
7. 实现导出路由:
- 所有成员 / 所有活动 / 所有时长明细(可多选)
- 按活动导出时长明细
- 所有部员累计总时长
- 所有部员参加的活动列表
### 阶段 3:前端页面实现
1. 前端基础:axios 封装、API 类型、路由(react-router-dom)
2. 用户端:
- 姓名输入首页(无鉴权,输入姓名查询匹配部员)
- 个人总览(总时长、参与活动列表)
3. 管理台:
- 登录页 + JWT 持久化(localStorage)+ 路由守卫
- 侧边栏布局(活动/时长/用户/导出四大模块)
- 活动设置页(列表、新建/编辑弹窗,设置工作组复选框)
- 时长登记页(选择活动 → 显示参与工作组所有成员 → 填写每人时长/备注 → 保存;提供导出为 Excel / 导出为图片按钮)
- 用户管理页(部员列表、新建/编辑弹窗、查看详情(累计时长+参与活动))
- 数据导出页(勾选要导出的内容:全部表格 / 总时长 / 活动记录 → 导出 Excel 或 图片)
### 阶段 4:容器化与部署
1. 编写 Dockerfile 多阶段构建:
- Stage 1:构建 client 生成静态资源
- Stage 2:构建 server TS → JS,复制 client/dist 作为静态资源
- Stage 3:node:20-alpine 运行,EXPOSE 3000,挂载 /app/server/data 卷
2. 编写 docker-compose.yml(本地调试)
3. 编写 Gitea Actions 工作流 `.gitea/workflows/deploy.yml`:
- 触发:push 到 main
- 步骤:checkout → 登录 Docker Registry(或直接本机构建后导出)→ 构建镜像 → 通过 SSH 连接服务器 → scp 复制 docker-compose(或 docker run)启动新容器 → 健康检查
### 阶段 5:本地验证 & 推送
1. 本地 `docker compose up` 验证系统各功能模块正常
2. 所有代码首次提交并推送到 Gitea main 分支,触发 Action 自动部署
3. 线上 `volunteer.bzw-hheb.top` 访问验证
***
## 依赖与注意事项
1. **npm 强制**:所有安装命令使用 `npm install`,不使用 pnpm。`.npmrc` 写入 `registry=https://registry.npmmirror.com`。
2. **管理员初始账号**:首次启动自动创建 `admin / admin123`,需在 README 提醒首次登录后修改(后端提供修改密码接口)。
3. **数据持久化**:SQLite 数据库文件位于容器内 `/app/server/data/volunteer.db`,部署时必须挂载为 Docker volume 或 bind mount,否则容器重建数据丢失。
4. **用户端查询**:按"姓名"匹配若有重名,展示列表让用户选择(班级+义工号辅助辨别)。
5. **图片导出**:前端将表格渲染成 HTML 后用 html2canvas 生成 PNG 下载;Excel 导出由前端拿到 JSON 数据后用 xlsx 生成。
6. **UI 风格**:TailwindCSS 默认禁用圆角(配置 `borderRadius: { DEFAULT: '0px' }` 或组件级手动零圆角),浅色/黑白专业风。
7. **响应式**:TailwindCSS 断点 `md:` 适配移动端(菜单变为汉堡按钮、表格水平滚动)。
8. **反向代理**:服务器上由 nginx/caddy 将 `volunteer.bzw-hheb.top` 反代到容器端口(Action 部署后由用户在服务器上已配置好反向代理)。
9. **Gitea Actions 机密(Secrets)**:用户需要在 Gitea 仓库设置中配置以下 Secrets:
- `SSH_HOST`:服务器 IP/域名
- `SSH_PORT`:SSH 端口(默认 22)
- `SSH_USER`:SSH 用户名
- `SSH_PRIVATE_KEY`:服务器 SSH 私钥
***
## 验证清单
- [ ] 管理台登录/退出
- [ ] 工作组增删改查
- [ ] 部员增删改查;查看个人累计时长与活动明细
- [ ] 活动发布(设置工作组);活动编辑/删除
- [ ] 活动时长登记(批量设置);修改/删除登记
- [ ] 单次活动导出:Excel 文件包含姓名、班级、义工号、工作组、时长、备注
- [ ] 单次活动导出:图片样式美观、中文不乱码
- [ ] 总数据导出:支持多选导出项;Excel 多 Sheet 或分文件
- [ ] 所有部员总时长导出(按时长降序)
- [ ] 所有部员参加的活动列表导出
- [ ] 用户端:输入姓名→选择部员→展示总时长与活动列表
- [ ] 移动端:关键页面无横滚(除表格内滚动),点击区域适合手指
- [ ] Docker 构建成功并运行;`/app/server/data` 持久化正常
- [ ] Gitea Actions push main 后自动部署成功
- [ ] <https://volunteer.bzw-hheb.top> 可访问各页面
***
## 风险与处理
| 风险 | 处理方案 |
| ------------------------------ | ----------------------------------------------------- |
| html2canvas 在中文/表格复杂时截图截断或样式偏差 | 对导出区域设置固定宽高、关闭动画、使用 `useCORS:true`;提供 Excel 导出作为可靠主力 |
| 重名部员导致用户端查询混乱 | 列出所有匹配项,展示班级+义工号让用户二次确认 |
| SQLite 并发写入性能 | 义工系统写入量低(仅管理员操作),无并发瓶颈;使用 WAL 模式(better-sqlite3 默认支持) |
| Action SSH 部署失败 | 先本地手动部署验证一次后再启用 Action;提供备用手动部署步骤(README) |
| 服务器反向代理未配置 WebSocket(如有需要) | 本系统无 WebSocket 实时推送,纯 HTTP 即可 |