Files
laoyang c8515632fb 节点与活动支持导出 ICS 日历(批 27)
- 新增 src/Ics.php:RFC 5545 生成器(CRLF、75 octet 折行且不切断
  UTF-8 字符、TEXT 转义、时间输出 UTC Z、UID 固定为 triplog-node-{id}
  使重复导入按 UID 更新而不堆重复事件)。
- 新增路由 nodes/ics、activities/ics:节点级导出单个事件
  (SUMMARY=活动名·节点标题、DTSTART/DTEND、LOCATION=出发地、
  DESCRIPTION=车次/航班号+备注);活动级导出整个行程(跳过已取消
  节点与已生成执行记录的计划节点,口径与详情页展示一致)。
- 入口:活动详情页「导出日历」、节点详情页「导出日历」、
  节点卡片「日历」链接。
- 修复隐性事故:index.php 漏 require src/Ics.php(无 autoloader 的
  项目里新增类必须同步入口),部署哨兵新增「src/ 每个类文件都被
  index.php require」逐文件对账。
- 验证:php -l 61 文件全过;渲染检查 386 项全过;Ics 单测 42 项
  全过(转义/折行/UTC/拼装);服务器 e2e 391 项全过(含 11c 节
  17 项 ICS 断言)。
2026-09-29 07:58:31 +08:00

151 lines
6.3 KiB
Markdown
Raw Permalink 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.
# TripLog
**家庭旅行日记** —— 把一次旅行的行程、照片、花销、同行人,完整地记录和回看。
以「活动(一次旅行)」为容器,内部按「节点(当天/某一段行程)」串联,
每个节点可以带时间地点、交通方式、参与人、照片附件与花销分摊;
首页是一张地图,把去过的家和走过的地方标出来。
技术栈:**PHP 8 + MySQL**,无框架、无 Composer、无前端构建工具。
路由自写(`index.php?r=控制器/方法`),视图为原生 PHP 模板,前端为原生 CSS + JS。
---
## 功能
**旅行与行程**
- 活动(旅行)的增删改查,支持封面图、起止时间、状态
- 行程节点:时间、地点(高德选点)、备注,支持「由计划一键成行」
- 节点交通:出行方式(自驾/高铁/飞机…)+ 车辆,可绑定起终点
- 一键跳高德导航 / 搜索(服务端与前端共用一处配置,见下文)
**记录与协作**
- 照片附件:多图上传、可视化裁剪、当前页灯箱浏览(左右切换)
- 封面拖拽上传,自动走裁剪
- 参与人与角色标签(家庭成员角色、当时情绪等)
- 活动级与节点级评论
**花销**
- 只记明细 + 总计,不做预算
- 分摊到参与人
**首页地图**
- 同城活动拥挤时扇形拉出排布,引线带箭头指向真实位置
- 卡片为「左图右文」方形卡片
**日历导出**
- 每个节点可导出 `.ics`(标题、起止时间、车次/航班号、出发地、备注),
导入手机/电脑的系统日历
- 整个活动一键导出为一个日历文件(已取消与已成行计划不重复导出)
**存储与基础设施**
- 存储抽象层:**本地磁盘** 或 **阿里云 OSS**,后台可切换与自检
- 媒体代理路由:照片/封面经 `media/*` 输出,**不对外暴露 OSS 地址**
- 站点图标与 PWA 清单(可添加到手机主屏)
---
## 目录结构
```
index.php 入口与路由表(白名单 + 登录拦截)
config.example.php 配置模板(复制为 config.php 使用)
src/
Database.php PDO 连接
Auth.php Access.php 登录态与权限
Migrate.php 幂等迁移定义(VERSION 常量)
Settings.php 站点级键值设置(存储驱动等)
Storage.php Oss.php 存储抽象层 / OSS 客户端
Uploads.php Attachments.php Mime.php
Members.php Expenses.php Comments.php
helpers.php 全局辅助函数(asset()、e()、amap_nav_url() 等)
Controllers/ 各业务控制器
templates/ 视图模板(layout.php 为公共骨架)
assets/ 样式、图标、第三方前端库(cropper)
sql/migrations/ SQL 迁移留档
tools/migrate.php 迁移执行入口(仅命令行)
uploads/ 用户上传内容(不入库)
```
---
## 部署
### 1. 环境要求
- PHP **7.4+**(推荐 8.x;开发与线上均在 8.1 与 7.4 双版本下做过语法检查与冒烟)
- MySQL 5.7+ / 8.0(MariaDB 亦可),字符集 `utf8mb4`
- PHP 扩展:`pdo_mysql`、`curl`、`gd`、`mbstring`、`json`、`openssl`
- 站点根目录对 Web 进程**可写**(安装时生成 `config.php` 用;`uploads/` 始终需要可写)
### 2. 安装向导(推荐)
1. 把代码放入站点目录,确保站点根对 Web 进程可写;
2. 在 MySQL 里创建一个**空的**数据库(表结构由安装向导自动生成):
```sql
CREATE DATABASE trip DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
-- 再创建专用账号并授予 trip 库全部权限(推荐,不要用 root)
```
3. 浏览器访问站点根 —— 未安装时 `index.php` 会自动跳转到 `install.php` 安装向导;
4. 按表单填写:网站标题、家庭名称、数据库连接、高德地图 Key(可留空稍后补)、
管理员账号(手机号 + 密码);
5. 提交后向导会:全量建表(`sql/schema.sql`)→ 执行增量迁移(`src/Migrate.php`)→
写入基本数据(你的家庭、管理员账号、节点类型、角色标签、常用出行方式)→
生成 `config.php` → **自动删除 `install.php`**。
安装完成后即可用管理员账号登录。「已安装」的判定以 `config.php` 为准:
即使 `install.php` 没有被成功删除,再次访问也只会看到「已安装」提示,无法重新安装。
> 种子的出行方式不含「自驾」两种 —— 自驾方式必须关联具体车辆,
> 请先在「车辆管理」里添加车辆,再自行添加自驾出行方式。
### 3. 手动安装(备选)
不想用向导时,也可以完全手动:
```bash
git clone <repo-url> triplog
cd triplog
cp config.example.php config.php # 手工填写数据库与高德参数
php tools/migrate.php # 不够:首次还需要全量建表,见下
```
全量建表:把 `sql/schema.sql` 导入空库(`mysql trip < sql/schema.sql`),
再执行 `php tools/migrate.php` 补齐增量迁移。管理员账号目前需自行向 `families`、
`users` 插入(密码用 `password_hash()`,手机号存 `phone_hash`(SHA-256)与
`phone_encrypted`(AES-256-CBC)),**推荐直接使用安装向导**。
`config.php` 不入库(含口令),只提交模板 `config.example.php`。
所有配置项都支持环境变量覆盖(`DB_HOST` / `DB_NAME` / `AMAP_NAV_SRC` 等)。
### 4. Web 服务器
把站点根指向项目根目录。Apache 需允许 `.htaccess`(`uploads/` 下有一条禁止执行脚本的规则,
不可删除);Nginx 请自行配置等价规则,并注意 `uploads/` 内不得解析 PHP。
### 5. 高德地图
在 `config.php` 的 `amap` 段填写(安装向导里填过的可跳过):
- `key` —— 服务端接口用
- `security_js` —— 前端 JS API 2.0 的安全密钥
- `nav_src` —— URI API 的调用来源(`src`)参数,**仅用于高德侧来源统计**,
填任意英数字串都能工作。服务端 `amap_nav_url()` 与前端表单共用这一个值,
只改这一处即可。示例值用 `trip.example.com`,请替换为你自己的域名。
---
## 使用
访问站点根 → 未登录会跳转登录页。首次部署后由管理员在后台创建用户。
后台可维护:用户、活动、节点类型、出行方式、车辆、角色标签、存储设置。
---
## 许可
见 [LICENSE](LICENSE)。