Files
FamilyBook/templates/books/read.php
T

108 lines
4.5 KiB
PHP
Raw Normal View History

<?php
/**
* 在线阅读(v24 第 14 批 用户第 5 条:「可以点开图书进行查看、阅读」)。
*
* 两种读法,按文件类型分:
* · 解析出正文的(EPUB / TXT)→ 直接把这一章的文本铺在这里(目录在侧栏);
* · PDF(服务端不提取正文)→ 用浏览器自带的 PDF 阅读器内嵌看,排版不会丢。
*
* ⚠️ 翻章就顺手**记进度**(读到第几章):下次点"继续读"直接回到这里。
* 这件事必须自动做 —— 让人手动记"我读到第几章"的阅读器没人会用。
*
* @param array $b 书
* @param array $chapters 目录
* @param array|null $chapter 当前章(含正文)
* @param int $seq 当前章号
*/
$canWrite = \App\Auth::canWrite();
$seq = (int)($seq ?? 1);
$total = count($chapters);
$isPdf = \App\BookParser::inlinable($b['file_format'] ?? '');
$prev = $seq > 1 ? $seq - 1 : 0;
$next = $seq < $total ? $seq + 1 : 0;
?>
<div class="page-head">
<h1><?= e((string)$b['title']) ?></h1>
<span class="sub">
<?= $isPdf ? 'PDF · 浏览器内嵌阅读'
: ('第 ' . $seq . ' / ' . max(1, $total) . ' 章'
. ($chapter ? ' · ' . e((string)$chapter['title']) : '')) ?>
</span>
<div class="actions">
<?php if ($canWrite): ?>
<?php /* 最后一章读完 → 顺手就能标完(这一步做掉了,人才会真的点) */ ?>
<form method="post" action="<?= e(url('books/status')) ?>" class="res-inline">
<?= csrf_field() ?>
<input type="hidden" name="id" value="<?= (int)$b['id'] ?>">
<input type="hidden" name="status" value="done">
<button class="btn<?= (string)$b['status'] === 'done' ? ' btn-ghost' : '' ?>" type="submit">
<?= (string)$b['status'] === 'done' ? '已读完(点这退回在读)' : '读完了' ?>
</button>
</form>
<?php endif; ?>
<a class="btn btn-ghost" href="<?= e(url('books/show', ['id' => (int)$b['id']])) ?>">这本书</a>
<a class="btn btn-ghost" href="<?= e(url('books')) ?>">书架</a>
<?php $bkSetCurrent = 'read'; require __DIR__ . '/_settings_menu.php'; ?>
</div>
</div>
<div class="book-read">
<?php if (!$isPdf && $total > 0): ?>
<aside class="br-side">
<div class="br-side-h">目录</div>
<ol class="br-toc">
<?php foreach ($chapters as $c): ?>
<li<?= (int)$c['seq'] === $seq ? ' class="is-cur"' : '' ?>>
<a href="<?= e(url('books/read', ['id' => (int)$b['id'], 'seq' => (int)$c['seq']])) ?>">
<?= e((string)$c['title']) ?>
</a>
</li>
<?php endforeach; ?>
</ol>
</aside>
<?php endif; ?>
<div class="br-main">
<?php if ($isPdf): ?>
<?php /* PDF:交给浏览器自己的阅读器。object 比 iframe 兼容性更好,
里面那句提示是"浏览器不支持内嵌"时才显示的兜底。 */ ?>
<div class="br-pdf">
<object data="<?= e(media_url((string)$b['file_key'])) ?>" type="application/pdf">
<p class="empty-hint">
这个浏览器不能直接内嵌看 PDF。
<a href="<?= e(media_url((string)$b['file_key'], ['dl' => 1])) ?>">点这里下载</a>后再看。
</p>
</object>
</div>
<?php elseif (!$chapter): ?>
<p class="empty-hint">
这本书还没有解析出正文。<?php if ($canWrite): ?>
到「编辑」里重新上传一次文件(EPUB / TXT 会自动拆章)。<?php endif; ?>
</p>
<?php else: ?>
<article class="br-text">
<h2 class="br-ch-title"><?= e((string)$chapter['title']) ?></h2>
<?php /* ⚠️ 正文是**纯文本**:nl2br + 转义,绝不 innerHTML ——
书的内容来自用户上传的文件,当成不可信输入处理。 */ ?>
<div class="br-body"><?= nl2br(e((string)$chapter['content'])) ?></div>
</article>
<div class="br-nav">
<?php if ($prev > 0): ?>
<a class="btn btn-ghost" href="<?= e(url('books/read', ['id' => (int)$b['id'], 'seq' => $prev])) ?>">
← 上一章
</a>
<?php endif; ?>
<span class="br-pos small muted"><?= $seq ?> / <?= $total ?></span>
<?php if ($next > 0): ?>
<a class="btn" href="<?= e(url('books/read', ['id' => (int)$b['id'], 'seq' => $next])) ?>">
下一章 →
</a>
<?php else: ?>
<span class="small muted">已经是最后一章了</span>
<?php endif; ?>
</div>
<?php endif; ?>
</div>
</div>