181 lines
7.8 KiB
PHP
181 lines
7.8 KiB
PHP
<?php
|
|||
|
|
/**
|
||
|
|
* 旅程详情(v12):封面 + 小结 + 同行的人 + 照片 + 行程节点(计划 / 执行双轨)。
|
||
|
|
*
|
||
|
|
* ⚠️ 双轨的意义:出发前排的是「打算怎么走」,走完记的是「实际怎么走的」。
|
||
|
|
* 两轨并存才能回看"本来想去哪、后来去了哪"—— 这是 TripLog 最有价值的一点,搬过来时保留了。
|
||
|
|
*/
|
||
|
|
$canWrite = \App\Auth::canWrite();
|
||
|
|
$plan = [];
|
||
|
|
$reality = [];
|
||
|
|
foreach ((array)($nodes ?? []) as $n) {
|
||
|
|
if (($n['category'] ?? 'plan') === 'reality') {
|
||
|
|
$reality[] = $n;
|
||
|
|
} else {
|
||
|
|
$plan[] = $n;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
$memberIds = array_map('intval', array_column((array)($t['attendees'] ?? []), 'id'));
|
||
|
|
?>
|
||
|
|
<div class="page-head">
|
||
|
|
<h1><?= e((string)$t['title']) ?></h1>
|
||
|
|
<span class="sub"><?= e(\App\Trip::formatSpan($t['starts_at'] ?? null, $t['ends_at'] ?? null)) ?></span>
|
||
|
|
<div class="actions">
|
||
|
|
<?php if ($canWrite): ?>
|
||
|
|
<a class="btn btn-ghost" href="<?= e(url('trips/edit', ['id' => (int)$t['id']])) ?>">编辑</a>
|
||
|
|
<form method="post" action="<?= e(url('trips/destroy')) ?>"
|
||
|
|
onsubmit="return confirm('确定删除「<?= e((string)$t['title']) ?>」吗?照片与行程节点会一起删掉,不可恢复。')">
|
||
|
|
<?= csrf_field() ?>
|
||
|
|
<input type="hidden" name="id" value="<?= (int)$t['id'] ?>">
|
||
|
|
<button class="btn btn-danger" type="submit">删除</button>
|
||
|
|
</form>
|
||
|
|
<?php endif; ?>
|
||
|
|
<a class="btn btn-ghost" href="<?= e(url('trips')) ?>">返回旅程</a>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="card card-pad trip-hero">
|
||
|
|
<div class="trip-hero-cover">
|
||
|
|
<?php if (!empty($t['cover_key'])): ?>
|
||
|
|
<img src="<?= e(media_url((string)$t['cover_key'])) ?>" alt="">
|
||
|
|
<?php else: ?>
|
||
|
|
<span class="trip-cover-empty">🧳</span>
|
||
|
|
<?php endif; ?>
|
||
|
|
</div>
|
||
|
|
<div class="trip-hero-body">
|
||
|
|
<?php if (!empty($t['location'])): ?>
|
||
|
|
<p class="trip-loc">📍 <?= e((string)$t['location']) ?></p>
|
||
|
|
<?php endif; ?>
|
||
|
|
<?php if (!empty($t['summary'])): ?>
|
||
|
|
<p class="info-text"><?= nl2br(e((string)$t['summary'])) ?></p>
|
||
|
|
<?php endif; ?>
|
||
|
|
<?php if (!empty($t['attendees'])): ?>
|
||
|
|
<div class="viewers-list">
|
||
|
|
<?php foreach ($t['attendees'] as $a): ?>
|
||
|
|
<?= person_chip($a, url('people/show', ['id' => (int)$a['id']])) ?>
|
||
|
|
<?php endforeach; ?>
|
||
|
|
</div>
|
||
|
|
<?php endif; ?>
|
||
|
|
<?php if (!empty($t['note'])): ?>
|
||
|
|
<p class="remark-text"><?= nl2br(e((string)$t['note'])) ?></p>
|
||
|
|
<?php endif; ?>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<?php /* ---- 照片 ---- */ ?>
|
||
|
|
<div class="card card-pad">
|
||
|
|
<h2 class="cinema-h2">照片</h2>
|
||
|
|
<?php if (!$photos): ?>
|
||
|
|
<p class="empty-hint">还没有照片。</p>
|
||
|
|
<?php else: ?>
|
||
|
|
<div class="photo-grid">
|
||
|
|
<?php foreach ($photos as $ph): ?>
|
||
|
|
<figure class="photo-cell">
|
||
|
|
<a href="<?= e(media_url((string)$ph['key'])) ?>" target="_blank" rel="noopener">
|
||
|
|
<img src="<?= e(media_url((string)$ph['key'])) ?>" alt="<?= e((string)($ph['name'] ?? '')) ?>">
|
||
|
|
</a>
|
||
|
|
<?php if ($canWrite): ?>
|
||
|
|
<form method="post" action="<?= e(url('trips/photo_del')) ?>" class="photo-del">
|
||
|
|
<?= csrf_field() ?>
|
||
|
|
<input type="hidden" name="id" value="<?= (int)$t['id'] ?>">
|
||
|
|
<input type="hidden" name="photo_id" value="<?= (int)$ph['id'] ?>">
|
||
|
|
<button class="btn btn-ghost btn-sm" type="submit"
|
||
|
|
onclick="return confirm('删掉这张照片?')">删除</button>
|
||
|
|
</form>
|
||
|
|
<?php endif; ?>
|
||
|
|
</figure>
|
||
|
|
<?php endforeach; ?>
|
||
|
|
</div>
|
||
|
|
<?php endif; ?>
|
||
|
|
<?php if ($canWrite): ?>
|
||
|
|
<form class="inline-form" method="post" enctype="multipart/form-data" action="<?= e(url('trips/photo_add')) ?>">
|
||
|
|
<?= csrf_field() ?>
|
||
|
|
<input type="hidden" name="id" value="<?= (int)$t['id'] ?>">
|
||
|
|
<input type="file" name="photo" accept="image/*" multiple required>
|
||
|
|
<button class="btn btn-sm" type="submit">上传照片</button>
|
||
|
|
</form>
|
||
|
|
<?php endif; ?>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<?php /* ---- 行程节点(双轨)---- */ ?>
|
||
|
|
<?php foreach ([['plan', '计划行程', $plan], ['reality', '实际走过', $reality]] as [$cat, $catName, $list]): ?>
|
||
|
|
<div class="card card-pad">
|
||
|
|
<h2 class="cinema-h2"><?= e($catName) ?> <span class="group-n"><?= count($list) ?> 段</span></h2>
|
||
|
|
|
||
|
|
<?php if (!$list): ?>
|
||
|
|
<p class="empty-hint"><?= $cat === 'plan' ? '还没有排计划。' : '还没有记录实际行程。' ?></p>
|
||
|
|
<?php else: ?>
|
||
|
|
<ol class="node-list">
|
||
|
|
<?php foreach ($list as $n): ?>
|
||
|
|
<li class="node-row status-<?= e((string)$n['status']) ?>">
|
||
|
|
<span class="node-ico" title="<?= e(\App\Trip::typeWord((string)$n['node_type'])) ?>">
|
||
|
|
<?= e(\App\Trip::typeIcon((string)$n['node_type'])) ?>
|
||
|
|
</span>
|
||
|
|
<div class="node-body">
|
||
|
|
<div class="node-head">
|
||
|
|
<b><?= e((string)$n['title']) ?></b>
|
||
|
|
<span class="node-badge"><?= e(\App\Trip::statusWord((string)$n['status'])) ?></span>
|
||
|
|
<?php if (!empty($n['place'])): ?>
|
||
|
|
<span class="node-place">📍 <?= e((string)$n['place']) ?></span>
|
||
|
|
<?php endif; ?>
|
||
|
|
</div>
|
||
|
|
<?php $span = \App\Trip::formatSpan($n['starts_at'] ?? null, $n['ends_at'] ?? null); ?>
|
||
|
|
<?php if ($span !== '日期待补'): ?>
|
||
|
|
<div class="node-time"><?= e($span) ?></div>
|
||
|
|
<?php endif; ?>
|
||
|
|
<?php if (!empty($n['detail'])): ?>
|
||
|
|
<p class="node-detail"><?= nl2br(e((string)$n['detail'])) ?></p>
|
||
|
|
<?php endif; ?>
|
||
|
|
<?php if (!empty($n['members'])): ?>
|
||
|
|
<div class="trip-people">
|
||
|
|
<?php foreach ($n['members'] as $mm): ?><?= person_chip($mm) ?><?php endforeach; ?>
|
||
|
|
</div>
|
||
|
|
<?php endif; ?>
|
||
|
|
<?php if (!empty($n['attachs'])): ?>
|
||
|
|
<div class="attach-row">
|
||
|
|
<?php foreach ($n['attachs'] as $at): ?>
|
||
|
|
<a class="attach-item" href="<?= e(media_url((string)$at['key'], ['dl' => 1])) ?>">
|
||
|
|
<?= (int)$at['is_image'] === 1 ? '🖼' : '📄' ?> <?= e((string)($at['name'] ?: '附件')) ?>
|
||
|
|
</a>
|
||
|
|
<?php endforeach; ?>
|
||
|
|
</div>
|
||
|
|
<?php endif; ?>
|
||
|
|
</div>
|
||
|
|
<?php if ($canWrite): ?>
|
||
|
|
<div class="node-ops">
|
||
|
|
<details class="node-edit">
|
||
|
|
<summary class="link-quiet">编辑</summary>
|
||
|
|
<?php
|
||
|
|
$nfNode = $n; $nfTripId = (int)$t['id']; $nfCategory = $cat;
|
||
|
|
$nfPeople = $people ?? [];
|
||
|
|
$nfMembers = array_map('intval', array_column((array)($n['members'] ?? []), 'id'));
|
||
|
|
require __DIR__ . '/_node_form.php';
|
||
|
|
?>
|
||
|
|
</details>
|
||
|
|
<form method="post" action="<?= e(url('trips/node_del')) ?>"
|
||
|
|
onsubmit="return confirm('删掉这一段?')">
|
||
|
|
<?= csrf_field() ?>
|
||
|
|
<input type="hidden" name="id" value="<?= (int)$n['id'] ?>">
|
||
|
|
<input type="hidden" name="trip_id" value="<?= (int)$t['id'] ?>">
|
||
|
|
<button class="btn btn-ghost btn-sm" type="submit">删除</button>
|
||
|
|
</form>
|
||
|
|
</div>
|
||
|
|
<?php endif; ?>
|
||
|
|
</li>
|
||
|
|
<?php endforeach; ?>
|
||
|
|
</ol>
|
||
|
|
<?php endif; ?>
|
||
|
|
|
||
|
|
<?php if ($canWrite): ?>
|
||
|
|
<details class="node-add">
|
||
|
|
<summary class="link-quiet">+ 加一段<?= e($catName) ?></summary>
|
||
|
|
<?php
|
||
|
|
$nfNode = null; $nfTripId = (int)$t['id']; $nfCategory = $cat;
|
||
|
|
$nfPeople = $people ?? []; $nfMembers = $memberIds;
|
||
|
|
require __DIR__ . '/_node_form.php';
|
||
|
|
?>
|
||
|
|
</details>
|
||
|
|
<?php endif; ?>
|
||
|
|
</div>
|
||
|
|
<?php endforeach; ?>
|