

# **双列表 SDK 统一调用方案**

> 本文档解决同一份 JS 代码（或同一个按钮脚本）在**表格视图**和**数据列表**两种列表中均可生效的问题。
> 
> - 表格视图：旧版表格视图，SDK 为 `window.ebdListSdk`
> - 数据列表：基于设计器实现，，可以使用设计器方法。也有自封装的仅支持数据列表的SDK `window.eblistSdk`，

---

## **一、背景说明**

### **1.1 两种 SDK 的 API 层级**

**表格视图 SDK**（`window.ebdListSdk`）：

```
window.ebdListSdk.getCheckedID()    // 直接调用
window.ebdListSdk.reloadTable()
```

**数据列表 SDK**（`window.eblistSdk`）：

```
window.eblistSdk.getCheckedID()    // 方法由 registerTableMethods 动态挂载，直接调用
window.eblistSdk.reloadTable()
window.eblistSdk.getInstance(pageId, compId?)  // 实例查找
```

### **1.2 方法对照表**

| **功能** | **表格视图 **`window.ebdListSdk` | **数据列表 **`window.eblistSdk` |
| --- | --- | --- |
| 获取选中 ID | `getCheckedID()` | `getCheckedID()` |
| 获取选中数据 | `getListCheckedData()` | `getListCheckedData()` |
| 获取未选中 ID | `getUnCheckedID()` | `getUnCheckedID()` |
| 全选 | `setAllChecked()` | `setAllChecked()` |
| 按 ID 选中 | `setCheckedKeys(string\[\])` | `setCheckedKeys(string\[\])` |
| 清除选中 | `clearChecked()` | `clearChecked()` |
| 刷新列表 | `reloadTable()` | `reloadTable()` |
| 获取当前页数据 | `getListData()` | `getListData()` |
| 获取视图 ID | `getViewID()` | —（数据列表无此概念） |
| 获取数据集 ID | `getObjID()` | `getObjID()` |
| 获取应用 ID | `getAppID()` | `getAppID()` |

### **1.3 仅表格视图 SDK 拥有的方法**

| **功能** | **方法** |
| --- | --- |
| 触发按钮 | `triggerButtonAction(buttonId, routerProps?)` |
| 设置右上角按钮 | `setTopButtons(menus)` |
| 隐藏/禁用按钮 | `controlBtnHidden(isHide, ids?)` / `controlBtnDisabled(isDisabled)` |
| 获取筛选条件值 | `getFilterSearchDatas()` |
| 获取高级搜索值 | `getAdQuickSearchDatas()` |
| 自定义数据加工 | `customRenderData(handler)` |
| 自定义 HTML 渲染 | `customRenderHTML(handler)` |
| 挂载完成回调 | `onAfterMount(callback)` |
| 数据加载完成回调 | `onAfterDataLoaded(callback)` |

### **1.4 仅数据列表 SDK 拥有的方法**

| **功能** | **方法** |
| --- | --- |
| 注册插件 | `registerPlugin(PluginClass)` |
| 查找实例 | `getInstance(pageId, compId?)` |
| 获取组件 ID | `getUniqueId()` |
| 获取页面 ID | `getListId()` |
| 销毁实例 | `destroy()` |

### **1.5 仅数据列表支持的插件钩子（20+ 个）**

渲染类：`reRender`、`renderAddonBefore`、`renderAddonAfter`、`renderAddonHeader`、`renderContent`、`renderContentHeaderBefore`、`renderContentHeaderAfter`、`getEnableContentHeader`、`getEnableContentHeaderCell`、`renderTitle`、`renderCell`、`renderRow`、`renderListItem`、`renderListContent`、`renderTableContent`、`renderLayout`、`renderLayoutAddonBefore`、`renderLayoutAddonAfter`、`renderRowAddonBefore`、`renderGridAddonAfter`

权限类：`getRowLineButtonEnabled`、`getButtonPermissionParams`、`getButtonPermissionAfter`、`getRightButtonsPermission`、`getRowButtonsPermission`、`getCustomBtnExecConfig`、`getPersonalFieldsFilter`

数据类：`getDataParams`、`getListDatas`、`getExcuEventActions`、`onDataChecked`、`getViewMount`

列配置类：`getTableColumns`、`getTableViewColumns`

---

## **二、核心问题**

按钮 JS 触发时不知道当前是哪种列表——`routerProps` 中只有 `buttonId`、`selectedKeys`、`pos`、`data`，**不包含列表类型标识**。

---

## **三、JavaScript限制**

JS动作有以下重要限制：

1. **无持久状态**：每次按钮点击或代码块执行都是独立运行环境，上一次 `function` 声明不会保留到下一次调用
2. **不能 **`import`：JS 不支持 ES Module 的 `import` 语法，所有依赖必须通过全局对象访问（如 `window`、`eventEmitter`）
3. **因此**：适配器函数必须在每个 JS 代码块中**内联展开**，不能依赖预先定义的全局函数

---

## **四、完整示例（可直接粘贴到按钮 JS）**

### **4.1 基础版：自动探测 + 直接调用**

适用于只需要"选中数据"、"刷新列表"等通用操作的场景。

```
// === 自动探测当前列表类型 ===
// 优先尝试数据列表（window.eblistSdk），其次表格视图（window.ebdListSdk）

var sdk = window.eblistSdk || window.ebdListSdk;
if (!sdk) {
    console.warn('未找到列表 SDK');
    return;
}

// 判断列表类型（用于调用专属方法时做分支）
var isNList = !!window.eblistSdk;
var isTable = !!window.ebdListSdk;

// === 通用操作：两种列表方法签名一致，直接调用 ===
var checkedIds = sdk.getCheckedID ? sdk.getCheckedID() : [];
var checkedData = sdk.getListCheckedData ? sdk.getListCheckedData() : [];
var listData = sdk.getListData ? sdk.getListData() : [];

console.log('选中ID:', checkedIds);
console.log('选中数据:', checkedData);
console.log('当前页数据:', listData);

// 刷新列表
if (sdk.reloadTable) sdk.reloadTable();

// 全选 / 清除选中
if (sdk.setAllChecked) sdk.setAllChecked();
if (sdk.clearChecked) sdk.clearChecked();
if (sdk.setCheckedKeys) sdk.setCheckedKeys(['id1', 'id2']);
```

### **4.2 标准版：含判断分支**

适用于需要根据列表类型走不同逻辑的场景（如是否调用 `triggerButtonAction` 或 `registerPlugin`）。

```
// === 自动探测当前列表 SDK ===
var nlistSdk = window.eblistSdk;
var tableSdk = window.ebdListSdk;

if (!nlistSdk && !tableSdk) {
    console.warn('未找到列表 SDK');
    return;
}

// 确定当前类型和可用 SDK
var currentSdk = nlistSdk || tableSdk;
var isNList = !!nlistSdk;
var isTable = !!tableSdk;

console.log('列表类型:', isNList ? '数据列表' : '表格视图');

// === 通用操作（两种列表均可） ===
var checkedIds = currentSdk.getCheckedID ? currentSdk.getCheckedID() : [];
var listData = currentSdk.getListData ? currentSdk.getListData() : [];

if (!checkedIds || !checkedIds.length) {
    console.warn('请先选择数据');
    return;
}

console.log('选中ID:', checkedIds);
console.log('当前页数据:', listData);

// === 表格视图专属方法 ===
if (isTable) {
    // 触发按钮
    if (tableSdk.triggerButtonAction) {
        tableSdk.triggerButtonAction('按钮ID');
    }
    // 动态设置右上角按钮
    if (tableSdk.setTopButtons) {
        tableSdk.setTopButtons([{ id: 'btn1', name: '自定义按钮' }]);
    }
    // 隐藏按钮
    if (tableSdk.controlBtnHidden) {
        tableSdk.controlBtnHidden(true, 'btnId');
    }
    // 获取筛选条件
    if (tableSdk.getFilterSearchDatas) {
        var filterData = tableSdk.getFilterSearchDatas();
        console.log('筛选条件:', filterData);
    }
    // 刷新
    if (tableSdk.reloadTable) {
        tableSdk.reloadTable();
    }
}

// === 数据列表专属方法 ===
if (isNList) {
    // 注册插件（必须在组件 mount 前通过 eventEmitter 注册，这里仅示例）
    // 注意：实际注册需要在页面 JS 或组件初始化时完成，此处演示如何调用
    if (nlistSdk.registerPlugin) {
        // nlistSdk.registerPlugin(MyPlugin);  // 需配合 eventEmitter 在 mount 前执行
    }
    // 刷新
    if (nlistSdk.reloadTable) {
        nlistSdk.reloadTable();
    }
}
```

### **4.3 完整版：含插件注册 + 各方法演示**

适用于需要在数据列表中使用插件钩子、或需要做精细化控制的场景。

```
// ============================================================
// 双列表 SDK 完整示例（可直接粘贴到按钮 JS）
// ============================================================

// --- 探测层 ---
var nlistSdk = window.eblistSdk;
var tableSdk = window.ebdListSdk;
var sdk = nlistSdk || tableSdk;

if (!sdk) {
    console.warn('未找到列表 SDK');
    return;
}

var isNList = !!nlistSdk;
var isTable = !!tableSdk;

// --- 通用数据操作（两种列表均可直接调用） ---
var checkedIds = sdk.getCheckedID ? sdk.getCheckedID() : [];
var uncheckedIds = sdk.getUnCheckedID ? sdk.getUnCheckedID() : [];
var checkedData = sdk.getListCheckedData ? sdk.getListCheckedData() : [];
var allData = sdk.getListData ? sdk.getListData() : [];
var viewInfo = {
    appId: sdk.getAppID ? sdk.getAppID() : null,
    objId: sdk.getObjID ? sdk.getObjID() : null,
    // 视图 ID：表格视图有 getViewID()，数据列表用 getListId()
    viewId: isTable ? (sdk.getViewID ? sdk.getViewID() : null) : (sdk.getListId ? sdk.getListId() : null),
};

console.log('列表类型:', isNList ? '数据列表' : '表格视图');
console.log('视图信息:', viewInfo);
console.log('选中ID:', checkedIds);
console.log('未选中ID:', uncheckedIds);
console.log('选中数据:', checkedData);
console.log('当前页数据条数:', Array.isArray(allData) ? allData.length : 0);

// --- 操作方法 ---
if (sdk.setCheckedKeys) sdk.setCheckedKeys(['id1', 'id2']);  // 指定选中
if (sdk.clearChecked) sdk.clearChecked();                   // 清除选中
if (sdk.setAllChecked) sdk.setAllChecked();                  // 全选
if (sdk.setAllChecked) sdk.setAllChecked(false);             // 取消全选
if (sdk.reloadTable) sdk.reloadTable();                      // 刷新列表

// --- 表格视图专属功能 ---
if (isTable && tableSdk) {
    // 触发右键按钮
    if (tableSdk.triggerButtonAction) {
        tableSdk.triggerButtonAction('buttonIdHere');
    }
    // 动态设置右上角按钮
    if (tableSdk.setTopButtons) {
        tableSdk.setTopButtons([
            { id: 'customBtn1', name: '自定义按钮1', icon: 'reload' },
            { id: 'customBtn2', name: '自定义按钮2' },
        ]);
    }
    // 控制按钮显隐
    if (tableSdk.controlBtnHidden) tableSdk.controlBtnHidden(true, 'btnId1,btnId2');
    // 控制按钮禁用
    if (tableSdk.controlBtnDisabled) tableSdk.controlBtnDisabled(true);
    // 获取筛选条件
    if (tableSdk.getFilterSearchDatas) {
        var filterParams = tableSdk.getFilterSearchDatas();
        console.log('筛选条件:', filterParams);
    }
    // 获取快捷/高级搜索
    if (tableSdk.getAdQuickSearchDatas) {
        var searchParams = tableSdk.getAdQuickSearchDatas();
        console.log('搜索参数:', searchParams);
    }
    // 挂载完成后回调
    if (tableSdk.onAfterMount) {
        tableSdk.onAfterMount(function() { console.log('表格视图挂载完成'); });
    }
    // 数据加载完成后回调
    if (tableSdk.onAfterDataLoaded) {
        tableSdk.onAfterDataLoaded(function() { console.log('数据加载完成'); });
    }
    // 获取内部 Store（可访问更多底层方法）
    if (tableSdk.getListStore) {
        var store = tableSdk.getListStore();
        console.log('Store:', store);
    }
}

// --- 数据列表专属功能 ---
if (isNList && nlistSdk) {
    // 注册插件——通过 eventEmitter 在组件 mount 前注册（此处演示调用方式）
    // 实际使用时需在页面 JS 或专用初始化代码中执行，以下为示意
    if (nlistSdk.registerPlugin) {
        // 示例插件结构（实际插件类需在页面 JS 中定义）
        // var MyPlugin = {
        //     name: 'MyPlugin',
        //     renderContent: function(hook) {
        //         return function() {
        //             return hook.apply(this, arguments);
        //         };
        //     }
        // };
        // nlistSdk.registerPlugin(MyPlugin);
    }
    // 通过 eventEmitter 注册（需已知 comId）
    // eventEmitter.once('@weapp/designer', 'onBeforeMount_' + comId, function(plugin) {
    //     plugin.registerPlugin(MyPlugin);
    // });

    // 通过 compId 查找实例
    if (nlistSdk.getInstance) {
        var instances = nlistSdk.getInstance('pageIdHere');
        console.log('数据列表实例:', instances);
    }
}
```

---

## **五、场景化速查**

| **场景** | **推荐写法** |
| --- | --- |
| 只获取选中 ID 和数据 | `var sdk = window.eblistSdk \|\| window.ebdListSdk; var ids = sdk.getCheckedID();` |
| 刷新当前列表 | `var sdk = window.eblistSdk \|\| window.ebdListSdk; sdk.reloadTable();` |
| 全选/清除选中 | `sdk.setAllChecked()` / `sdk.clearChecked()` |
| 根据列表类型走不同逻辑 | `if (window.eblistSdk) { /\* 数据列表 \*/ } else if (window.ebdListSdk) { /\* 表格视图 \*/ }` |
| 触发按钮（仅表格视图） | `window.ebdListSdk.triggerButtonAction('btnId')` |
| 设置右上角按钮（仅表格视图） | `window.ebdListSdk.setTopButtons(\[...\])` |
| 数据列表插件注册 | `window.eblistSdk.registerPlugin(PluginClass)`（需配合 `eventEmitter` 在 mount 前注册） |
| 同时支持两种列表刷新 | `(window.eblistSdk \|\| window.ebdListSdk).reloadTable()` |

---

## **六、附录：SDK 实例来源**

### **表格视图 SDK**

- 挂载：`window.ebdListSdk`（getter 访问，每次返回 stack 顶部的实例）
- 注册时机：列表 store `onMount` 时调用 `EbdfpageSDK.initListSdk(uniqueId, viewId, store)`
- 实例数量：每个列表页面对应一个实例，存储在 `EbdfpageSDK.uniqueListSDKS` 字典中

### **数据列表 SDK**

- 挂载：`window.eblistSdk`（`EblistSdk.init()` 直接赋值，全局唯一实例）
- 注册时机：`EbListViewPlugin.onBeforeMount` 时调用 `EblistSdk.init(pageId, compId, instanceId)`
- 方法来源：`table-methods/base.ts` 等文件通过 `registerTableMethods()` 动态注册到实例上
