任务面板:加保存按钮,负责人和分类改为可编辑 (#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:
@@ -749,6 +749,56 @@ final class Task
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 只更新「截止时间 / 负责人 / 分类」三项(#76)。
|
||||
*
|
||||
* 🔴 用户 2026-11-05:「负责人和分类都没法修改,按道理讲都应该可以修改才对。」
|
||||
* 上一版面板里这三项都是只读的 `dl.kv` 行。
|
||||
*
|
||||
* ⚠️ **不要复用 `update()`**:那是全字段覆盖。面板只交这三项的话,
|
||||
* title / note / status / repeat / parent / board 会被默认值抹空 ——
|
||||
* 与 `setDue()` 记的是同一个坑。
|
||||
*
|
||||
* ⚠️ 三个参数都「显式传」才算改:`due_at` 传 `null` = 不动;
|
||||
* 传 `''` = 清掉。这样调用方可以只改其中一项。
|
||||
* (用 `array_key_exists` 判"传没传",而不是 `isset` ——
|
||||
* `isset(null)` 为 false,会把"显式传 null"误判成"没传"。)
|
||||
*
|
||||
* @param array $d 可含 due_at / assignee_id / category_id
|
||||
*/
|
||||
public static function setAttrs(int $familyId, int $id, array $d): bool
|
||||
{
|
||||
$old = self::row($familyId, $id);
|
||||
if (!$old) {
|
||||
return false;
|
||||
}
|
||||
$sets = [];
|
||||
$args = [];
|
||||
if (array_key_exists('due_at', $d)) {
|
||||
$sets[] = 'due_at = ?';
|
||||
$args[] = self::dtOrNull((string)($d['due_at'] ?? ''));
|
||||
}
|
||||
if (array_key_exists('assignee_id', $d)) {
|
||||
/* 0 / 空 = 不指定(存 NULL,与 update() 里 `?: null` 同一口径) */
|
||||
$sets[] = 'assignee_id = ?';
|
||||
$aid = (int)($d['assignee_id'] ?? 0);
|
||||
$args[] = $aid > 0 ? $aid : null;
|
||||
}
|
||||
if (array_key_exists('category_id', $d)) {
|
||||
$sets[] = 'category_id = ?';
|
||||
$args[] = self::categoryIdOf($familyId, (int)($d['category_id'] ?? 0));
|
||||
}
|
||||
if (!$sets) {
|
||||
return true; // 三个都没传:什么都不做,但也算"成功"(幂等)
|
||||
}
|
||||
$args[] = $id;
|
||||
$args[] = $familyId;
|
||||
Database::get()->prepare(
|
||||
'UPDATE tasks SET ' . implode(', ', $sets) . ' WHERE id = ? AND family_id = ?'
|
||||
)->execute($args);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static function setStatus(int $familyId, int $id, string $status, int $position = 0): int
|
||||
{
|
||||
$old = self::row($familyId, $id);
|
||||
|
||||
@@ -6930,6 +6930,29 @@ h6.md-h { font-size: 17px; color: var(--muted); }
|
||||
/* 「还剩 3 天」那类小字:贴在控件右边,不与控件抢宽度 */
|
||||
.tk-due-word { flex: 0 0 auto; font-size: 12.5px; color: var(--faint); white-space: nowrap; }
|
||||
.tk-due-word.kb-late { color: var(--red); }
|
||||
|
||||
/* 🔴 #76:「更多信息」小节 —— 截止 / 负责人 / 分类 三行 + 保存。
|
||||
用户 2026-11-05:「没有保存按钮…负责人和分类都没法修改。」
|
||||
每行结构 = 固定宽标签 + 占满剩余宽度的控件,与 .mv-row 同一套观感
|
||||
(但标签用 tk-attr-lb,因为面板里字号比整页表单小一号)。 */
|
||||
.tk-attrs { display: flex; flex-direction: column; gap: 10px; }
|
||||
.tk-attr-row {
|
||||
display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
|
||||
}
|
||||
.tk-attr-lb {
|
||||
flex: 0 0 46px; font-size: 12.5px; color: var(--faint); text-align: right;
|
||||
}
|
||||
/* 控件区占满标签右侧(min-width:0 让它能被压缩,不会把标签挤出去) */
|
||||
.tk-attr-row > *:not(.tk-attr-lb) { flex: 1 1 auto; min-width: 0; }
|
||||
/* AntD 的 picker 本身有固定宽度,别让它撑满整行 */
|
||||
.tk-attr-row > .dt-input { max-width: 300px; }
|
||||
.tk-attr-row > select.select { max-width: 300px; }
|
||||
/* 保存按钮那一行:与上面的控件左缘对齐(= 46px 标签宽 + 10px gap) */
|
||||
.tk-attr-actions {
|
||||
display: flex; align-items: center; gap: 10px;
|
||||
padding-left: 56px;
|
||||
}
|
||||
.tk-attr-tip { font-size: 12px; color: var(--green, #2E7D4F); }
|
||||
.tk-sec-lb { flex: 0 0 34px; font-size: 12.5px; color: var(--faint); }
|
||||
.tk-seg { display: flex; gap: 6px; flex-wrap: wrap; }
|
||||
/* 面板里的状态徽标比卡片上的大一档(这里是要点的按钮,不是标签) */
|
||||
|
||||
@@ -226,10 +226,6 @@
|
||||
if (typeof window.fbBootAntd === 'function') {
|
||||
try { window.fbBootAntd(); } catch (e) { /* 挂不上就留在原生下拉,不阻断面板 */ }
|
||||
}
|
||||
/* 截止控件的 change 监听(#74):首次打开也要绑,否则选完时间不会保存 */
|
||||
if (typeof window.fbTaskPanelBindDue === 'function') {
|
||||
try { window.fbTaskPanelBindDue(); } catch (e) { /* 忽略 */ }
|
||||
}
|
||||
})
|
||||
.catch(function () {
|
||||
if (!bodyEl()) { return; }
|
||||
|
||||
+43
-58
@@ -92,56 +92,9 @@
|
||||
if (typeof window.fbBootAntd === 'function') {
|
||||
try { window.fbBootAntd(); } catch (err) { /* 挂不上就留在原生下拉,不阻断面板 */ }
|
||||
}
|
||||
/* 重画之后节点是新的 ⇒ 监听要重新绑一遍(旧的已经随旧节点一起没了) */
|
||||
bindDue();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 监听「截止时间」控件的变化,改完**立即保存**(#74)。
|
||||
*
|
||||
* 为什么不用 `data-tk-act="due"` 那种按钮:
|
||||
* 面板里其它动作都是"点一下就生效",截止时间是**选完时间**就该生效,
|
||||
* 再让用户点一次「保存」会让这一处与其它处不一致。
|
||||
*
|
||||
* 为什么监听**隐藏字段的 change** 而不是 AntD 的回调:
|
||||
* · AntD 挂载时会把选中的值写回 `.dt-date` / `.dt-hour` / `.dt-minute`
|
||||
* 这些原生字段,并 copy 一个 `change` 事件(见 app.js 的 writeDT);
|
||||
* · 原生下拉那一档(AntD 没挂上时的兜底)也是同一批发 `change`;
|
||||
* · ⇒ 监听一次就能覆盖**两种形态**,不用分别处理。
|
||||
*
|
||||
* ⚠️ `data-fb-due-bound` 幂等标记:`bindDue()` 在每次 paint 后都会跑,
|
||||
* 没有它会给同一个节点挂上多个监听 ⇒ 改一次时间发好几条请求。
|
||||
*/
|
||||
function bindDue() {
|
||||
var b = bodyEl();
|
||||
if (!b) { return; }
|
||||
var box = b.querySelector('.dt-input[data-dt]');
|
||||
if (!box) { return; }
|
||||
var cfg = {};
|
||||
try { cfg = JSON.parse(box.getAttribute('data-dt') || '{}'); } catch (e) { return; }
|
||||
if (cfg.name !== 'due_at') { return; }
|
||||
if (box.getAttribute('data-fb-due-bound') === '1') { return; }
|
||||
box.setAttribute('data-fb-due-bound', '1');
|
||||
|
||||
/* 用 `change`(不是 `input`):AntD 选完日期/时间才写回,
|
||||
中途打字不该触发几十次请求。 */
|
||||
box.addEventListener('change', function () {
|
||||
var d = box.querySelector('.dt-date');
|
||||
var date = d ? String(d.value || '').trim() : '';
|
||||
if (date === '') {
|
||||
/* 清空 = 去掉截止时间(allowClear 会走到这里) */
|
||||
act(urlOf('due'), { due_at: '' });
|
||||
return;
|
||||
}
|
||||
var h = box.querySelector('.dt-hour');
|
||||
var m = box.querySelector('.dt-minute');
|
||||
var hh = h && String(h.value || '').trim() !== '' ? String(h.value) : '00';
|
||||
var mm = m && String(m.value || '').trim() !== '' ? String(m.value) : '00';
|
||||
act(urlOf('due'), { due_at: date + ' ' + hh + ':' + mm + ':00' });
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 把面板里的最新状态**顺手**同步到首页那张卡上(v78)。
|
||||
*
|
||||
@@ -282,6 +235,49 @@
|
||||
act(urlOf('move'), { board: btn.getAttribute('data-board') || '0' });
|
||||
return;
|
||||
}
|
||||
/* 🔴 #76(用户 2026-11-05):「时间控件是对的,但是现在没有保存按钮…
|
||||
另外,负责人和分类都没法修改,按道理讲都应该可以修改才对。」
|
||||
|
||||
⇒ 「截止 / 负责人 / 分类」三项一次性提交。
|
||||
⚠️ 上一版是"选完截止时间立即保存"(监听 change),用户不认可 ——
|
||||
他要的是"改完点保存"这种确定感。
|
||||
⚠️ 只提交这三项,服务端 `Task::setAttrs()` 也只写这三列,
|
||||
不碰 title/note/status/repeat(见那个方法的注释)。 */
|
||||
if (what === 'save-attrs') {
|
||||
e.preventDefault();
|
||||
if (btn.disabled) { return; }
|
||||
var bd = bodyEl();
|
||||
if (!bd) { return; }
|
||||
var dbox = bd.querySelector('.dt-input[data-dt]');
|
||||
var dueVal = '';
|
||||
if (dbox) {
|
||||
var dt = dbox.querySelector('.dt-date');
|
||||
var dstr = dt ? String(dt.value || '').trim() : '';
|
||||
if (dstr !== '') {
|
||||
/* 截止时间是"日期 + 时刻":时分没选就补 00:00(与 readDT 同一口径) */
|
||||
var hh = dbox.querySelector('.dt-hour');
|
||||
var mm = dbox.querySelector('.dt-minute');
|
||||
var h2 = hh && String(hh.value || '').trim() !== '' ? String(hh.value) : '00';
|
||||
var m2 = mm && String(mm.value || '').trim() !== '' ? String(mm.value) : '00';
|
||||
dueVal = dstr + ' ' + h2 + ':' + m2 + ':00';
|
||||
}
|
||||
}
|
||||
var asg = bd.querySelector('select[name="assignee_id"]');
|
||||
var cat = bd.querySelector('select[name="category_id"]');
|
||||
var extra = {};
|
||||
/* ⚠️ 只有控件真的在 DOM 里才提交该项 —— 没有成员时负责人下拉不渲染,
|
||||
那时不该把它当成 0 去清掉原值。 */
|
||||
extra['due_at'] = dueVal;
|
||||
if (asg) { extra['assignee_id'] = asg.value; }
|
||||
if (cat) { extra['category_id'] = cat.value; }
|
||||
|
||||
btn.disabled = true;
|
||||
act(urlOf('save'), extra);
|
||||
/* 面板会被整块换掉(act → send → paint),按钮随之重建,不用手动恢复 */
|
||||
setTimeout(function () { btn.disabled = false; }, 4000);
|
||||
return;
|
||||
}
|
||||
|
||||
if (what === 'cmt-del') {
|
||||
e.preventDefault();
|
||||
if (!window.confirm('删掉这条留言?')) { return; }
|
||||
@@ -406,15 +402,4 @@
|
||||
step();
|
||||
}
|
||||
|
||||
/**
|
||||
* 对外暴露「给截止控件绑 change 监听」(#74)。
|
||||
*
|
||||
* 为什么需要:首次打开面板走的是 `entry_popup.js` 的 `loadPanel()`,
|
||||
* 那条路只 innerHTML、不经过本文件的 `paint()` ⇒ `bindDue()` 不会自动跑
|
||||
* ⇒ 用户选完截止时间不会保存(只有做过一次别的动作、触发过一次重画才会生效)。
|
||||
* `loadPanel()` 在插入 HTML 后显式调这个。
|
||||
*
|
||||
* ⚠️ 内部有 `data-fb-due-bound` 幂等标记,重复调用不会重复绑。
|
||||
*/
|
||||
window.fbTaskPanelBindDue = bindDue;
|
||||
})();
|
||||
|
||||
@@ -7326,6 +7326,60 @@ $want = array_keys($want);
|
||||
}
|
||||
redirect('tasks');
|
||||
|
||||
/* 🔴 #76(用户 2026-11-05):「时间控件是对的,但是现在没有保存按钮,
|
||||
只有下面一个评论的发表按钮。另外,负责人和分类都没法修改,
|
||||
按道理讲都应该可以修改才对。」
|
||||
|
||||
⇒ 面板里「截止 / 负责人 / 分类」三项做成可编辑控件 + 一颗「保存」。
|
||||
这是用户明确要的交互:先改完,再一次性提交,而不是每动一下发一次请求
|
||||
(上一版 `tasks/due` 是"选完立即保存",用户不认可)。
|
||||
|
||||
⚠️ 用 `Task::setAttrs()`,只写这三列 —— 不是 `Task::update()`。
|
||||
后者全字段覆盖,面板没交的 title/note/status/repeat 会被抹空。
|
||||
⚠️ 三个字段都**可选**:表单里 `category_id` 没提交就不动它
|
||||
(`setAttrs` 用 `array_key_exists` 判,与 `?? null` 的"没传"区分开)。 */
|
||||
case 'tasks/panel_save':
|
||||
$familyId = (int)Auth::familyId();
|
||||
$me = (int)Auth::personId();
|
||||
Auth::requireWrite();
|
||||
csrf_check();
|
||||
$id = (int)($_POST['id'] ?? 0);
|
||||
$t = Task::find($familyId, $id, $me);
|
||||
if (!$t || !Task::canWrite($t, $me)) {
|
||||
if (($_SERVER['HTTP_X_REQUESTED_WITH'] ?? '') === 'XMLHttpRequest') {
|
||||
header('Content-Type: application/json; charset=utf-8', true, 403);
|
||||
echo json_encode(['ok' => false, 'msg' => '这项任务不能改。'], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
flash('err', '这项任务不能改。');
|
||||
redirect('tasks');
|
||||
}
|
||||
/* 只把**表单真的提交了**的字段放进 $sd:
|
||||
面板里负责人下拉在"没有成员"等极端情况下可能不渲染,
|
||||
那时就不该把 assignee_id 当成 0 去清掉原值。 */
|
||||
$sd = [];
|
||||
if (array_key_exists('due_at', $_POST)) {
|
||||
$sd['due_at'] = trim((string)$_POST['due_at']);
|
||||
}
|
||||
if (array_key_exists('assignee_id', $_POST)) {
|
||||
$sd['assignee_id'] = (int)$_POST['assignee_id'];
|
||||
}
|
||||
if (array_key_exists('category_id', $_POST)) {
|
||||
$sd['category_id'] = (int)$_POST['category_id'];
|
||||
}
|
||||
Task::setAttrs($familyId, $id, $sd);
|
||||
$msg = '已保存。';
|
||||
if (task_panel_wanted()) {
|
||||
task_panel_json($id, $msg);
|
||||
}
|
||||
if (($_SERVER['HTTP_X_REQUESTED_WITH'] ?? '') === 'XMLHttpRequest') {
|
||||
header('Content-Type: application/json; charset=utf-8');
|
||||
echo json_encode(['ok' => true, 'msg' => $msg], JSON_UNESCAPED_UNICODE);
|
||||
exit;
|
||||
}
|
||||
flash('ok', $msg);
|
||||
redirect('tasks/show', ['id' => $id]);
|
||||
|
||||
case 'tasks/comment_add':
|
||||
$familyId = (int)Auth::familyId();
|
||||
$me = (int)Auth::personId();
|
||||
|
||||
+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