(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; }; // (b) 模板引擎优先级解析:tplFunction > tplLay > tplVue > tplLayId > tplVueId, // 提供一种即生效;五种全无且非 table 条目 → console.warn 并回退 table。 // lay/vue/layId/vueId 的引擎挂载在任务 16(laytpl)/17(Vue),此处只做分发判定。 var resolveLayoutEngine = function (entry) { if (entry.name === 'table') { return {kind: 'table', entry: entry}; } 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); }; // 形态可见性同步:引擎数据区(表头+表体+合计行)与模板容器互斥显隐, // 引擎视图的工具栏(刷新/新增/批量删除等)两形态共用保持可见,搜索区 // 本就挂在表格元素之前不受影响。非 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 形态走 // 模板管线(渲染上下文 + 行级循环);模板管线不可用(引擎未挂载, // 任务 16/17 接管)时回退引擎纯渲染兜底 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 调用约定(任务 16/17 对接契约)】 // 单行 HTML = tplFunction.call(rowCtx, rowCtx, listCtx) // - this/第一参 = 行上下文 {...row, _cells, _operatHtml, _checked, _disabled} // - 第二参 = 列表上下文 {tableId, rows, page, count, checkedAll} // - 返回值 = 该行的 HTML 字符串(框架直接拼接,不做转义) // 【两条硬约束】 // 1. 模板容器恒带 class="layui-form"(form 控件渲染与事件受 .layui-form // 祖先约束,缺失则模板里的 switch/checkbox 全部失效); // 2. laytpl/Vue 模板节点(