Files
FamilyBook/templates/tasks/_add_modal.php
T
laoyang 40fd6c501c v78 服务端:首页任务改成「就地处理」面板 + 新建任务搬到首页
用户原话:
「网页端,首页点击一个任务后,除了展示信息,应该有相应的功能,可以修改状态:
  待办、进行中,可以挪动分组,可以拖动上传附件,可以添加评论,添加子任务等。
  其目地,是为了让用户不离开首页,就能对任务进行简单的处理。」
「另外,在全部任务旁边,放一个新建任务的功能,其实就是把任务中的新建和编辑功能,
  搬过来,用弹出框来处理。」

一、首页任务浮层由「只读信息」改成「可操作面板」
- 新增 templates/tasks/_panel.php:状态三段 / 看板 chips(带看板色)/
  子任务(复用 _task_check.php)/ 附件拖放框(复用 _attachments.php)/ 讨论
- 新增路由 tasks/panel:只吐一块 HTML(找不到 404)
- 既有七个动作路由各加一条 ajax_panel 回包分支(状态 / 挪分组 / 新建子任务 /
  评论增删 / 附件增删),没有新开写接口
- helpers.php 新增 task_panel_wanted() / task_panel_json();
  fb_entry_json() 的 payload 增加 panel 字段(只有任务会给)
- 每次动作回**整块新面板**:一次动作会牵动子任务计数、附件张数、看板选中态,
  逐处同步 DOM 必然漏一处
- 拖进来的附件**立刻上传**(任务已存在,不该再让用户点一次保存),
  不复用 _stage_drop.php 那套「暂存 + 认领」

二、新建任务搬到首页
- 从 templates/tasks/index.php 抽出公共片段 templates/tasks/_add_modal.php
  (字段与原来一字未改),首页与任务页共用同一份
- 新增 assets/js/task_add.js 管开关(两页共用,幂等绑定);
  打开那一刻才 fbUpgradeRange() + fbBootAntd()(hidden 时宽高为 0,antd 会定位错乱)
- App\HomeCards 登记表里加 add => 新建任务,首页卡头与「全部任务」并排
- tasks/create 支持 back=home(白名单),新建完回首页

三、其它
- assets/js/task_panel.js:事件委托;动作后整块换面板;
  顺手同步首页那张卡的状态徽标与复选框(关掉浮层不能还是旧状态);
  传附件时保住用户写了一半的留言与子任务标题;取不到面板时退回只读信息
- app.css 追加面板样式(含 color-mix 的 @supports 兜底)与卡片窄到宽 2 时允许折行

验证:本地 e2e 1558/0、几何 428/0 + 660/0、v78 反向验证 11/0、
片段作用域体检 35/0、php -l 与 node --check 全过
2026-10-22 12:40:14 +08:00

170 lines
9.0 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
/**
* 「新建任务」弹框(v78 从 `tasks/index.php` 里抽出来的)。
*
* 为什么抽出来:用户 2026-10-22 说「在全部任务旁边,放一个新建任务的功能,
* 其实就是把任务中的新建和编辑功能,搬过来,用弹出框来处理。」
* ⇒ 首页也要有这张弹框。**绝不能各写一张**:
* 两张表单的字段迟早不同步(本项目在 `_edit_form.php` 上已经栽过一次,
* 见那份文件头部"为什么独立出来"的说明)。
*
* 用法(require 之前设好这几个变量):
* $tkAddBack 新建完回哪儿:'tasks'(看板,默认)/ 'home'(首页)
* $tkAddBoards 看板清单(Task::boards 的结果)
* $tkAddCats 分类清单(Task::categories 的结果)
* $tkAddPeople 名册(Person::roster 的结果)
*
* ⚠️ 表单字段名 / action / 契约与原来**一字未改**(服务端 `tasks/create` 收的就是这些)。
* ⚠️ 打开/关闭由 `assets/js/task_add.js` 管(全站加载,页面里没有这张弹框就什么都不做)——
* 两页共用一份脚本,不在这里写内联 script(内联脚本在 AJAX 换正文时不会被重跑,
* 这个坑 v42/v47 连着踩过两次)。
*/
$tkAddBack = (string)($tkAddBack ?? 'tasks');
$tkAddBoards = (array)($tkAddBoards ?? []);
$tkAddCats = (array)($tkAddCats ?? []);
$tkAddPeople = (array)($tkAddPeople ?? []);
?>
<?php if (\App\Auth::canWrite()): ?>
<div class="cal-modal" id="taskAddCard" role="dialog" aria-modal="true"
aria-label="新建任务" hidden>
<div class="cal-modal-panel">
<div class="cal-modal-head">
<b>新建任务</b>
<button type="button" class="cal-modal-x" data-tk-add-close aria-label="关闭">✕</button>
</div>
<?php /* ⚠️ enctype 必须有:本批新增了**附件**上传(用户第 6 条第 2 点
「新建任务时,竟然没有添加附件,这个应该加上」)。
没有它的话文件根本不会随表单发出去,而且 $_FILES 是空的。 */ ?>
<form method="post" action="<?= e(url('tasks/create')) ?>"
enctype="multipart/form-data" id="taskAddForm">
<?= csrf_field() ?>
<?php /* ⚠️ 新建后回**看板**(用户:「新建完之后刷新…看板页面」)。
`back=tasks` / `back=home` 走服务端白名单,见 index.php 的 tasks/create。 */ ?>
<input type="hidden" name="back" value="<?= e($tkAddBack) ?>">
<div class="cal-modal-body">
<?php /* 🔴 v44(用户 2026-10-12 第 5 条):「新建任务页面的排版还没有统一,
应该把标题放在前面,树框放在后面。」
⇒ 用观影/行程/日程那套 **`.mv-grid`**(标签 62px 右对齐 + CSS `::after` 冒号 +
控件占满剩余宽度),标题那一行在最前、其余字段依次跟上。 */ ?>
<div class="mv-grid">
<div class="mv-row">
<span class="mv-lb">任务名称<i>*</i></span>
<input class="input" id="tk-title" name="title" required
placeholder="如:周末大扫除">
</div>
<?php /* v24 第 5 条:截止时刻也走全局统一的「日期 + 时分秒」控件。
秒这一档保留(与其它模块同一口径),默认 23:59:59 —— "这天之前做完"
比"这天 00:00 之前"更符合直觉。
🔴 v44(用户第 5 条):「截止时间也用我们最新的日历控件,
记得把现在这个控件删掉。」
⇒ 换成 AntD 的**单点** DatePicker(带时刻):
`$dtPlugin='antd-single'`(见 app.js 的 mountAntdSingleDT)。 */ ?>
<div class="mv-row">
<span class="mv-lb">截止时间</span>
<?php $dtName = 'due_at'; $dtId = 'tk-due'; $dtValue = null;
$dtRequired = false; $dtPlugin = 'antd-single';
require __DIR__ . '/../_datetime.php'; ?>
</div>
<?php /* 🔴 v44(用户第 5 条):「负责人默认是自己。」
⇒ 默认选中当前登录的人(原来 `$ppSelected = []`,空着)。 */ ?>
<div class="mv-row">
<span class="mv-lb">负责人</span>
<?php
$ppName = 'assignee_id';
$ppPeople = $tkAddPeople;
$ppSelected = [(int)\App\Auth::personId()];
$ppMode = 'single';
$ppOpenBtn = '更换负责人';
$ppTitle = '谁负责这件事';
$ppEmptyText = '不指定';
$ppAllowEmpty = true;
require __DIR__ . '/../_person_picker.php';
?>
</div>
<?php /* 🔴 v44(用户第 5 条):「状态下面选"已完成"的话,它只在"已完成"里出现,
看板上不再显示,这句话也去掉。」⇒ 删掉那句 `.tip`(状态语义由徽标本身表达)。 */ ?>
<div class="mv-row">
<span class="mv-lb">状态</span>
<select class="select" id="tk-status" name="status">
<?php foreach (\App\Task::STATUS as $sk => $sv): ?>
<option value="<?= e($sk) ?>" <?= $sk === 'todo' ? 'selected' : '' ?>><?= e($sv) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="mv-row">
<span class="mv-lb">循环</span>
<select class="select" id="tk-repeat" name="repeat_rule">
<?php foreach (\App\Task::REPEAT as $rk => $rv): ?>
<option value="<?= e($rk) ?>"><?= e($rv) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="mv-row">
<span class="mv-lb">分类</span>
<select class="select" id="tk-cat" name="category_id">
<option value="0">未分类</option>
<?php foreach ($tkAddCats as $c): ?>
<option value="<?= (int)$c['id'] ?>"><?= e((string)$c['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<?php /* 用户第 7 条:看板 = 任务"归属哪摊事",新建时直接选(不是顶上的切换条) */ ?>
<div class="mv-row">
<span class="mv-lb">看板</span>
<select class="select" id="tk-board" name="board_id">
<?php foreach ($tkAddBoards as $b): ?>
<option value="<?= (int)$b['id'] ?>"><?= e((string)$b['name']) ?></option>
<?php endforeach; ?>
</select>
</div>
<?php /* 🔴 v44(用户第 5 条):「"共享给"后面有个括号,可多选,任何人完成都算完成,
这个括号里面的内容也去掉。」⇒ 标签只留「共享给」。
第 8 条的同一诉求:人多时不要下拉里瞪眼找。换成弹窗 + 首字母联想。
⚠️ 候选里去掉**自己**——「共享给自己」是空操作。 */ ?>
<div class="mv-row">
<span class="mv-lb">共享给</span>
<?php
$ppName = 'shares[]';
$ppPeople = array_values(array_filter($tkAddPeople,
fn($p) => (int)$p['id'] !== (int)\App\Auth::personId()));
$ppSelected = [];
$ppMode = 'multi';
$ppOpenBtn = '+ 添加人';
$ppTitle = '共享给谁';
require __DIR__ . '/../_person_picker.php';
?>
</div>
<div class="mv-row">
<span class="mv-lb">备注</span>
<textarea class="input" id="tk-note" name="note" rows="2"></textarea>
</div>
<?php /* 🔴 v37 用户第 6 条第 2 点:「新建任务时,竟然没有添加附件,这个应该加上。」
走全站统一的「点击或拖动进行上传」框(templates/_stage_drop.php);
字段名 `attach[]` 与详情页的附件上传**一致**。 */ ?>
<div class="mv-row">
<span class="mv-lb">附件</span>
<?php $sdName = 'attach[]'; $sdId = 'sd-tk-attach'; $sdSlot = 'photo';
require __DIR__ . '/../_stage_drop.php'; ?>
</div>
</div><?php /* /.mv-grid */ ?>
</div><?php /* /.cal-modal-body */ ?>
<div class="cal-modal-foot">
<span class="cal-modal-tip" id="taskAddTip"></span>
<button class="btn btn-sm" type="submit" form="taskAddForm" id="taskAddSubmit">新建</button>
<button class="btn btn-ghost btn-sm" type="button" data-tk-add-close>取消</button>
</div>
</form>
</div>
</div>
<?php endif; ?>
<?php
/* ⚠️ 只清本片段自己的变量:宿主页面后面还要用 $boards / $people 这些。
(`_edit_form.php` 头部记着"把宿主变量 unset 掉 → 子任务与评论区静默消失"那次事故。) */
unset($tkAddBack, $tkAddBoards, $tkAddCats, $tkAddPeople,
$dtName, $dtId, $dtValue, $dtRequired, $dtPlugin,
$ppName, $ppPeople, $ppSelected, $ppMode, $ppOpenBtn, $ppTitle,
$ppEmptyText, $ppAllowEmpty,
$sdName, $sdId, $sdSlot);
?>