mirror of
https://gitee.com/ulthon/ulthon_admin.git
synced 2026-11-03 10:58:22 +08:00
2026 lines
94 KiB
PHP
2026 lines
94 KiB
PHP
(function () {
|
||
var ua = window.UA_ADMIN;
|
||
var form = window.UA_CORE.form,
|
||
layer = window.UA_CORE.layer,
|
||
table = window.UA_CORE.table,
|
||
laydate = window.UA_CORE.laydate,
|
||
laytpl = window.UA_CORE.laytpl,
|
||
util = window.UA_CORE.util;
|
||
|
||
var lastTableWhere = {};
|
||
var selectMode, selectConfirmCallback;
|
||
|
||
// reloadData 引擎接线(加载期执行一次):受控表(UA_TABLE_STORE 已注册)的数据
|
||
// 重载分流到 store,非受控表透传原引擎调用。原引用只备份一次,防止重复加载时
|
||
// 把包装层当原引用再包一层;透传用 arguments 保真,reloadData(id, opts, type)
|
||
// 三参形态的 type 语义不变。
|
||
if (table.__uaOriginalReloadData === undefined) {
|
||
table.__uaOriginalReloadData = table.reloadData;
|
||
}
|
||
var originalTableReloadData = table.__uaOriginalReloadData;
|
||
table.reloadData = function (tableId, opts) {
|
||
if (window.UA_TABLE_STORE.has(tableId)) {
|
||
return window.UA_TABLE_STORE.reload(tableId, opts);
|
||
}
|
||
return originalTableReloadData.apply(this, arguments);
|
||
};
|
||
|
||
// 受控表渲染接线(加载期执行一次):store 的 fetch/reload 只负责取数与状态、
|
||
// 不触发渲染,这里在唯一的数据到达点(store.reload 的成功回调)注入引擎
|
||
// 纯渲染——首屏/搜索/排序/switch 回滚/删除刷新全部经 shim 汇入 reload。
|
||
// 渲染必须走备份的原引擎引用:走 table.reloadData 会被上方 shim 路由回
|
||
// store 造成请求循环。initSort 透传保持表头排序箭头(与引擎 url 模式的
|
||
// listenTableSort 行为一致)。受控表分页条由 render() 内的
|
||
// syncControlledPager 自管:store 的 pager.jump 在内部直呼 fetch,外部
|
||
// 注入不了渲染回调,故 register 时不传 pagerElem 使 store 分页静默跳过,
|
||
// laypage 的 jump 经 shim(table.reloadData)回 store.reload 形成闭环。
|
||
var syncControlledPager = function (tableId) {
|
||
var state = window.UA_TABLE_STORE.dataProvider.getState(tableId);
|
||
if (!state) {
|
||
return;
|
||
}
|
||
layui.laypage.render({
|
||
elem: 'ua-store-pager-' + tableId,
|
||
count: state.count,
|
||
curr: state.page.curr,
|
||
limit: state.page.limit,
|
||
limits: state.limits,
|
||
layout: ['count', 'prev', 'page', 'next', 'limit', 'skip'],
|
||
jump: function (obj, first) {
|
||
if (!first) {
|
||
table.reloadData(tableId, {
|
||
page: {curr: obj.curr, limit: obj.limit}
|
||
});
|
||
}
|
||
}
|
||
});
|
||
};
|
||
|
||
// ========== 多形态渲染(五级模板协议)==========
|
||
// 形态注册表:tableId → {elem, cols, init, entries, byName, current}。
|
||
// render() 受控分支写入;受控渲染 wrapper 与 ua.table.renderLayoutForm 消费。
|
||
var controlledLayouts = {};
|
||
|
||
// 已回退告警去重表(同一形态条目只 warn 一次)
|
||
var warnedLayouts = {};
|
||
|
||
// (a) layoutList 规范化:字符串 'table'/'card' 转对象 {name, title};自定义条目
|
||
// {name, title, icon?, tplFunction?, tplLay?, tplVue?, tplLayId?, tplVueId?} 原样保留
|
||
var normalizeLayoutList = function (layoutList) {
|
||
var stringTitles = {table: '表格', card: '卡片'};
|
||
var result = [];
|
||
$.each(layoutList || [], function (i, item) {
|
||
if (typeof item === 'string') {
|
||
result.push({name: item, title: stringTitles[item] || item});
|
||
} else if (item && typeof item === 'object' && item.name) {
|
||
result.push(item);
|
||
}
|
||
});
|
||
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/layId 引擎挂载于 renderLayoutForm(任务 16,layui.laytpl);vue/vueId 挂载于任务 17。
|
||
var resolveLayoutEngine = function (entry) {
|
||
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};
|
||
}
|
||
if (typeof entry.tplLay === 'string' && entry.tplLay !== '') {
|
||
return {kind: 'lay', entry: entry};
|
||
}
|
||
if (typeof entry.tplVue === 'string' && entry.tplVue !== '') {
|
||
return {kind: 'vue', entry: entry};
|
||
}
|
||
if (typeof entry.tplLayId === 'string' && entry.tplLayId !== '') {
|
||
return {kind: 'layId', entry: entry};
|
||
}
|
||
if (typeof entry.tplVueId === 'string' && entry.tplVueId !== '') {
|
||
return {kind: 'vueId', entry: entry};
|
||
}
|
||
if (!warnedLayouts[entry.name]) {
|
||
warnedLayouts[entry.name] = true;
|
||
console.warn('[ua.table] layoutList 条目 "' + entry.name + '" 未提供任何模板钩子(tplFunction/tplLay/tplVue/tplLayId/tplVueId),已回退 table 形态');
|
||
}
|
||
return {kind: 'table', entry: entry};
|
||
};
|
||
|
||
// 当前形态解析:先取 options.layoutDefault(缺省 'table');运行期切形态
|
||
// 经 ua.table.setLayoutForm 改写 current。条目缺失/未登记时恒 table。
|
||
var resolveCurrentLayout = function (tableId) {
|
||
var layout = controlledLayouts[tableId];
|
||
var entry = (layout && layout.byName[layout.current]) || {name: 'table', title: '表格'};
|
||
return resolveLayoutEngine(entry);
|
||
};
|
||
|
||
// 模板管线失败回退(tplLayId 节点缺失 / laytpl 渲染错误 / Vue 引擎未挂载):
|
||
// 当前形态归位 'table'(与"无钩子条目回退"同语义,幂等、不写 localStorage
|
||
// 记忆,用户重新切换可再次触发),容器清空隐藏。调用方据 false 返回值做
|
||
// 引擎纯渲染,随后的 syncLayoutVisibility 按 table kind 复显引擎数据区,
|
||
// 避免"容器残留上一形态旧内容 + 引擎数据被隐藏"的视觉错位。
|
||
var fallbackLayoutToTable = function (tableId, $container) {
|
||
var layout = controlledLayouts[tableId];
|
||
if (layout) {
|
||
layout.current = 'table';
|
||
}
|
||
if ($container && $container.length) {
|
||
$container.addClass('layui-hide').empty();
|
||
}
|
||
return false;
|
||
};
|
||
|
||
// 形态可见性同步:引擎数据区(表头+表体+合计行)与模板容器互斥显隐,
|
||
// 引擎视图的工具栏(刷新/新增/批量删除等)两形态共用保持可见,搜索区
|
||
// 本就挂在表格元素之前不受影响。非 table 形态下引擎根本不渲染行数据
|
||
// (wrapper 非 table 分支不走引擎渲染),并非旧寄生实现"引擎恒渲+CSS 隐藏"。
|
||
var syncLayoutVisibility = function (tableId) {
|
||
var layout = controlledLayouts[tableId];
|
||
if (!layout) {
|
||
return;
|
||
}
|
||
var $view = $(layout.elem).siblings('.layui-table-view').first();
|
||
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') {
|
||
$box.add($total).removeClass('layui-hide');
|
||
$container.addClass('layui-hide').empty();
|
||
} else {
|
||
$box.add($total).addClass('layui-hide');
|
||
$container.removeClass('layui-hide');
|
||
}
|
||
};
|
||
|
||
if (window.UA_TABLE_STORE) {
|
||
var storeReload = window.UA_TABLE_STORE.reload;
|
||
window.UA_TABLE_STORE.reload = function (tableId, opts) {
|
||
opts = opts || {};
|
||
var userDone = opts.done;
|
||
// 模板形态的加载态容器标记(容器内加载样式由任务 14 的内置形态接入)
|
||
var $layoutContainer = $('#ua-layout-' + tableId);
|
||
$layoutContainer.addClass('ua-layout-loading');
|
||
opts.done = function (res) {
|
||
// 受控渲染分发:table 形态走引擎纯渲染(现状),非 table 形态走
|
||
// 模板管线(渲染上下文 + 行级循环);模板管线不可用(引擎未挂载,
|
||
// Vue 待任务 17;tplLayId 节点缺失/laytpl 渲染错误)时回退引擎纯渲染兜底
|
||
var engineRender = function () {
|
||
originalTableReloadData.call(table, tableId, {
|
||
data: res.data,
|
||
totalRow: res.totalRow,
|
||
initSort: opts.initSort
|
||
});
|
||
};
|
||
if (resolveCurrentLayout(tableId).kind === 'table' || !ua.table.renderLayoutForm(tableId)) {
|
||
engineRender();
|
||
}
|
||
$layoutContainer.removeClass('ua-layout-loading');
|
||
syncControlledPager(tableId);
|
||
syncLayoutVisibility(tableId);
|
||
if (typeof userDone === 'function') {
|
||
userDone(res);
|
||
}
|
||
};
|
||
return storeReload(tableId, opts);
|
||
};
|
||
}
|
||
|
||
ua.table = {
|
||
// 受控/非受控分发入口(后续任务直呼改造的定义点):非受控路径走备份的
|
||
// 原引擎引用,不经过上方已包装的 table.reloadData,避免递归
|
||
reloadData: function (tableId, opts) {
|
||
if (window.UA_TABLE_STORE.has(tableId)) {
|
||
return window.UA_TABLE_STORE.reload(tableId, opts);
|
||
}
|
||
return originalTableReloadData.apply(this, arguments);
|
||
},
|
||
checkStatus: function (tableId) {
|
||
if (window.UA_TABLE_STORE.has(tableId)) {
|
||
return window.UA_TABLE_STORE.checkStatus(tableId);
|
||
}
|
||
return table.checkStatus(tableId);
|
||
},
|
||
// ========== 多形态渲染管线(五级模板协议)==========
|
||
// (c) 渲染上下文构建器:对 store 当页每行产出
|
||
// {...row, _cells: {field: 列 templet 渲染后的 HTML}, _operatHtml: 操作按钮 HTML,
|
||
// _checked: 是否选中, _disabled: 是否禁选}
|
||
// _cells 复用 formatCols 之后的列渲染器族(image/switch/list/自定义 templet 与
|
||
// 引擎同行为),逐列注入 LAY_COL(与引擎 templet 调用同构:渲染器经 data.LAY_COL
|
||
// 读列配置);_operatHtml 走既有 ua.table.tool(按钮权限 data-* 属性原样输出,
|
||
// 事件靠页面级委托天然覆盖,无旧的"暂时隐藏按钮"逻辑);_checked/_disabled
|
||
// 数据源为 store 选中集合(selectedIds)与行 LAY_DISABLED 标记。
|
||
buildLayoutContext: function (tableId) {
|
||
var layout = controlledLayouts[tableId];
|
||
var state = window.UA_TABLE_STORE.dataProvider.getState(tableId);
|
||
var rows = (state && state.currentPageData) || [];
|
||
var selectedIds = (state && state.selectedIds) || [];
|
||
var cols = (layout && layout.cols[0]) || [];
|
||
|
||
var operatCol = null;
|
||
var cellCols = [];
|
||
$.each(cols, function (i, col) {
|
||
if (!col) {
|
||
return;
|
||
}
|
||
// 操作列无 field,须先于 field 判定识别
|
||
if (col.templet === ua.table.tool) {
|
||
operatCol = col;
|
||
return;
|
||
}
|
||
if (!col.field) {
|
||
// checkbox/radio 等无字段列:勾选语义由 _checked/_disabled 与模板作者承接
|
||
return;
|
||
}
|
||
cellCols.push(col);
|
||
});
|
||
|
||
var context = {
|
||
tableId: tableId,
|
||
rows: [],
|
||
page: state ? state.page : {curr: 1, limit: 0},
|
||
count: state ? state.count : 0,
|
||
checkedAll: state ? window.UA_TABLE_STORE.selection.isAll(tableId) : false
|
||
};
|
||
|
||
$.each(rows, function (i, row) {
|
||
var rowCtx = $.extend({}, row);
|
||
rowCtx._cells = {};
|
||
$.each(cellCols, function (j, col) {
|
||
var cellData = $.extend({}, row);
|
||
cellData.LAY_COL = col;
|
||
try {
|
||
if (typeof col.templet === 'function') {
|
||
rowCtx._cells[col.field] = col.templet(cellData) || '';
|
||
} else if (typeof col.templet === 'string') {
|
||
rowCtx._cells[col.field] = laytpl(col.templet).render(cellData) || '';
|
||
} else {
|
||
rowCtx._cells[col.field] = '';
|
||
}
|
||
} catch (e) {
|
||
rowCtx._cells[col.field] = '';
|
||
}
|
||
});
|
||
|
||
if (operatCol) {
|
||
var toolData = $.extend({}, row);
|
||
toolData.LAY_COL = operatCol;
|
||
rowCtx._operatHtml = ua.table.tool(toolData);
|
||
} else {
|
||
rowCtx._operatHtml = '';
|
||
}
|
||
|
||
rowCtx._checked = selectedIds.indexOf(String(row.id)) > -1;
|
||
rowCtx._disabled = !!row.LAY_DISABLED;
|
||
|
||
context.rows.push(rowCtx);
|
||
});
|
||
|
||
return context;
|
||
},
|
||
// (d) 行级循环渲染框架:模板只定义单行 HTML 生成函数,框架循环拼接并维护
|
||
// 空态容器;加载态由 store.fetch 的全局 loading 与容器的 ua-layout-loading
|
||
// 标记承接(内置形态的加载态样式在任务 14 接入)。
|
||
//
|
||
// 【tplFunction 调用约定】
|
||
// 单行 HTML = tplFunction.call(rowCtx, rowCtx, listCtx)
|
||
// - this/第一参 = 行上下文 {...row, _cells, _operatHtml, _checked, _disabled}
|
||
// - 第二参 = 列表上下文 {tableId, rows, page, count, checkedAll}
|
||
// - 返回值 = 该行的 HTML 字符串(框架直接拼接,不做转义)
|
||
// 【laytpl 调用约定(tplLay / tplLayId)】
|
||
// 单行 HTML = laytpl(tplLay | $(tplLayId).html()).render(rowCtx)
|
||
// - d = 行上下文,与 tplFunction 第一参同构,另挂 d._list = 列表上下文
|
||
// (与 tplFunction 第二参对齐;laytpl 仅支持单数据对象)
|
||
// - 模板语法(layui 内置 laytpl v2.0.0 实测):{{ d.x }} 与 {{= d.x }}
|
||
// 均经 laytpl.escape 转义;{{- d.x }} 原样输出(_cells/_operatHtml 等
|
||
// HTML 内容必须用此形态);{{# }} 为 JS 语句(if/each 等)
|
||
// - tplLayId 是页面 <script type="text/html"> 节点选择器,节点必须位于
|
||
// 渲染容器之外(下方硬约束 2);script 内容为原始文本,laytpl 的 {{ }}
|
||
// 不会被浏览器解析,.html() 读取即可
|
||
// - laytpl 编译/运行错误不抛异常,render() 返回 "Laytpl Error: ..." 字符串
|
||
// (laytpl 内部已 console.error 细节),框架探测到后按条目名 console.error
|
||
// 并返回 false,调用方回退引擎纯渲染
|
||
// 【两条硬约束】
|
||
// 1. 模板容器恒带 class="layui-form"(form 控件渲染与事件受 .layui-form
|
||
// 祖先约束,缺失则模板里的 switch/checkbox 全部失效);
|
||
// 2. laytpl/Vue 模板节点(<script type="text/html"> / text/x-template)必须
|
||
// 位于渲染容器之外,防止被模板引擎编译时吞掉 {{ }} 插值(节点由页面
|
||
// 模板区提供)。
|
||
// 返回 false 表示管线不可渲染(table 形态或模板引擎未挂载/渲染失败),调用
|
||
// 方回退引擎纯渲染。
|
||
renderLayoutForm: function (tableId) {
|
||
if (controlledLayouts[tableId] === undefined) {
|
||
return false;
|
||
}
|
||
var resolved = resolveCurrentLayout(tableId);
|
||
if (resolved.kind === 'table') {
|
||
return false;
|
||
}
|
||
|
||
var $container = $('#ua-layout-' + tableId);
|
||
if ($container.length === 0) {
|
||
return false;
|
||
}
|
||
|
||
// laytpl 引擎(任务 16):tplLay = 模板字符串;tplLayId = 模板节点选择器
|
||
var laytplCompiled = null;
|
||
if (resolved.kind === 'lay' || resolved.kind === 'layId') {
|
||
var template;
|
||
if (resolved.kind === 'layId') {
|
||
var $tplNode = $(resolved.entry.tplLayId);
|
||
if ($tplNode.length === 0) {
|
||
console.error('[ua.table] tplLayId 节点不存在:' + resolved.entry.tplLayId
|
||
+ '(形态 "' + resolved.entry.name + '"),本次回退 table 形态');
|
||
return fallbackLayoutToTable(tableId, $container);
|
||
}
|
||
template = $tplNode.html();
|
||
} else {
|
||
template = resolved.entry.tplLay;
|
||
}
|
||
laytplCompiled = laytpl(template);
|
||
} else if (resolved.kind !== 'function') {
|
||
// vue/vueId 分发点:引擎挂载于任务 17(Vue)
|
||
console.warn('[ua.table] 模板引擎未挂载:' + resolved.kind + '(任务 17 实现),本次回退 table 形态');
|
||
return fallbackLayoutToTable(tableId, $container);
|
||
}
|
||
|
||
var context = ua.table.buildLayoutContext(tableId);
|
||
var html = '';
|
||
if (context.rows.length === 0) {
|
||
html = '<div class="ua-layout-empty">无数据</div>';
|
||
} else {
|
||
try {
|
||
$.each(context.rows, function (i, rowCtx) {
|
||
if (laytplCompiled) {
|
||
rowCtx._list = context;
|
||
var rowHtml = laytplCompiled.render(rowCtx) || '';
|
||
if (rowHtml.indexOf('Laytpl Error:') === 0) {
|
||
// laytpl 错误不抛异常(实测),探测返回值后主动抛出,
|
||
// 由外层 catch 统一告警并整体回退
|
||
throw new Error(rowHtml);
|
||
}
|
||
html += rowHtml;
|
||
} else {
|
||
html += resolved.entry.tplFunction.call(rowCtx, rowCtx, context);
|
||
}
|
||
});
|
||
} catch (e) {
|
||
console.error('[ua.table] 模板渲染失败(形态 "' + resolved.entry.name + '"):'
|
||
+ e.message + ',本次回退 table 形态');
|
||
return fallbackLayoutToTable(tableId, $container);
|
||
}
|
||
}
|
||
|
||
// 内置 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 控件
|
||
form.render(null, 'ua-layout-' + tableId);
|
||
return true;
|
||
},
|
||
// 当前形态名(任务 15 的切换 UI 消费)
|
||
getLayoutForm: function (tableId) {
|
||
return controlledLayouts[tableId] ? controlledLayouts[tableId].current : 'table';
|
||
},
|
||
// 切换当前形态:仅改写运行期状态并重渲染,不发起网络请求(数据取自
|
||
// store 当页状态)。目标条目不存在返回 false;模板管线不可用(无钩子
|
||
// 条目 / tplLayId 节点缺失 / laytpl 渲染错误,均已在 renderLayoutForm
|
||
// 内归位 current='table')时走引擎纯渲染兜底。
|
||
setLayoutForm: function (tableId, name) {
|
||
var layout = controlledLayouts[tableId];
|
||
if (!layout || !layout.byName[name]) {
|
||
return false;
|
||
}
|
||
layout.current = name;
|
||
|
||
if (!ua.table.renderLayoutForm(tableId)) {
|
||
// table 形态(含无钩子条目回退):引擎纯渲染当页数据,直呼备份
|
||
// 原引用不走 shim(防路由回 store 造成 fetch)
|
||
var state = window.UA_TABLE_STORE.dataProvider.getState(tableId);
|
||
originalTableReloadData.call(table, tableId, {
|
||
data: state ? state.currentPageData : [],
|
||
totalRow: state && state.lastResponse ? state.lastResponse.totalRow : undefined
|
||
});
|
||
}
|
||
syncLayoutVisibility(tableId);
|
||
syncControlledPager(tableId);
|
||
return true;
|
||
},
|
||
render: function (options) {
|
||
options.init = options.init || ua.init;
|
||
options.modifyReload = ua.parame(options.modifyReload, true);
|
||
options.elem = options.elem || options.init.tableElem;
|
||
options.id = options.id || options.init.tableRenderId;
|
||
options.scrollPos = options.scrollPos || 'fixed';
|
||
options.layFilter = options.id + '_LayFilter';
|
||
options.url = options.url || ua.url(options.init.indexUrl);
|
||
options.headers = ua.headers();
|
||
options.page = ua.parame(options.page, true);
|
||
options.search = ua.parame(options.search, true);
|
||
options.skin = options.skin || 'line';
|
||
options.autoSort = options.autoSort || false;
|
||
options.limit = options.limit || 15;
|
||
options.limits = options.limits || [10, 15, 20, 25, 50, 100];
|
||
options.cols = options.cols || [];
|
||
options.rowDisableCallback = options.rowDisableCallback || null;
|
||
|
||
var defaultToolbar = ['filter', 'print'];
|
||
|
||
if (options.search) {
|
||
defaultToolbar.push({
|
||
title: '搜索',
|
||
layEvent: 'TABLE_SEARCH',
|
||
icon: 'layui-icon-search',
|
||
extend: 'data-table-id="' + options.id + '"'
|
||
});
|
||
}
|
||
|
||
// 受控表形态清单规范化须先于引擎渲染:视图切换按钮的注入条件
|
||
// (条目数>1)依赖它,受控分支直接复用。非受控表不 normalize。
|
||
var layoutEntries = [];
|
||
if (options.controlled === true) {
|
||
layoutEntries = normalizeLayoutList(options.layoutList);
|
||
if (layoutEntries.length > 1) {
|
||
// 视图切换按钮(任务 15 (b),交互结构参照旧 TABLE_LAYOUT
|
||
// 实现重建):下拉条目在点击时按 layoutEntries 动态构建
|
||
defaultToolbar.push({
|
||
title: '视图',
|
||
layEvent: 'TABLE_LAYOUT',
|
||
icon: 'layui-icon-template-1',
|
||
extend: 'data-table-id="' + options.id + '"'
|
||
});
|
||
}
|
||
}
|
||
|
||
if (options.defaultToolbar === undefined) {
|
||
options.defaultToolbar = defaultToolbar;
|
||
}
|
||
|
||
|
||
var optionBefore = function () { };
|
||
if (options.before != undefined) {
|
||
optionBefore = options.before;
|
||
}
|
||
options.before = function (tableIns) {
|
||
optionBefore(tableIns);
|
||
};
|
||
|
||
var optionDone = function () { };
|
||
if (options.done != undefined) {
|
||
optionDone = options.done;
|
||
}
|
||
options.done = function (res, curr, count) {
|
||
optionDone(res, curr, count);
|
||
|
||
// 监听表格内的复制组件
|
||
ua.api.copyText('[lay-id=' + options.id + ']');
|
||
};
|
||
|
||
/**
|
||
* 为空时认为自己是普通状态,否则是单选、多选、子页面,此时添加等默认行为走弹框而不是新标签页
|
||
*/
|
||
selectMode = ua.getQueryVariable("select_mode");
|
||
|
||
selectConfirmCallback = ua.getQueryVariable('select_confirm_callback', 'onTableDataConfirm');
|
||
|
||
if (selectMode == 'checkbox') {
|
||
if (options.cols[0][0].type == 'radio') {
|
||
options.cols[0][0].type = 'checkbox';
|
||
} else if (options.cols[0][0].type != 'checkbox') {
|
||
options.cols[0].unshift({
|
||
type: 'checkbox'
|
||
});
|
||
}
|
||
} else if (selectMode == 'radio') {
|
||
if (options.cols[0][0].type == 'checkbox') {
|
||
options.cols[0][0].type = 'radio';
|
||
|
||
} else if (options.cols[0][0].type != 'radio') {
|
||
options.cols[0].unshift({
|
||
type: 'radio'
|
||
});
|
||
|
||
}
|
||
} else {
|
||
if(!ua.isParentIndex()){
|
||
selectMode = 'childPage'
|
||
}
|
||
}
|
||
|
||
|
||
// 判断元素对象是否有嵌套的
|
||
options.cols = ua.table.formatCols(options.cols, options.init);
|
||
|
||
// 初始化表格lay-filter
|
||
$(options.elem).attr('lay-filter', options.layFilter);
|
||
|
||
// 初始化表格搜索
|
||
if (options.search === true) {
|
||
options = ua.table.renderSearch(options.cols, options.elem, options.id, options);
|
||
}
|
||
|
||
// 初始化表格左上方工具栏
|
||
options.toolbar = options.toolbar || ['refresh', 'add', 'delete', 'export'];
|
||
|
||
if (selectMode == 'checkbox' || selectMode == 'radio') {
|
||
options.toolbar.unshift('selectConfirm');
|
||
|
||
options.height = 'full-85';
|
||
}
|
||
|
||
if (options.init.formFullScreen == true) {
|
||
options.init.formFullScreen = 'true';
|
||
} else {
|
||
options.init.formFullScreen = 'false';
|
||
}
|
||
|
||
options.toolbar = ua.table.renderToolbar(options.toolbar, options.elem, options.id, options.init);
|
||
|
||
// 判断是否有操作列表权限
|
||
options.cols = ua.table.renderOperat(options.cols, options.elem);
|
||
|
||
// 判断是否有操作列表权限
|
||
options.cols = ua.table.renderTrueHide(options.cols, options);
|
||
|
||
|
||
var parseData = function (res) { return res; };
|
||
|
||
if (typeof options.parseData === 'function') {
|
||
parseData = options.parseData;
|
||
}
|
||
|
||
if (options.controlled === true) {
|
||
// 受控灰度模式:数据请求与分页职责移交 UA_TABLE_STORE,引擎只做
|
||
// 纯渲染(空数据起步、关闭引擎分页,由 store 的 laypage 自绘)。
|
||
// 选择态注入(rowDisableCallback / URL selectedIds / LAY_CHECKED
|
||
// 跨页回显)由 store.fetch 的 injectSelectionMarks 承接,故不装
|
||
// 引擎 parseData。默认关闭——未显式 controlled:true 的页面保持
|
||
// 引擎 url 模式,行为与历史版本完全一致。
|
||
delete options.url;
|
||
delete options.parseData;
|
||
options.data = [];
|
||
options.page = false;
|
||
} else {
|
||
options.parseData = function (res) {
|
||
|
||
// 初始化已经选择的值
|
||
if (selectMode == 'checkbox' || selectMode == 'radio') {
|
||
if (typeof options.rowDisableCallback == 'function') {
|
||
for (let index = 0; index < res.data.length; index++) {
|
||
const dataItem = res.data[index];
|
||
|
||
var rowDisableResult = options.rowDisableCallback(dataItem);
|
||
if (rowDisableResult === false || rowDisableResult === true) {
|
||
res.data[index].LAY_DISABLED = rowDisableResult;
|
||
}
|
||
}
|
||
}
|
||
|
||
var selectedIds = ua.getQueryVariable('selectedIds', '');
|
||
|
||
if (selectedIds.length > 0) {
|
||
var selectedIdArr = selectedIds.split(',');
|
||
|
||
for (let index = 0; index < res.data.length; index++) {
|
||
const dataItem = res.data[index];
|
||
|
||
if (selectedIdArr.indexOf(dataItem.id.toString()) > -1) {
|
||
res.data[index].LAY_DISABLED = true;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
res = parseData(res);
|
||
return res;
|
||
};
|
||
}
|
||
|
||
|
||
// 初始化表格
|
||
var newTable = table.render(options);
|
||
|
||
// 监听表格搜索开关显示
|
||
ua.table.listenToolbar(options.layFilter, options.id);
|
||
|
||
// 监听表格瓶排序
|
||
ua.table.listenTableSort(options);
|
||
|
||
// 监听表格开关切换
|
||
ua.table.renderSwitch(options.cols, options.init, options.id, options.modifyReload);
|
||
|
||
// 监听表格开关切换
|
||
ua.table.listenEdit(options.init, options.layFilter, options.id, options.modifyReload);
|
||
|
||
// 监听导出事件
|
||
ua.table.listenExport(options);
|
||
|
||
// 监听表格选择器
|
||
ua.table.listenTableSelectConfirm(options);
|
||
|
||
// 受控模式接线(在共享监听挂载之后):注册 store、自建分页容器、
|
||
// 同步勾选事件、首屏取数。搜索/排序/switch/编辑等既有监听的
|
||
// table.reloadData 调用经 shim 自动分流到 store.reload(渲染由顶部
|
||
// 接线层注入的 done 承接),此处无需逐点改造。
|
||
if (options.controlled === true) {
|
||
// 分页容器挂在引擎视图容器之后(表格容器外),不与引擎分页共存。
|
||
// 注意 layui render 后原 table 元素被移出视图(成为 view 的兄弟
|
||
// 节点),不能用 closest 向上找 view
|
||
var pagerId = 'ua-store-pager-' + options.id;
|
||
$('#' + pagerId).remove();
|
||
$(options.elem).siblings('.layui-table-view').first().after(
|
||
'<div id="' + pagerId + '" class="ua-store-pager"></div>'
|
||
);
|
||
|
||
// 模板形态容器:与 ua-store-pager 并列(分页条两形态共用)。
|
||
// 两条硬约束:容器恒带 class="layui-form"(form 控件渲染与事件受
|
||
// .layui-form 祖先约束);laytpl/Vue 模板节点必须位于本容器之外
|
||
// (由页面模板区提供,本层不生成任何模板节点)
|
||
var layoutId = 'ua-layout-' + options.id;
|
||
$('#' + layoutId).remove();
|
||
$('#' + pagerId).before(
|
||
'<div id="' + layoutId + '" class="ua-layout-container layui-form" lay-filter="ua-layout-' + options.id + '"></div>'
|
||
);
|
||
|
||
// 形态注册:layoutList 已在 defaultToolbar 段规范化(视图按钮
|
||
// 注入共用)。运行期切形态经 ua.table.setLayoutForm。
|
||
// options.cols 此时已过 formatCols/renderOperat/renderTrueHide,
|
||
// 渲染器族与 operat 缺省值已就绪,构建上下文直接消费
|
||
var layoutByName = {};
|
||
$.each(layoutEntries, function (i, entry) {
|
||
layoutByName[entry.name] = entry;
|
||
});
|
||
|
||
// 默认形态解析(任务 15 (a)):优先级 localStorage 按页记忆 >
|
||
// 显式 layoutDefault / 手机端自动检测 > 'table'。手机端默认
|
||
// card 仅当 layoutList 含 card 条目;记忆值不在 layoutList 内
|
||
// 时忽略(防脏数据);未配 layoutList 的页面恒 table,行为
|
||
// 零变化。layoutDefault=true 旧协议即"自动判断",与新默认
|
||
// 行为一致,无需单独分支。
|
||
var defaultLayoutName = 'table';
|
||
if (layoutEntries.length > 0) {
|
||
if (options.layoutDefault && layoutByName[options.layoutDefault]) {
|
||
defaultLayoutName = options.layoutDefault;
|
||
} else if (ua.checkMobile() && layoutByName['card']) {
|
||
defaultLayoutName = 'card';
|
||
}
|
||
var savedLayout = ua.getPageSetting('table-layout-default', '');
|
||
if (layoutByName[savedLayout]) {
|
||
defaultLayoutName = savedLayout;
|
||
}
|
||
}
|
||
|
||
controlledLayouts[options.id] = {
|
||
elem: options.elem,
|
||
cols: options.cols,
|
||
init: options.init,
|
||
entries: layoutEntries,
|
||
byName: layoutByName,
|
||
current: defaultLayoutName
|
||
};
|
||
|
||
window.UA_TABLE_STORE.register(options.id, {
|
||
indexUrl: options.init.indexUrl,
|
||
where: options.where,
|
||
page: {curr: 1, limit: options.limit},
|
||
limits: options.limits,
|
||
selectMode: selectMode,
|
||
rowDisableCallback: options.rowDisableCallback
|
||
// 不传 pagerElem:store 的 pager.jump 内部直呼 fetch 无法
|
||
// 触发引擎渲染,分页条由接线层 syncControlledPager 自管
|
||
});
|
||
|
||
// 引擎勾选事件 → store 选中集合:跨页勾选回显(LAY_CHECKED 注入)
|
||
// 的数据源。layui 2.10 事件回调 obj.data 是当次操作的单行对象
|
||
// (type=all 时不含可用行数据),全选场景以 store 的当页数据为准
|
||
//(selection.checkAll 缺省即当页数据,禁用行由其内部跳过)
|
||
table.on('checkbox(' + options.layFilter + ')', function (obj) {
|
||
if (obj.type === 'all') {
|
||
window.UA_TABLE_STORE.selection.checkAll(options.id, undefined, obj.checked);
|
||
} else {
|
||
window.UA_TABLE_STORE.selection.set(options.id, obj.data);
|
||
}
|
||
});
|
||
table.on('radio(' + options.layFilter + ')', function (obj) {
|
||
window.UA_TABLE_STORE.selection.set(options.id, obj.data);
|
||
});
|
||
|
||
// 初始形态可见性:layoutDefault 非 table 时先隐引擎空视图(避免
|
||
// 空表头闪烁),首个 reload 完成后 wrapper 再次同步
|
||
syncLayoutVisibility(options.id);
|
||
|
||
// 首屏取数:经接线后的 store.reload 触发 fetch + 引擎纯渲染
|
||
window.UA_TABLE_STORE.reload(options.id);
|
||
}
|
||
|
||
return newTable;
|
||
},
|
||
renderToolbar: function (data, elem, tableId, init) {
|
||
data = data || [];
|
||
var toolbarHtml = '';
|
||
$.each(data, function (i, v) {
|
||
if (v === 'refresh') {
|
||
toolbarHtml += ' <button class="layui-btn layui-btn-sm layuimini-btn-primary" data-table-refresh="' + tableId + '"><i class="fa fa-refresh"></i> </button>\n';
|
||
} else if (v === 'add') {
|
||
if (ua.checkAuth('add', elem)) {
|
||
if(selectMode){
|
||
toolbarHtml += '<button class="layui-btn layui-btn-normal layui-btn-sm" data-open="' + init.addUrl + '" data-title="添加" data-full="' + init.formFullScreen + '"><i class="fa fa-plus"></i> 添加</button>\n';
|
||
}else{
|
||
toolbarHtml += '<button class="layui-btn layui-btn-normal layui-btn-sm" layuimini-content-href="' + init.addUrl + '" data-title="添加" data-full="' + init.formFullScreen + '"><i class="fa fa-plus"></i> 添加</button>\n';
|
||
}
|
||
}
|
||
} else if (v === 'delete') {
|
||
if (ua.checkAuth('delete', elem)) {
|
||
toolbarHtml += '<button class="layui-btn layui-btn-sm layui-btn-danger" data-url="' + init.deleteUrl + '" data-table-delete="' + tableId + '"><i class="fa fa-trash-o"></i> 删除</button>\n';
|
||
}
|
||
} else if (v === 'export') {
|
||
if (ua.checkAuth('export', elem)) {
|
||
toolbarHtml += '<button class="layui-btn layui-btn-sm layui-btn-success easyadmin-export-btn" data-url="' + init.exportUrl + '" data-table-export="' + tableId + '"><i class="fa fa-file-excel-o"></i> 导出</button>\n';
|
||
}
|
||
} else if (v === 'selectConfirm') {
|
||
toolbarHtml += '<button class="layui-btn layui-btn-sm layui-btn-success select-confirm" data-table-target="' + tableId + '"> 确定选择</button>\n';
|
||
} else if (typeof v === "object") {
|
||
$.each(v, function (ii, vv) {
|
||
vv.class = vv.class || '';
|
||
vv.icon = vv.icon || '';
|
||
vv.auth = vv.auth || 'add';
|
||
vv.url = vv.url || '';
|
||
vv.method = vv.method || 'open';
|
||
vv.title = vv.title || vv.text;
|
||
vv.text = vv.text || vv.title;
|
||
vv.extend = vv.extend || '';
|
||
vv.checkbox = vv.checkbox || false;
|
||
if (ua.checkAuth(vv.auth, elem)) {
|
||
toolbarHtml += ua.table.buildToolbarHtml(vv, tableId);
|
||
}
|
||
});
|
||
}
|
||
});
|
||
return '<div>' + toolbarHtml + '</div>';
|
||
},
|
||
renderSearch: function (cols, elem, tableId, options) {
|
||
// TODO 只初始化第一个table搜索字段,如果存在多个(绝少数需求),得自己去扩展
|
||
cols = cols[0] || {};
|
||
var newCols = [];
|
||
var formHtml = '';
|
||
var tabSetting = {};
|
||
var formatFilter = {},
|
||
formatOp = {};
|
||
$.each(cols, function (i, d) {
|
||
d.field = d.field || false;
|
||
d.fieldAlias = ua.parame(d.fieldAlias, d.field);
|
||
d.title = d.title || d.field || '';
|
||
d.selectList = d.selectList || {};
|
||
d.search = ua.parame(d.search, true);
|
||
d.searchTip = d.searchTip || '请输入' + d.title || '';
|
||
d.searchValue = d.searchValue || undefined;
|
||
d.searchHide = d.searchHide || '';
|
||
d.defaultSearchValue = d.defaultSearchValue;
|
||
d.searchOp = d.searchOp || '%*%';
|
||
d.timeType = d.timeType || 'datetime';
|
||
|
||
d.elemIdName = d.fieldAlias;
|
||
|
||
var a = '';
|
||
var b = '';
|
||
|
||
if (typeof d.fieldAlias == 'string') {
|
||
|
||
if (d.fieldAlias.indexOf('[') == 0) {
|
||
|
||
var fieldPlusArr = d.fieldAlias.replace('[').split(']');
|
||
|
||
d.elemIdName = fieldPlusArr.join('-');
|
||
}
|
||
|
||
d.elemIdName = d.elemIdName.replace('.', '-');
|
||
}
|
||
|
||
|
||
if (d.defaultSearchValue !== undefined) {
|
||
if (!d.searchValue || d.searchValue.length == 0) {
|
||
d.searchValue = d.defaultSearchValue;
|
||
}
|
||
} else {
|
||
if (d.field) {
|
||
d.defaultSearchValue = ua.getQueryVariable(d.field);
|
||
if (d.defaultSearchValue != undefined) {
|
||
d.searchValue = d.defaultSearchValue;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (d.searchValue !== undefined) {
|
||
|
||
if (d.search == 'number_limit') {
|
||
var paramsArr = d.searchValue.split(',');
|
||
|
||
a = paramsArr[0];
|
||
b = paramsArr[1];
|
||
|
||
if (a) {
|
||
formatFilter['[' + d.field + ']min'] = a;
|
||
formatOp['[' + d.field + ']min'] = 'min';
|
||
}
|
||
|
||
if (b) {
|
||
formatFilter['[' + d.field + ']max'] = b;
|
||
formatOp['[' + d.field + ']max'] = 'max';
|
||
}
|
||
} else if (d.search == 'time_limit') {
|
||
var paramsArr = d.searchValue.split(',');
|
||
|
||
a = paramsArr[0];
|
||
b = paramsArr[1];
|
||
|
||
if (a) {
|
||
formatFilter['[' + d.field + ']min_date'] = a;
|
||
formatOp['[' + d.field + ']min_date'] = 'min_date';
|
||
}
|
||
|
||
if (b) {
|
||
formatFilter['[' + d.field + ']max_date'] = b;
|
||
formatOp['[' + d.field + ']max_date'] = 'max_date';
|
||
}
|
||
} else {
|
||
formatFilter[d.field] = d.searchValue;
|
||
formatOp[d.field] = d.searchOp;
|
||
}
|
||
}
|
||
|
||
var formSearchHideClass = '';
|
||
|
||
if (d.searchHide) {
|
||
formSearchHideClass = ' search-hide-item';
|
||
}
|
||
|
||
if (d.searchValue === undefined) {
|
||
d.searchValue = '';
|
||
}
|
||
|
||
if (d.field !== false) {
|
||
if (d.search !== false) {
|
||
switch (d.search) {
|
||
case true:
|
||
formHtml += '\t<div class="layui-form-item layui-inline ' + formSearchHideClass + ' ">\n' +
|
||
'<label class="layui-form-label">' + d.title + '</label>\n' +
|
||
'<div class="layui-input-inline">\n' +
|
||
'<input id="c-' + d.elemIdName + '" name="' + d.fieldAlias + '" data-search-op="' + d.searchOp + '" value="' + d.searchValue + '" placeholder="' + d.searchTip + '" class="layui-input">\n' +
|
||
'</div>\n' +
|
||
'</div>';
|
||
break;
|
||
case 'select':
|
||
d.searchOp = '=';
|
||
var selectHtml = '';
|
||
|
||
if (d.tab) {
|
||
tabSetting.field = d.field;
|
||
tabSetting.elemIdName = d.elemIdName;
|
||
tabSetting.list = d.selectList;
|
||
tabSetting.index = -1;
|
||
}
|
||
|
||
var selectListIndex = 0;
|
||
$.each(d.selectList, function (sI, sV) {
|
||
var selected = '';
|
||
if (sI === d.searchValue) {
|
||
selected = 'selected=""';
|
||
if (d.tab) {
|
||
tabSetting.index = selectListIndex;
|
||
}
|
||
}
|
||
selectHtml += '<option value="' + sI + '" ' + selected + '>' + sV + '</option>/n';
|
||
selectListIndex++;
|
||
});
|
||
if (d.tab) {
|
||
formHtml += '<input type="hidden" id="c-' + d.elemIdName + '" name="' + d.fieldAlias + '" value="' + d.searchValue + '">';
|
||
break;
|
||
}
|
||
formHtml += '\t<div class="layui-form-item layui-inline ' + formSearchHideClass + ' ">\n' +
|
||
'<label class="layui-form-label">' + d.title + '</label>\n' +
|
||
'<div class="layui-input-inline">\n' +
|
||
'<select class="layui-select" id="c-' + d.elemIdName + '" name="' + d.fieldAlias + '" data-search-op="' + d.searchOp + '" >\n' +
|
||
'<option value="">- 全部 -</option> \n' +
|
||
selectHtml +
|
||
'</select>\n' +
|
||
'</div>\n' +
|
||
'</div>';
|
||
break;
|
||
case 'range':
|
||
d.searchOp = 'range';
|
||
formHtml += '\t<div class="layui-form-item layui-inline ' + formSearchHideClass + ' ">\n' +
|
||
'<label class="layui-form-label">' + d.title + '</label>\n' +
|
||
'<div class="layui-input-inline">\n' +
|
||
'<input id="c-' + d.elemIdName + '" name="' + d.fieldAlias + '" data-search-op="' + d.searchOp + '" value="' + d.searchValue + '" placeholder="' + d.searchTip + '" class="layui-input">\n' +
|
||
'</div>\n' +
|
||
'</div>';
|
||
break;
|
||
case 'time':
|
||
d.searchOp = '=';
|
||
formHtml += '\t<div class="layui-form-item layui-inline ' + formSearchHideClass + ' ">\n' +
|
||
'<label class="layui-form-label">' + d.title + '</label>\n' +
|
||
'<div class="layui-input-inline">\n' +
|
||
'<input id="c-' + d.elemIdName + '" name="' + d.fieldAlias + '" data-search-op="' + d.searchOp + '" value="' + d.searchValue + '" placeholder="' + d.searchTip + '" class="layui-input">\n' +
|
||
'</div>\n' +
|
||
'</div>';
|
||
break;
|
||
case 'time_limit':
|
||
d.searchOp = '=';
|
||
formHtml += '\t<div class="layui-form-item form-item-time-limit layui-inline ' + formSearchHideClass + ' ">\n' +
|
||
'<label class="layui-form-label">' + d.title + '</label>\n' +
|
||
'<div class="layui-input-inline">\n' +
|
||
'<input id="c-' + d.elemIdName + '-min_date" name="[' + d.fieldAlias + ']min_date" data-search-op="min_date" value="' + a + '" placeholder="最小值" class="layui-input">\n' +
|
||
'<input id="c-' + d.elemIdName + '-max_date" name="[' + d.fieldAlias + ']max_date" data-search-op="max_date" value="' + b + '" placeholder="最大值" class="layui-input">\n' +
|
||
'</div>\n' +
|
||
'</div>';
|
||
break;
|
||
case 'number_limit':
|
||
d.searchOp = '=';
|
||
formHtml += '\t<div class="layui-form-item form-item-number-limit layui-inline ' + formSearchHideClass + ' ">\n' +
|
||
'<label class="layui-form-label">' + d.title + '</label>\n' +
|
||
'<div class="layui-input-inline">\n' +
|
||
'<input id="c-' + d.elemIdName + '-min" name="[' + d.fieldAlias + ']min" data-search-op="min" type="text" value="' + a + '" placeholder="最小值" class="layui-input">\n' +
|
||
'<input id="c-' + d.elemIdName + '-max" name="[' + d.fieldAlias + ']max" data-search-op="max" type="text" value="' + b + '" placeholder="最大值" class="layui-input">\n' +
|
||
'</div>\n' +
|
||
'</div>';
|
||
break;
|
||
}
|
||
newCols.push(d);
|
||
} else {
|
||
// TODO:支持更多种类型的初始化,比如number_limit、time_limit
|
||
formHtml += '<input type="hidden" id="c-' + d.elemIdName + '" name="' + d.fieldAlias + '" value="' + d.searchValue + '">';
|
||
}
|
||
}
|
||
});
|
||
|
||
if (tabSetting.field) {
|
||
var tabId = 'tabFieldset_' + tableId;
|
||
$(elem).before('<div id="' + tabId + '" class="search-tab" data-field="' + tabSetting.field + '"></div>');
|
||
var header = [
|
||
{
|
||
title: '全部',
|
||
key: '',
|
||
}
|
||
];
|
||
for (const tabSettingListKey in tabSetting.list) {
|
||
if (Object.prototype.hasOwnProperty.call(tabSetting.list, tabSettingListKey)) {
|
||
const tabItem = tabSetting.list[tabSettingListKey];
|
||
header.push({
|
||
title: tabItem,
|
||
key: tabSettingListKey,
|
||
});
|
||
}
|
||
}
|
||
layui.tabs.render({
|
||
elem: '#' + tabId,
|
||
header: header,
|
||
index: tabSetting.index + 1,
|
||
});
|
||
layui.tabs.on('afterChange(' + tabId + ')', function (data) {
|
||
var value = $(data.thisHeaderItem).attr('lay-key');
|
||
$('#c-' + tabSetting.elemIdName).val(value);
|
||
$('[lay-filter="' + tableId + '_filter"]').trigger('click');
|
||
|
||
});
|
||
}
|
||
|
||
if (formHtml !== '') {
|
||
|
||
$(elem).before('<fieldset id="searchFieldset_' + tableId + '" class="table-search-fieldset layui-hide">\n' +
|
||
'<legend>条件搜索</legend>\n' +
|
||
'<form class="layui-form layui-form-pane form-search" lay-filter="' + tableId + '_filter_form">\n' +
|
||
formHtml +
|
||
'<div class="layui-form-item layui-inline" style="margin-left: 115px">\n' +
|
||
'<button type="submit" class="layui-btn layui-btn-normal" data-type="tableSearch" data-table="' + tableId + '" lay-submit lay-filter="' + tableId + '_filter"> 搜 索</button>\n' +
|
||
'<button type="reset" class="layui-btn layui-btn-primary" data-table-reset="' + tableId + '"> 重 置 </button>\n' +
|
||
' </div>' +
|
||
'</form>' +
|
||
'</fieldset>');
|
||
|
||
ua.table.listenTableSearch(tableId);
|
||
|
||
// 初始化form表单
|
||
form.render();
|
||
$.each(newCols, function (ncI, ncV) {
|
||
if (ncV.search === 'range') {
|
||
laydate.render({ range: true, type: ncV.timeType, elem: '[name="' + ncV.fieldAlias + '"]' });
|
||
}
|
||
if (ncV.search === 'time') {
|
||
laydate.render({ type: ncV.timeType, elem: '[name="' + ncV.fieldAlias + '"]' });
|
||
}
|
||
if (ncV.search === 'time_limit') {
|
||
laydate.render({ type: ncV.timeType, elem: '[name="[' + ncV.fieldAlias + ']min_date"]' });
|
||
laydate.render({ type: ncV.timeType, elem: '[name="[' + ncV.fieldAlias + ']max_date"]' });
|
||
}
|
||
});
|
||
}
|
||
|
||
options.where = {
|
||
filter: JSON.stringify(formatFilter),
|
||
op: JSON.stringify(formatOp)
|
||
};
|
||
|
||
lastTableWhere[tableId] = options.where;
|
||
|
||
return options;
|
||
},
|
||
renderSwitch: function (cols, tableInit, tableId, modifyReload) {
|
||
tableInit.modifyUrl = tableInit.modifyUrl || false;
|
||
cols = cols[0] || {};
|
||
tableId = tableId || ua.init.tableRenderId;
|
||
if (cols.length > 0) {
|
||
$.each(cols, function (i, v) {
|
||
v.filter = v.filter || false;
|
||
if (v.filter !== false && tableInit.modifyUrl !== false) {
|
||
ua.table.listenSwitch({ filter: v.filter, url: tableInit.modifyUrl, tableId: tableId, modifyReload: modifyReload });
|
||
}
|
||
});
|
||
}
|
||
},
|
||
renderOperat(data, elem) {
|
||
for (dk in data) {
|
||
var col = data[dk];
|
||
var operat = col[col.length - 1].operat;
|
||
if (operat !== undefined) {
|
||
var check = false;
|
||
for (key in operat) {
|
||
var item = operat[key];
|
||
if (typeof item === 'string') {
|
||
if (ua.checkAuth(item, elem)) {
|
||
check = true;
|
||
break;
|
||
}
|
||
} else {
|
||
for (k in item) {
|
||
var v = item[k];
|
||
if (v.auth == undefined) {
|
||
v.auth = 'add';
|
||
}
|
||
if (ua.checkAuth(v.auth, elem)) {
|
||
check = true;
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
if (!check) {
|
||
data[dk].pop();
|
||
}
|
||
}
|
||
|
||
}
|
||
return data;
|
||
},
|
||
renderTrueHide(data, options) {
|
||
var newData = [];
|
||
for (dk in data) {
|
||
var newCol = [];
|
||
var col = data[dk];
|
||
|
||
col.forEach(colItem => {
|
||
var trueHide = false;
|
||
if (typeof colItem.trueHide == 'function') {
|
||
trueHide = colItem.trueHide(colItem, col, options);
|
||
} else if (typeof colItem.trueHide == 'string') {
|
||
trueHide = !ua.checkAuth(colItem.trueHide, options.elem);
|
||
} else {
|
||
trueHide = colItem.trueHide;
|
||
}
|
||
|
||
if (!trueHide) {
|
||
newCol.push(colItem);
|
||
}
|
||
});
|
||
|
||
newData.push(newCol);
|
||
}
|
||
|
||
return newData;
|
||
},
|
||
buildToolbarHtml: function (toolbar, tableId) {
|
||
var html = '';
|
||
toolbar.class = toolbar.class || '';
|
||
toolbar.icon = toolbar.icon || '';
|
||
toolbar.auth = toolbar.auth || 'add';
|
||
toolbar.url = toolbar.url || '';
|
||
toolbar.extend = toolbar.extend || '';
|
||
toolbar.method = toolbar.method || 'open';
|
||
toolbar.field = toolbar.field || 'id';
|
||
toolbar.title = toolbar.title || toolbar.text;
|
||
toolbar.text = toolbar.text || toolbar.title;
|
||
toolbar.checkbox = toolbar.checkbox || false;
|
||
|
||
var formatToolbar = toolbar;
|
||
formatToolbar.icon = formatToolbar.icon !== '' ? '<i class="' + formatToolbar.icon + '"></i> ' : '';
|
||
formatToolbar.class = formatToolbar.class !== '' ? 'class="' + formatToolbar.class + '" ' : '';
|
||
if (toolbar.method === 'open') {
|
||
formatToolbar.method = formatToolbar.method !== '' ? 'data-open="' + formatToolbar.url + '" data-title="' + formatToolbar.title + '" ' : '';
|
||
} else if (toolbar.method === 'none') { // 常用于与extend配合,自定义监听按钮
|
||
formatToolbar.method = '';
|
||
} else if (toolbar.method === 'blank') {
|
||
formatToolbar.method = ' href="' + formatToolbar.url + '" target="_blank" ';
|
||
} else if (operat.method === 'tab') {
|
||
formatToolbar.method = ' layuimini-content-href="' + formatToolbar.url + '" data-title="' + formatToolbar.title + '"';
|
||
} else {
|
||
formatToolbar.method = formatToolbar.method !== '' ? 'data-request="' + formatToolbar.url + '" data-title="' + formatToolbar.title + '" ' : '';
|
||
}
|
||
formatToolbar.checkbox = toolbar.checkbox ? ' data-checkbox="true" ' : '';
|
||
formatToolbar.tableId = tableId !== undefined ? ' data-table="' + tableId + '" ' : '';
|
||
html = '<button ' + formatToolbar.class + formatToolbar.method + formatToolbar.extend + formatToolbar.checkbox + formatToolbar.tableId + '>' + formatToolbar.icon + formatToolbar.text + '</button>';
|
||
|
||
return html;
|
||
},
|
||
buildOperatHtml: function (operat, data) {
|
||
var html = '';
|
||
operat.class = operat.class || '';
|
||
operat.icon = operat.icon || '';
|
||
operat.auth = operat.auth || 'add';
|
||
operat.url = operat.url || '';
|
||
operat.extend = operat.extend || '';
|
||
operat.method = operat.method || 'open';
|
||
operat.field = operat.field || 'id';
|
||
operat.data = operat.data || ['id'];
|
||
operat.titleField = operat.titleField || 'title';
|
||
operat.title = operat.title || operat.text;
|
||
operat.text = operat.text || operat.title;
|
||
|
||
var titleEndfix = '';
|
||
|
||
if (typeof operat.titleField == 'function') {
|
||
titleEndfix = operat.titleField(data, operat);
|
||
|
||
} else if (data[operat.titleField]) {
|
||
titleEndfix = '-' + data[operat.titleField];
|
||
}
|
||
|
||
if (typeof operat.text == 'function') {
|
||
operat.text = operat.text(data, operat);
|
||
}
|
||
|
||
if (typeof operat.title == 'function') {
|
||
operat.title = operat.title(data, operat);
|
||
}
|
||
|
||
var formatOperat = operat;
|
||
formatOperat.icon = formatOperat.icon !== '' ? '<i class="' + formatOperat.icon + '"></i> ' : '';
|
||
formatOperat.class = formatOperat.class !== '' ? 'class="' + formatOperat.class + '" ' : '';
|
||
if (operat.method === 'open') {
|
||
formatOperat.method = formatOperat.method !== '' ? 'data-open="' + formatOperat.url + '" data-title="' + formatOperat.title + titleEndfix + '" ' : '';
|
||
} else if (operat.method === 'none') { // 常用于与extend配合,自定义监听按钮
|
||
formatOperat.method = '';
|
||
} else if (operat.method === 'blank') {
|
||
formatOperat.method = ' href="' + formatOperat.url + '" target="_blank" ';
|
||
} else if (operat.method === 'tab') {
|
||
formatOperat.method = ' layuimini-content-href="' + formatOperat.url + '" data-title="' + formatOperat.title + titleEndfix + '"';
|
||
} else {
|
||
formatOperat.method = formatOperat.method !== '' ? 'data-request="' + formatOperat.url + '" data-title="' + formatOperat.title + titleEndfix + '" ' : '';
|
||
}
|
||
|
||
formatOperat.dataBind = ' ';
|
||
operat.data.forEach((item, index) => {
|
||
formatOperat.dataBind += 'data-' + item + '="' + data[item] + '" ';
|
||
});
|
||
|
||
html = '<a ' + formatOperat.class + formatOperat.method + formatOperat.extend + formatOperat.dataBind + '>' + formatOperat.icon + formatOperat.text + '</a>';
|
||
|
||
return html;
|
||
},
|
||
toolSpliceUrl(url, field, data) {
|
||
url = url.indexOf("?") !== -1 ? url + '&' + field + '=' + data[field] : url + '?' + field + '=' + data[field];
|
||
return url;
|
||
},
|
||
formatCols: function (cols, init) {
|
||
for (i in cols) {
|
||
var col = cols[i];
|
||
for (index in col) {
|
||
var val = col[index];
|
||
|
||
if (typeof val.hide == 'function') {
|
||
cols[i][index]['hide'] = val.hide(val, cols, init);
|
||
}
|
||
if (val['width'] == undefined && val['minWidth'] == undefined) {
|
||
var width = null;
|
||
if (val.title) {
|
||
width = val.title.length * 15 + 55;
|
||
}
|
||
|
||
if (width != null) {
|
||
cols[i][index]['minWidth'] = width;
|
||
}
|
||
}
|
||
|
||
// if str end with _time
|
||
if (val.field && val.field.indexOf('_time') !== -1) {
|
||
cols[i][index]['minWidth'] = 160;
|
||
}
|
||
|
||
|
||
if (val.sort === undefined) {
|
||
cols[i][index]['sort'] = true;
|
||
}
|
||
if (val.defaultValue === undefined) {
|
||
cols[i][index]['defaultValue'] = '';
|
||
}
|
||
|
||
// 判断是否包含初始化数据
|
||
if (val.init === undefined) {
|
||
cols[i][index]['init'] = init;
|
||
}
|
||
|
||
// 格式化列操作栏
|
||
if (val.templet === ua.table.tool && val.operat === undefined) {
|
||
cols[i][index]['operat'] = ['edit', 'delete'];
|
||
}
|
||
// 格式化列操作栏
|
||
if (val.templet === ua.table.tool) {
|
||
cols[i][index]['sort'] = false;
|
||
}
|
||
|
||
// 判断是否包含开关组件
|
||
if (val.templet === ua.table.switch && val.filter === undefined) {
|
||
cols[i][index]['filter'] = val.field;
|
||
}
|
||
|
||
// 判断是否含有搜索下拉列表
|
||
if (val.selectList !== undefined && val.search === undefined) {
|
||
cols[i][index]['search'] = 'select';
|
||
}
|
||
|
||
// 判断是否初始化对齐方式
|
||
if (val.align === undefined) {
|
||
cols[i][index]['align'] = 'left';
|
||
}
|
||
|
||
// 部分字段开启排序
|
||
var sortDefaultFields = ['id', 'sort'];
|
||
if (val.sort === undefined && sortDefaultFields.indexOf(val.field) >= 0) {
|
||
cols[i][index]['sort'] = true;
|
||
}
|
||
|
||
// 初始化图片高度
|
||
if (val.templet === ua.table.image && val.imageHeight === undefined) {
|
||
cols[i][index]['imageHeight'] = 26;
|
||
cols[i][index]['sort'] = false;
|
||
}
|
||
// 图片默认不搜索
|
||
if (val.templet === ua.table.image && val.search === undefined) {
|
||
cols[i][index]['search'] = false;
|
||
}
|
||
|
||
// 判断是否列表数据转换
|
||
if (val.selectList !== undefined && val.templet === undefined) {
|
||
cols[i][index]['templet'] = ua.table.list;
|
||
}
|
||
|
||
// 判断是否多层对象
|
||
if (val.field !== undefined && val.field.split(".").length > 1) {
|
||
if (val.templet === undefined) {
|
||
cols[i][index]['templet'] = ua.table.value;
|
||
}
|
||
}
|
||
|
||
// 如果未定义则默认使用value
|
||
if (cols[i][index]['templet'] === undefined) {
|
||
cols[i][index]['templet'] = ua.table.value;
|
||
} else {
|
||
// 针对特定的模板做数据调整
|
||
|
||
if (cols[i][index]['templet'] == ua.table.list) {
|
||
if (val.selectValue) {
|
||
|
||
var newSelectList = {};
|
||
val.selectList.map(item => {
|
||
newSelectList[item[val.selectValue]] = item[val.selectLabel];
|
||
});
|
||
|
||
cols[i][index]['selectList'] = newSelectList;
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
if (val.fieldFormat == undefined) {
|
||
|
||
switch (val.templet) {
|
||
case ua.table.image:
|
||
val.fieldFormat = 'image';
|
||
break;
|
||
case ua.table.date:
|
||
val.fieldFormat = 'date';
|
||
break;
|
||
default:
|
||
val.fieldFormat = 'text';
|
||
|
||
if (val.selectList !== undefined) {
|
||
val.fieldFormat = 'select';
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return cols;
|
||
},
|
||
tool: function (data) {
|
||
var option = data.LAY_COL;
|
||
option.operat = option.operat || ['edit', 'delete'];
|
||
var elem = option.init.tableElem || ua.init.tableElem;
|
||
var html = '';
|
||
$.each(option.operat, function (i, item) {
|
||
if (typeof item === 'string') {
|
||
switch (item) {
|
||
case 'edit':
|
||
var editMethod = 'tab';
|
||
if(selectMode){
|
||
editMethod = 'open';
|
||
}
|
||
var operat = {
|
||
class: 'layui-btn layui-btn-success layui-btn-xs',
|
||
method: editMethod,
|
||
field: 'id',
|
||
icon: '',
|
||
text: '编辑',
|
||
title: '编辑信息',
|
||
auth: 'edit',
|
||
url: option.init.editUrl,
|
||
extend: option.init.formFullScreen == 'true' ? ' data-full="true"' : ''
|
||
};
|
||
operat.url = ua.table.toolSpliceUrl(operat.url, operat.field, data);
|
||
if (ua.checkAuth(operat.auth, elem)) {
|
||
html += ua.table.buildOperatHtml(operat, data);
|
||
}
|
||
break;
|
||
case 'delete':
|
||
var operat = {
|
||
class: 'layui-btn layui-btn-danger layui-btn-xs',
|
||
method: 'get',
|
||
field: 'id',
|
||
icon: '',
|
||
text: '删除',
|
||
title: '确定删除?',
|
||
auth: 'delete',
|
||
url: option.init.deleteUrl,
|
||
extend: ""
|
||
};
|
||
operat.url = ua.table.toolSpliceUrl(operat.url, operat.field, data);
|
||
if (ua.checkAuth(operat.auth, elem)) {
|
||
html += ua.table.buildOperatHtml(operat, data);
|
||
}
|
||
break;
|
||
}
|
||
|
||
} else if (typeof item === 'object') {
|
||
$.each(item, function (i, operat) {
|
||
operat.class = operat.class || '';
|
||
operat.icon = operat.icon || '';
|
||
operat.auth = operat.auth || 'add';
|
||
operat.url = operat.url || '';
|
||
operat.method = operat.method || 'open';
|
||
operat.field = operat.field || 'id';
|
||
operat.title = operat.title || operat.text;
|
||
operat.text = operat.text || operat.title;
|
||
operat.extend = operat.extend || '';
|
||
|
||
operat._if = operat._if || function () { return true; };
|
||
|
||
if (typeof operat._if == 'function') {
|
||
if (operat._if(data, operat) !== true) {
|
||
return '';
|
||
}
|
||
} else if (typeof operat._if == 'string') {
|
||
var ifValue = ua.table.returnColumnValue(data, operat._if, false);
|
||
if (!ifValue) {
|
||
return '';
|
||
}
|
||
}
|
||
|
||
// 自定义表格opreat按钮的弹窗标题风格,extra是表格里的欲加入标题中的字段
|
||
operat.extra = operat.extra || '';
|
||
if (data[operat.extra] !== undefined) {
|
||
operat.title = data[operat.extra] + ' - ' + operat.title;
|
||
}
|
||
|
||
if (typeof operat.url == 'function') {
|
||
operat.url = operat.url(data, operat);
|
||
}
|
||
|
||
|
||
if (typeof operat.field != 'function') {
|
||
if (!ua.empty(operat.field)) {
|
||
operat.url = ua.table.toolSpliceUrl(operat.url, operat.field, data);
|
||
}
|
||
} else {
|
||
|
||
var fieldParam = operat.field(data, operat);
|
||
|
||
if (typeof fieldParam == 'string') {
|
||
operat.url = fieldParam;
|
||
} else {
|
||
var querys = '';
|
||
if (operat.url.indexOf("?") !== -1) {
|
||
if (operat.url.indexOf("?") !== operat.url.length - 1) {
|
||
querys = '&';
|
||
}
|
||
} else {
|
||
querys = '?';
|
||
}
|
||
operat.url += querys + $.param(fieldParam);
|
||
}
|
||
|
||
}
|
||
|
||
if (ua.checkAuth(operat.auth, elem)) {
|
||
html += ua.table.buildOperatHtml(operat, data);
|
||
}
|
||
});
|
||
}
|
||
});
|
||
return html;
|
||
},
|
||
list: function (data) {
|
||
var option = data.LAY_COL;
|
||
option.selectList = option.selectList || {};
|
||
|
||
var value = ua.table.returnColumnValue(data);
|
||
if (option.selectList[value] === undefined || option.selectList[value] === '' || option.selectList[value] === null) {
|
||
return value;
|
||
} else {
|
||
return option.selectList[value];
|
||
}
|
||
},
|
||
filePreview: function (data) {
|
||
var mimeName = data.mime_type.split('/')[0];
|
||
|
||
if (mimeName == 'image') {
|
||
return ua.table.image(data);
|
||
} else {
|
||
|
||
var value = ua.table.returnColumnValue(data);
|
||
|
||
var groupName = ua.getExtGroupName(data.file_ext);
|
||
|
||
return '<a href="' + value + '"><img style="height:40px;width:40px" src="/static/admin/images/upload-icons/' + groupName + '.png" /></a>';
|
||
}
|
||
|
||
},
|
||
image: function (data) {
|
||
var option = data.LAY_COL;
|
||
option.imageWidth = option.imageWidth || 200;
|
||
option.imageHeight = option.imageHeight || 26;
|
||
option.imageSplit = option.imageSplit || '|';
|
||
option.imageJoin = option.imageJoin || '<br>';
|
||
option.title = option.title || option.field;
|
||
var title = data[option.title];
|
||
var value = ua.table.returnColumnValue(data);
|
||
if (value === undefined || value === null) {
|
||
return '<img style="max-width: ' + option.imageWidth + 'px; max-height: ' + option.imageHeight + 'px;" src="' + value + '" data-image="' + title + '">';
|
||
} else {
|
||
var values = value.split(option.imageSplit),
|
||
valuesHtml = [];
|
||
values.forEach((value, index) => {
|
||
valuesHtml.push('<img style="max-width: ' + option.imageWidth + 'px; max-height: ' + option.imageHeight + 'px;" src="' + value + '" data-image="' + title + '">');
|
||
});
|
||
return valuesHtml.join(option.imageJoin);
|
||
}
|
||
},
|
||
url: function (data) {
|
||
var option = data.LAY_COL;
|
||
|
||
var urlNameField = option.urlNameField || '';
|
||
|
||
var value = ua.table.returnColumnValue(data);
|
||
|
||
if (ua.empty(value)) {
|
||
return '';
|
||
}
|
||
|
||
var urlName = value;
|
||
|
||
if (urlNameField != '') {
|
||
try {
|
||
var urlNameFieldType = typeof urlNameField;
|
||
|
||
if (urlNameFieldType == 'string') {
|
||
urlName = data[urlNameField];
|
||
} else if (urlNameFieldType == 'function') {
|
||
urlName = urlNameField(data);
|
||
}
|
||
|
||
} catch (e) {
|
||
|
||
}
|
||
}
|
||
|
||
return '<a class="layuimini-table-url" href="' + value + '" target="_blank" class="label bg-green">' + urlName + '</a>';
|
||
},
|
||
switch: function (data) {
|
||
var option = data.LAY_COL;
|
||
|
||
if (!ua.checkAuth('modify', option.init.tableElem)) {
|
||
return ua.table.list(data);
|
||
}
|
||
|
||
option.filter = option.filter || option.field || null;
|
||
option.checked = option.checked || 1;
|
||
|
||
|
||
var value = ua.table.returnColumnValue(data);
|
||
var checked = value === option.checked ? 'checked' : '';
|
||
return laytpl('<input type="checkbox" name="' + option.field + '" value="' + data.id + '" lay-skin="switch" lay-filter="' + option.filter + '" ' + checked + ' >').render(data);
|
||
},
|
||
price: function (data) {
|
||
var value = ua.table.returnColumnValue(data);
|
||
return '<span>¥' + value + '</span>';
|
||
},
|
||
percent: function (data) {
|
||
var value = ua.table.returnColumnValue(data);
|
||
return '<span>' + value + '%</span>';
|
||
},
|
||
icon: function (data) {
|
||
var value = ua.table.returnColumnValue(data);
|
||
return '<i class="' + value + '"></i>';
|
||
},
|
||
text: function (data) {
|
||
var value = ua.table.returnColumnValue(data);
|
||
return '<span class="line-limit-length">' + value + '</span>';
|
||
},
|
||
value: function (data) {
|
||
var value = ua.table.returnColumnValue(data);
|
||
return '<span>' + value + '</span>';
|
||
},
|
||
//时间戳转日期
|
||
date: function (data) {
|
||
var option = data.LAY_COL;
|
||
|
||
value = ua.table.returnColumnValue(data);
|
||
if (!ua.empty(value)) {
|
||
value = util.toDateString(value * 1000, option.format || 'yyyy-MM-dd HH:mm:ss');
|
||
}
|
||
return '<span>' + value + '</span>';
|
||
},
|
||
bytes: (data) => {
|
||
var size = ua.table.returnColumnValue(data);
|
||
sizeReadable = ua.bytes(size);
|
||
return sizeReadable;
|
||
},
|
||
copyText(data) {
|
||
var option = data.LAY_COL;
|
||
var value = ua.table.returnColumnValue(data);
|
||
var copyValue = value;
|
||
var copyText = option.copyText;
|
||
|
||
if (typeof copyText === 'function') {
|
||
copyValue = copyText(value, data);
|
||
}
|
||
|
||
return '<span data-toggle="copy-text" data-clipboard-text="' + copyValue + '"><i class="fa fa-copy"></i> ' + value + '</span>';
|
||
},
|
||
// 统一列返回数据处理
|
||
returnColumnValue(data, field, defaultValue) {
|
||
if (!data.LAY_COL) {
|
||
return '';
|
||
}
|
||
var option = data.LAY_COL;
|
||
|
||
field = field || option.field;
|
||
defaultValue = defaultValue || option.defaultValue;
|
||
|
||
var valueParser = option.valueParser;
|
||
var value = undefined;
|
||
try {
|
||
value = eval("data." + field);
|
||
} catch (e) {
|
||
|
||
}
|
||
if (typeof valueParser == 'function') {
|
||
value = valueParser(value, data);
|
||
}
|
||
|
||
if (value === null || value === undefined) {
|
||
value = defaultValue;
|
||
}
|
||
|
||
return value;
|
||
},
|
||
listenTableSearch: function (tableId) {
|
||
form.on('submit(' + tableId + '_filter)', function (data) {
|
||
var dataField = data.field;
|
||
var formatFilter = {},
|
||
formatOp = {};
|
||
$.each(dataField, function (key, val) {
|
||
if (val !== '') {
|
||
formatFilter[key] = val;
|
||
|
||
var elemId = ua.table.renderSearchFormItemElementId(key);
|
||
|
||
var op = $('#c-' + elemId).attr('data-search-op');
|
||
op = op || '%*%';
|
||
formatOp[key] = op;
|
||
}
|
||
});
|
||
|
||
var where = {
|
||
filter: JSON.stringify(formatFilter),
|
||
op: JSON.stringify(formatOp)
|
||
};
|
||
lastTableWhere[tableId] = where;
|
||
table.reloadData(tableId, {
|
||
page: {
|
||
curr: 1
|
||
}
|
||
, where: where
|
||
}, 'data');
|
||
return false;
|
||
});
|
||
},
|
||
listenSwitch: function (option, ok) {
|
||
option.filter = option.filter || '';
|
||
option.url = option.url || '';
|
||
option.field = option.field || option.filter || '';
|
||
option.tableId = option.tableId || ua.init.tableRenderId;
|
||
option.modifyReload = option.modifyReload || false;
|
||
form.on('switch(' + option.filter + ')', function (obj) {
|
||
var checked = obj.elem.checked ? 1 : 0;
|
||
if (typeof ok === 'function') {
|
||
return ok({
|
||
id: obj.value,
|
||
checked: checked,
|
||
});
|
||
} else {
|
||
var data = {
|
||
id: obj.value,
|
||
field: option.field,
|
||
value: checked,
|
||
};
|
||
ua.request.post({
|
||
url: option.url,
|
||
prefix: true,
|
||
data: data,
|
||
}, function (res) {
|
||
if (option.modifyReload) {
|
||
table.reloadData(option.tableId);
|
||
}
|
||
}, function (res) {
|
||
ua.msg.error(res.msg, function () {
|
||
table.reloadData(option.tableId);
|
||
});
|
||
}, function () {
|
||
table.reloadData(option.tableId);
|
||
});
|
||
}
|
||
});
|
||
},
|
||
listenTableSort(option) {
|
||
//触发排序事件
|
||
table.on('sort(' + option.layFilter + ')', function (obj) { //注:sort 是工具条事件名,test 是 table 原始容器的属性 lay-filter="对应的值"
|
||
|
||
var lastWhere = lastTableWhere[option.id] ? lastTableWhere[option.id] : {};
|
||
|
||
lastWhere.sort = {};
|
||
lastWhere.sort[obj.field] = obj.type;
|
||
|
||
table.reloadData(option.id, {
|
||
initSort: obj //记录初始排序,如果不设的话,将无法标记表头的排序状态。
|
||
, where: lastWhere
|
||
});
|
||
|
||
|
||
});
|
||
},
|
||
listenToolbar: function (layFilter, tableId) {
|
||
table.on('toolbar(' + layFilter + ')', function (obj) {
|
||
var options = obj.config;
|
||
var tableId = obj.config.id;
|
||
// 搜索表单的显示
|
||
switch (obj.event) {
|
||
case 'TABLE_SEARCH':
|
||
var searchFieldsetId = 'searchFieldset_' + tableId;
|
||
var _that = $("#" + searchFieldsetId);
|
||
if (_that.hasClass("layui-hide")) {
|
||
_that.removeClass('layui-hide');
|
||
} else {
|
||
_that.addClass('layui-hide');
|
||
}
|
||
break;
|
||
case 'TABLE_LAYOUT':
|
||
// 视图切换下拉(任务 15 (b),交互结构参照旧 TABLE_LAYOUT
|
||
// 实现重建):按钮仅在受控表 layoutList 条目>1 时注入,
|
||
// 条目清单来自 controlledLayouts 注册表。点击条目 =
|
||
// localStorage 按页记忆 + setLayoutForm 切换(数据取自
|
||
// store 当页状态,零网络请求)
|
||
var layoutEntryId = 'ua-layout-list-' + tableId;
|
||
var $toolbarLayoutElem = $('[lay-table-id="' + tableId + '"]').find('[lay-event="TABLE_LAYOUT"]');
|
||
var $layoutListElem = $('#' + layoutEntryId);
|
||
if ($layoutListElem.length > 0) {
|
||
$layoutListElem.remove();
|
||
break;
|
||
}
|
||
|
||
var layoutCurrent = ua.table.getLayoutForm(tableId);
|
||
var layoutIcons = {table: 'layui-icon-table', card: 'layui-icon-app'};
|
||
var layoutHtml = '<div id="' + layoutEntryId + '" class="ul-nav-block table-tpl-container">';
|
||
$.each(controlledLayouts[tableId].entries, function (i, item) {
|
||
var itemIcon = item.icon || layoutIcons[item.name] || 'layui-icon-template-1';
|
||
var itemClassName = item.name === layoutCurrent ? ' current' : '';
|
||
layoutHtml += '<div class="item' + itemClassName + '" data-name="' + item.name + '">'
|
||
+ '<div class="item-icon"><i class="layui-icon ' + itemIcon + '"></i></div>'
|
||
+ '<div class="item-title">' + item.title + '</div>'
|
||
+ '</div>';
|
||
});
|
||
layoutHtml += '</div>';
|
||
|
||
$layoutListElem = $(layoutHtml).appendTo($toolbarLayoutElem);
|
||
|
||
$layoutListElem.on('click', '.item', function (event) {
|
||
var layoutName = $(this).data('name');
|
||
ua.setPageSetting('table-layout-default', layoutName);
|
||
ua.table.setLayoutForm(tableId, layoutName);
|
||
$layoutListElem.remove();
|
||
$(document).off('click.ua-table-layout');
|
||
event.stopPropagation();
|
||
});
|
||
|
||
// 点击下拉外区域收起(命名空间事件,收起时解除)
|
||
$(document).off('click.ua-table-layout').on('click.ua-table-layout', function (event) {
|
||
if (!$(event.target).closest($toolbarLayoutElem).length) {
|
||
$('#' + layoutEntryId).remove();
|
||
$(document).off('click.ua-table-layout');
|
||
}
|
||
});
|
||
break;
|
||
}
|
||
});
|
||
},
|
||
listenEdit: function (tableInit, layFilter, tableId, modifyReload) {
|
||
tableInit.modifyUrl = tableInit.modifyUrl || false;
|
||
tableId = tableId || ua.init.tableRenderId;
|
||
if (tableInit.modifyUrl !== false) {
|
||
table.on('edit(' + layFilter + ')', function (obj) {
|
||
var value = obj.value,
|
||
data = obj.data,
|
||
id = data.id,
|
||
field = obj.field;
|
||
var _data = {
|
||
id: id,
|
||
field: field,
|
||
value: value,
|
||
};
|
||
ua.request.post({
|
||
url: tableInit.modifyUrl,
|
||
prefix: true,
|
||
data: _data,
|
||
}, function (res) {
|
||
if (modifyReload) {
|
||
table.reloadData(tableId);
|
||
}
|
||
}, function (res) {
|
||
ua.msg.error(res.msg, function () {
|
||
table.reloadData(tableId);
|
||
});
|
||
}, function () {
|
||
table.reloadData(tableId);
|
||
});
|
||
});
|
||
}
|
||
},
|
||
listenTableSelectConfirm(options) {
|
||
$('.select-confirm').click(function () {
|
||
var checkStatus = ua.table.checkStatus(options.id);
|
||
|
||
if (checkStatus.data.length == 0) {
|
||
layer.msg('请选择数据');
|
||
return false;
|
||
}
|
||
|
||
parent.window[selectConfirmCallback](checkStatus.data);
|
||
});
|
||
},
|
||
listenExport: function (options) {
|
||
|
||
var exportFields = {};
|
||
|
||
var imageFields = [];
|
||
|
||
var selectFields = {};
|
||
|
||
var dateFields = [];
|
||
|
||
options.cols[0].forEach(col => {
|
||
if (col.field) {
|
||
|
||
exportFields[col.field] = col.title;
|
||
|
||
options.cols[0].forEach(col => {
|
||
if (col.field) {
|
||
|
||
exportFields[col.field] = col.title;
|
||
|
||
switch (col.fieldFormat) {
|
||
case 'image':
|
||
imageFields.push(col.field);
|
||
break;
|
||
|
||
case 'select':
|
||
if (Object.keys(col.selectList).length > 0) {
|
||
selectFields[col.field] = col.selectList;
|
||
}
|
||
break;
|
||
case 'date':
|
||
|
||
dateFields.push(col.field);
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
}
|
||
});
|
||
|
||
}
|
||
});
|
||
|
||
// excel导出
|
||
$('body').on('click', '[data-table-export]', function () {
|
||
var tableId = $(this).attr('data-table-export'),
|
||
url = $(this).attr('data-url');
|
||
|
||
var searchVals = form.val(tableId + '_filter_form');
|
||
|
||
var dataField = searchVals;
|
||
|
||
var formatFilter = {},
|
||
formatOp = {};
|
||
$.each(dataField, function (key, val) {
|
||
if (val !== '') {
|
||
formatFilter[key] = val;
|
||
|
||
var elemId = ua.table.renderSearchFormItemElementId(key);
|
||
|
||
var op = $('#c-' + elemId).attr('data-search-op');
|
||
op = op || '%*%';
|
||
formatOp[key] = op;
|
||
}
|
||
});
|
||
|
||
var searchQuery = {
|
||
filter: JSON.stringify(formatFilter),
|
||
op: JSON.stringify(formatOp),
|
||
fields: JSON.stringify(exportFields),
|
||
image_fields: JSON.stringify(imageFields),
|
||
select_fields: JSON.stringify(selectFields),
|
||
date_fields: JSON.stringify(dateFields),
|
||
};
|
||
|
||
var query = $.param(searchQuery);
|
||
|
||
var index = ua.msg.confirm('根据查询进行导出,确定导出?', function () {
|
||
|
||
toUrl = ua.url(url);
|
||
if (toUrl.indexOf('?') < 0) {
|
||
toUrl += '?';
|
||
} else {
|
||
toUrl += '&';
|
||
}
|
||
toUrl += query;
|
||
|
||
window.open(toUrl);
|
||
|
||
layer.close(index);
|
||
});
|
||
});
|
||
},
|
||
renderSearchFormItemElementId(key) {
|
||
|
||
var elemId = key;
|
||
if (key.indexOf('[') == 0) {
|
||
var keyArr = key.replace('[', '').split(']');
|
||
|
||
elemId = keyArr[0] + '-' + keyArr[1];
|
||
}
|
||
|
||
elemId = elemId.replace('.', '-');
|
||
|
||
return elemId;
|
||
}
|
||
};
|
||
})();
|