fix(images): 按老师要求回滚「点图片不勾选」,并去掉标签行内的状态字样

1. 回滚第 3 条:删掉整套「单击图片不改变勾选」逻辑(捕获阶段记按下前选中 + 松手还原),
   小圆勾的 click 恢复全平台生效 —— 点图片本身照旧参与勾选(老师决定)。
   保留本轮的另一半修复:Zoom 坐标修正(html zoom:1.1 与 DragSelect 的冲突)与
   图片/卡片原生拖拽禁用(这两条是「框选起点偏右、松手不释放」的真因)。
2. 标签管理每一行不再显示任何状态字样(已有的「已有 / 移除 / 部分有」全删,DOM 里也没了),
   状态只看左边那个勾:实心勾=有、方框=无、减号=部分有、红色方框=待移除。

验收:jsdom 全仓 396(标签那份 109/109);真机 51/51 全绿(含手机 390 一段)。
This commit is contained in:
mole404 committed 2026-10-02 02:14:21 +08:00
1 parent 8108cae88b
commit 2b57bcbbbb
4 files changed
+17 -78

No files matched your search

+2 -2
View File
@@ -165,7 +165,7 @@ RUN php -r "file_exists('.env') || copy('.env.example', '.env');" \
RUN printf '%s\n' \
'c0e513ec8e93fd81b34b3c6de5cf5eb8 ./public/js/context-js/context-js.js' \
'c0e513ec8e93fd81b34b3c6de5cf5eb8 ./resources/js/context-js.js' \
'402ff29758a50f5ed992434f434371a2 ./resources/views/user/images.blade.php' \
'2510df3a1e428177d9ab7affbb6a5489 ./resources/views/user/images.blade.php' \
| md5sum -c - \
&& grep -q "assetVersion('js/context-js/context-js.js')" ./resources/views/user/images.blade.php \
&& grep -q 'isIOSWebKit' ./public/js/context-js/context-js.js \
@@ -208,7 +208,7 @@ RUN APP_SRC_MD5=$(find app config routes -type f -print0 2>/dev/null | sort -z |
"fork_sha=${FORK_SHA}" \
"lsky_commit=${LSKY_COMMIT}" \
"context_js_md5=c0e513ec8e93fd81b34b3c6de5cf5eb8" \
"images_blade_md5=402ff29758a50f5ed992434f434371a2" \
"images_blade_md5=2510df3a1e428177d9ab7affbb6a5489" \
"app_src_md5=${APP_SRC_MD5}" \
"app_js_md5=${APP_JS_MD5}" \
"app_css_md5=${APP_CSS_MD5}" \
+1 -1
View File
@@ -52,7 +52,7 @@
# 三个文件各自的 md5(与 Dockerfile「自证 2」里的期望值一致):
# c0e513ec8e93fd81b34b3c6de5cf5eb8 src/resources/js/context-js.js
# c0e513ec8e93fd81b34b3c6de5cf5eb8 src/public/js/context-js/context-js.js
# 402ff29758a50f5ed992434f434371a2 src/resources/views/user/images.blade.php
# 2510df3a1e428177d9ab7affbb6a5489 src/resources/views/user/images.blade.php
#
# 上游原文件 md5(改动前,供比对):
# c8e57f6232848ca8277341ddf1a3a7a6 resources/js/context-js.js
+3 -62
View File
@@ -433,7 +433,6 @@
<i class="tag-state-icon fas fa-square w-4 shrink-0 text-ink-3" aria-hidden="true"></i>
<div class="min-w-0 flex-1 truncate text-[14px] name">__name__</div>
<div class="shrink-0 text-[13px] text-ink-3"><span class="images-count">__images_count__</span> 张</div>
<div class="tag-state-label shrink-0 text-[13px] text-ink-3"></div>
</a>
<div class="tag-row-actions flex shrink-0 items-center border-l border-line">
<button type="button" class="update flex h-11 w-11 items-center justify-center text-ink-2 hover:bg-surface-3 hover:text-brand" aria-label="重命名标签"><i class="fas fa-edit text-[15px]"></i></button>
@@ -934,23 +933,16 @@ classes: ['dragselect'],
let pendingRemove = removeIds.indexOf(id) !== -1;
let partial = ! checked && ! pendingRemove && someHave(id) && ! allHave(id);
// 行内只留左边那个勾表达状态(老师要求:不要「已有 / 移除」这类字样,太误导)
let icon = 'fa-square text-ink-3';
let label = '';
let labelCls = 'text-ink-3';
if (checked) {
icon = 'fa-check-square text-brand';
label = hasSelection ? '已有' : '';
labelCls = pendingAdd ? 'text-brand font-medium' : 'text-ink-3';
} else if (pendingRemove) {
icon = 'fa-square text-danger';
label = '移除';
labelCls = 'text-danger font-medium';
} else if (partial) {
icon = 'fa-minus-square text-brand';
label = '部分有';
}
$row.find('.tag-state-icon').attr('class', 'tag-state-icon fas w-4 shrink-0 ' + icon);
$row.find('.tag-state-label').attr('class', 'tag-state-label shrink-0 text-[13px] ' + labelCls).text(label);
if (pendingAdd) {
$row.addClass('border-brand bg-brand-soft');
} else if (pendingRemove) {
@@ -1273,53 +1265,6 @@ classes: ['dragselect'],
});
// 单击(没拖动)不改变勾选 —— 见上面 ②
let pressSel = null;
let pressFrom = null;
let pressMoved = false;
let pressCircle = null;
// 用捕获阶段的原生监听:DragSelect 会给每张可选卡片挂 click/mousedown 并在自己的处理里
// 停传播,挂在冒泡阶段(jQuery 的 $(document).on)会被它拦掉,实测那些处理根本收不到。
document.addEventListener('mousedown', e => {
if (! $(e.target).closest(IMAGES_GRID).length) {
return;
}
pressSel = ds.getSelection().slice();
pressFrom = {x: e.clientX, y: e.clientY};
pressMoved = false;
// 只有按在右上角小圆勾上才算「要勾选」
pressCircle = $(e.target).closest('.image-selector').length ? e.target : null;
}, true);
document.addEventListener('mousemove', e => {
if (pressFrom && (Math.abs(e.clientX - pressFrom.x) > 3 || Math.abs(e.clientY - pressFrom.y) > 3)) {
pressMoved = true;
}
}, true);
document.addEventListener('mouseup', () => {
const sel = pressSel;
const circle = pressCircle;
const moved = pressMoved;
pressSel = null;
pressFrom = null;
pressMoved = false;
pressCircle = null;
// 手机上 DragSelect 是停掉的、这条逻辑不参与(勾选仍走 .image-selector 的 click)
if (sel === null || moved || utils.isMobile()) {
return;
}
// 目标选中集合一次算好(幂等,可以反复盖):
// 按下前有什么就还原成什么;如果按的是小圆勾,再把这张图加/去掉。
const card = circle ? $(circle).closest(IMAGES_ITEM).get(0) : null;
const want = () => (! card ? sel
: (sel.indexOf(card) === -1 ? sel.concat([card]) : sel.filter(item => item !== card)));
const apply = () => {
ds.setSelection(want()); // 单击 → 还原按下前的选中(点图片不会顺手勾上)
bindOperates();
};
// 库在 mouseup、click、以及下一帧 rAF 里都可能「点哪个选哪个」,连盖两拍才稳
setTimeout(apply, 0);
requestAnimationFrame(() => setTimeout(apply, 0));
}, true);
// 兜底:万一库没收到 mouseup(拖到窗口外等),松手也要解锁,别让界面卡在拖动状态
document.addEventListener('mouseup', () => {
if (ds.Interaction && ds.Interaction.isInteracting) {
@@ -1393,13 +1338,9 @@ classes: ['dragselect'],
}, 320);
});
// 手机上 DragSelect 被 ds.stop() 停了、Interaction:end 不会再来,所以这条 click 路径留给手机;
// 桌面走上面那套(单击不改变勾选、只有小圆勾才切换),两条路径同时生效会对同一张图拨两次。
$photos.on('click', '.image-selector', function () {
if (utils.isMobile()) {
ds.toggleSelection($(this).closest('a'));
bindOperates();
}
ds.toggleSelection($(this).closest('a'));
bindOperates();
})
/* ---------------- 卡片角标开关(显示图片标签) ---------------- */
+11 -13
View File
@@ -162,8 +162,8 @@ console.log('\n[A. 静态] 标签落点:详情行 / 卡片角标 / 批量打
! blade.includes('data-state="none"') && ! blade.includes('fa-circle-plus') && ! blade.includes('fa-circle-minus')
&& blade.includes('const isChecked = (id)')
&& blade.includes('勾上 = 给这些图片加上')
&& blade.includes("label = hasSelection ? '已有' : ''") && blade.includes("label = '移除'")
&& ! blade.includes("'添加'"));
&& ! blade.includes('tag-state-label')
&& ! blade.includes("'已有'") && ! blade.includes("'移除'") && ! blade.includes("'部分有'"));
check('「确定」默认禁用、且没选中图片时整个不显示', /id="image-tags-confirm"[^>]*disabled/.test(tpl('image-tags-tpl'))
&& /\$confirm\.prop\('disabled', true\)\.toggle\(hasSelection\)/.test(blade));
check('批量打标请求形状:ids + tags + remove_tags(同一 route user.images.tags,id 仍是数字)',
@@ -233,12 +233,9 @@ console.log('\n[A. 静态] 「显示图片标签」开关 + 框选修复');
&& blade.includes("attributeFilter: ['style']") && blade.includes('ds.SelectorArea._rect = undefined'));
check('禁掉图片原生拖拽(-webkit-user-drag + dragstart 兜底)—— 否则拖动会「锁定不释放」',
blade.includes('-webkit-user-drag: none') && /\$photos\.on\('dragstart'/.test(blade));
check('单击图片不改勾选:捕获阶段记下按下前的选中,松手没位移就还原(只有小圆勾才切换)',
/pressSel = ds\.getSelection\(\)\.slice\(\)/.test(blade)
&& blade.includes("document.addEventListener('mousedown'")
&& blade.includes("document.addEventListener('mouseup'")
&& /ds\.setSelection\(want\(\)\)/.test(blade)
&& blade.includes("closest('.image-selector')"));
check('(已按老师要求回滚)点图片本身照旧参与勾选:不做任何「单击回滚」,小圆勾 click 全平台生效',
! blade.includes('pressCircle') && ! blade.includes('pressMoved')
&& /\$photos\.on\('click', '\.image-selector', function \(\) \{\s*ds\.toggleSelection/.test(blade));
check('标签管理窗口版式:新建行在列表之前、条目行 overflow-hidden、副标题只留已选数量',
blade.indexOf('id="image-tags-new"') < blade.indexOf('id="image-tags-list"')
&& /class="image-tag-row[^"]*overflow-hidden/.test(blade)
@@ -530,16 +527,16 @@ console.log('\n[B. 行为] 标签管理:给选中的图片加 / 移除标签
const rows = () => $('#image-tags-list .image-tag-row');
check('两行标签,每行都有改名 / 删除按钮', rows().length === 2
&& rows().eq(0).find('.update').length === 1 && rows().eq(0).find('.delete').length === 1);
check('两张图都有的标签默认就是勾上的(fa-check-square + 「已有」)',
check('两张图都有的标签默认就是勾上的(fa-check-square),行内不带任何字样',
rows().eq(0).find('.tag-state-icon').attr('class').includes('fa-check-square')
&& rows().eq(0).text().includes('已有'));
&& ! rows().eq(0).text().includes('已有'));
check('没动过任何东西时「确定」是禁用的', $('#image-tags-confirm').prop('disabled') === true);
// 取消勾选「风景」(两张图上都有)→ 变成「移除」
rows().eq(0).find('.image-tag-toggle').trigger('click');
check('取消勾选 → 未勾选 + 文案「移除」+ 行描红(危险色)',
rows().eq(0).find('.tag-state-icon').attr('class').includes('fa-square')
&& rows().eq(0).text().includes('移除')
&& ! rows().eq(0).text().includes('移除') && rows().eq(0).find('.tag-state-label').length === 0
&& rows().eq(0).attr('class').includes('border-danger'));
check('「确定」变成可用', $('#image-tags-confirm').prop('disabled') === false);
@@ -577,8 +574,9 @@ console.log('\n[B. 行为] 「部分选中的图片有这个标签」→ 半勾
t.methods.tag();
const row = () => $('#image-tags-list .image-tag-row[data-id="11"]');
check('半勾态:fa-minus-square + 文案「部分有」',
row().find('.tag-state-icon').attr('class').includes('fa-minus-square') && row().text().includes('部分有'));
check('半勾态:只看图标(fa-minus-square),行内没有任何字样',
row().find('.tag-state-icon').attr('class').includes('fa-minus-square')
&& ! row().text().includes('部分有'));
row().find('.image-tag-toggle').trigger('click');
check('点一下 → 全勾(打了勾),确定可用', row().find('.tag-state-icon').attr('class').includes('fa-check-square')