v26 第 26 批(5 条):财务多选按集合取图 / 首页全天置顶与红线定位 / 任务复选框去提示与看板颜色 / 导航搜索引擎切换与站点复用 / 详情页去复选框
- 财务:勾选多个标签时上面那张「总金额」图按**选中集合**统计(新增 ledger/total_chart 路由 + 单一容器 data-ck-total-host,按集合现取并缓存; Ledger::timeline 第二参数放宽为 string|array) - 首页日程:全天日程移出滚动容器固定置顶;进场把当前时刻红线居中 (scrollTop 计算,不用 scrollIntoView),触发条件不绑 $showNow - 任务:复选框去除 title 提示;看板可设颜色(Task::boardColor/updateBoard), 首页任务行用该颜色显示所属看板 - 导航:展示页补回 id=engine-tabs(切换搜索引擎无效的根因);补内置引擎; 新增站点输 URL 可复用他人已加过的站点(sharedByUrl/copyIconFile/adoptSite) - 任务详情页页头去掉复选框(已有「标记完成」按钮)
This commit is contained in:
+95
-20
@@ -222,22 +222,34 @@ $showNow = $nowPos >= 0 && $nowPos <= 1;
|
||||
<h2 class="cinema-h2">今天的日程</h2>
|
||||
<a class="btn btn-ghost btn-sm" href="<?= e(url('calendar')) ?>">看整月</a>
|
||||
</div>
|
||||
<div class="hd-pane-body">
|
||||
<?php if (!$todayEvents): ?>
|
||||
<?php /* 🔴 v24 第 26 批 用户第 2 条(前半):「今天的日程,除了全天日程**一直显示在上面**外,
|
||||
其他日程随着滚动」。
|
||||
⇒ DOM 结构必须分成两层:
|
||||
① `.ag-allday` **留在 pane 里、不在滚动容器内** —— 它永远钉在标题下方;
|
||||
② `.hd-pane-body`(滚动容器)**只包** `.ag-grid` —— 只有时段网格随滚动。
|
||||
为什么不能在同一个滚动容器里给全天区 `position: sticky`:
|
||||
它在滚动区**内部**,sticky 只能粘在滚动区顶端,而滚动区顶端在标题下面 ——
|
||||
滚起来时全天区会被"标题 + 滚动区"两层挤着,看起来仍然在动;
|
||||
而且 sticky 需要不透明底色遮住底下滚过去的日程,与现在的浅色卡片叠色不好看。
|
||||
直接把它移出滚动容器,是**零副作用**的做法。 */ ?>
|
||||
<?php if (!$todayEvents): ?>
|
||||
<div class="hd-pane-body">
|
||||
<p class="empty-hint">今天没有安排。</p>
|
||||
<?php else: ?>
|
||||
<?php if ($allDay): ?>
|
||||
<div class="ag-allday">
|
||||
<?php foreach ($allDay as $ev): ?>
|
||||
<a class="ag-allday-item" href="<?= e((string)$ev['href']) ?>">
|
||||
<span class="dash-dot" style="background:<?= e((string)$ev['color']) ?>;"></span>
|
||||
<span class="ag-ad-t">全天</span>
|
||||
<span class="ag-ad-w"><?= e((string)$ev['title']) ?></span>
|
||||
<span class="dash-cal" style="background:<?= e((string)$ev['color']) ?>;"><?= e((string)$ev['calname']) ?></span>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php if ($allDay): ?>
|
||||
<div class="ag-allday">
|
||||
<?php foreach ($allDay as $ev): ?>
|
||||
<a class="ag-allday-item" href="<?= e((string)$ev['href']) ?>">
|
||||
<span class="dash-dot" style="background:<?= e((string)$ev['color']) ?>;"></span>
|
||||
<span class="ag-ad-t">全天</span>
|
||||
<span class="ag-ad-w"><?= e((string)$ev['title']) ?></span>
|
||||
<span class="dash-cal" style="background:<?= e((string)$ev['color']) ?>;"><?= e((string)$ev['calname']) ?></span>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<div class="hd-pane-body" data-ag-scroll>
|
||||
<div class="ag-grid">
|
||||
<?php for ($h = $startH; $h < $endH; $h++): ?>
|
||||
<div class="ag-row">
|
||||
@@ -266,10 +278,10 @@ $showNow = $nowPos >= 0 && $nowPos <= 1;
|
||||
<span class="dash-cal" style="background:<?= e((string)$ev['color']) ?>;"><?= e((string)$ev['calname']) ?></span>
|
||||
</a>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div><?php /* /.ag-grid */ ?>
|
||||
</div><?php /* /.hd-pane-body(滚动区,只含时段网格) */ ?>
|
||||
<?php endif; ?>
|
||||
</div><?php /* /.hd-pane */ ?>
|
||||
|
||||
<?php /* ---- 右:进行中的任务(标题 + 状态 + 看板名)---- */ ?>
|
||||
<div class="card card-pad hd-pane" id="homeTasks">
|
||||
@@ -305,7 +317,16 @@ $showNow = $nowPos >= 0 && $nowPos <= 1;
|
||||
</span>
|
||||
<?php /* 用户第 3 条:「还要显示他所处的看板的名称,就是他现在被放在哪一个看板里面」 */ ?>
|
||||
<?php if (trim((string)($t['board_name'] ?? '')) !== ''): ?>
|
||||
<span class="tk-board"><?= e((string)$t['board_name']) ?></span>
|
||||
<?php /* 🔴 v24 第 26 批 用户第 3 条(后半):「任务在设置看板的时候,可以选择颜色,
|
||||
这样在首页列表中显示的时候,就可以更加直观的看到他属于哪个看板。」
|
||||
⇒ 徽标**同时带颜色**:左边一个小圆点(看板色)+ 看板名。
|
||||
为什么不用"整块背景染色":首页这一行已经有状态徽标、看板徽标、逾期等几个
|
||||
色块,整块染色会互相打架、反而看不出哪个色对应哪个语义。
|
||||
一个小圆点信息量足够、又不抢戏。 */
|
||||
$bColor = \App\Task::boardColor($t['board_color'] ?? null, (string)$t['board_name']); ?>
|
||||
<span class="tk-board" style="--bc: <?= e($bColor) ?>;">
|
||||
<i class="tk-board-dot" aria-hidden="true"></i><?= e((string)$t['board_name']) ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
<?php if ((int)($t['child_total'] ?? 0) > 0): ?>
|
||||
<span class="dash-tag"><?= (int)$t['child_done'] ?>/<?= (int)$t['child_total'] ?></span>
|
||||
@@ -422,4 +443,58 @@ $showNow = $nowPos >= 0 && $nowPos <= 1;
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php /* ==================== 日程滚动区:进场定位到当前时刻(v24 第 26 批 用户第 2 条)======
|
||||
用户原话:「每次进来,都要定位到当前时刻,就是红线出现的位置,让红线在中间。」
|
||||
⇒ 打开首页时把**滚动容器**滚到一个位置,使"当前时刻"落在可视区**正中**。
|
||||
|
||||
⚠️ 触发条件只看**网格在不在**(`$timed` 非空才有网格),**不要**再加 `$showNow`。
|
||||
第一版写了 `if (!empty($timed) && $showNow)`,后果是:
|
||||
· 红线落在区间外(现在 23:40、日程只到 18 点 → 页面不画红线)时**整段脚本不渲染**
|
||||
→ "每次进来都要定位"这条需求在最常见的场景(晚上开首页)直接失效;
|
||||
· 更糟的是**判据依赖了被优化掉的东西**:探针那次库里没有分时段日程,
|
||||
脚本根本没输出,页面看着"没报错",实测 `scrollTop=0`(本轮实测抓到的)。
|
||||
⇒ 现在:**有网格就定位**。红线在就对齐红线;红线不在(在区间外)就用
|
||||
`$nowPos` 同一个比例算出"此刻"在网格里的位置来对齐(数值同源,不会两套口径)。
|
||||
|
||||
⚠️ 用 `scrollTop = 目标偏移 - 容器高/2`,**不要**用 `scrollIntoView({block:'center'})`:
|
||||
它会**连带滚动外层页面**(把整个浏览器窗口也滚下去),
|
||||
用户一进首页就被拽到"页面中部" —— 那比不定位更糟。
|
||||
直接给容器赋 `scrollTop` 只动这一个盒子,外层纹丝不动。
|
||||
⚠️ 容器"没得滚"时(内容比容器矮)赋任何值都是 0,天然安全,不必特判。
|
||||
⚠️ 目标位置**由服务端算好**传进来(`$nowPos`),不在 JS 里再算一遍时间 ——
|
||||
两处各算一次迟早不一致(服务端用的是站点时区,JS 用的是浏览器时区)。 */ ?>
|
||||
<?php if (!$todayEvents || empty($timed)): ?>
|
||||
<?php /* 没有分时段日程 → 没有网格可滚,什么都不做 */ ?>
|
||||
<?php else: ?>
|
||||
<script>
|
||||
(function () {
|
||||
var box = document.querySelector('[data-ag-scroll]');
|
||||
if (!box) { return; }
|
||||
// 红线(在的话)优先;不在就用服务端算好的 nowPos 现算一个位置。
|
||||
var line = box.querySelector('.ag-now');
|
||||
var RATIO = <?= json_encode(round($nowPos, 6)) ?>; // 0~1(可能落在区间外)
|
||||
function targetOffset() {
|
||||
if (line) { return line.offsetTop; }
|
||||
var grid = box.querySelector('.ag-grid');
|
||||
if (!grid) { return 0; }
|
||||
// ⚠️ 用**排掉全天区之后**的内容高度算:全天区现在不在滚动容器里,
|
||||
// 所以 grid 的高度就是"整条时间轴"的高度(与服务端算 nowPos 的口径一致)。
|
||||
return grid.offsetHeight * RATIO;
|
||||
}
|
||||
function centerOnNow() {
|
||||
// offsetTop 相对**定位祖先**(.ag-grid,position:relative),即"内容坐标"
|
||||
box.scrollTop = Math.max(0, targetOffset() - (box.clientHeight / 2));
|
||||
}
|
||||
centerOnNow();
|
||||
/* ⚠️ 再补两拍:字体加载完 / 浏览器恢复滚动位置(back-forward cache)之后,
|
||||
内容高度会变,第一次算出来的 scrollTop 可能偏。
|
||||
用 rAF 而不是 setTimeout:rAF 在排版完成后跑,时序更准;
|
||||
两拍是为了覆盖"布局在渲染后才最终确定"的那一帧。 */
|
||||
if (window.requestAnimationFrame) {
|
||||
requestAnimationFrame(function () { requestAnimationFrame(centerOnNow); });
|
||||
}
|
||||
})();
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
Reference in New Issue
Block a user