v9: 观影对齐 MovieLog —— 瀑布流/影院管理/评价评论/起止时间
- events 起止时间精确到秒(starts_at DATE→DATETIME + ends_at),_datetime.php 复用 - 影院独立成表(cinemas,地方/名称/地址/主题色 + 50 色板),movie_details 归一为 cinema_id - 评价模型 MovieLog 同款:movie_reviews 每账号每片一条(1-10 分+正文+感受 key), movie_review_comments 两级平铺评论(回复的回复规范化到顶层、跨评价回复拦截) - 感受目录迁到 MovieReview::CATALOG(12 种,Emoji 11.0 老码位) - 观影列表改瀑布流(CSS grid 海报墙),详情页五大块 + 灯箱 + 评价区 - 升级路径:v8 老数据自动归一(影院三段按 (family,place,name) 去重建行、 评价回填、中文感受反查英文 key),回填全部幂等;老库补 cinema_id 列+索引+外键 - 修三 bug:建表顺序(cinemas 必须在 movie_details 前,否则全新安装 1215)、 layout 导航用键名当路由(影院链接指向 r=cinemas)、 _datetime.php 分钟循环变量 $m 覆盖宿主模板的观影记录(编辑页简介/备注回填被清空)
This commit is contained in:
+58
-40
@@ -1,61 +1,79 @@
|
||||
<?php
|
||||
/**
|
||||
* 观影时间线 —— 按年分组倒序(v8,MovieLog 迁入后的新家)。
|
||||
* 观影瀑布流(v9,MovieLog 同款海报墙)。
|
||||
*
|
||||
* 没填日期的记录落在键 0,沉到最底下单独一组「日期待补」,
|
||||
* 不让它混进任何一个年份里(跟名册「未分类」栏是同一个思路)。
|
||||
* 卡片 = 海报(2:3,无海报给渐变占位)+ 片名 + 日期/影院(主题色)/评分均分 + 同行人头像标签。
|
||||
* 顶部搜索栏:关键词搜片名 / 影院 / 同行人(Movie::all 的 LIKE 查询)。
|
||||
*/
|
||||
$canWrite = \App\Auth::canWrite();
|
||||
$fmtNum = static function ($v): string {
|
||||
if ($v === null) {
|
||||
return '';
|
||||
}
|
||||
return rtrim(rtrim(number_format((float)$v, 1, '.', ''), '0'), '.');
|
||||
};
|
||||
?>
|
||||
<div class="page-head">
|
||||
<h1>观影记录</h1>
|
||||
<span class="sub">一共 <?= (int)$total ?> 场</span>
|
||||
<span class="sub">
|
||||
<?php if ($keyword !== ''): ?>
|
||||
找到 <?= (int)$total ?> 部匹配「<b><?= e($keyword) ?></b>」的电影
|
||||
<?php else: ?>
|
||||
共 <?= (int)$total ?> 部 · 按观影时间排序
|
||||
<?php endif; ?>
|
||||
</span>
|
||||
<div class="actions">
|
||||
<a class="btn btn-ghost btn-sm" href="<?= e(url('movies/cinemas')) ?>">影院管理</a>
|
||||
<?php if ($canWrite): ?>
|
||||
<a class="btn" href="<?= e(url('movies/new')) ?>">记一场电影</a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="get" action="index.php" class="search-bar">
|
||||
<input type="hidden" name="r" value="movies">
|
||||
<input type="text" name="keyword" value="<?= e($keyword) ?>" placeholder="搜索片名、影院、观影人…" aria-label="搜索">
|
||||
<button type="submit">搜索</button>
|
||||
<?php if ($keyword !== ''): ?>
|
||||
<a class="search-clear" href="<?= e(url('movies')) ?>">清除</a>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
|
||||
<?php if ($total === 0): ?>
|
||||
<div class="card card-pad empty">
|
||||
<b>还没有观影记录</b>
|
||||
一家人一起看过的电影,都会按年份排在这里。
|
||||
<b><?= $keyword !== '' ? '没有找到匹配的电影' : '还没有观影记录' ?></b>
|
||||
<?= $keyword !== '' ? '换个关键词试试。' : '一家人一起看过的电影,都会以海报墙的方式排在这里。' ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php foreach ($years as $y => $list): ?>
|
||||
<section class="section">
|
||||
<h2 class="section-title"><?= $y > 0 ? (int)$y : '日期待补' ?> <span class="hint"><?= count($list) ?> 场</span></h2>
|
||||
<div class="movie-list">
|
||||
<?php foreach ($list as $mv): ?>
|
||||
<?php
|
||||
// 评分统一一位小数内显示:9 → "9",8.5 → "8.5"(库里是 0-10 整数,这里只做展示兜底)
|
||||
$rtTxt = $mv['rating'] !== null
|
||||
? rtrim(rtrim(number_format((float)$mv['rating'], 1, '.', ''), '0'), '.')
|
||||
: '';
|
||||
?>
|
||||
<a class="movie-card" href="<?= e(url('movies/show', ['id' => (int)$mv['id']])) ?>">
|
||||
<?php if (!empty($mv['poster_key'])): ?>
|
||||
<img class="m-poster" src="<?= e(media_url($mv['poster_key'])) ?>" alt="" loading="lazy">
|
||||
<?php else: ?>
|
||||
<span class="m-poster m-poster-empty" aria-hidden="true">影</span>
|
||||
<?php endif; ?>
|
||||
<span class="m-main">
|
||||
<span class="m-title">
|
||||
<?= e($mv['title']) ?>
|
||||
<?php if ($rtTxt !== ''): ?><span class="rating"><?= e($rtTxt) ?></span><?php endif; ?>
|
||||
</span>
|
||||
<span class="m-meta">
|
||||
<?= e((string)($mv['starts_at'] ?? '日期待补')) ?>
|
||||
<?php if (!empty($mv['cinema_name'])): ?> · <?= e($mv['cinema_name']) ?><?php endif; ?>
|
||||
</span>
|
||||
<?php if (!empty($mv['attendee_names'])): ?>
|
||||
<span class="m-who">和 <?= e($mv['attendee_names']) ?></span>
|
||||
<?php endif; ?>
|
||||
<div class="waterfall">
|
||||
<?php foreach ($rows as $mv): ?>
|
||||
<a class="movie-card" href="<?= e(url('movies/show', ['id' => (int)$mv['id']])) ?>">
|
||||
<span class="card-image">
|
||||
<?php if (!empty($mv['poster_key'])): ?>
|
||||
<img src="<?= e(media_url($mv['poster_key'])) ?>" alt="<?= e($mv['title']) ?>" loading="lazy">
|
||||
<?php else: ?>
|
||||
<span class="placeholder-poster">
|
||||
<span class="ph-icon" aria-hidden="true">影</span>
|
||||
<span class="placeholder-title"><?= e($mv['title']) ?></span>
|
||||
</span>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</section>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</span>
|
||||
<span class="card-body">
|
||||
<span class="card-title"><?= e($mv['title']) ?></span>
|
||||
<span class="card-meta">
|
||||
<span class="meta-date">📅 <?= e(\App\Movie::formatWatch($mv['starts_at'], $mv['ends_at'])) ?></span>
|
||||
<?php if (!empty($mv['cinema_name'])): ?>
|
||||
<span class="meta-cinema" style="color: <?= e((string)($mv['cinema_color'] ?: '#888888')) ?>;">🏛️ <?= e($mv['cinema_name']) ?></span>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($mv['review_count'])): ?>
|
||||
<span class="meta-rating" title="共 <?= (int)$mv['review_count'] ?> 条评价">⭐ <?= e($fmtNum($mv['review_avg'])) ?><span class="meta-rating-max">/10</span></span>
|
||||
<?php endif; ?>
|
||||
</span>
|
||||
<?php if (!empty($mv['attendee_names'])): ?>
|
||||
<span class="card-viewers"><span class="viewer-tag">👥 <?= e($mv['attendee_names']) ?></span></span>
|
||||
<?php endif; ?>
|
||||
</span>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
Reference in New Issue
Block a user