取消「票根」概念,并入观影照片(数据迁移 220 条)(#87)

用户:现在不是已经没有票根的概念了吗?全部都换成观影照片了。别管是票根
还是观影照片,都在一起。现在只分两类:一类是海报,一类是观影照片。
海报是来自豆瓣的,这个不用管它,主要就是观影照片,所有的都在观影照片里边。

事实核查:概念取消了,数据没取消。网页端 v35 只在**模板层**把它们画进
同一个网格,数据层仍是两条路:票根在 movie_details.ticket_key(单张槽位),
不在 event_photos 里 ⇒ 没有 id ⇒ 删不掉,端上得写"票根另算"特判。

线上数据:有票根 220 条,其中 209 条只有票根、没有任何照片;
event_photos 总数才 14 —— 也就是说「观影照片」里装的几乎全是票根。

① 数据迁移(已执行,220/220 成功,失败 0):
   逐条把 ticket_key 插进 event_photos(position 取比现有最小值再小 10,
   ⇒ 排第一,因为票根是"这场电影的凭证",用户认知里排最前),然后置 NULL。
   event_photos 14 → 234,旧票根残留 0。
   ⚠️ 幂等:靠"该 key 已在该 event 的 event_photos 里"判断,重复跑不插重复行;
   ⚠️ 不删存储对象:只搬引用,图片原地不动,失败也不丢图。

② 同一段逻辑写进 Schema VERSION 36→37,让新库/重装库走同一套,
   不靠"记得手工跑脚本"。对线上是空操作(已验证 234→234)。

③ 服务端停止读写票根字段(字段保留作历史审计,代码不再碰):
   - Movie::find 不再 SELECT ticket_key;
   - Movie::saveDetails UPSERT 去掉 ticket_key;
   - Movie::destroy 不再单独查/删票根对象(已并入 photos 循环);
   - index.php:上传槽位 [poster,ticket] → [poster],
     stage_ticket 不再认领,media_del 白名单只剩 poster;
   - form.php:删票根特殊格子 + mv-del-ticket 表单 + $mHasTicket;
   - show.php:删票根格子 + 灯箱 ticket 项 + $hasTicket。

验证:find(1,1)/find(1,224) 已不返回 ticket_key,photos 3/4 条票根在首位;
直接 include 模板无 Fatal,form.php 里 mv-del-ticket / stage_ticket 各 0 次;
6 个文件 md5 逐个核对一致、php -l 全过、已上线且升级到 37。
This commit is contained in:
2026-11-06 11:25:47 +08:00
parent 94a557cd2e
commit 835f2846f2
5 changed files with 118 additions and 71 deletions
+18 -9
View File
@@ -3536,7 +3536,11 @@ switch ($r) {
// 存不进去,看起来像功能坏了)。现在是先存记录,图片的事单独提示。
// 海报 / 票根:free 槽位,不需要裁剪框;编辑时换新图就顺带删掉旧对象。
$warns = [];
foreach (['poster', 'ticket'] as $slot) {
/* 🔴 2026-11-06:只处理 `poster`。票根槽位取消 —— 静态票根已并入
`event_photos`,新的照片统一走「观影照片」那条多选通道。
⚠️ 别再把它加回这个数组:加了就会往 `ticket_key` 死列里写,
而那些图永远不会出现在「观影照片」里(看着像上传丢了)。 */
foreach (['poster'] as $slot) {
$up = Upload::image($familyId, $_FILES[$slot] ?? [], $slot);
if ($up['ok']) {
$oldKey = $isEdit ? (string)($m[$slot === 'poster' ? 'poster_key' : 'ticket_key'] ?? '') : '';
@@ -3641,17 +3645,19 @@ switch ($r) {
$d['photos'] = $photoKeys;
}
/* ---- v24 第 20 批 第 4 条:拖动**即时上传**的海报 / 票根 ----
/* ---- v24 第 20 批 第 4 条:拖动**即时上传**的海报 ----
用户原话:「拖动一个进去,就开始上传…最后统一保存即可。」
拖动会上传到暂存区并回一个 stoken,前端放进隐藏字段 `stage_poster` /
`stage_ticket`(**海报/票根各一个字段名**,因为它们要区分槽位)。
拖动会上传到暂存区并回一个 stoken,前端放进隐藏字段 `stage_poster`。
🔴 2026-11-06:**票根那条取消了**(`stage_ticket` 不再认领)。
票根概念并入「观影照片」,新图一律走通用那组 `stage_token[]`
(多选、可多次拖),与现场照片同一条管道。
⚠️ 这里直接取 stoken 对应的暂存文件来重跑 Upload::image(按该槽位的比例),
而不是把暂存文件原样搬过去 —— 海报是 2:3、票根是 free,
而不是把暂存文件原样搬过去 —— 海报是 2:3,
不按槽位处理就会存成比例不对的图(页面上会变形)。
⚠️ 临时文件上传(`$_FILES[$slot]`)优先:用户**又选又拖**时以"选"的为准
(那是他更明确的动作),免得两个来源打架。
⚠️ 认领失败要记进 $warns(不静默丢),且**不影响保存**(与既有口径一致)。 */
foreach (['poster' => 'stage_poster', 'ticket' => 'stage_ticket'] as $slotKey => $fieldName) {
foreach (['poster' => 'stage_poster'] as $slotKey => $fieldName) {
if (!empty($_FILES[$slotKey]) && (int)($_FILES[$slotKey]['error'] ?? 4) === UPLOAD_ERR_OK) {
continue; // 选了新文件 → 上面的常规路径已经处理过了
}
@@ -3846,8 +3852,11 @@ switch ($r) {
flash('err', '找不到这条观影记录。');
redirect('movies');
}
// 白名单:只认这两个槽位(表单可以被改,不能凭它去删别的字段/别的对象)
$col = ['poster' => 'poster_key', 'ticket' => 'ticket_key'][$slot] ?? '';
/* 白名单:只认 `poster` 这一个槽位。
🔴 2026-11-06:`ticket` 取消了 —— 票根已并入 `event_photos`,
要删它走 `movies/photo_del`(按 photo_id 删,与其它照片同一条路)。
⚠️ 表单能被改,所以白名单必须留着,不能凭它去删别的字段/别的对象。 */
$col = ['poster' => 'poster_key'][$slot] ?? '';
if ($col === '') {
flash('err', '不知道要删哪一样。');
redirect('movies/edit', ['id' => $id]);
@@ -3858,7 +3867,7 @@ switch ($r) {
if ($old !== '') {
\App\Storage\Storage::delete($familyId, $old);
}
flash('ok', ($slot === 'poster' ? '海报' : '票根') . '已删除。');
flash('ok', '海报已删除。');
redirect('movies/edit', ['id' => $id]);
break;