Files
ulthon_admin/public/static/plugs/ulthon-admin/admin-table.js

2240 lines
106 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

(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;
};
// 统一行选中委托(任务 18):模板渲染容器内凡带 data-table-id + data-id 属性
// 的行元素——内置 card 的 .ua-data-card 与自定义 laytpl/Vue 模板的卡片/勾位
// 元素——点击即切换选中,全部走本委托,无任何形态专用事件。模板作者契约:
// 给行根元素(或勾位元素)加这两属性即获得点选交互,无需页面级监听。
// 交互元素(按钮/表单控件/layui 美化层)豁免不触发勾选;禁用行
// (ua-data-card-disabled 标记或行 LAY_DISABLED)整元素不可勾选。选择态落
// store(与引擎勾选同一事实源,批量删除经 ua.table.checkStatus 分发即取到),
// 随后重渲模板管线回显勾位标记。
$(document).on('click', '[data-table-id][data-id]', function (e) {
var $card = $(this);
var tableId = $card.attr('data-table-id');
// 仅模板渲染容器内的行元素生效(页面其他区域的 data-id 元素不受影响)
if ($card.closest('#ua-layout-' + tableId).length === 0) {
return;
}
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 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(任务 16,layui.laytpl)与 vue/vueId(任务 17,全局 Vue 2.6.10
// 运行时编译)均挂载于 renderLayoutForm。
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/tplVueId 节点缺失 / laytpl 渲染错误 / Vue 未引入
// 或挂载渲染失败):当前形态归位 'table'(与"无钩子条目回退"同语义,幂等、
// 不写 localStorage 记忆,用户重新切换可再次触发),容器销毁 Vue 实例后清空
// 隐藏。调用方据 false 返回值做引擎纯渲染,随后的 syncLayoutVisibility 按
// table kind 复显引擎数据区,避免"容器残留上一形态旧内容 + 引擎数据被隐藏"
// 的视觉错位。
var fallbackLayoutToTable = function (tableId, $container) {
var layout = controlledLayouts[tableId];
if (layout) {
layout.current = 'table';
}
destroyLayoutVueInstances(tableId);
if ($container && $container.length) {
$container.addClass('layui-hide').empty();
}
return false;
};
// ========== vue/vueId 引擎(任务 17,全局 Vue 2.6.10 运行时编译)==========
// 渲染模式为列表级单实例:模板内 v-for="d in rows" 循环行,一次渲染只挂载
// 一个实例(逐行 new Vue 的成本随行数线性膨胀,销毁纪律也难以收口)。
// 实例存活表:tableId → 当前实例数组。
var layoutVueInstances = {};
// 销毁本表全部存活实例(渲染入口 / fallbackLayoutToTable /
// syncLayoutVisibility 三处统一调用,幂等)。$destroy 只拆 watcher 与事件,
// 不动 DOM,容器清空由调用方完成。任何重渲路径(store done 管线/搜索/
// 切换/回退)都必须先销毁旧实例再挂新实例——销毁重建式是"实例存活期禁止
// 响应式数据变更"约束(约束 2)的落地方式:form.render 美化插入的 DOM
// (div.layui-form-switch 等)不受 Vue 虚拟 DOM 管理,存活期 re-patch 会
// 清除它们。
var destroyLayoutVueInstances = function (tableId) {
var list = layoutVueInstances[tableId] || [];
$.each(list, function (i, vm) {
try {
vm.$destroy();
} catch (e) {}
});
layoutVueInstances[tableId] = [];
};
// Vue 生产构建中模板编译错误不抛异常也不打日志(dev 告警被裁剪),坏模板
// 只会在挂载渲染时经全局 errorHandler 暴露——链式接管 Vue.config.errorHandler:
// 本框架实例(vm.__uaLayout 标记)按形态名 console.error 并记录
// lastVueLayoutError,由 renderLayoutForm 探测后回退;其余实例
// (propertyInput/tagInput 等页面自有 Vue)透传既有处理器或复刻默认行为。
var lastVueLayoutError = null;
var vueErrorHandlerInstalled = false;
var installVueErrorHandler = function () {
if (vueErrorHandlerInstalled) {
return;
}
vueErrorHandlerInstalled = true;
var previous = window.Vue.config.errorHandler;
window.Vue.config.errorHandler = function (err, vm, info) {
if (vm && vm.__uaLayout) {
var meta = vm.__uaLayout;
lastVueLayoutError = {tableId: meta.tableId, name: meta.name};
console.error('[ua.table] Vue 模板渲染失败(形态 "' + meta.name + '"):'
+ ((err && err.message) || err) + ',本次回退 table 形态');
return;
}
if (typeof previous === 'function') {
previous(err, vm, info);
return;
}
console.error(err);
};
};
// 形态可见性同步:引擎数据区(表头+表体+合计行)与模板容器互斥显隐,
// 引擎视图的工具栏(刷新/新增/批量删除等)两形态共用保持可见,搜索区
// 本就挂在表格元素之前不受影响。非 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') {
destroyLayoutVueInstances(tableId);
$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;
var userFail = opts.fail;
// 模板形态的加载态容器标记(容器内加载样式由任务 14 的内置形态接入)
var $layoutContainer = $('#ua-layout-' + tableId);
$layoutContainer.addClass('ua-layout-loading');
// 失败通道(res.code != 0 / HTTP error)不进 done,需经 fail 摘除加载态,
// 避免请求失败后容器残留半透明禁点状态
opts.fail = function () {
$layoutContainer.removeClass('ua-layout-loading');
if (typeof userFail === 'function') {
userFail.apply(null, arguments);
}
};
opts.done = function (res) {
// 受控渲染分发:table 形态走引擎纯渲染(现状),非 table 形态走
// 模板管线(渲染上下文 + 行级循环);模板管线不可用(Vue 未引入/
// 挂载渲染失败;tplLayId/tplVueId 节点缺失/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,调用方回退引擎纯渲染
// 【Vue 调用约定(tplVue / tplVueId,任务 17)】
// 列表级单实例:框架把模板包进单一根节点 <div class="ua-layout-vue">
// (Vue 2 实例模板根元素禁用 v-for 且生产构建该错误静默,包裹层规避
// 全部根约束问题,多根模板也因此可用),行循环由模板作者用
// v-for="d in rows" 承接:
// - rows = 行上下文数组,d 与 tplFunction/tplLay 的行上下文同构
// (d._cells.xxx / d._operatHtml / d._checked / d._disabled);
// - list = 列表上下文 {tableId, rows, page, count, checkedAll}
// (laytpl 的 d._list 同物;Vue 实例对 _/$ 前缀 data 键不做代理,
// 裸标识符 _list 会 ReferenceError,故 Vue 形态改名为 list);
// - _cells/_operatHtml 含 HTML,必须用 v-html 输出,纯文本用 {{ }};
// - tplVueId 是页面 <script type="text/x-template"> 节点选择器,节点
// 必须位于渲染容器之外(下方硬约束 2),.html() 读取原始文本;
// - 挂载成功后一次性 form.render(约束 1);实例存活期禁止响应式数据
// 变更(约束 2):渲染上下文经 Object.freeze 冻结,数据不可变即不会
// re-patch,form.render 美化 DOM 不被清除,更新一律销毁重建;
// - 模板编译错误在 Vue 生产构建不抛异常,经链式全局 errorHandler 记录
// (installVueErrorHandler),框架探测后按条目名 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;
}
// 销毁重建式(约束 2):任何重渲路径进入本函数先销毁上一轮 Vue 实例,
// 容器被清空的其余路径由 fallbackLayoutToTable / syncLayoutVisibility
// 兜底同规则销毁
destroyLayoutVueInstances(tableId);
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);
}
// vue/vueId 引擎(任务 17):tplVue = 模板字符串;tplVueId =
// <script type="text/x-template"> 节点选择器(节点须在渲染容器之外)
var vueTemplate = null;
if (resolved.kind === 'vue' || resolved.kind === 'vueId') {
if (typeof window.Vue === 'undefined') {
console.error('[ua.table] 全局 Vue 未引入(形态 "' + resolved.entry.name + '"),本次回退 table 形态');
return fallbackLayoutToTable(tableId, $container);
}
installVueErrorHandler();
if (resolved.kind === 'vueId') {
var $vueTplNode = $(resolved.entry.tplVueId);
if ($vueTplNode.length === 0) {
console.error('[ua.table] tplVueId 节点不存在:' + resolved.entry.tplVueId
+ '(形态 "' + resolved.entry.name + '"),本次回退 table 形态');
return fallbackLayoutToTable(tableId, $container);
}
vueTemplate = $vueTplNode.html();
} else {
vueTemplate = resolved.entry.tplVue;
}
}
var context = ua.table.buildLayoutContext(tableId);
if (vueTemplate !== null) {
// 自定义模板形态移除内置 card 网格类(与 laytpl 同规则)
$container.toggleClass('ua-layout-cards', resolved.entry.builtinCard === true);
if (context.rows.length === 0) {
$container.html('<div class="ua-layout-empty">无数据</div>');
form.render(null, 'ua-layout-' + tableId);
return true;
}
// 冻结渲染上下文(约束 2 的强制保证):顶层数据不可扩展即不会被
// observe,模板表达式改写失效、不触发 re-patch,form.render 插入
// 的美化 DOM 安全;数据更新只经销毁重建(本函数开头已销毁)
Object.freeze(context.rows);
$.each(context.rows, function (i, rowCtx) {
Object.freeze(rowCtx);
});
Object.freeze(context);
var vm = null;
try {
vm = new window.Vue({
template: '<div class="ua-layout-vue">' + vueTemplate + '</div>',
data: {rows: context.rows, list: context}
});
vm.__uaLayout = {tableId: tableId, name: resolved.entry.name};
vm.$mount();
} catch (e) {
// 挂载期同步异常(CSP Function 构造失败等);渲染期错误已由
// 全局 errorHandler 记录并告警,此处不再重复;此时实例尚未
// 注册进存活表,需就地销毁
if (lastVueLayoutError === null) {
console.error('[ua.table] Vue 模板挂载失败(形态 "' + resolved.entry.name + '"):'
+ ((e && e.message) || e) + ',本次回退 table 形态');
}
if (vm) {
try {
vm.$destroy();
} catch (ignored) {}
}
return fallbackLayoutToTable(tableId, $container);
}
// 编译/渲染错误探测(errorHandler 已按形态名 console.error);
// 同上,实例未注册,先就地销毁再归位
if (lastVueLayoutError && lastVueLayoutError.tableId === tableId) {
lastVueLayoutError = null;
try {
vm.$destroy();
} catch (ignored) {}
return fallbackLayoutToTable(tableId, $container);
}
lastVueLayoutError = null;
if (!vm || !vm.$el) {
console.error('[ua.table] Vue 模板渲染为空(形态 "' + resolved.entry.name + '"),本次回退 table 形态');
return fallbackLayoutToTable(tableId, $container);
}
layoutVueInstances[tableId] = [vm];
// $destroy 只拆实例不动 DOM(见 destroyLayoutVueInstances 注释),
// 上一轮实例的 DOM 残留必须在此显式清空,否则每次重渲都会累积
$container.empty().append(vm.$el);
// 约束 1:容器恒为 .layui-form(lay-filter 与容器 id 同名),
// 挂载后一次性 scoped form.render 美化模板产出的 switch/checkbox
form.render(null, 'ua-layout-' + tableId);
return true;
}
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/tplVueId 节点缺失 / laytpl 渲染错误 / Vue 未引入或
// 挂载渲染失败,均已在 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 = [];
var autoInjected = false;
// 受控是默认数据流,仅显式 controlled:false 的逃生口页跳过
if (options.controlled !== false) {
// 未配置 layoutList 的受控页双端自动启用内置 card:内置
// card 无需页面模板(数据全来自渲染上下文),自动注入可行。
// 注入后条目数>1,双端工具栏自动出现"视图"按钮。显式配置
// layoutList 的页面仍优先不注入(含 usercard 示例页等存量配置)。
if (!options.layoutList || !options.layoutList.length) {
options.layoutList = ['table', 'card'];
autoInjected = 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;
} else if (autoInjected) {
// 自动注入 card 且页面显式配置了 defaultToolbar 时,上方
// push 视图按钮的 defaultToolbar 数组被整体丢弃,"默认 card
// 且可切回 table"会落空,这里对最终配置去重追加(仅注入场景
// 触发;显式 layoutList 页均不受影响)
var hasLayoutBtn = false;
$.each(options.defaultToolbar, function (i, btn) {
if (btn && typeof btn === 'object' && btn.layEvent === 'TABLE_LAYOUT') {
hasLayoutBtn = true;
return false;
}
});
if (!hasLayoutBtn) {
options.defaultToolbar.push({
title: '视图',
layEvent: 'TABLE_LAYOUT',
icon: 'layui-icon-template-1',
extend: 'data-table-id="' + options.id + '"'
});
}
}
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;
}
// 受控是默认数据流(store 取数 + 引擎纯渲染),controlled:false
// 是逃生口:依赖引擎 url 模式行为(如自定义 parseData)的下游
// 页面可显式传 controlled:false 退回。
if (options.controlled !== false) {
// 受控数据流:数据请求与分页职责移交 UA_TABLE_STORE,引擎只做
// 纯渲染(空数据起步、关闭引擎分页,由 store 的 laypage 自绘)。
// 选择态注入(rowDisableCallback / URL selectedIds / LAY_CHECKED
// 跨页回显)由 store.fetch 的 injectSelectionMarks 承接,故不装
// 引擎 parseData。
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 承接),此处无需逐点改造。
// controlled:false 的逃生口页不走此分支,保持引擎 url 模式。
if (options.controlled !== false) {
// 分页容器挂在引擎视图容器之后(表格容器外),不与引擎分页共存。
// 注意 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;
}
};
})();