Files
FamilyBook/templates/days/form.php
T
laoyang 7544fb9f6a v41 第 41 批:流水线提速 + 12 项界面/交互开发 + DAV 彻底修复
DAV(用户「务必彻底解决」):
- 真根因是 home-set 层级错:CalDav::HOME_PATH 原为 /dav/calendars/、
  CardDav 原为 /carddav/addressbooks/,而日历本/通讯录的 href 在
  /dav/N.ics/ 与 /carddav/N.vcf/ —— home-set 下面一本都没有。
  Thunderbird 按 home-set 前缀认成员,于是「找不到日历本 / 找不到联系人」。
  改为 /dav/ 与 /carddav/(所有既有 URL 一字不变,老配置不作废)。
- 又发现并修掉 Depth:0 违反 RFC 4918:原实现无论 depth 都列出全部子集合,
  且第一条 response 是日历本(不含 current-user-principal)。改为按 depth 分流,
  Depth:0 只回资源自身、Depth:1 才列出子集合。

界面与交互:
- 观影:新建影院弹窗层级修正 + 详细地址;照片左右按钮悬停不再位移;
  弹框底栏改「确定 / 取消」。
- 旅程:新建旅程改弹窗并按观影式排版;详情页四个动作按钮按用户指定顺序与配色;
  编辑与新增行程弹窗化(单容器 + AJAX);行程时间控件改 AntD(精确到分);
  参与人默认带上自己;车次号/车牌号紧跟交通方式词。
- 资源:新建/编辑改弹窗 + 观影式排版 + 新建时即定共享人。
- 纪念日:新建改弹框 + 观影式排版。

验证:
- e2e 1510/0;v41 十二项真机 48/0;DAV 反向验证 8/0;
  部署断言空跑 337/0;模板 div 深度三形态穷举 33 组全配平。
- 线上 DAV 终验(--resolve 真实入口 + 真 DAV 口令)12/0;
  线上确认 Depth:0 恰好 1 个 response。
2026-10-11 10:12:11 +08:00

178 lines
7.4 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
/**
* 新建 / 编辑纪念日(v24 用户第 13 条;**v41 改成弹框 + 观影式排版**)
*
* 用户原话:
* · 第 13 条:「可以根据阴历和阳历来设置纪念日 …… 纪念日,需要按照阴历和阳历进行重复。」
* · v41 第 10 条:「新建纪念日,采用弹框形式,排版参考观影模块。」
*
* ⇒ 两条落实:
* ① **弹框**(`$anModal`):从列表页内嵌,初始关闭;直达 `days/new` 时以打开状态渲染;
* ② **排版**:整表单改用观影那套 `.mv-row`(左标签 62px + 右对齐 + 自动冒号,
* 控件占满剩余宽度),不再用 `.field` 堆叠。
*
* ⚠️ 重复方式这一栏是核心:阳历 / 农历 / 只此一次。选农历时下面的月/日
* 填的是**农历**的月日(不是公历换算)。
*
* @param array|null $editing 编辑时的既有记录
* @param array $people 名册
*/
/* 🔴 v41:被列表页 `require` 内嵌时必须**自己兜住变量**。
否则 `$editing` 未定义 → 每一处都吐 `Warning: Undefined variable`
且**打进 HTML 正文**(`HTTP 200`,看着"页面正常",实际满屏警告,
还把 `class="cal-modal"` 那行**切断**了 —— 实测:弹框容器因此变成
`<div class="cal-modal"<br /><b>Warning</b>…` ⇒ 前端 `getElementById` 拿不到,
"点新建没反应"。这正是全站那条"模板片段不许偷宿主变量"的同一类坑。 */
$editing = $editing ?? null;
$people = $people ?? [];
$kinds = $kinds ?? null;
$e0 = $editing ?: [];
$v = static fn(string $k, $def = '') => $e0[$k] ?? $def;
$repeat = (string)($e0['repeat_type'] ?? 'solar');
// 用户 2026-10-03 第 9 条:分类下拉的选项来自**可配置**的分类清单
$kinds = (array)($kinds ?? \App\Anniversary::PRESET_KINDS);
$curKind = (string)($e0['kind'] ?? '');
if ($curKind !== '' && !in_array($curKind, $kinds, true)) {
array_unshift($kinds, $curKind);
}
/* 🔴 v41 弹框开关(与观影/旅程同一套命名习惯):
$anModal —— 渲染成弹框壳
$anModalOnly —— 被列表页内嵌(初始关闭)
$anOpen —— 初始打开(直达 / AJAX 校验失败重画)
$anEmbed —— 只吐片段(详情页/列表页弹框 fetch 用) */
$anModal = !isset($anModal) ? true : (bool)$anModal;
$anModalOnly = !empty($anModalOnly);
$anOpen = !empty($anOpen);
$anEmbed = !empty($anEmbed);
$anShell = !isset($anShell) ? !$anEmbed : (bool)$anShell;
$backUrl = url('days');
?>
<?php if (!$anEmbed && !$anModal): ?>
<div class="page-head">
<h1><?= $editing ? '编辑纪念日' : '新建纪念日' ?></h1>
<div class="actions">
<a class="btn btn-ghost" href="<?= e($backUrl) ?>">返回</a>
</div>
</div>
<?php endif; ?>
<?php if ($anShell): ?>
<div class="<?= $anModal ? 'cal-modal' : 'card card-pad' ?>"<?php
if ($anModal) {
echo ' id="anNewCard" role="dialog" aria-modal="true" aria-label="'
. ($editing ? '编辑纪念日' : '新建纪念日') . '"' . ($anOpen ? '' : ' hidden');
} ?>>
<?php if ($anModal): ?>
<div class="cal-modal-panel mv-panel">
<div class="cal-modal-head">
<b><?= $editing ? '编辑纪念日' : '新建纪念日' ?></b>
<button type="button" class="cal-modal-x" id="anNewX" aria-label="关闭">&#10005;</button>
</div>
<?php endif; ?>
<?php endif; ?>
<form method="post" action="<?= e(url('days/save')) ?>" id="anForm">
<?= csrf_field() ?>
<?php if ($editing): ?><input type="hidden" name="id" value="<?= (int)$e0['id'] ?>"><?php endif; ?>
<?php if ($anModal && !$editing): ?>
<input type="hidden" name="back" value="days">
<?php endif; ?>
<div class="mv-form-inner">
<div class="mv-grid">
<div class="mv-row">
<span class="mv-lb">叫什么<i>*</i></span>
<input class="input" id="an-title" name="title" required
value="<?= e((string)$v('title')) ?>" placeholder="如:结婚纪念日">
</div>
<div class="mv-row">
<span class="mv-lb">按什么重复<i>*</i></span>
<select class="select" id="an-repeat" name="repeat_type">
<?php foreach (\App\Anniversary::REPEAT as $rk => $rv): ?>
<option value="<?= e($rk) ?>" <?= $repeat === $rk ? 'selected' : '' ?>><?= e($rv) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="mv-row">
<span class="mv-lb">分类</span>
<select class="select" id="an-kind" name="kind">
<option value="">不分类</option>
<?php foreach ($kinds as $k): ?>
<option value="<?= e((string)$k) ?>" <?= $curKind === (string)$k ? 'selected' : '' ?>><?= e((string)$k) ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="mv-row">
<span class="mv-lb">月 / 日<i>*</i></span>
<div class="an-md">
<input class="input" id="an-month" name="month" type="number" min="1" max="12" required
value="<?= (int)$v('month', 1) ?>" aria-label="月">
<span class="an-md-sep">月</span>
<input class="input" id="an-day" name="day" type="number" min="1" max="31" required
value="<?= (int)$v('day', 1) ?>" aria-label="日">
<span class="an-md-sep">日</span>
</div>
</div>
<div class="mv-row">
<span class="mv-lb">与谁相关</span>
<div class="mv-fill">
<?php
$ppName = 'person_ids[]';
$ppPeople = $people;
$ppSelected = (array)($e0['person_ids'] ?? []);
if (!$ppSelected && (int)($e0['person_id'] ?? 0) > 0) {
$ppSelected = [(int)$e0['person_id']];
}
$ppMode = 'multi';
$ppOpenBtn = '+ 关联人';
$ppTitle = '这个纪念日与谁相关';
require __DIR__ . '/../_person_picker.php';
?>
</div>
</div>
<div class="mv-row">
<span class="mv-lb">农历闰月</span>
<label class="chk-inline">
<input type="checkbox" id="an-leap" name="is_leap" value="1" <?= !empty($e0['is_leap']) ? 'checked' : '' ?>>
<span>这个农历月是闰月</span>
</label>
</div>
<div class="mv-row">
<span class="mv-lb">备注</span>
<textarea class="input" id="an-note" name="note" rows="2"><?= e((string)$v('note')) ?></textarea>
</div>
</div>
</div>
<?php if ($anShell && $anModal): ?>
<div class="cal-modal-foot">
<span class="cal-modal-tip" id="anNewTip"></span>
<button class="btn btn-sm" type="submit" form="anForm" id="anNewSubmit">确定</button>
<button class="btn btn-ghost btn-sm" type="button" id="anNewCancel">取消</button>
</div>
</div><?php /* /.cal-modal-panel */ ?>
<?php elseif ($anEmbed): ?>
<div class="cal-modal-foot">
<span class="cal-modal-tip" id="anNewTip"></span>
<button class="btn btn-sm" type="submit" form="anForm" id="anNewSubmit">确定</button>
<button class="btn btn-ghost btn-sm" type="button" data-nf-close>取消</button>
</div>
<?php else: ?>
<div class="btn-row">
<button class="btn" type="submit" id="anNewSubmit"><?= $editing ? '确定' : '添加' ?></button>
<a class="btn btn-ghost" href="<?= e($backUrl) ?>">取消</a>
</div>
<?php endif; ?>
</form>
<?php if ($anShell): ?>
</div><?php /* 关掉开头那个外层(.cal-modal 或 .card) */ ?>
<?php endif; ?>