Files
FamilyBook/templates/notes/index.php
T
laoyang 6852b4ee2c v28 第 28 批(12 条):名册分组改标签 / 资源合并为两按钮 / 首页定位与主题色 / 笔记富文本双模式
其中 4 条是**上批遗漏的真 bug**(1/4/8/9),根因已逐条定位:

1. 首页日程没定位到红线 —— 真根因:刻度区间**不含当前时刻** → $showNow=false
   → 红线**整个不渲染**,而定位脚本用同一个越界比例算目标,被 clamp 到底部。
   修:把当前小时并进区间端点(现在必然落在区间内)。
2. 「看整月」→「更多日程」+ 日程主题色;3. 「手头在做」→「近期任务」、
   「任务看板」→「全部任务」+ 任务主题色(注入 --hd-c,不再写死白底)。
4. 任务复选框提示还在 —— 真根因:**JS 在点击后**给状态徽标挂 title
   (`badge.setAttribute('title',…)`),上批只去了静态渲染,静态断言永远抓不到。
5. 名册「分组」→「标签」(用户:一个人可能既是小学同学又是初中同学,没法分组):
   新增 person_tags(每人一份、一人多标签),名册改**平铺 + 顶部标签筛选**;
   🔴 迁移用**一次性哨兵**(第一版用 NOT EXISTS,实测被"用户清空标签"绕过 → 旧分组名被灌回)。
6. 名册卡片按钮加语义底色。
7. 资源四按钮 → **编辑 / 删除**两颗:三块内容进一个带页签的弹框(信息/附件/共享)。
8. 财务多选数字不变 —— 真根因:前端发 `kinds=a,b`(逗号串),服务端 `(array)` 收成
   单元素 → 求交为空 → **静默回落整本账**。修:两种形状都收。
9. 微信读书偶发很慢 —— 真根因:syncNow 扫 60 本 × 每本 1~3 次网关调用(单次超时 20s),
   全同步阻塞在列表页请求里。修:总时长预算 + 单次超时 8s + 自动/手动分批。
10. 新增全局可见的联想接口库(6 个实测可用来源)+ 三种新解析类型。
11. 导航右上角「设置」:默认进"添加网址 + 全部网址",四类设置收进 ?set=1 视图。
12. 笔记:段落/清单支持 Markdown(自研渲染器,**不允许原始 HTML**),
    实时预览走服务端(前后端只一份规则);底部附件上传;清单多级;
    列表改**定尺寸卡片网格**(溢出显示摘要、图片缩放下方);按用户要求**去掉标签侧栏**。
2026-10-08 02:20:19 +08:00

163 lines
6.9 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
/**
* 个人笔记 · 列表(v27 建;v28 用户第 12 条重构)。
*
* 🔴 v28 第 12 条原话:「笔记列表页面,要注意大小,要么按照列表展示,要么按照块展示,
* 一行几个块,但是块大小要确定,如果显示不下,就显示简要信息,图片缩放后,放在下面。
* 这样看起来更美观。标签这个侧边栏,我感觉可以不要。」
*
* ⇒ 两处改动:
* ① **定尺寸卡片网格**(一行多个)—— 卡片高度固定,装不下就显示摘要,
* 图片等比缩放在卡片下方。原来是一列长卡片(一条占整屏),列表页很长、很难扫。
* ② **去掉左侧标签栏** —— 标签筛选改成顶部一条细筛选条(占位小得多),
* 宽度全给卡片。"可以不要"是用户的判断,照做。
*
* ⚠️ 卡片高度**固定**(CSS 里给固定高度 + 内容裁切),这是用户明确要求
* "块大小要确定"。所以卡片里不能放"会撑高的东西":
* · 正文只放**摘要**(不渲染全部块);
* · 图片只放第一张缩略图(按卡片宽度等比缩放,不会把卡片顶高)。
*
* @param array $rows 我能看到的笔记(带 blocks / tags / excerpt / is_mine)
* @param array $tagCloud 标签 + 条数
* @param string $keyword 搜索词
* @param string $tag 当前筛的标签
* @param int $totalAll 一共几条
* @param bool $showAll 是否已展开全部
* @param int $limit 列表默认条数
*/
$canWrite = \App\Auth::canWrite();
?>
<div class="page-head">
<h1>笔记</h1>
<span class="sub">共 <?= (int)$totalAll ?> 条</span>
<div class="actions">
<?php if ($canWrite): ?>
<a class="btn" href="<?= e(url('notes/form')) ?>">写笔记</a>
<?php else: ?>
<span class="link-quiet">只读账号</span>
<?php endif; ?>
</div>
</div>
<?php /* ---------------- 顶部:搜索 + 标签筛选(v28 去掉了左侧标签栏)---------------- */ ?>
<div class="card card-pad note-bar">
<form class="search note-search" method="get" action="index.php">
<input type="hidden" name="r" value="notes">
<?php if ($tag !== ''): ?>
<input type="hidden" name="tag" value="<?= e($tag) ?>">
<?php endif; ?>
<label class="sr-only" for="noteKw">搜索笔记</label>
<input class="input" id="noteKw" name="keyword" value="<?= e($keyword) ?>"
placeholder="搜标题 / 正文 / 标签" autocomplete="off">
<button class="btn btn-ghost btn-sm" type="submit">搜索</button>
<?php if ($keyword !== '' || $tag !== ''): ?>
<a class="btn btn-ghost btn-sm" href="<?= e(url('notes')) ?>">清除</a>
<?php endif; ?>
</form>
<?php if ($tagCloud): ?>
<div class="note-tags note-tagbar">
<a class="note-tag<?= $tag === '' ? ' is-on' : '' ?>" href="<?= e(url('notes')) ?>">
全部 <b><?= (int)$totalAll ?></b>
</a>
<?php foreach ($tagCloud as $t): ?>
<a class="note-tag<?= $tag === (string)$t['tag'] ? ' is-on' : '' ?>"
href="<?= e(url('notes', ['tag' => (string)$t['tag']])) ?>">
#<?= e((string)$t['tag']) ?> <b><?= (int)$t['n'] ?></b>
</a>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<?php if (!$rows): ?>
<div class="card card-pad">
<p class="empty-hint">
<?php if ($keyword !== '' || $tag !== ''): ?>
没有匹配的笔记。
<?php elseif ($canWrite): ?>
还没有笔记。点右上角「写笔记」随手记一条吧。
<?php else: ?>
还没有笔记。
<?php endif; ?>
</p>
</div>
<?php else: ?>
<?php /* 定尺寸网格:一行多个,卡片高度固定(用户第 12 条"块大小要确定") */ ?>
<div class="note-grid">
<?php foreach ($rows as $n): ?>
<?php
$mine = !empty($n['is_mine']);
$nid = (int)$n['id'];
$title = trim((string)$n['title']);
// 卡片上的第一张图(等比缩放在卡片下方)—— 只取一张,多了会把卡片顶高
$firstImg = '';
foreach ((array)$n['blocks'] as $b) {
if ((string)$b['kind'] === 'image' && (string)$b['content'] !== '') {
$firstImg = (string)$b['content'];
break;
}
}
?>
<article class="note-card" data-note="<?= $nid ?>">
<header class="note-head">
<span class="note-meta">
<?php if (!empty($n['is_shared'])): ?>
<span class="note-share" title="全家可见">共享</span>
<?php else: ?>
<span class="note-private" title="只有自己可见">私有</span>
<?php endif; ?>
<span class="note-time"><?= e(substr((string)$n['updated_at'], 0, 16)) ?></span>
</span>
<?php if ($mine && $canWrite): ?>
<span class="note-ops">
<a class="note-op" href="<?= e(url('notes/form', ['id' => $nid])) ?>"
title="编辑这条笔记">改</a>
<form method="post" action="<?= e(url('notes/destroy')) ?>" class="inline-form"
onsubmit="return confirm('删掉这条笔记?');">
<?= csrf_field() ?>
<input type="hidden" name="id" value="<?= $nid ?>">
<button type="submit" class="note-op note-op-del" title="删除这条笔记">删</button>
</form>
</span>
<?php endif; ?>
</header>
<a class="note-hit" href="<?= e(url('notes/form', ['id' => $nid])) ?>">
<?php if ($title !== ''): ?>
<h3 class="note-title"><?= e($title) ?></h3>
<?php endif; ?>
<?php if (trim((string)($n['excerpt'] ?? '')) !== ''): ?>
<p class="note-ex"><?= e((string)$n['excerpt']) ?></p>
<?php elseif ($title === ''): ?>
<p class="note-ex note-ex-empty">(这条笔记没有正文)</p>
<?php endif; ?>
</a>
<?php /* 图片:等比缩放到卡片宽度,放在摘要下方(用户第 12 条原话) */ ?>
<?php if ($firstImg !== ''): ?>
<div class="note-thumb">
<img src="<?= e(media_url($firstImg)) ?>" alt="" loading="lazy" decoding="async">
</div>
<?php endif; ?>
<?php if (!empty($n['tags'])): ?>
<div class="note-tags note-tags-inline">
<?php foreach ((array)$n['tags'] as $t): ?>
<a class="note-tag" href="<?= e(url('notes', ['tag' => (string)$t])) ?>">
#<?= e((string)$t) ?>
</a>
<?php endforeach; ?>
</div>
<?php endif; ?>
</article>
<?php endforeach; ?>
</div>
<?php if (!$showAll && (int)$totalAll > count($rows)): ?>
<div class="note-more">
<a class="btn btn-ghost" href="<?= e(url('notes', ['all' => 1, 'keyword' => $keyword, 'tag' => $tag])) ?>">
显示全部 <?= (int)$totalAll ?> 条
</a>
</div>
<?php endif; ?>
<?php endif; ?>