51b27bdfd4dfd5d72f82fe54b14d0afac206d8f0
Deploy to Server / deploy (push) Successful in 1m41s
- schema.sql + db/index.ts 迁移:hours 表移除 UNIQUE(activity_id,user_id)
约束,改由 id 自增主键唯一定位;启动时检测到旧结构会自动
RENAME+重建表+INSERT 搬迁历史数据;外部 FK pragma 仍生效
- hours.ts batch 接口:为兼容去掉 UNIQUE 后的行为等价,改成
『先 DELETE 旧行 + 再 INSERT 新行』,同人同活动仍为一行覆盖语义
- 新增 POST /hours/direct-add:
· items = [{user_id, hours, reason}],每条记录前置校验(uid 存在、
hours>0、reason 非空),错误以分号拼接返回
· 首次调用自动创建活动「【补录】直接加义工时长」(start/end
2024-01-01 ~ 2099-12-31)作为虚拟承载活动,后续复用
· 全事务 INSERT,每次加时独立写入多行(不合并)
· 响应:{ ok, added, total_hours, results:[{class,name,...}], direct_add_activity_id }
- api/index.ts hoursApi.directAdd:新增带完整返回类型签名的 TS 封装
- Users.tsx 双入口:
· 工具栏:选中部员后与『批量删除』并列,出现『批量加义工时(N)』
主按钮 → 打开共用 Modal 一次加多人
· 部员详情弹窗:「累计时长」卡片独立加『加义工时』小按钮,
点后复用同一表单只为当前人录 1 条
- 共用 Direct Add Modal:
· 顶部说明卡(每条原因独立保存;挂在【补录】活动;勾选人名 chip 列表)
· 时长输入:number,min=0.1 step=0.1,前端校验 >0
· 原因输入:textarea 必填,标红字星号,字数计数,提交前 trim 非空校验
· 提交 loading 锁按钮;成功 toast 显示前 5 人名字 + 总人数 + 总小时;
然后 load() 刷新列表累计时长列,若详情弹窗开着自动重新拉详情
义工时长管理系统
功能概述
- 管理台:活动设置、义工时长登记、用户管理、数据导出(表格/图片)
- 用户端:输入姓名查询个人参与活动及累计义工时长
- 响应式:同时适配移动设备与 PC 端
技术栈
- 前端:React 18 + Vite 5 + TypeScript + TailwindCSS 3
- 后端:Node.js + Express + TypeScript
- 数据库:SQLite 3 (better-sqlite3)
- 部署:Docker + Gitea Actions 自动部署
- 域名:https://volunteer.bzw-hheb.top
初始管理员账号
- 用户名:
admin - 密码:
admin123
首次登录后请立即修改密码。
本地开发
# 安装后端依赖
cd server && npm install
# 安装前端依赖
cd ../client && npm install
# 启动后端(端口 3001)
cd server && npm run dev
# 启动前端(端口 5173,代理 /api 到 3001)
cd client && npm run dev
Docker 本地运行
docker compose up -d --build
部署配置(Gitea Secrets)
在仓库 Settings -> Secrets 中配置:
| 名称 | 说明 |
|---|---|
SSH_HOST |
服务器 IP/域名 |
SSH_PORT |
SSH 端口(默认 22) |
SSH_USER |
SSH 用户名 |
SSH_PRIVATE_KEY |
SSH 私钥(对应服务器上的公钥需加入 authorized_keys) |
数据持久化
SQLite 数据库文件位于容器 /app/server/data/volunteer.db,docker-compose.yml 中已配置为 bind mount 到 ./server/data。
Languages
TypeScript
98.8%
CSS
0.6%
Dockerfile
0.4%
HTML
0.2%