This is an old revision of the document!
Table of Contents
家庭管理系统 H5 · 冷启动文件
版本 1.0 | 更新 2026-09-16 | 访问 `https://rd.huiflytech.com/family/`
与研发任务/库房/测试/评审会同一服务(`rd-h5.service`,Flask :13544)
4.x 果果工资模块(2026-09-17 新增,仅管理员)
需求:记录请假(类型/天数)与加班(带睡/日班),自动计算工资(参考用户提供的 Excel 工资表)。
① 数据表 `salary_month`(family.db)
| 字段 | 说明 |
| — | — |
| month | 月份(2026-08) |
| base / days_per_month / day_rate | 月工资 / 计薪天数(默认 26)/ 日工资(0=自动=base÷dpm) |
| sleep_rate | 带睡单价(默认 100 元/晚) |
| leave_items | 请假明细 JSON `[{type,days,note}]`(病假/事假/调休/其他) |
| ot_items | 加班明细 JSON `[{type,days,note}]`(带睡/日班/其他) |
| leave_days / leave_deduct | 请假合计天数 / 扣费 |
| ot_days_sleep / ot_pay_sleep | 加班天数(带睡) / 加班费(带睡) |
| ot_days_day / ot_pay_day | 加班天数(日班) / 加班费(日班) |
| total / actual / paid / note | 月总薪水(自动)/ 实际薪水(可手填覆盖)/ 是否发放 / 备注 |
② 计算规则(后端 `_calc_salary_month()` 权威计算 + 前端实时预览)
日工资 = 月工资 ÷ 计薪天数 (5000 ÷ 26 = 192.31) 请假扣费 = 请假天数 × 日工资 (2 天 × 192.31 = 384.62) 加班费(带睡) = 带睡晚数 × 带睡单价 (3 晚 × 100 = 300) 加班费(日班) = 日班天数 × 日工资 (1 天 × 192.31 = 192.31) 月总薪水 = 月工资 + 加班费 − 请假扣费 实际薪水 = 手填(留空则取月总薪水)★ 最终发放金额以手填为准
③ 接口(`family_api.py`) - `GET /api/family/salary_month` → 月度列表(按月份倒序) - `POST /api/family/salary_month` → 新增/更新(带 id 即更新);仅管理员(`_is_admin_user()`) - `DELETE /api/family/salary_month` → 删除 - ⚠️ 权限守卫是全局 `@bp.before_request def _guard()`(登录校验);新增管理员判定函数命名为 `_is_admin_user`(★ 不能叫 `_guard`,会覆盖全局守卫)
④ 前端(`family.html`) - 新 tab「💰 果果工资」→ 仅管理员(加入 `ALL_TABS`,不入 `USER_TABS`) - 列表:月份 | 月工资 | 请假(天) | 扣费 | 加班费 | 实发 | 操作(编辑/删)+ 备注行 - 表单:月份 / 月工资 / 计薪天数(自动显示日工资)/ 带睡单价 + 请假明细(可增删行) + 加班明细(可增删行,单位自动切换 晚/天) + 实际薪水(留空=自动)+ 备注 + 实时计算预览框 - ★ 关键实现细节:`salPaint()` 只更新“日工资/单位/计算框”,绝不重建输入行(否则用户输入到一半的值会被清空 —— 曾出现此 bug,拆出 `salRows()` 专责渲染明细行);增删行前用 `salSync()` 记住当前表单其它字段
⑤ 验证 - 与用户图片逐项核对:日工资 192.31 ✅|3月 请假2天 → 扣 384.62 ✅|带睡 2 晚 = 200 ✅|4月 日班 1 天 = 192.31 ✅ - 前端实测:日工资自动显示 ✅|请假 2 天 → 扣 384.62 ✅|带睡 3 晚 = 300 ✅|月总薪水 = 5000+300−384.62 = 4915.38 ✅|输入过程中值不丢失 ✅ - 非管理员访问 → 403 / 不可见 tab ✅
1. 系统概览
| 项 | 值 |
| — | — |
| 后端 | `/home/ubuntu/.hermes/scripts/family_api.py`(Blueprint `bp`,前缀 `/api/family`) |
| 前端 | `/home/ubuntu/.hermes/scripts/family.html`(页面 `/family/`) |
| 数据 | `/home/ubuntu/docs/family/family.db`(附件目录 `attachments/`) |
| 管理员白名单 | `ADMIN_PHONES = {“18932573927”}`(武燕青) |
| 现有用户 | 18932573927 武燕青(admin) | 16603395188 倾心(user) | 13780562913 果果(user) |
| 启动 | `sudo systemctl restart rd-h5.service`(改代码后必须重启) |
2. 模块与权限
全部 tab:🏠家务 | ⭐积分 | 💬语录 | 🎂生日 | 🍳菜谱 | 💰缴费 | ⚠️预警 | 📋信息 | 📜日志 | 👤我的
普通用户可见(`USER_TABS`):仅 `house / points / warn / me`
权限网关 `_guard()`(`@bp.before_request`): - 未登录 → 401 - `role == 'admin'` → 全部放行 - 普通用户 → 仅白名单路径(tasks GET/PATCH、tasks/refresh、points、warns、me、log、user/*),其余 403 - ★ 新增的管理员模块路径不在白名单 → 天然仅管理员可用
3. 信息模块(2026-09-16 新增,仅管理员)
用途:家庭档案 / 学籍等敏感信息集中存储与展示。
表结构
CREATE TABLE IF NOT EXISTS info( key TEXT PRIMARY KEY, val TEXT DEFAULT '', updated TEXT DEFAULT '');
(`val` 存 JSON 字符串)
API
| 方法 | 路径 | 说明 |
| — | — | — |
| GET | `/api/family/info` | 返回 `{ok, data:{key: {…}}}`;未登录 401 / 普通用户 403 |
| POST | `/api/family/info` | body `{data:{key:{…}}}`,`INSERT OR REPLACE` 保存 |
身份传递:`cur_user()` 从 `phone` 参数读取(query / JSON body / form)——测试时可直接 `?phone=18932573927`
前端:`ALL_TABS` 含 `['info','📋 信息']`,不入 `USER_TABS` → 普通用户看不到入口;`renderInfo()` 渲染卡片(主体信息 `INFO_FIELDS` + `__lists` 描述的成员列表)
数据结构(学籍示例)
{
"xueji_xizien": {
"__title": "席子恩 学籍信息",
"姓名": "…", "性别": "…", "身份证件号": "…", "出生日期": "…",
"__lists": [{"key": "监护人", "title": "监护人信息", "fields": ["姓名","关系","是否监护人","民族","身份证件类型","身份证件号","工作单位","户口所在地行政编码","户口所在地具体地址","联系电话"]}],
"监护人": [{"姓名": "…", "关系": "母亲", "联系电话": "…"}, {"姓名": "…", "关系": "父亲", "联系电话": "…"}]
}
}
已录入:
| key | 内容 | 说明 |
| — | — | — |
| `xueji_xizien` | 席子恩学籍(学生 19 字段 + 2 位监护人各 10 字段) | 卡片折叠显示(点标题展开) |
| `id_cards` | 身份证记录(7 条:姓名 + 身份证号) | 卡片折叠显示;支持新增/删除(表格下方「+ 新增」输入姓名+号码) |
前端渲染规则(`renderInfo()`) - 每个 key 渲染为 `<details class=“card”>`(默认收起,summary 前缀 ▸/▾ 随展开状态切换) - `type === 'idlist'` → 渲染为「姓名 | 身份证号 | ✕删除」表格 + 新增输入行(`addIdRec` / `delIdRec`) - 其他 → 按 `INFO_FIELDS` 渲染主体字段,按 `lists` 渲染成员列表(如监护人) - 保存:读取当前节点 → 修改 → 整节点 `POST`(`saveInfoKey`)
⚠️ 文档中不记录具体证件号码(数据仅存本地 `docs/family/family.db`,站点 HTTPS,接口仅管理员)
4. 学籍字段清单
学生(19 项):姓名 | 曾用名 | 性别 | 国籍/地区 | 港澳台侨外 | 民族 | 身份证件类型 | 身份证件号 | 出生日期 | 政治面貌 | 现居住地行政编码 | 现居住地址详细地址 | 户口所在地行政编码 | 户口所在地具体地址 | 是否寄宿生 | 是否残疾人 | 是否农村留守儿童 | 残疾类型 | 特教学生就读类型
监护人(10 项/人):姓名 | 关系 | 是否监护人 | 民族 | 身份证件类型 | 身份证件号 | 工作单位 | 户口所在地行政编码 | 户口所在地具体地址 | 联系电话
5. 排障速查
| 现象 | 原因 | 处理 |
| — | — | — |
| API 返回 401 | 未登录(请求未带 `phone`) | 带 `?phone=<手机号>` |
| API 返回 403 | 普通用户访问管理员模块 | 正常(预期行为) |
| `info` tab 不显示 | 当前用户非管理员 | 正常 |
| `/family/` 打开后显示原始 JSON | ★ 插入代码时把 `@bp.route(“/family/”)` 装饰器与 `def family_page()` 分开 → 装饰器错位挂到了新函数上 | 确保装饰器紧贴其函数(新增函数时要插在注释块之后,别插在装饰器与函数之间) |
| 服务起不来(activating/失败) | 路由用了 `@app.route` | 必须用 `@bp.route`(family_api 用 Blueprint) |
| 页面改动不生效 | 服务未重启 | `sudo systemctl restart rd-h5.service` |
6. 安全注意
- 信息模块含身份证号、住址、电话等敏感信息 → 仅管理员可见(前后端双重限制:前端 tab 不显示 + 后端 `_guard` 403) - 文档中不记录具体证件号码;数据仅存本地 SQLite(`docs/family/family.db`,权限 600) - 站点为 HTTPS(`rd.huiflytech.com`)
