任务面板:加保存按钮,负责人和分类改为可编辑 (#76)
用户 2026-11-05:「时间控件是对的,但是现在没有保存按钮,只有下面一个
评论的发表按钮。另外,负责人和分类都没法修改,按道理讲都应该可以修改才对。」
三处改动:
① 取消"立即保存",改成显式「保存」按钮
上一版(#74)做的是"选完截止时间就发请求"。用户不认可:他要的是
"改完点一下保存"那种确定感。
⇒ 移除 bindDue() 的 change 监听,改成 save-attrs 动作一次性提交三项。
② 负责人 / 分类 从只读改成可编辑
改前是只读 dl.kv 行,而且**值为空时整行不渲染**
(if (!empty($tpT[assignee_name])) / if ($tpCatName !== ))
⇒ 用户不仅改不了,连"这一项存在"都看不出来。
现在三项合成「更多信息」小节:
截止 [ AntD 日期控件 ]
负责人 [ 下拉 ]
分类 [ 下拉 ]
[ 保存 ]
负责人用原生 select 而不是 _person_picker.php 的弹窗选人:
面板已在浮层里,再弹一层模态 = 两层遮罩,手机上容易点错;
且 picker 需要 fbInitPickers() 初始化,loadPanel() 目前没调它。
家里 3~10 人 select 够用;人多了再换,那时记得把 fbInitPickers
也补进 loadPanel()。
③ Task::setAttrs()(新增)
只更新 due_at / assignee_id / category_id 三列。
不复用 update():那是全字段覆盖,面板只交三项的话
title/note/status/repeat/parent/board 会被默认值抹空
—— 与 setDue() 记的是同一个坑。
用 array_key_exists 判"传没传",这样可以只改其中一项
(面板在"没有成员"等极端情况下可能不渲染负责人下拉,
那时不该把它当成 0 去清掉原值)。
路由 tasks/panel_save:只把表单**真的提交了**的字段放进 $sd,
与 status/move 同一套约定(ajax_panel=1 回整块新面板)。
清理:bindDue / window.fbTaskPanelBindDue 全部移除
(entry_popup.js 里的调用、task_panel.js 里的定义与导出)
—— 留着会引用未定义函数,直接抛错。
实测:
三项一起改 => due_at/assignee/category 全对 ✅
标题/状态/备注/看板 均未被破坏 ✅
只改 due_at => 另两项保留、未被清空 ✅
面板渲染 => save-url / 保存按钮 / 两个下拉 / AntD 控件 /
原有状态/附件/评论 全部在位 ✅
This commit is contained in:
+90
-40
@@ -77,7 +77,9 @@ $tpLate = $tpDue !== '' && $tpStatus !== 'done' && \App\Task::isOverdue($tpD
|
||||
data-tk-url-cmt-del="<?= e(url('tasks/comment_del')) ?>"
|
||||
data-tk-url-attach="<?= e(url('tasks/attach_add')) ?>"
|
||||
<?php /* #74:面板里直接改截止时间(不必点「编辑」进整页表单) */ ?>
|
||||
data-tk-url-due="<?= e(url('tasks/due')) ?>">
|
||||
data-tk-url-due="<?= e(url('tasks/due')) ?>"
|
||||
<?php /* #76:截止/负责人/分类 三项一起保存(用户要显式「保存」按钮) */ ?>
|
||||
data-tk-url-save="<?= e(url('tasks/panel_save')) ?>">
|
||||
<?php /* CSRF 放在面板里(见头部第 ① 条):表单各自带一份,JS 里的按钮动作
|
||||
从这里取一份 —— 两处同一个值,`csrf_token()` 天然幂等。 */ ?>
|
||||
<input type="hidden" name="_csrf" value="<?= e(csrf_token()) ?>" data-tk-csrf>
|
||||
@@ -125,51 +127,99 @@ $tpLate = $tpDue !== '' && $tpStatus !== 'done' && \App\Task::isOverdue($tpD
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php /* ---- 截止时间:**可直接改**(#74) ----
|
||||
用户 2026-11-05:「点开之后,就可以修改任务的所有信息,包括…
|
||||
修改截止时间。当然,如果现在已经有截止时间,就把它带进来。」
|
||||
<?php /* ---- 更多信息:截止 / 负责人 / 分类 ---- 可编辑 + 保存(#76) ----
|
||||
|
||||
🔴 原来是**只读的一行**:
|
||||
<?php if ($tpDue !== ''): ?><div class="kv-row"><dt>截止</dt><dd>…</dd></div><?php endif; ?>
|
||||
而且**没有截止时间时整行连显示都不显示** —— 用户根本不知道该去哪填。
|
||||
⇒ 换成与 `_edit_form.php` 同一套的 AntD 单点控件(`dtPlugin=antd-single`),
|
||||
并且**不管有没有值都画出来**(空着就是"还没设",比"没有这个字段"清楚)。
|
||||
`$dtValue = $tpDue` ⇒ 已有截止时间会带进控件(用户明确要求)。
|
||||
🔴 用户 2026-11-05:「时间控件是对的,但是现在没有保存按钮,只有下面一个
|
||||
评论的发表按钮。另外,负责人和分类都没法修改,按道理讲都应该可以修改才对。」
|
||||
|
||||
⚠️ 控件里改完**立即保存**(`data-tk-act="due"`,见 task_panel.js),
|
||||
与状态/看板/子任务/评论/附件同一套交互 —— 面板里不该有"保存按钮"。
|
||||
⚠️ 这个面板是 AJAX 塞进来的,AntD 要靠 `fbBootAntd()` 补挂,
|
||||
见 task_panel.js 的 paint()。 */ ?>
|
||||
<div class="tk-sec tk-sec-inline">
|
||||
<span class="tk-sec-lb">截止</span>
|
||||
<?php if ($tpCan): ?>
|
||||
<?php
|
||||
/* ⚠️ 变量名必须与 `_datetime.php` 的约定一致;
|
||||
它内部一律用 `dt` 前缀的临时变量,不会踩到这里的 $tp* 或宿主页的 $t。 */
|
||||
$dtName = 'due_at';
|
||||
$dtValue = $tpDue;
|
||||
$dtPlugin = 'antd-single';
|
||||
$dtRequired = false;
|
||||
require __DIR__ . '/../_datetime.php';
|
||||
?>
|
||||
<?php if ($tpDueWord !== ''): ?>
|
||||
<span class="tk-due-word<?= $tpLate ? ' kb-late' : '' ?>"><?= e($tpDueWord) ?></span>
|
||||
改之前的状态:
|
||||
· 截止:上一版做成"选完立即保存",用户不认可 —— 他要显式保存按钮;
|
||||
· 负责人 / 分类:**只读的 `dl.kv` 行**,而且值为空时整行都不渲染
|
||||
(`if (!empty($tpT['assignee_name']))` / `if ($tpCatName !== '')`)
|
||||
⇒ 用户不仅改不了,连"这一项存在"都看不出来。
|
||||
|
||||
⇒ 三项合成一个带「保存」的小节:先改完,点一次提交。
|
||||
`Task::setAttrs()` 只写这三列,不碰 title/note/status(见那里的说明)。
|
||||
|
||||
⚠️ 负责人用原生 `<select>` 而不是 `_person_picker.php` 的弹窗选人:
|
||||
面板本身已在浮层里,再弹一层模态 = 两层遮罩,手机上很容易点错;
|
||||
而且 picker 需要 `fbInitPickers()` 初始化,`loadPanel()` 目前没调它。
|
||||
家庭成员通常 3~10 人,select 够用。**人多了再换弹窗**,那时记得
|
||||
把 `fbInitPickers` 也补进 `loadPanel()`。 */ ?>
|
||||
<div class="tk-sec">
|
||||
<div class="tk-sec-h">更多信息</div>
|
||||
<div class="tk-attrs">
|
||||
<div class="tk-attr-row">
|
||||
<span class="tk-attr-lb">截止</span>
|
||||
<?php if ($tpCan): ?>
|
||||
<?php
|
||||
/* ⚠️ 变量名必须与 `_datetime.php` 的约定一致;
|
||||
它内部一律用 `dt` 前缀的临时变量,不会踩到这里的 $tp* 或宿主页的 $t。 */
|
||||
$dtName = 'due_at';
|
||||
$dtValue = $tpDue;
|
||||
$dtPlugin = 'antd-single';
|
||||
$dtRequired = false;
|
||||
$dtId = 'tkp-due';
|
||||
require __DIR__ . '/../_datetime.php';
|
||||
?>
|
||||
<?php if ($tpDueWord !== ''): ?>
|
||||
<span class="tk-due-word<?= $tpLate ? ' kb-late' : '' ?>"><?= e($tpDueWord) ?></span>
|
||||
<?php endif; ?>
|
||||
<?php else: ?>
|
||||
<span class="<?= $tpLate ? 'kb-late' : '' ?>"><?= $tpDue !== '' ? e($tpDue) : '未设' ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="tk-attr-row">
|
||||
<span class="tk-attr-lb">负责人</span>
|
||||
<?php if ($tpCan): ?>
|
||||
<select class="select" name="assignee_id" id="tkp-assignee">
|
||||
<option value="0">不指定</option>
|
||||
<?php foreach ($tpPeople as $tpP): ?>
|
||||
<?php $tpPid = (int)($tpP['id'] ?? 0); ?>
|
||||
<option value="<?= $tpPid ?>"
|
||||
<?= $tpPid === (int)($tpT['assignee_id'] ?? 0) ? ' selected' : '' ?>>
|
||||
<?= e(person_name($tpP)) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<?php else: ?>
|
||||
<span><?= !empty($tpT['assignee_name'])
|
||||
? e(person_name(['name' => $tpT['assignee_name'],
|
||||
'my_nickname' => $tpT['assignee_nick'] ?? '']))
|
||||
: '不指定' ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="tk-attr-row">
|
||||
<span class="tk-attr-lb">分类</span>
|
||||
<?php if ($tpCan): ?>
|
||||
<select class="select" name="category_id" id="tkp-category">
|
||||
<option value="0">未分类</option>
|
||||
<?php foreach ($tpCats as $tpC): ?>
|
||||
<?php $tpCid = (int)($tpC['id'] ?? 0); ?>
|
||||
<option value="<?= $tpCid ?>"
|
||||
<?= $tpCid === (int)($tpT['category_id'] ?? 0) ? ' selected' : '' ?>>
|
||||
<?= e((string)($tpC['name'] ?? '')) ?>
|
||||
</option>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
<?php else: ?>
|
||||
<span><?= $tpCatName !== '' ? e($tpCatName) : '未分类' ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ($tpCan): ?>
|
||||
<div class="tk-attr-actions">
|
||||
<button type="button" class="btn btn-sm" data-tk-act="save-attrs">保存</button>
|
||||
<span class="tk-attr-tip" data-tk-save-tip hidden>已保存</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php else: ?>
|
||||
<span class="<?= $tpLate ? 'kb-late' : '' ?>"><?= $tpDue !== '' ? e($tpDue) : '未设' ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php /* ---- 只读的事实(有才显示) ---- */ ?>
|
||||
<?php /* ---- 其余只读事实(循环 / 备注) ---- */ ?>
|
||||
<dl class="kv tk-kv">
|
||||
<?php if (!empty($tpT['assignee_name'])): ?>
|
||||
<div class="kv-row"><dt>负责人</dt>
|
||||
<dd><?= e(person_name(['name' => $tpT['assignee_name'], 'my_nickname' => $tpT['assignee_nick'] ?? ''])) ?></dd>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ($tpCatName !== ''): ?>
|
||||
<div class="kv-row"><dt>分类</dt><dd><?= e($tpCatName) ?></dd></div>
|
||||
<?php endif; ?>
|
||||
<?php if (!empty($tpT['repeat_rule'])): ?>
|
||||
<div class="kv-row"><dt>循环</dt><dd><?= e(\App\Task::repeatWord((string)$tpT['repeat_rule'])) ?></dd></div>
|
||||
<?php endif; ?>
|
||||
|
||||
Reference in New Issue
Block a user