diff --git a/public/static/admin/css/public.css b/public/static/admin/css/public.css index 2012a91..2297b5d 100644 --- a/public/static/admin/css/public.css +++ b/public/static/admin/css/public.css @@ -859,6 +859,81 @@ table样式 margin: 0; } +/* 卡片操作按钮三态显隐:卡片网格内默认隐藏(保占位防 footer 跳动)、 + hover 显示;设置面板开关写入容器的 ua-card-operat-always 类后常显 + (admin-table.js 两条渲染路径挂类);触屏设备无 hover 能力恒显。 */ +.ua-layout-cards .ua-data-card-operat { + opacity: 0; + visibility: hidden; + transition: opacity 0.2s, visibility 0.2s; +} + +.ua-data-card:hover .ua-data-card-operat { + opacity: 1; + visibility: visible; +} + +.ua-card-operat-always .ua-data-card-operat { + opacity: 1; + visibility: visible; +} + +@media (hover: none) { + .ua-layout-cards .ua-data-card-operat { + opacity: 1; + visibility: visible; + } +} + +.ua-card-setting-panel { + min-width: 200px; +} + +.ua-card-setting-title { + padding: 10px 18px 2px; + color: #999; + font-size: 12px; +} + +.ua-card-setting-item { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + padding: 8px 18px; +} +.ua-card-setting-item:hover { + background-color: #f8f8f8; +} + +.ua-card-setting-switch { + position: relative; + flex: none; + width: 36px; + height: 18px; + border-radius: 9px; + background-color: #d2d2d2; + cursor: pointer; + transition: background-color 0.2s; +} +.ua-card-setting-switch::after { + content: ""; + position: absolute; + top: 2px; + left: 2px; + width: 14px; + height: 14px; + border-radius: 50%; + background-color: #fff; + transition: left 0.2s; +} +.ua-card-setting-switch.on { + background-color: rgb(22, 183, 119); +} +.ua-card-setting-switch.on::after { + left: 20px; +} + @media (max-width: 768px) { .ua-layout-cards { grid-template-columns: 1fr; diff --git a/public/static/admin/css/public.scss b/public/static/admin/css/public.scss index 8abd42b..1ce6c95 100644 --- a/public/static/admin/css/public.scss +++ b/public/static/admin/css/public.scss @@ -881,6 +881,87 @@ table样式 } } +// 卡片操作按钮三态显隐:卡片网格内默认隐藏(保占位防 footer 跳动)、 +// hover 显示;设置面板开关写入容器的 ua-card-operat-always 类后常显 +// (admin-table.js 两条渲染路径挂类);触屏设备无 hover 能力恒显。 +.ua-layout-cards .ua-data-card-operat { + opacity: 0; + visibility: hidden; + transition: opacity .2s, visibility .2s; +} + +.ua-data-card:hover .ua-data-card-operat { + opacity: 1; + visibility: visible; +} + +.ua-card-operat-always .ua-data-card-operat { + opacity: 1; + visibility: visible; +} + +@media (hover: none) { + .ua-layout-cards .ua-data-card-operat { + opacity: 1; + visibility: visible; + } +} + +// 卡片设置面板(admin-table.js listenToolbar case 'TABLE_CARD_SETTING' 产出; +// 面板骨架复用上方 .ul-nav-block 基类,此处只补面板本体、配置行与自绘开关) +.ua-card-setting-panel { + min-width: 200px; +} + +.ua-card-setting-title { + padding: 10px 18px 2px; + color: #999; + font-size: 12px; +} + +.ua-card-setting-item { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + padding: 8px 18px; + + &:hover { + background-color: #f8f8f8; + } +} + +.ua-card-setting-switch { + position: relative; + flex: none; + width: 36px; + height: 18px; + border-radius: 9px; + background-color: #d2d2d2; + cursor: pointer; + transition: background-color .2s; + + &::after { + content: ''; + position: absolute; + top: 2px; + left: 2px; + width: 14px; + height: 14px; + border-radius: 50%; + background-color: #fff; + transition: left .2s; + } + + &.on { + background-color: rgb(22, 183, 119); + + &::after { + left: 20px; + } + } +} + @media (max-width: 768px) { .ua-layout-cards { grid-template-columns: 1fr; diff --git a/public/static/plugs/ulthon-admin/admin-table.js b/public/static/plugs/ulthon-admin/admin-table.js index 1b7e0b7..313b283 100644 --- a/public/static/plugs/ulthon-admin/admin-table.js +++ b/public/static/plugs/ulthon-admin/admin-table.js @@ -342,8 +342,9 @@ }; // 形态可见性同步:引擎数据区(表头+表体+合计行)与模板容器互斥显隐, - // 引擎视图的工具栏(刷新/新增/批量删除等)两形态共用保持可见,搜索区 - // 本就挂在表格元素之前不受影响。非 table 形态下引擎根本不渲染行数据 + // 引擎视图的工具栏(刷新/新增/批量删除等)两形态共用保持可见(print 与 + // 卡片设置图标除外,随形态互斥显隐),搜索区本就挂在表格元素之前不受影响。 + // 非 table 形态下引擎根本不渲染行数据 // (wrapper 非 table 分支不走引擎渲染),并非旧寄生实现"引擎恒渲+CSS 隐藏"。 var syncLayoutVisibility = function (tableId) { var layout = controlledLayouts[tableId]; @@ -354,7 +355,8 @@ var $box = $view.find('.layui-table-box').first(); var $total = $view.find('.layui-table-total').first(); var $container = $('#ua-layout-' + tableId); - if (resolveCurrentLayout(tableId).kind === 'table') { + var isTable = resolveCurrentLayout(tableId).kind === 'table'; + if (isTable) { destroyLayoutVueInstances(tableId); $box.add($total).removeClass('layui-hide'); $container.addClass('layui-hide').empty(); @@ -362,6 +364,10 @@ $box.add($total).addClass('layui-hide'); $container.removeClass('layui-hide'); } + // 工具栏形态联动:print 仅表格形态有意义;卡片设置仅非表格形态有意义。 + // filter(LAYTABLE_COLS)与视图切换(TABLE_LAYOUT)两形态常驻不动 + $view.find('[lay-event="LAYTABLE_PRINT"]').toggleClass('layui-hide', !isTable); + $view.find('[lay-event="TABLE_CARD_SETTING"]').toggleClass('layui-hide', isTable); }; if (window.UA_TABLE_STORE) { @@ -466,7 +472,9 @@ rows: [], page: state ? state.page : {curr: 1, limit: 0}, count: state ? state.count : 0, - checkedAll: state ? window.UA_TABLE_STORE.selection.isAll(tableId) : false + checkedAll: state ? window.UA_TABLE_STORE.selection.isAll(tableId) : false, + // 面板设置快照:模板经 d._list.settings / list.settings 只读 + settings: {cardOperatAlways: ua.getPageSetting('card-operat-always', '') === '1'} }; $.each(rows, function (i, row) { @@ -511,7 +519,7 @@ // 【tplFunction 调用约定】 // 单行 HTML = tplFunction.call(rowCtx, rowCtx, listCtx) // - this/第一参 = 行上下文 {...row, _cells, _operatHtml, _checked, _disabled} - // - 第二参 = 列表上下文 {tableId, rows, page, count, checkedAll} + // - 第二参 = 列表上下文 {tableId, rows, page, count, checkedAll, settings} // - 返回值 = 该行的 HTML 字符串(框架直接拼接,不做转义) // 【laytpl 调用约定(tplLay / tplLayId)】 // 单行 HTML = laytpl(tplLay | $(tplLayId).html()).render(rowCtx) @@ -533,7 +541,7 @@ // v-for="d in rows" 承接: // - rows = 行上下文数组,d 与 tplFunction/tplLay 的行上下文同构 // (d._cells.xxx / d._operatHtml / d._checked / d._disabled); - // - list = 列表上下文 {tableId, rows, page, count, checkedAll} + // - list = 列表上下文 {tableId, rows, page, count, checkedAll, settings} // (laytpl 的 d._list 同物;Vue 实例对 _/$ 前缀 data 键不做代理, // 裸标识符 _list 会 ReferenceError,故 Vue 形态改名为 list); // - _cells/_operatHtml 含 HTML,必须用 v-html 输出,纯文本用 {{ }}; @@ -616,6 +624,9 @@ if (vueTemplate !== null) { // 自定义模板形态移除内置 card 网格类(与 laytpl 同规则) $container.toggleClass('ua-layout-cards', resolved.entry.builtinCard === true); + // 常显开关类随渲染重挂(设置面板开关已写入页级 pageSetting, + // 切形态/重渲后保持;CSS 三态效果见 public.scss) + $container.toggleClass('ua-card-operat-always', ua.getPageSetting('card-operat-always', '') === '1'); if (context.rows.length === 0) { $container.html('