日期框换成自控输入(原生 date 会吞位)+ 气温图桌面端铺满 + 同行卡片不再被拉伸
三件事都由用户实测反馈,前两件先复现再动手。
一、日期框:敲 20260606 变成 202606/06(用户要「永远解决」)
- **实测复现**:写了个真实按键工具(CDP Input.dispatchKeyEvent 每字符带 text;
技能里的 `--press` 只给 Enter 带 text,数字敲不进去)。在 /stats 的「起始日期」上敲 20260606:
敲之前 `INPUT|date|`、attached=false;敲完显示 `202606/06`、`el.value` 是**空**(非法)—— 截图为证。
- **根因**:筛选区的起止日期是原生 `<input type="date">`,而挂载代码只写了
`querySelectorAll('input[type=datetime-local]')` ⇒ **type=date 从没人管**。
Chrome 的年段允许超过 4 位数字(年份上限 275760),8 位被切成 年=202606 + 月=06。
原生分段状态读不到、`setSelectionRange` 对 date 类输入直接抛 ⇒ 修不了,只能换控件
(用户也说了「如果当前控件无法实现就换别的」)。
- **做法**:`datetime-input.js` 加「只日期」模式(`SPEC.date`:年/月/日三段,输出 `Y-m-d`),
并提供**统一入口 `attachAll(root)`** 按 `el.type` 分派;`attach` 里先把控件换成 `text`
(引导会写 `2026-06-` 这种半成品,而原生控件对非法值一律置空)。
`datetime-input.js` 改为**无条件引入**(公共页筛选区也要用;flatpickr 仍按需加载 ——
没有它时只挂输入引导、不给日历,省 60 多 KB),挂载在 body 末尾**立刻**跑一次
(别只等 DOMContentLoaded,否则会先露出原生框再变文本框)。三个后台页改用 `attachAll`,
顺带覆盖行程筛选的 `mfrom/mto`(date 类走 `enableTime:false`,实测无时间选择器)。
- **验证**:真实按键敲 20260606 → `value="2026-06-06"`;端到端 `from=2025-08-01&to=2025-08-31`
筛出 **186 次**,与月度图峰值月(186)完全吻合(排除「解析成空导致恒 0」)。
门禁 `TestDateInputsGoThroughAttachAll`:模板里再出现按 type 挑的选择器即红(做过变异验证);
JS 单测补 11 条逐键模拟(45/45)。
二、逐月平均气温图在桌面端很小
- 量出来的:10 个月固定 36px 宽,只占 1042px 里的 **396px**,右边 600 多像素全空。
- 窄屏保持「固定 36px + 横滚」(挤在一起月份标签会糊),宽屏改 `flex: 1 1 36px; max-width: 96px`
并把轨道从 84px 加到 130px、字号提到 `--fs-sm`。
三、类型分布与一天中的分布同行高度不齐
- grid 默认 `align-items: stretch`,把 256px 的「一天中的分布」拉到与 1411px 的「类型分布」一样高,
卡片内部留一大片空白。改成 `.grid { align-items: start }`。
回归:./scripts/verify.sh **PASS=349 FAIL=0 SKIP=0**;移动端 390 / 桌面 1440 溢出与改前一致。
⚠️ 两个验证纪律(都写进 details 三十二):
- 验收跑着的时候别并发跑测试/变异实验(两次踩到,其中一次变异正好被验收抓到,那轮结果作废)。
- **变异验证「内嵌文件」(templates/static)之后必须 `go clean -cache`**:`//go:embed` 的内容
在「改坏→还原」后,构建缓存会继续给出变异期间编译的那份 —— 实测同一个测试
`go test ./internal/web/` 绿、`go test ./...` 红,`go clean -testcache` 不管用。
This commit is contained in:
@@ -801,13 +801,11 @@
|
||||
// 注意 l10n 对象叫 flatpickr.l10ns(复数);且必须 try 住——这里抛错会把
|
||||
// 同一回调里后面的地图和地点搜索初始化一起炸掉。
|
||||
try {
|
||||
if (window.flatpickr) {
|
||||
if (flatpickr.l10ns && flatpickr.l10ns.zh) flatpickr.localize(flatpickr.l10ns.zh);
|
||||
document.querySelectorAll('input[type=datetime-local]').forEach(function (el) {
|
||||
window.rondDatetime.attachPicker(el);
|
||||
});
|
||||
}
|
||||
} catch (e) { console.error('flatpickr 初始化失败', e); }
|
||||
if (window.flatpickr && flatpickr.l10ns && flatpickr.l10ns.zh) flatpickr.localize(flatpickr.l10ns.zh);
|
||||
// 统一入口:一次覆盖 datetime-local 与 date(行程筛选的 mfrom / mto 就是 date)。
|
||||
// 别再手写 querySelector('input[type=...]') —— 2026-10-09 的日期框 bug 就是这么漏掉 type=date 的。
|
||||
window.rondDatetime.attachAll();
|
||||
} catch (e) { console.error('日期控件初始化失败', e); }
|
||||
|
||||
// 融合表单的模式切换。required 不能写在 name/lat 等字段上——切到
|
||||
// 「补已有地点」时它们虽被隐藏,HTML5 仍会校验并拦住提交,所以校验交给后端。
|
||||
|
||||
@@ -505,12 +505,10 @@
|
||||
|
||||
function initPickers() {
|
||||
try {
|
||||
if (!window.flatpickr) return;
|
||||
if (flatpickr.l10ns && flatpickr.l10ns.zh) flatpickr.localize(flatpickr.l10ns.zh);
|
||||
rowsBox.querySelectorAll('input[type=datetime-local]').forEach(function (el) {
|
||||
window.rondDatetime.attachPicker(el);
|
||||
});
|
||||
} catch (e) { console.error('flatpickr 初始化失败', e); }
|
||||
if (window.flatpickr && flatpickr.l10ns && flatpickr.l10ns.zh) flatpickr.localize(flatpickr.l10ns.zh);
|
||||
// 统一入口(datetime-local + date)。限定在 rowsBox 里:页面别处的输入前面已经挂过了。
|
||||
window.rondDatetime.attachAll(rowsBox);
|
||||
} catch (e) { console.error('日期控件初始化失败', e); }
|
||||
}
|
||||
|
||||
// 反查地址:坐标交给服务端(坐标系换算也在那边做),拿回地址与换算后的坐标
|
||||
|
||||
@@ -93,12 +93,10 @@
|
||||
}
|
||||
whenReady(function () {
|
||||
try {
|
||||
if (!window.flatpickr) return;
|
||||
if (flatpickr.l10ns && flatpickr.l10ns.zh) flatpickr.localize(flatpickr.l10ns.zh);
|
||||
document.querySelectorAll('input[type=datetime-local]').forEach(function (el) {
|
||||
window.rondDatetime.attachPicker(el);
|
||||
});
|
||||
} catch (e) { console.error('flatpickr 初始化失败', e); }
|
||||
if (window.flatpickr && flatpickr.l10ns && flatpickr.l10ns.zh) flatpickr.localize(flatpickr.l10ns.zh);
|
||||
// 统一入口:一次覆盖 datetime-local 与 date(见 datetime-input.js 顶部说明)
|
||||
window.rondDatetime.attachAll();
|
||||
} catch (e) { console.error('日期控件初始化失败', e); }
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
|
||||
@@ -246,10 +246,25 @@
|
||||
{{if .Flatpickr}}
|
||||
<script src="/static/vendor/flatpickr/flatpickr.min.js?v={{.AssetV}}"></script>
|
||||
<script src="/static/vendor/flatpickr/l10n/zh.js?v={{.AssetV}}"></script>
|
||||
{{/* 时间框的解析器与输入引导。必须在 flatpickr 之后、页面内联脚本之前:
|
||||
它不自己调 flatpickr,只提供 parseDate 与 attach,由各页 whenReady 调 attachPicker。 */}}
|
||||
<script src="/static/js/datetime-input.js?v={{.AssetV}}"></script>
|
||||
{{end}}
|
||||
{{/* 日期输入的解析器与手输引导。**无条件引入**:公共页的筛选区也有 <input type=date>,
|
||||
那边不加载 flatpickr(省 60 多 KB),走纯输入引导 —— 关键是原生 date 自己也不可靠
|
||||
(Chrome 的年段能吞 6 位数字,敲 20260606 会变成 202606/06 且 value 为空)。
|
||||
必须在 flatpickr 之后、页面内联脚本之前。 */}}
|
||||
<script src="/static/js/datetime-input.js?v={{.AssetV}}"></script>
|
||||
<script>
|
||||
/* 每一页都把日期输入改造一次(见 datetime-input.js 顶部说明)。
|
||||
页面自己的 whenReady 里还会再调一次 attachAll —— 那是为了覆盖**动态创建**的输入
|
||||
(照片页是分批建行的);重复调用安全,元素上有 _rondAttached 守卫。 */
|
||||
(function () {
|
||||
var run = function () { if (window.rondDatetime) window.rondDatetime.attachAll(); };
|
||||
/* 这个脚本在 body 末尾,内容都已经解析出来了 —— 立刻改一次,别等 DOMContentLoaded:
|
||||
否则用户会先看到一个原生日期框、过一会儿才变成文本框(本机实测 DCL 在 1.18s,
|
||||
网络慢时更明显)。DCL 再补一次是为了兜住别的脚本往页面里塞的输入。 */
|
||||
run();
|
||||
if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", run);
|
||||
})();
|
||||
</script>
|
||||
{{/* 输入弹层:替代 window.prompt(它会把提示文本与默认值写进地址栏)。
|
||||
全站都可能用到(报告页复制链接、后台活动改名),所以无条件引入。 */}}
|
||||
<script src="/static/js/prompt-box.js?v={{.AssetV}}"></script>
|
||||
|
||||
Reference in New Issue
Block a user