From a9f9045d1035bd271bf4bb0c203de811340bc8b5 Mon Sep 17 00:00:00 2001 From: augushong Date: Sat, 3 Oct 2026 11:55:56 +0000 Subject: [PATCH] =?UTF-8?q?fix(table):=20=E5=8D=A1=E7=89=87=E5=8B=BE?= =?UTF-8?q?=E9=80=89=E6=94=B6=E6=95=9B=E8=87=B3=E5=8B=BE=E4=BD=8D=E5=9B=BE?= =?UTF-8?q?=E6=A0=87=E5=B9=B6=E6=B6=88=E9=99=A4=E5=8B=BE=E9=80=89=E9=87=8D?= =?UTF-8?q?=E6=B8=B2=E9=97=AA=E7=83=81=EF=BC=88pro#4=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 委托收敛勾位判定+快速路径 class 回显 - 勾位光标样式 - usercard/goodscard 勾位适配 - 两个技能文档契约同步 --- .agents/skills/ulthon-admin-table/SKILL.md | 4 +-- .agents/skills/ulthon-card-template/SKILL.md | 14 ++++---- extend/base/admin/view/mall/goods/index.html | 10 +++--- .../base/admin/view/system/admin/index.html | 5 +-- public/static/admin/css/public.css | 6 +++- public/static/admin/css/public.scss | 7 +++- .../static/plugs/ulthon-admin/admin-table.js | 33 ++++++++++++++++--- 7 files changed, 57 insertions(+), 22 deletions(-) diff --git a/.agents/skills/ulthon-admin-table/SKILL.md b/.agents/skills/ulthon-admin-table/SKILL.md index 485a847..ae15b77 100644 --- a/.agents/skills/ulthon-admin-table/SKILL.md +++ b/.agents/skills/ulthon-admin-table/SKILL.md @@ -775,11 +775,11 @@ layoutDefault: true, // 旧协议"自动判断",视 - 双端自动注入后 PC 端同样有视图切换按钮与卡片形态,端差异只体现在缺省形态上:PC 缺省 `table`,手机缺省 `card`(记忆与按端 layoutDefault 的优先级更高,见 11.2 解析链) - 手机端判定 `ua.checkMobile()`(`admin-utils.js` 转发,实现位于 `public/static/common/js/app.js`):UA 关键字(Android/iPhone/iPad 等)或 `window.screen` 宽 < 600 且高 < 800。判的是物理屏幕指标,**浏览器开发者工具仅改视口宽度不会触发**;设备仿真验证手机默认形态时,必须同时覆写 UA 或仿真 screen 尺寸,仅设 viewport 无效 -- 卡片形态能力边界:工具栏(刷新/新增/批量删除/导出)与搜索区两形态共用、照常可用;行选中、豁免与 `_disabled` 等模板侧语义由卡片模板契约定义(见 11.4) +- 卡片形态能力边界:工具栏(刷新/新增/批量删除/导出)与搜索区两形态共用、照常可用;行选中、豁免与 `_disabled` 等模板侧语义由卡片模板契约定义(见 11.4);`_cells` 隐藏列(col.hide)不产出对应键,模板按原始字段直取即可 ### 11.4 自定义模板指引 -自定义卡片/模板形态的创作不在本技能展开,统一由 [ulthon-card-template](./ulthon-card-template/SKILL.md) 技能承接:渲染上下文契约(`_cells`/`_operatHtml`/`_checked`/`_disabled`、上下文冻结、列表上下文命名)、模板节点位置硬约束、行选中委托与豁免名单、取值通道三规则、usercardTpl/goodscardTpl 范例走读、实战配方、设计模式库、模板作者坑与验收 checklist。本技能只负责机制如何把模板跑起来;两个官方范例的 render 配置块(layoutList 三形态、layoutDefault 对象式与字符串式)见第十章引用表末行,可作机制示范直接对照。 +自定义卡片/模板形态的创作不在本技能展开,统一由 [ulthon-card-template](./ulthon-card-template/SKILL.md) 技能承接:渲染上下文契约(`_cells`/`_operatHtml`/`_checked`/`_disabled`、上下文冻结、列表上下文命名)、模板节点位置硬约束、行选中委托与豁免名单(勾位契约:点行内 `.ua-data-card-check` 勾位元素切换勾选,勾位元素须在行内,行根元素仍需携带 `data-table-id` + `data-id` 两属性)、取值通道三规则、usercardTpl/goodscardTpl 范例走读、实战配方、设计模式库、模板作者坑与验收 checklist。本技能只负责机制如何把模板跑起来;两个官方范例的 render 配置块(layoutList 三形态、layoutDefault 对象式与字符串式)见第十章引用表末行,可作机制示范直接对照。 ## 相关技能 diff --git a/.agents/skills/ulthon-card-template/SKILL.md b/.agents/skills/ulthon-card-template/SKILL.md index 7b4c48e..50d6264 100644 --- a/.agents/skills/ulthon-card-template/SKILL.md +++ b/.agents/skills/ulthon-card-template/SKILL.md @@ -1,6 +1,6 @@ --- name: "ulthon-card-template" -description: "自定义卡片/模板形态创作指南:面向想让列表页变好看、为自己的列表页定制专属卡片形态的下游开发者。涵盖适用判断(内置 card 兜底 vs 定制时机、锁定纯表格)、五级模板协议选型建议(官方范例为何都选 tplVueId)、渲染上下文契约(_cells/_operatHtml/_checked/_disabled 与上下文冻结、模板节点容器外硬约束、行选中委托与豁免名单)、以商品卡为蓝本的 step-by-step 配方、设计模式库(头部三件套/图面悬浮开关/价格层级/状态徽标/底部分隔/图片降级/响应式/统一设计语言)、取值通道三规则、坑与红线、验收 checklist。需要定制卡片/自定义卡片模板/卡片模板/商品卡/名片/自定义形态/layoutList 自定义条目/tplVueId,或想让列表变好看、排查自定义模板不渲染/点卡片误勾选/模板内开关失效时调用。多形态机制(受控数据流、五级协议引擎、双端注入、layoutDefault 三层链)见 ulthon-admin-table 技能第十一章,本技能定位是动手创作,不复述机制。" +description: "自定义卡片/模板形态创作指南:面向想让列表页变好看、为自己的列表页定制专属卡片形态的下游开发者。涵盖适用判断(内置 card 兜底 vs 定制时机、锁定纯表格)、五级模板协议选型建议(官方范例为何都选 tplVueId)、渲染上下文契约(_cells/_operatHtml/_checked/_disabled 与上下文冻结、模板节点容器外硬约束、行选中委托与豁免名单)、以商品卡为蓝本的 step-by-step 配方、设计模式库(头部三件套/图面悬浮开关/价格层级/状态徽标/底部分隔/图片降级/响应式/统一设计语言)、取值通道三规则、坑与红线、验收 checklist。需要定制卡片/自定义卡片模板/卡片模板/商品卡/名片/自定义形态/layoutList 自定义条目/tplVueId,或想让列表变好看、排查自定义模板不渲染/点勾位图标不切换勾选/模板内开关失效时调用。多形态机制(受控数据流、五级协议引擎、双端注入、layoutDefault 三层链)见 ulthon-admin-table 技能第十一章,本技能定位是动手创作,不复述机制。" --- # 自定义卡片模板创作指南(ulthon-card-template) @@ -50,7 +50,7 @@ Vue 形态的 `v-for="d in rows"` 里的 `d`: | 字段 | 说明 | |------|------| | `...row` | 行原始字段全部可用(username、title、price、create_time 等) | -| `_cells` | 对象,field 到该列 templet 渲染产物 HTML 的映射。只有配了渲染器的列才有内容;纯文本列恒为空串,**勿引用,直接用原始字段** | +| `_cells` | 对象,field 到该列 templet 渲染产物 HTML 的映射。只有配了渲染器的列才有内容;纯文本列恒为空串,**勿引用,直接用原始字段**;隐藏列(col.hide)不产出对应键 | | `_operatHtml` | 操作列渲染产物(编辑/删除等按钮 HTML,已按 `data-auth-*` 裁剪权限) | | `_checked` | 该行是否选中(store 选中集合) | | `_disabled` | 该行是否禁选 | @@ -77,7 +77,7 @@ Vue 形态的 `v-for="d in rows"` 里的 `d`: ### 3.5 行选中委托与豁免名单 -行根元素携带 `data-table-id` + `data-id` 两属性即获得统一行选中委托,点卡片任意空白处切换勾选,零 JS。选中态经 `:class` 高亮回显,禁选行整元素不可勾选: +点行内 `.ua-data-card-check` 勾位元素切换勾选,零 JS;行根元素仍需携带 `data-table-id` + `data-id` 两属性(委托按行根属性定位行),且勾位元素必须写在行内(委托按该类判定点击意图,行内没有勾位元素则该行无法勾选)。选中态经 `:class` 高亮回显,禁选行整元素不可勾选: ```html @@ -136,7 +136,7 @@ layoutList: ['table', {name: 'mycard', title: '自定义卡', tplLayId: '#myCard
- + @@ -279,7 +279,7 @@ layoutDefault: 'goodscard', - 操作按钮配置对象自 commit 53ee2e3 起有拷贝保护(渲染函数对配置只读):自定义按钮的 class/method 不会被渲染过程污染,形态反复切换后按钮样式与 URL 拼接保持稳定。这是已修复的历史坑:修复前的版本存在"切换形态后按钮 class 丢失、URL 滚雪球"的缺陷,老版本升级后若仍见此症状先确认包含 53ee2e3。 - 形态切换零请求,但 switch 开关切换不是:点击开关会触发 modify 提交加一次列表重查(各 1 个 XHR),这是框架标准链路,验收时勿与"切换零请求"混淆。 -- 卡片字段清单是 render 注册时的 cols 快照,搜索列面板运行时隐藏的列不会从卡片消失(两套状态解耦),属已知边界,已立议题跟踪,模板侧无需规避。 +- 卡片字段清单实时跟随列显隐:列筛选面板隐藏/恢复列后,卡片形态自动重渲(colToggled 监听 + store 当页数据零请求重渲),隐藏列不产出 `_cells` 对应键,模板侧无需规避。 ## 八、验收 checklist @@ -288,9 +288,9 @@ layoutDefault: 'goodscard', - [ ] **三形态循环零网络请求**:表格、自定义模板、内置 card 来回切,XHR 计数不变 - [ ] **F5 记忆保持**:通过视图下拉切到自定义形态后刷新,形态保持(说明下拉写入的记忆被正确读取) - [ ] **手机单列不崩**:390 宽视口下网格单列、无横向滚动(端判定与仿真要点见 ulthon-admin-table 第十一章 11.3) -- [ ] **开关可切且不触发勾选**:点卡片内 switch,POST modify 200,该卡片不出现选中态(无 `ua-data-card-checked` 类、无勾位图标),豁免名单生效 +- [ ] **开关可切且不触发勾选**:点卡片内 switch,POST modify 200,该卡片不出现选中态(无 `ua-data-card-checked` 类、勾位图标保持灰色未选中态),豁免名单生效 - [ ] **console 零新增错误**:数据固有 404(如测试图片)可豁免,模板相关零报错;模板渲染失败时框架会自动回退表格(机制见 ulthon-admin-table 第十一章 11.2),回退本身也是排查信号 -- [ ] **交互豁免有效**:点操作按钮(编辑/删除等)打开预期行为且不勾选卡片;点卡片空白处正常切换勾选 +- [ ] **交互豁免有效**:点操作按钮(编辑/删除等)打开预期行为且不勾选卡片;点勾位图标正常切换勾选,点卡片正文空白处不触发勾选 - [ ] **(如有图片字段)404 降级**:无图与加载失败都显示占位,卡片高度不塌 验证工具建议:命令行接口冒烟用 [ulthon-tools-http-call](../ulthon-tools-http-call/SKILL.md);页面断言(形态、XHR、豁免)用浏览器实测,具体断言选择器与仿真要点见 [ulthon-page-qa](../ulthon-page-qa/SKILL.md)。 diff --git a/extend/base/admin/view/mall/goods/index.html b/extend/base/admin/view/mall/goods/index.html index afdafa5..4887370 100644 --- a/extend/base/admin/view/mall/goods/index.html +++ b/extend/base/admin/view/mall/goods/index.html @@ -17,8 +17,8 @@ 上下文契约(admin-table.js buildLayoutContext): - rows:行上下文数组,d 与表格行数据同构(含原始字段 + _cells/_operatHtml/_checked/_disabled) - list:列表上下文 {tableId, page, count, checkedAll}(Vue 形态不叫 _list) - - 行根元素携带 data-table-id + data-id 两属性即获得统一行选中委托(点击卡片 - 切换勾选,按钮/表单控件/layui 美化层自动豁免),选中态经 :class 高亮回显 + - 行根元素携带 data-table-id + data-id 两属性即获得统一行选中委托(点击勾位 + 图标切换勾选,按钮/表单控件/layui 美化层自动豁免),选中态经 :class 高亮回显 - _cells/_operatHtml 含渲染产物 HTML,必须用 v-html 输出;纯文本字段用 {{ }} 原生插值(自动转义);处理函数内不得修改渲染上下文数据(冻结契约) - 事件无需自行绑定:操作按钮与 switch 经页面级委托和 form 事件天然生效 @@ -40,13 +40,13 @@ :class="{'ua-data-card-checked': d._checked, 'ua-data-card-disabled': d._disabled}"> + 左上角勾位图标常显(.ua-data-card-check:未选中灰可点、选中变绿) -->
- +
diff --git a/public/static/admin/css/public.css b/public/static/admin/css/public.css index c4d1725..2012a91 100644 --- a/public/static/admin/css/public.css +++ b/public/static/admin/css/public.css @@ -753,7 +753,7 @@ table样式 border: 1px solid #f2f2f2; border-radius: 5px; background-color: #fff; - cursor: pointer; + cursor: default; transition: border-color 0.2s, box-shadow 0.2s; } .ua-data-card:hover { @@ -797,6 +797,10 @@ table样式 color: #d2d2d2; font-size: 18px; line-height: 1; + cursor: pointer; +} +.ua-data-card-check:hover { + color: rgb(22, 183, 119); } .ua-data-card-checked .ua-data-card-check { diff --git a/public/static/admin/css/public.scss b/public/static/admin/css/public.scss index b1e6e08..8abd42b 100644 --- a/public/static/admin/css/public.scss +++ b/public/static/admin/css/public.scss @@ -768,7 +768,7 @@ table样式 border: 1px solid #f2f2f2; border-radius: 5px; background-color: #fff; - cursor: pointer; + cursor: default; transition: border-color .2s, box-shadow .2s; &:hover { @@ -815,6 +815,11 @@ table样式 color: #d2d2d2; font-size: 18px; line-height: 1; + cursor: pointer; + + &:hover { + color: rgb(22, 183, 119); + } } .ua-data-card-checked .ua-data-card-check { diff --git a/public/static/plugs/ulthon-admin/admin-table.js b/public/static/plugs/ulthon-admin/admin-table.js index aa749b3..1b7e0b7 100644 --- a/public/static/plugs/ulthon-admin/admin-table.js +++ b/public/static/plugs/ulthon-admin/admin-table.js @@ -155,12 +155,14 @@ // 统一行选中委托(任务 18):模板渲染容器内凡带 data-table-id + data-id 属性 // 的行元素——内置 card 的 .ua-data-card 与自定义 laytpl/Vue 模板的卡片/勾位 - // 元素——点击即切换选中,全部走本委托,无任何形态专用事件。模板作者契约: - // 给行根元素(或勾位元素)加这两属性即获得点选交互,无需页面级监听。 + // 元素——仅当点击落在行内 .ua-data-card-check 勾位元素内才切换选中,全部走 + // 本委托,无任何形态专用事件。模板作者契约:给行根元素(或勾位元素)加这两 + // 属性、勾位区域挂 .ua-data-card-check 类即获得点选交互,无需页面级监听。 // 交互元素(按钮/表单控件/layui 美化层)豁免不触发勾选;禁用行 // (ua-data-card-disabled 标记或行 LAY_DISABLED)整元素不可勾选。选择态落 // store(与引擎勾选同一事实源,批量删除经 ua.table.checkStatus 分发即取到), - // 随后重渲模板管线回显勾位标记。 + // 随后走快速路径按模式只改勾位卡片 class 回显(radio 替换 / checkbox 切换), + // 目标卡元素找不到时兜底整容器重渲模板管线回显勾位标记。 $(document).on('click', '[data-table-id][data-id]', function (e) { var $card = $(this); var tableId = $card.attr('data-table-id'); @@ -171,6 +173,10 @@ if ($card.hasClass('ua-data-card-disabled')) { return; } + // 仅勾位点击生效:点卡片正文不触发勾选(点正文零开销) + if ($(e.target).closest('.ua-data-card-check').length === 0) { + return; + } if ($(e.target).closest('a,button,input,select,textarea,label,.layui-form-switch,.layui-form-checkbox,.layui-form-radio').length) { return; } @@ -189,8 +195,27 @@ if (!row || row.LAY_DISABLED) { return; } + // 快速路径(pro#4):不做整容器重渲,仅按模式调整勾位卡片 class—— + // radio 替换(清旧卡、点新卡,重复点同一卡净效果保持选中)、checkbox + // 切换(含再点取消);DOM 不重建,含图卡片不闪。自定义模板未按契约 + // 输出勾位元素时兜底整容器重渲,不丢功能。 + var prevRadioId = (state.selectMode === 'radio' && state.selectedIds && state.selectedIds.length) + ? state.selectedIds[0] + : null; window.UA_TABLE_STORE.selection.set(tableId, row); - ua.table.renderLayoutForm(tableId); + var $target = $('#ua-layout-' + tableId).find('[data-id="' + rowId + '"]'); + if ($target.length === 0) { + ua.table.renderLayoutForm(tableId); + return; + } + if (state.selectMode === 'radio') { + if (prevRadioId !== null && String(prevRadioId) !== String(rowId)) { + $('#ua-layout-' + tableId).find('[data-id="' + prevRadioId + '"]').removeClass('ua-data-card-checked'); + } + $target.addClass('ua-data-card-checked'); + } else { + $target.toggleClass('ua-data-card-checked'); + } }); // (b) 模板引擎优先级解析:tplFunction > tplLay > tplVue > tplLayId > tplVueId,