README.md
Rama main · réplica de lectura del repositorio original.
# 🏠 装修账本
装修预算清单与记账工具。数据全部保存在本机,无账号、无广告;日常使用完全离线(仅首次安装依赖需联网)。
## 功能一览
- **预算清单(核心)**:板块(硬装施工/全屋电器/全屋智能/家具软装/其他杂费…)→ 项目两级结构,
每项有规格品牌、单位、数量、单价,预算总价自动计算;板块小计、全案总计、与「预算目标」的
超支/结余一目了然
- **整行编辑**:点击清单行打开编辑弹窗,一次修改名称/规格/数量/单价/备注
- **实际花费两种记法**:小件买完勾「已买」登记实际支付金额(预算单价保持不变,支持抹零/打包价);
定金/尾款等多次付款的大件用「订单」挂到项目下
- **从 Excel 导入**:上传你的评估表(.xlsx),自动识别板块/项目/预算目标,「已买」列自动还原勾选
(实际按实付计,未填实付回退 数量×单价)
- **Excel 导出**:预算评估表(含公式,可继续在 Excel 里用)+ 付款明细 + 板块汇总
- **板块单独导出**:每个板块可单独导出 Excel(可选含价格列)或打印另存 PDF,微信发给装修公司/工长直接看
- **统计图表**:板块预算 vs 实际、月度趋势与花费日历(含已买支出)、最近付款流水
- **票据照片**:每笔付款可附发票/收据照片;退货退款记负数自动冲抵
- **居家暖木主题**:亚麻/暖木/陶土/鼠尾草配色,深浅双模式(设置页可切换或跟随系统)
- **拖拽排序**:按住 ⠿ 手柄拖动板块或清单行直接排序
- **行内编辑即存**:点击清单行打开编辑弹窗保存;金额数字滚动动画
- **误删可撤销**:板块/项目/订单删除均为软删除,toast 里 8 秒内一键恢复;
恢复会重复计入实际时(如订单删除期间项目已勾「已买」)会先弹确认
- **移动端适配**:手机同 WiFi 访问自动切换「记录优先」移动布局(首页 / 清单 / 记 / 订单四个标签)
## 日常使用
**双击项目目录下的 `start.bat`**,浏览器自动打开 `http://localhost:5174`。
- 使用期间不要关闭弹出的命令行窗口;用完关窗即可,数据实时保存
- 提示端口被占用 = 账本已在运行,直接访问 `http://localhost:5174`
**手机安装到桌面(PWA)**:手机浏览器通过 **HTTPS 域名**访问账本后——
Android Chrome 菜单选「安装应用」,iOS Safari 分享菜单选「添加到主屏幕」,
桌面即出现「装修账本」图标,点开全屏运行(无地址栏)。注意:浏览器仅允许在
HTTPS 页面安装,局域网 `http://192.168.x.x` 地址访问时不能安装(正常浏览不受影响)。
## 使用流程建议
1. **建清单**:「预算清单」页添加板块和项目(或导入 Excel),填数量、单价
2. **定目标**:点顶部主卡「改目标」填总预算上限(如 160000),随时看超支/结余
3. **买东西**(按付款方式三选一):
- 一次付清的小件 → 「+订单」勾选「一次付清」,票据直接拖进去,一个表单搞定
- 不想留票据的小件 → 直接勾「已买」登记实际支付金额(预算单价保持不变)
- 定金/尾款的大件 → 关闭「一次付清」建订单,每次付款记一笔、拍照上传
4. **每周巡检**:看顶部主卡和板块小计,红色超支提醒一眼可见
## Docker 部署
前提:已安装 Docker 与 Docker Compose。
```bash
# 1. 构建并启动(单容器:应用 + 内置每日备份 cron)
docker compose up -d --build
# 2. 访问
# http://<NAS或服务器IP>:5174
# 3. 查看状态与日志
docker compose ps
docker compose logs -f app
```
- **数据持久化**:SQLite、票据、日志全部落在宿主 `./data/`(bind mount),升级镜像/重建容器数据不丢
- **自动备份**:主容器内置 cron 每天 03:00 把 `data/` 打包到 `./backups/renovation-expenses-时间戳.tar.gz`(renovation-expenses.db 先经 SQLite 在线备份做一致性快照,运行中备份也安全),保留最近 30 份;失败会写入 `backups/backup.log`。手动触发:`docker exec renovation-expenses /app/backup.sh`
- **恢复备份**:停容器 → 清空 `data/` → 解包备份覆盖(`tar xzf backups/renovation-expenses-xxxx.tar.gz -C data`)→ 重启
- **端口/主机名**:复制 `.env.example` 为 `.env` 可改宿主端口、追加放行的主机名(`EXTRA_ALLOWED_HOSTS`,通过 NAS 主机名或域名访问时需要)
- **权限**:Linux 上若容器写数据报 EACCES,执行 `sudo chown -R 1000:1000 ./data`
## 数据在哪里?如何备份?
```
data/
├── renovation-expenses.db # 全部数据(清单/订单/付款/票据记录)
├── uploads/ # 全部票据照片
└── logs/ # 运行日志(按天轮转,保留 14 天)
```
**备份(应用内一键)**:设置页「立即备份」下载数据库快照 + 票据的 zip;「恢复备份」上传
该 zip 即可全量覆盖(恢复前请确认已有备份,恢复不可撤销)。
**备份(裸机方式)**:关闭账本后复制整个 `data/` 文件夹;恢复时覆盖回来。
**备份(Docker 方式)**:主容器内置 cron 每天 03:00 自动打包到 `backups/`(数据库为一致性快照,失败见 `backups/backup.log`),恢复方法见 Docker 部署章节。
**轻量备份**:清单页「导出 Excel」(不含照片与付款记录)。
## 开发相关
```bash
npm run dev # 开发模式(前端 5173 + 后端 5174 热重载)
npm run build # 构建前端到 dist/
npm start # 单进程启动(托管前端+API,端口 5174)
node server/tests/api.test.mjs # 后端场景测试(自隔离运行:临时库+独立端口,无需先启动服务)
```
技术栈:Fastify + better-sqlite3 + ExcelJS(后端)· React + Vite + TypeScript + Ant Design + ECharts(前端)。
## 许可证
[MIT](LICENSE)