取消「票根」概念,并入观影照片(数据迁移 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
+11 -23
View File
@@ -289,7 +289,8 @@ $fbAdd = !empty($fbAddModalAttr);
* 按钮留在原位、用 HTML5 的 `form="id"` 关联到外面那个表单。
*/
$mHasPoster = $isEdit && !empty($m['poster_key']);
$mHasTicket = $isEdit && !empty($m['ticket_key']);
/* 🔴 2026-11-06:`$mHasTicket` 取消。票根概念已并入「观影照片」,
旧字段迁完置 NULL,页面不再有第三个分类。 */
$mPhotos = $isEdit ? (array)($m['photos'] ?? []) : [];
$mDelForms = []; // 收集起来,在表单**外面**统一渲染
?>
@@ -355,21 +356,13 @@ $mDelForms = []; // 收集起来,在表单**外面**统一渲染
<div class="mv-row mv-row-media">
<span class="mv-lb no-colon">观影照片</span>
<div class="mv-media-body">
<?php if ($mHasTicket || $mPhotos): ?>
<?php if ($mPhotos): ?>
<div class="photo-grid">
<?php if ($mHasTicket): /* 历史数据:旧票根(不在 event_photos 里,只展示) */ ?>
<?php $mDelForms['ticket'] = 'movies/media_del'; ?>
<figure class="photo-cell">
<a href="<?= e(media_url((string)$m['ticket_key'])) ?>" data-prev="image"
data-src="<?= e(media_url((string)$m['ticket_key'])) ?>"
data-dl="<?= e(media_url((string)$m['ticket_key'], ['dl' => 1])) ?>"
data-name="票根">
<img src="<?= e(media_url((string)$m['ticket_key'])) ?>" alt="票根">
</a>
<button class="btn btn-ghost btn-sm" type="submit" form="mv-del-ticket"
onclick="return confirm('删掉这张旧票根?')">删除</button>
</figure>
<?php endif; ?>
<?php /* 🔴 2026-11-06:**票根那个特殊格子删掉了**。用户要求只分两类
(海报 / 观影照片),旧票根已经一次性迁进 `event_photos`
(220 条,position 排最前),现在它就是下面 foreach 里的
一条普通照片 —— 有 id、能删、能拖进灯箱。
⚠️ 别再把它加回来。留着就等于承认还有第三类。 */ ?>
<?php foreach ($mPhotos as $mp): $mpId = (int)$mp['id']; ?>
<figure class="photo-cell">
<a href="<?= e(media_url((string)$mp['key'])) ?>" data-prev="image"
@@ -450,13 +443,8 @@ $mDelForms = []; // 收集起来,在表单**外面**统一渲染
<input type="hidden" name="slot" value="poster">
</form>
<?php endif; ?>
<?php if ($mHasTicket): ?>
<form id="mv-del-ticket" method="post" action="<?= e(url('movies/media_del')) ?>" class="form-outside">
<?= csrf_field() ?>
<input type="hidden" name="id" value="<?= (int)$m['id'] ?>">
<input type="hidden" name="slot" value="ticket">
</form>
<?php endif; ?>
<?php /* 🔴 2026-11-06:`mv-del-ticket` 这个表单删掉了 —— 票根已并入
`event_photos`,走下面那条按 photo_id 删的通用表单。 */ ?>
<?php foreach ($mPhotos as $mp): ?>
<form id="mv-del-photo-<?= (int)$mp['id'] ?>" method="post"
action="<?= e(url('movies/photo_del')) ?>" class="form-outside">
@@ -467,7 +455,7 @@ $mDelForms = []; // 收集起来,在表单**外面**统一渲染
<input type="hidden" name="back" value="edit">
</form>
<?php endforeach; ?>
<?php unset($mHasPoster, $mHasTicket, $mPhotos, $mDelForms, $mp, $mpId); ?>
<?php unset($mHasPoster, $mPhotos, $mDelForms, $mp, $mpId); ?>
<?php /* ---- 新建影院:弹框(不跳转,见上)---- */ ?>
<div class="cn-modal" id="cinemaNewModal" hidden>
+16 -28
View File
@@ -3,13 +3,14 @@
* 观影详情页(v9,展示方式照搬 MovieLog 的 detail.php)。
*
* 五大块:英雄区(左海报右信息)→ 一起看的人 → 电影院信息 → 观影照片(灯箱)→ 评价与评论。
* 海报/票根/照片一律走 media_url() 代理;感受标签只存 key,emoji 与文案查 CATALOG。
* 海报/观影照片一律走 media_url() 代理;感受标签只存 key,emoji 与文案查 CATALOG。
* 访客(只读)看不到编辑/删除/传照片/评价表单 —— 与名册同一口径。
* 评价人是「登录账号背后的人」,与同行观影人无关(MovieLog 同款规则)。
*/
$canWrite = \App\Auth::canWrite();
$hasPoster = !empty($m['poster_key']);
$hasTicket = !empty($m['ticket_key']);
/* 🔴 2026-11-06:`$hasTicket` 取消 —— 票根已并入 `event_photos`,
只分「海报 / 观影照片」两类。 */
// 豆瓣元数据(v10):整体 JSON 存 douban_meta,随用随解;解不开就当没有
$doubanMeta = [];
if (!empty($m['douban_meta'])) {
@@ -160,7 +161,7 @@ $commentBox = static function (int $reviewId, int $parentId, string $summary) us
<button class="btn" type="button" id="mvEditBtn" aria-haspopup="dialog" aria-expanded="false"
data-href="<?= e(url('movies/edit', ['id' => (int)$m['id']])) ?>">编辑</button>
<form method="post" action="<?= e(url('movies/destroy')) ?>"
onsubmit="return confirm('删除这条观影记录?海报、票根、照片也会一并删除,不可恢复。')">
onsubmit="return confirm('删除这条观影记录?海报、观影照片也会一并删除,不可恢复。')">
<?= csrf_field() ?>
<input type="hidden" name="id" value="<?= (int)$m['id'] ?>">
<button type="submit" class="btn btn-del">删除</button>
@@ -258,30 +259,19 @@ $commentBox = static function (int $reviewId, int $parentId, string $summary) us
<?php endif; ?>
</div>
<!-- 观影照片(v35:票根 + 现场照片 + 其它相关图片,**不再分类**,合成一块) -->
<?php if ($hasTicket || $m['photos']): ?>
<!-- 观影照片(v38:**只此一类**,票根已并入 event_photos) -->
<?php if ($m['photos']): ?>
<div class="detail-section">
<h3>观影照片 <span class="badge"><?= count($m['photos']) + ($hasTicket ? 1 : 0) ?> 张</span></h3>
<h3>观影照片 <span class="badge"><?= count($m['photos']) ?> 张</span></h3>
<div class="gallery-grid">
<?php /* ⚠️ 旧票根(movie_details.ticket_key)是历史数据,仍要能看到;
归并后它跟 event_photos 里的照片**同一块展示、同一套灯箱**,
但删除要走它自己的槽位表单(media_del)。 */ ?>
<?php if ($hasTicket): $lbIdx = 1; ?>
<div class="gallery-item lb-openable" data-lb-index="<?= $lbIdx ?>" role="button" tabindex="0" aria-label="放大查看" title="点击查看大图">
<img src="<?= e(media_url($m['ticket_key'])) ?>" alt="" loading="lazy">
<?php if ($canWrite): ?>
<form method="post" action="<?= e(url('movies/media_del')) ?>"
onsubmit="return confirm('删除这张照片?')">
<?= csrf_field() ?>
<input type="hidden" name="id" value="<?= (int)$m['id'] ?>">
<input type="hidden" name="slot" value="ticket">
<button type="submit" class="photo-del" title="删除这张照片">×</button>
</form>
<?php endif; ?>
</div>
<?php endif; ?>
<?php /* 🔴 2026-11-06:**票根那个特殊格子删掉了**。用户要求只分两类
(海报 / 观影照片);旧 `movie_details.ticket_key` 里的票根
已经一次性迁进 `event_photos`(220 条,position 排最前),
现在它就是下面 foreach 里的普通一张 —— 同一个灯箱、同一个删除路由。
⚠️ 别再把它加回来,留着就等于承认还有第三类。
⚠️ `$lbIdx` 也因此从 1 起直接算,不再需要 `+ ($hasTicket ? 2 : 1)`。 */ ?>
<?php foreach ($m['photos'] as $i => $ph): ?>
<div class="gallery-item lb-openable" data-lb-index="<?= $i + ($hasTicket ? 2 : 1) ?>" role="button" tabindex="0" aria-label="放大查看照片" title="点击查看大图">
<div class="gallery-item lb-openable" data-lb-index="<?= $i + 1 ?>" role="button" tabindex="0" aria-label="放大查看照片" title="点击查看大图">
<img src="<?= e(media_url((string)$ph['key'])) ?>" alt="" loading="lazy">
<?php if ($canWrite): ?>
<form method="post" action="<?= e(url('movies/photo_del')) ?>"
@@ -434,7 +424,7 @@ $commentBox = static function (int $reviewId, int $parentId, string $summary) us
<?php endif; ?>
</div>
<?php if ($hasPoster || $hasTicket || $m['photos']): ?>
<?php if ($hasPoster || $m['photos']): ?>
<!-- 图片灯箱:点任意一张图在当前页弹出,可左右翻看 / Esc 关闭(MovieLog 同款) -->
<div class="lightbox" id="lightbox" role="dialog" aria-modal="true" aria-hidden="true" aria-label="图片查看器">
<?php /* v24 第 3 条:预览层右上角恒有下载按钮(与全局附件预览一个规矩) */ ?>
@@ -454,9 +444,7 @@ $commentBox = static function (int $reviewId, int $parentId, string $summary) us
<?php if ($hasPoster): ?>
items.push({url: <?= json_encode(media_url((string)$m['poster_key']), JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) ?>, cap: <?= json_encode('海报 · ' . $m['title'], JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) ?>});
<?php endif; ?>
<?php if ($hasTicket): ?>
items.push({url: <?= json_encode(media_url((string)$m['ticket_key']), JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) ?>, cap: <?= json_encode('观影照片 · ' . $m['title'], JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) ?>});
<?php endif; ?>
<?php /* 🔴 2026-11-06:票根那条 items.push 删掉了 —— 它已在 `$m['photos']` 里 */ ?>
<?php foreach ($m['photos'] as $ph): ?>
items.push({url: <?= json_encode(media_url((string)$ph['key']), JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) ?>, cap: <?= json_encode('观影照片 · ' . $m['title'], JSON_UNESCAPED_UNICODE | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT) ?>});
<?php endforeach; ?>