- #6 名册线上真实数据(1184 人)卡顿:根因是**每张卡片内联一整份分组弹层**—— 全页 2369 个 form / 27234 个 input / 22496 个 radio / 98100 DOM 节点, 密码管理器(Bitwarden 等)逐个扫描 form 把主线程占死(用户报的就是这个冲突)。 改为卡片只带 data 属性 + 全页**唯一一份**共享浮层 #rosterMenus。 实测:form 2369→3、input 27234→25、DOM 98100→17659、解压 7694→2306 KB、 长任务 1/52ms → 0。新增哨兵 _fb_formbloat_check.py(含反向验证)。 - #5 日视图翻页失效:day_columns() 无条件吸到周一,天视图只有 1 列 → 永远显示那周周一。 改为仅 span>1 时吸附(周视图行为不变)。 - #2 财务「欠款」类别(负债);并修一个真 bug:负债填负数会让净资产**反向变大**。 写入口 normalizeAmount 归一化 + summary/timeline 侧 abs 防御 + Schema v17 纠正老数据。 - #3 账目行「盘点」「修改」两个并列按钮(各自就地弹面板);图移到账目上方, 总金额图跨整行 + 每个账目一条线 + 类别筛选条;charts() 改为覆盖全部账目。 - #4 日程新增「农历」「节假日」两本不可删除只读日历(app/Holiday.php): 两级自动更新 —— 内置规则(公历固定 + 清明节气 + 农历节日)保证断网也有; 官方 JSON 镜像自动抓取补齐调休。抓取**不在渲染路径联网**(响应后 fastcgi_finish_request + 频率闸门),缓存落 storage/cache。仅派生本不可写日程。 - #6 日程页设置按钮前加「跳到某一天」(选中即跳)。 - #7 起止范围改用一个 Semi dateTimeRange 控件(观影/旅程/节点/日程共 4 处); 新增 window.fbSetDT / fbUpgradeRange;修范围重挂(React 非受控组件须 unmount 再 createRoot) 与范围里 required 未摘除导致表单无法提交两个真实问题。 验证:e2e 786/0、batch10 44/0、batch9 38/0、batch_e 91/0、upgrade 126/0、picker 28/0、 semi_integrate 27/0、formbloat 5/0(+反向 3 红)、mobile 688/0、interact 97/0、drag 5/0、geom 5/5; 线上自检 19/19 + 线上真实账号巡检 28/0(含 Firefox 实测)。
92 lines
4.1 KiB
PHP
92 lines
4.1 KiB
PHP
<?php
|
||
/**
|
||
* 行程节点表单(新增 / 编辑共用;被 show.php 循环 require)。
|
||
*
|
||
* 计划与执行是**双轨**:同一段行程可以先在 plan 里排一遍,走完再在 reality 里记一遍。
|
||
* 所以表单里带一个隐藏的 category —— 加在哪一轨就进哪一轨。
|
||
*
|
||
* 变量(require 前设好):
|
||
* $nfNode 被编辑的节点数组,或 null(新增)
|
||
* $nfTripId 旅程 id(events.id)
|
||
* $nfCategory 'plan' | 'reality'
|
||
* $nfPeople 可选人名册(选参与人用),为空就不显示成员多选
|
||
* $nfMembers 已选成员 id 列表
|
||
*/
|
||
$nfIsEdit = !empty($nfNode);
|
||
$nfPrefix = $nfIsEdit ? 'ne' . (int)$nfNode['id'] : ('n' . ($nfCategory === 'reality' ? 'r' : 'p'));
|
||
?>
|
||
<form class="node-form" method="post" action="<?= e(url($nfIsEdit ? 'trips/node_update' : 'trips/node_add')) ?>">
|
||
<?= csrf_field() ?>
|
||
<input type="hidden" name="trip_id" value="<?= (int)$nfTripId ?>">
|
||
<input type="hidden" name="category" value="<?= e($nfCategory) ?>">
|
||
<?php if ($nfIsEdit): ?>
|
||
<input type="hidden" name="id" value="<?= (int)$nfNode['id'] ?>">
|
||
<?php endif; ?>
|
||
|
||
<div class="nf-grid">
|
||
<div class="field">
|
||
<label for="<?= e($nfPrefix) ?>-title">这一段 *</label>
|
||
<input class="input" id="<?= e($nfPrefix) ?>-title" name="title" required
|
||
value="<?= e($nfNode['title'] ?? '') ?>" placeholder="如:栈桥看海">
|
||
</div>
|
||
<div class="field">
|
||
<label for="<?= e($nfPrefix) ?>-type">类型</label>
|
||
<select class="select" id="<?= e($nfPrefix) ?>-type" name="node_type">
|
||
<?php foreach (\App\Trip::NODE_TYPES as $tk => $tv): ?>
|
||
<option value="<?= e($tk) ?>"<?= ($nfNode['node_type'] ?? 'other') === $tk ? ' selected' : '' ?>>
|
||
<?= e($tv[1] . ' ' . $tv[0]) ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
<div class="field">
|
||
<label for="<?= e($nfPrefix) ?>-place">地点</label>
|
||
<input class="input" id="<?= e($nfPrefix) ?>-place" name="place"
|
||
value="<?= e($nfNode['place'] ?? '') ?>" placeholder="选填">
|
||
</div>
|
||
<div class="field">
|
||
<label for="<?= e($nfPrefix) ?>-status">状态</label>
|
||
<select class="select" id="<?= e($nfPrefix) ?>-status" name="status">
|
||
<?php foreach (\App\Trip::NODE_STATUS as $sk => $sv): ?>
|
||
<option value="<?= e($sk) ?>"<?= ($nfNode['status'] ?? 'planned') === $sk ? ' selected' : '' ?>>
|
||
<?= e($sv) ?>
|
||
</option>
|
||
<?php endforeach; ?>
|
||
</select>
|
||
</div>
|
||
<?php /* 用户 2026-10-04 第 7 条:节点的起止也是**一个范围**,一次选完 */ ?>
|
||
<div class="field dt-range">
|
||
<label>开始 / 结束</label>
|
||
<?php $dtName = 'starts_at'; $dtValue = $nfNode['starts_at'] ?? '';
|
||
$dtId = $nfPrefix . '-s'; $dtSeconds = true; $dtRange = 'start';
|
||
require __DIR__ . '/../_datetime.php'; ?>
|
||
<?php $dtName = 'ends_at'; $dtValue = $nfNode['ends_at'] ?? '';
|
||
$dtId = $nfPrefix . '-e'; $dtSeconds = true; $dtRange = 'end';
|
||
require __DIR__ . '/../_datetime.php'; ?>
|
||
<span class="tip">结束时间可不填。</span>
|
||
</div>
|
||
<div class="field full">
|
||
<label for="<?= e($nfPrefix) ?>-detail">记录</label>
|
||
<textarea class="input" id="<?= e($nfPrefix) ?>-detail" name="detail" rows="2"
|
||
placeholder="这一段发生了什么"><?= e($nfNode['detail'] ?? '') ?></textarea>
|
||
</div>
|
||
<?php if (!empty($nfPeople)): ?>
|
||
<div class="field full">
|
||
<label>这一段里有谁(不勾 = 全趟同行的人)</label>
|
||
<div class="nf-members">
|
||
<?php foreach ($nfPeople as $p): ?>
|
||
<label class="check-item">
|
||
<input type="checkbox" name="members[]" value="<?= (int)$p['id'] ?>"
|
||
<?= in_array((int)$p['id'], $nfMembers, true) ? 'checked' : '' ?>>
|
||
<span><?= e(person_name($p)) ?></span>
|
||
</label>
|
||
<?php endforeach; ?>
|
||
</div>
|
||
</div>
|
||
<?php endif; ?>
|
||
</div>
|
||
<div class="btn-row">
|
||
<button class="btn btn-sm" type="submit"><?= $nfIsEdit ? '保存' : '加一段' ?></button>
|
||
</div>
|
||
</form>
|