mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-10-29 08:58:22 +08:00
feat(table): 内置卡片形态与本地化样式
This commit is contained in:
@@ -175,8 +175,7 @@ body {
|
||||
|
||||
.layuimini-upload-show a img {
|
||||
height: 80px;
|
||||
-o-object-fit: cover;
|
||||
object-fit: cover;
|
||||
object-fit: cover;
|
||||
}
|
||||
|
||||
.layuimini-upload-show .uploads-delete-tip {
|
||||
@@ -414,6 +413,8 @@ table样式
|
||||
}
|
||||
|
||||
.layui-layer-easy .layui-layer-moves {
|
||||
-webkit-box-sizing: content-box;
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
@@ -727,6 +728,138 @@ table样式
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.ua-layout-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.ua-layout-empty {
|
||||
padding: 24px 0;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.ua-layout-loading {
|
||||
min-height: 60px;
|
||||
opacity: 0.55;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.ua-data-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid #f2f2f2;
|
||||
border-radius: 5px;
|
||||
background-color: #fff;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
.ua-data-card:hover {
|
||||
border-color: #d2d2d2;
|
||||
}
|
||||
|
||||
.ua-data-card-checked {
|
||||
border-color: rgb(22, 183, 119);
|
||||
box-shadow: 0 0 0 1px rgb(22, 183, 119) inset;
|
||||
}
|
||||
|
||||
.ua-data-card-disabled {
|
||||
background-color: #fafafa;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.ua-data-card-disabled .ua-data-card-title,
|
||||
.ua-data-card-disabled .ua-data-card-item-value,
|
||||
.ua-data-card-disabled .ua-data-card-time {
|
||||
color: #c2c2c2;
|
||||
}
|
||||
|
||||
.ua-data-card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-bottom: 8px;
|
||||
margin-bottom: 8px;
|
||||
border-bottom: 1px solid #f2f2f2;
|
||||
}
|
||||
|
||||
.ua-data-card-title {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.ua-data-card-check {
|
||||
flex: none;
|
||||
margin-left: 8px;
|
||||
color: #d2d2d2;
|
||||
font-size: 18px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.ua-data-card-checked .ua-data-card-check {
|
||||
color: rgb(22, 183, 119);
|
||||
}
|
||||
|
||||
.ua-data-card-body {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.ua-data-card-item {
|
||||
display: flex;
|
||||
margin-bottom: 4px;
|
||||
line-height: 22px;
|
||||
}
|
||||
.ua-data-card-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.ua-data-card-item-title {
|
||||
flex: none;
|
||||
color: #999;
|
||||
}
|
||||
.ua-data-card-item-title::after {
|
||||
content: ":";
|
||||
}
|
||||
|
||||
.ua-data-card-item-value {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ua-data-card-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 8px;
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid #f2f2f2;
|
||||
}
|
||||
|
||||
.ua-data-card-time {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ua-data-card-operat {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.ua-data-card-operat a {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.ua-layout-cards {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
@media (max-width: 768px) {
|
||||
.layuimini-form .layui-form-item {
|
||||
padding-right: 0;
|
||||
@@ -761,4 +894,4 @@ table样式
|
||||
|
||||
.search-tab .layui-tabs-body {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -740,6 +740,148 @@ table样式
|
||||
|
||||
}
|
||||
|
||||
// 多形态渲染:内置 card 形态(模板管线给容器挂 .ua-layout-cards,卡片本体为
|
||||
// .ua-data-card 族;admin-table.js 内置 card 模板产出,样式本地化不依赖 CDN)
|
||||
.ua-layout-cards {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.ua-layout-empty {
|
||||
padding: 24px 0;
|
||||
text-align: center;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
// 模板管线 reload 期间的加载态标记(wrapper 在 done 后移除)
|
||||
.ua-layout-loading {
|
||||
min-height: 60px;
|
||||
opacity: .55;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.ua-data-card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 10px 12px;
|
||||
border: 1px solid #f2f2f2;
|
||||
border-radius: 5px;
|
||||
background-color: #fff;
|
||||
cursor: pointer;
|
||||
transition: border-color .2s, box-shadow .2s;
|
||||
|
||||
&:hover {
|
||||
border-color: #d2d2d2;
|
||||
}
|
||||
}
|
||||
|
||||
.ua-data-card-checked {
|
||||
border-color: rgb(22, 183, 119);
|
||||
box-shadow: 0 0 0 1px rgb(22, 183, 119) inset;
|
||||
}
|
||||
|
||||
// 禁用行(_disabled):整卡置灰不可勾选(卡内操作按钮仍可用,与引擎 LAY_DISABLED 只锁勾选的语义一致)
|
||||
.ua-data-card-disabled {
|
||||
background-color: #fafafa;
|
||||
cursor: not-allowed;
|
||||
|
||||
.ua-data-card-title,
|
||||
.ua-data-card-item-value,
|
||||
.ua-data-card-time {
|
||||
color: #c2c2c2;
|
||||
}
|
||||
}
|
||||
|
||||
.ua-data-card-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding-bottom: 8px;
|
||||
margin-bottom: 8px;
|
||||
border-bottom: 1px solid #f2f2f2;
|
||||
}
|
||||
|
||||
.ua-data-card-title {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.ua-data-card-check {
|
||||
flex: none;
|
||||
margin-left: 8px;
|
||||
color: #d2d2d2;
|
||||
font-size: 18px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.ua-data-card-checked .ua-data-card-check {
|
||||
color: rgb(22, 183, 119);
|
||||
}
|
||||
|
||||
.ua-data-card-body {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.ua-data-card-item {
|
||||
display: flex;
|
||||
margin-bottom: 4px;
|
||||
line-height: 22px;
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ua-data-card-item-title {
|
||||
flex: none;
|
||||
color: #999;
|
||||
|
||||
&::after {
|
||||
content: ':';
|
||||
}
|
||||
}
|
||||
|
||||
.ua-data-card-item-value {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ua-data-card-footer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-top: 8px;
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid #f2f2f2;
|
||||
}
|
||||
|
||||
.ua-data-card-time {
|
||||
color: #999;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.ua-data-card-operat {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
justify-content: flex-end;
|
||||
|
||||
a {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.ua-layout-cards {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.layuimini-form .layui-form-item {
|
||||
padding-right: 0;
|
||||
|
||||
@@ -79,6 +79,106 @@
|
||||
return result;
|
||||
};
|
||||
|
||||
// ========== 内置 card 形态(name='card' 且无自定义钩子时启用)==========
|
||||
// 结构参照旧寄生实现的 header/body/footer 骨架(代码全新):header(标题 +
|
||||
// 勾位图标)、body(键值对字段列表)、footer(create_time + 操作按钮)。
|
||||
// 数据全部来自渲染上下文(_cells/_operatHtml/_checked/_disabled),列元信息读
|
||||
// controlledLayouts 的 cols(本闭包内),无任何业务字段硬编码。
|
||||
//
|
||||
// 【与 buildLayoutContext 同规则的单元格列筛选】操作列无 field,须先于
|
||||
// field 判定识别;checkbox/radio 等无字段列跳过(勾选语义由勾位图标承接)
|
||||
var builtinCardCellCols = function (tableId) {
|
||||
var cols = (controlledLayouts[tableId] && controlledLayouts[tableId].cols[0]) || [];
|
||||
var cellCols = [];
|
||||
$.each(cols, function (i, col) {
|
||||
if (!col) {
|
||||
return;
|
||||
}
|
||||
if (col.templet === ua.table.tool) {
|
||||
return;
|
||||
}
|
||||
if (!col.field) {
|
||||
return;
|
||||
}
|
||||
cellCols.push(col);
|
||||
});
|
||||
return cellCols;
|
||||
};
|
||||
|
||||
// 内置 card 单行模板(tplFunction 调用约定:this/第一参 = 行上下文,第二参 = 列表上下文)
|
||||
// - 标题列 = 首个字段列(含 checkbox 列的表格即"第二列",无 checkbox 表格即"首字段")
|
||||
// - 标题列与 create_time 列不重复进 body(分别在 header/footer 展示)
|
||||
// - create_time 无对应列时 footer 时间留空,不回退原始字段值(避免裸时间戳)
|
||||
var builtinCardTemplate = function (row, list) {
|
||||
var cellCols = builtinCardCellCols(list.tableId);
|
||||
var titleCol = cellCols.length > 0 ? cellCols[0] : null;
|
||||
|
||||
var html = '<div class="ua-data-card'
|
||||
+ (row._checked ? ' ua-data-card-checked' : '')
|
||||
+ (row._disabled ? ' ua-data-card-disabled' : '')
|
||||
+ '" data-table-id="' + list.tableId + '" data-id="' + row.id + '">';
|
||||
|
||||
html += '<div class="ua-data-card-header">';
|
||||
html += '<div class="ua-data-card-title">' + (titleCol ? (row._cells[titleCol.field] || '') : '') + '</div>';
|
||||
html += '<div class="ua-data-card-check"><i class="layui-icon layui-icon-ok-circle"></i></div>';
|
||||
html += '</div>';
|
||||
|
||||
html += '<div class="ua-data-card-body">';
|
||||
$.each(cellCols, function (i, col) {
|
||||
if (titleCol && col.field === titleCol.field) {
|
||||
return;
|
||||
}
|
||||
if (col.field === 'create_time') {
|
||||
return;
|
||||
}
|
||||
html += '<div class="ua-data-card-item">'
|
||||
+ '<span class="ua-data-card-item-title">' + (col.title || col.field) + '</span>'
|
||||
+ '<span class="ua-data-card-item-value">' + (row._cells[col.field] || '') + '</span>'
|
||||
+ '</div>';
|
||||
});
|
||||
html += '</div>';
|
||||
|
||||
html += '<div class="ua-data-card-footer">';
|
||||
html += '<div class="ua-data-card-time">' + (row._cells['create_time'] || '') + '</div>';
|
||||
html += '<div class="ua-data-card-operat">' + (row._operatHtml || '') + '</div>';
|
||||
html += '</div>';
|
||||
|
||||
html += '</div>';
|
||||
return html;
|
||||
};
|
||||
|
||||
// 内置 card 勾选交互:点卡片任意处切换选中(操作按钮/表单控件等交互元素除外),
|
||||
// 禁用行(_disabled)整卡不可勾选。选择态落 store(与引擎勾选同一事实源,
|
||||
// 批量删除经 ua.table.checkStatus 分发即取到),随后重渲模板管线回显勾位图标。
|
||||
// 自定义模板形态的统一行选中委托是任务 18 范围,本委托只认 .ua-data-card。
|
||||
$(document).on('click', '.ua-data-card', function (e) {
|
||||
var $card = $(this);
|
||||
if ($card.hasClass('ua-data-card-disabled')) {
|
||||
return;
|
||||
}
|
||||
if ($(e.target).closest('a,button,input,select,textarea,label,.layui-form-switch,.layui-form-checkbox,.layui-form-radio').length) {
|
||||
return;
|
||||
}
|
||||
var tableId = $card.attr('data-table-id');
|
||||
var state = window.UA_TABLE_STORE && window.UA_TABLE_STORE.dataProvider.getState(tableId);
|
||||
if (!state) {
|
||||
return;
|
||||
}
|
||||
var row = null;
|
||||
var rowId = $card.attr('data-id');
|
||||
$.each(state.currentPageData || [], function (i, item) {
|
||||
if (String(item.id) === String(rowId)) {
|
||||
row = item;
|
||||
return false;
|
||||
}
|
||||
});
|
||||
if (!row || row.LAY_DISABLED) {
|
||||
return;
|
||||
}
|
||||
window.UA_TABLE_STORE.selection.set(tableId, row);
|
||||
ua.table.renderLayoutForm(tableId);
|
||||
});
|
||||
|
||||
// (b) 模板引擎优先级解析:tplFunction > tplLay > tplVue > tplLayId > tplVueId,
|
||||
// 提供一种即生效;五种全无且非 table 条目 → console.warn 并回退 table。
|
||||
// lay/vue/layId/vueId 的引擎挂载在任务 16(laytpl)/17(Vue),此处只做分发判定。
|
||||
@@ -86,6 +186,21 @@
|
||||
if (entry.name === 'table') {
|
||||
return {kind: 'table', entry: entry};
|
||||
}
|
||||
// 内置 card 形态:name='card' 且未提供任何模板钩子时挂内置模板;提供了
|
||||
// 钩子(tplFunction/tplLay/tplVue/tplLayId/tplVueId 任一)则照常走五级
|
||||
// 优先级,自定义实现完全覆盖内置形态。builtinCard 标记供模板管线给容器
|
||||
// 挂网格布局类(.ua-layout-cards)
|
||||
if (entry.name === 'card') {
|
||||
var hasHook = typeof entry.tplFunction === 'function'
|
||||
|| (typeof entry.tplLay === 'string' && entry.tplLay !== '')
|
||||
|| (typeof entry.tplVue === 'string' && entry.tplVue !== '')
|
||||
|| (typeof entry.tplLayId === 'string' && entry.tplLayId !== '')
|
||||
|| (typeof entry.tplVueId === 'string' && entry.tplVueId !== '');
|
||||
if (!hasHook) {
|
||||
var builtinEntry = $.extend({}, entry, {tplFunction: builtinCardTemplate, builtinCard: true});
|
||||
return {kind: 'function', entry: builtinEntry};
|
||||
}
|
||||
}
|
||||
if (typeof entry.tplFunction === 'function') {
|
||||
return {kind: 'function', entry: entry};
|
||||
}
|
||||
@@ -310,6 +425,9 @@
|
||||
});
|
||||
}
|
||||
|
||||
// 内置 card 形态容器挂网格布局类(样式见 public.scss 的 .ua-layout-cards),
|
||||
// 自定义模板形态移除该标记,不受卡片网格影响
|
||||
$container.toggleClass('ua-layout-cards', resolved.entry.builtinCard === true);
|
||||
$container.html(html);
|
||||
// 容器恒为 .layui-form(lay-filter 与容器 id 同名),scoped form.render
|
||||
// 美化模板产出的 switch/checkbox 控件
|
||||
|
||||
Reference in New Issue
Block a user