Files
FamilyBook/templates/movies/show.php
T
laoyang ff353b1eee v8:观影落地(MovieLog 整体迁入统一事件原语)+ 三处 UI 撤除
- Schema v8:events / movie_details / event_attendees / event_photos 四张表,
  uk_event_source(family_id, source_ref) 作迁移幂等锚
- Movie 模型:时间线/详情/增删改、同行人整组替换、照片逐张管理、感受英→中映射
- ImageSlot 新增 poster(2:3) / ticket(free) / photo(free) 三槽位;
  free 槽位不裁剪、整图等比缩进框(只缩不放大)
- OssDriver::copyObject:同桶 CopyObject(手写 V1 签名,x-oss-* 头按字典序进签名串)
- 路由:movies 时间线/详情/新增/编辑/删除/补照片/删照片;同行人按家庭过滤;
  访客只读(requireWrite)
- UI 撤除:首页「我的一句话」、家谱页「补充我的亲属关系 / 看整个名册」两个按钮;
  顶栏加「观影」入口
- 修潜伏 bug:ImageSlot::parseRatio 的正则用 / 作分隔符,字符类里的 / 把模式
  提前截断(Unknown modifier ']')—— ratio() 只在上传 POST 里被调到,一直没被观察到
- 线上数据迁移(临时 token 门禁页,用完即删):MovieLog 219 条观影 → events,
  14 位观影人新增进名册(带 MovieLog 头像),431 个 OSS 对象同桶拷贝
  (movielog/uploads/<dir>/x → family/<dir>/x),review/feelings/影院三段/照片全量搬
2026-09-30 20:22:46 +08:00

135 lines
5.6 KiB
PHP
Raw 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.
<?php
/**
* 观影详情页。
*
* 海报 / 票根 / 照片一律走 media_url() 代理(全站唯一出口,见 helpers.php);
* 感受标签是迁移时已翻成中文的 JSON 数组,这里只展示不加工。
* 访客(只读)看不到编辑/删除/传照片那些表单 —— 与名册同一口径。
*/
$canWrite = \App\Auth::canWrite();
$feel = [];
if (!empty($m['feelings'])) {
$feel = json_decode((string)$m['feelings'], true);
if (!is_array($feel)) {
$feel = [];
}
}
$hasPoster = !empty($m['poster_key']);
$hasTicket = !empty($m['ticket_key']);
?>
<div class="page-head">
<h1><?= e($m['title']) ?></h1>
<span class="sub"><?= e((string)($m['starts_at'] ?? '日期待补')) ?></span>
<div class="actions">
<?php if ($canWrite): ?>
<a class="btn btn-ghost btn-sm" href="<?= e(url('movies/edit', ['id' => (int)$m['id']])) ?>">编辑</a>
<form method="post" action="<?= e(url('movies/destroy')) ?>"
onsubmit="return confirm('删除这条观影记录?海报、票根、照片也会一并删除,不可恢复。')">
<?= csrf_field() ?>
<input type="hidden" name="id" value="<?= (int)$m['id'] ?>">
<button type="submit" class="btn btn-danger btn-sm">删除</button>
</form>
<?php endif; ?>
<a class="btn btn-ghost btn-sm" href="<?= e(url('movies')) ?>">返回</a>
</div>
</div>
<div class="movie-detail">
<div class="m-poster-col">
<?php if ($hasPoster): ?>
<a href="<?= e(media_url($m['poster_key'])) ?>" target="_blank" rel="noopener">
<img class="m-poster-lg" src="<?= e(media_url($m['poster_key'])) ?>" alt="海报">
</a>
<?php else: ?>
<span class="m-poster-lg m-poster-empty" aria-hidden="true">影</span>
<?php endif; ?>
<?php if ($hasTicket): ?>
<a href="<?= e(media_url($m['ticket_key'])) ?>" target="_blank" rel="noopener">
<img class="m-ticket" src="<?= e(media_url($m['ticket_key'])) ?>" alt="票根" loading="lazy">
</a>
<?php endif; ?>
</div>
<div class="card card-pad m-info">
<?php if ($m['rating'] !== null || $feel): ?>
<div class="m-score">
<?php if ($m['rating'] !== null): ?>
<span class="rating rating-lg"><?= e(rtrim(rtrim(number_format((float)$m['rating'], 1, '.', ''), '0'), '.')) ?></span>
<?php endif; ?>
<?php foreach ($feel as $f): ?>
<span class="badge badge-feel"><?= e($f) ?></span>
<?php endforeach; ?>
</div>
<?php endif; ?>
<dl class="kv">
<div class="kv-row"><dt>观影日期</dt><dd><?= e((string)($m['starts_at'] ?? '日期待补')) ?></dd></div>
<?php if (!empty($m['cinema_place']) || !empty($m['cinema_name']) || !empty($m['cinema_address'])): ?>
<div class="kv-row"><dt>影院</dt><dd>
<?= e(trim(implode(' ', array_filter([
(string)($m['cinema_place'] ?? ''),
(string)($m['cinema_name'] ?? ''),
(string)($m['cinema_address'] ?? ''),
], static fn($s) => $s !== '')))) ?>
</dd></div>
<?php endif; ?>
<?php if (!empty($m['location'])): ?>
<div class="kv-row"><dt>地点</dt><dd><?= e($m['location']) ?></dd></div>
<?php endif; ?>
<div class="kv-row"><dt>同行的人</dt><dd>
<?php if ($m['attendees']): ?>
<?php foreach ($m['attendees'] as $i => $a): ?><?= $i > 0 ? '、' : '' ?><a href="<?= e(url('people/show', ['id' => (int)$a['id']])) ?>"><?= e($a['name']) ?></a><?php endforeach; ?>
<?php else: ?>一个人看的<?php endif; ?>
</dd></div>
</dl>
<?php if (!empty($m['info'])): ?>
<div class="m-block"><h3>简介</h3><p><?= nl2br(e($m['info'])) ?></p></div>
<?php endif; ?>
<?php if (!empty($m['review'])): ?>
<div class="m-block"><h3>观后感</h3><p><?= nl2br(e($m['review'])) ?></p></div>
<?php endif; ?>
<?php if (!empty($m['note'])): ?>
<div class="m-block"><h3>备注</h3><p><?= nl2br(e($m['note'])) ?></p></div>
<?php endif; ?>
</div>
</div>
<?php if ($m['photos']): ?>
<section class="section">
<h2 class="section-title">现场照片 <span class="hint"><?= count($m['photos']) ?> 张</span></h2>
<div class="photo-grid">
<?php foreach ($m['photos'] as $ph): ?>
<div class="photo-cell">
<a href="<?= e(media_url($ph['key'])) ?>" target="_blank" rel="noopener">
<img src="<?= e(media_url($ph['key'])) ?>" alt="" loading="lazy">
</a>
<?php if ($canWrite): ?>
<form method="post" action="<?= e(url('movies/photo_del')) ?>"
onsubmit="return confirm('删除这张照片?')">
<?= csrf_field() ?>
<input type="hidden" name="id" value="<?= (int)$m['id'] ?>">
<input type="hidden" name="photo_id" value="<?= (int)$ph['id'] ?>">
<button type="submit" class="photo-del" title="删除这张照片">×</button>
</form>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
</section>
<?php endif; ?>
<?php if ($canWrite): ?>
<section class="section">
<form method="post" enctype="multipart/form-data" action="<?= e(url('movies/photo_add')) ?>" class="card card-pad photo-add">
<?= csrf_field() ?>
<input type="hidden" name="id" value="<?= (int)$m['id'] ?>">
<label for="photo">补一张现场照片</label>
<div class="photo-add-row">
<input class="input" id="photo" name="photo" type="file" accept="image/*" required>
<button type="submit" class="btn btn-ghost btn-sm">上传</button>
</div>
</form>
</section>
<?php endif; ?>