bl-common-vue3 3.8.132 → 3.8.133

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bl-common-vue3",
3
- "version": "3.8.132",
3
+ "version": "3.8.133",
4
4
  "main": "index.js",
5
5
  "module": "index.js",
6
6
  "description": "bailing vue3 common components lib",
@@ -1342,7 +1342,7 @@
1342
1342
  :url="requestInfo?.serviceUrl"
1343
1343
  :service="requestInfo?.service"
1344
1344
  :method="requestInfo?.serviceType"
1345
- :params="listParams"
1345
+ :params="exportParams"
1346
1346
  :limit="exportLimit"
1347
1347
  :columnstitle="exportColumnsTitle"
1348
1348
  :merge_options="exportMergeOptions"
@@ -1892,6 +1892,7 @@ export default defineComponent({
1892
1892
  dictMenuAlias: "", // 后端返回的字典标识
1893
1893
  isExport: false,
1894
1894
  listParams: {},
1895
+ exportParams: {},
1895
1896
  exportResultData: [], // 导出结果处理
1896
1897
  importVisible: false,
1897
1898
  tableScrollHeight: 0,
@@ -2440,7 +2441,8 @@ export default defineComponent({
2440
2441
  let columnIndexObj = {};
2441
2442
  let haveSlot = false;
2442
2443
  cloneDeep(realColumns.value).forEach((columnItem, index) => {
2443
- // 从后往前处理
2444
+ // 不导出的展示列可能没有 dataIndex,也可能返回 VNode,不能参与数据转换。
2445
+ if (columnItem.exportHidden) return;
2444
2446
  let virtualDataIndex = replaceObjDataIndex(columnItem.dataIndex);
2445
2447
  if (columnItem.columnType) {
2446
2448
  columnIndexObj[virtualDataIndex] = {
@@ -2488,20 +2490,21 @@ export default defineComponent({
2488
2490
  localRowSelection.value?.selectedRowKeys
2489
2491
  );
2490
2492
  }
2493
+ // 导出组件会更新分页并追加选中条件,使用快照避免污染列表的后续查询。
2494
+ state.exportParams = cloneDeep(state.listParams);
2495
+ state.exportParams.filters = (state.exportParams.filters || []).filter(
2496
+ (item) => item.field !== "ids"
2497
+ );
2491
2498
  if (localRowSelection.value?.selectedRowKeys.length > 0) {
2492
- state.listParams.filters.push({
2499
+ state.exportParams.filters.push({
2493
2500
  field: "ids",
2494
2501
  type: "custom",
2495
- value: localRowSelection.value?.selectedRowKeys,
2502
+ value: [...localRowSelection.value.selectedRowKeys],
2496
2503
  });
2497
- } else {
2498
- state.listParams.filters = state.listParams.filters.filter(
2499
- (item) => item.field != "ids"
2500
- );
2501
2504
  }
2502
2505
  if (props.customExport) {
2503
2506
  /* 自定义导出 */
2504
- props.customExport(state.listParams);
2507
+ props.customExport(state.exportParams);
2505
2508
  } else {
2506
2509
  /* 默认导出 */
2507
2510
  state.isExport = true;
@@ -1,7 +1,7 @@
1
1
  <template>
2
2
  <bl-drawer
3
3
  :title="t('ExtraManage.index.845270-0')"
4
- :maskClosable="false"
4
+ :maskClosable="!editVisible"
5
5
  :visible="visible"
6
6
  :width="1040"
7
7
  :destroyOnClose="true"
@@ -0,0 +1,114 @@
1
+ const assert = require('node:assert/strict');
2
+ const {test, before, after} = require('node:test');
3
+ const {readFileSync} = require('node:fs');
4
+ const path = require('node:path');
5
+ const Module = require('node:module');
6
+ const Vue = require('vue');
7
+ const {parse, compileTemplate} = require('@vue/compiler-sfc');
8
+ const {transformSync} = require('@babel/core');
9
+ const originalFrame = global.requestAnimationFrame;
10
+ before(() => {global.requestAnimationFrame = () => 0;});
11
+ after(() => {global.requestAnimationFrame = originalFrame;});
12
+ const filename = path.resolve(__dirname, '../src/components/CustomTable/index.vue');
13
+ const {descriptor} = parse(readFileSync(filename, 'utf8'));
14
+ assert.deepEqual(compileTemplate({id: 'table-export-test', filename, source: descriptor.template.content}).errors, []);
15
+ const loaded = new Module(filename, module);
16
+ loaded.require = (name) => {
17
+ if (name === 'vue') return {...Vue, onMounted() {}, onBeforeUnmount() {}};
18
+ if (name === 'lodash' || name.startsWith('dayjs')) return require(name);
19
+ if (name.includes('locale')) return {t: key => key, loadLanguageAsync() {}};
20
+ if (name.endsWith('/util')) return {getCommonLocal() {}, getLang: () => 'zh-CN', isEnv: () => false,
21
+ i18nMapShow: (item, keys) => item[keys[0]]};
22
+ return {};
23
+ };
24
+ loaded._compile(transformSync(descriptor.script.content, {filename, configFile: false, babelrc: false,
25
+ plugins: ['@babel/plugin-transform-modules-commonjs']}).code, filename);
26
+ const component = loaded.exports.default;
27
+ const defaults = () => Object.fromEntries(Object.entries(component.props).map(([key, value]) => [key,
28
+ typeof value.default === 'function' && value.type !== Function ? value.default() : value.default]));
29
+ const flush = async () => {for (let i = 0; i < 20; i++) await Promise.resolve();};
30
+
31
+ async function table(columns, overrides = {}) {
32
+ const events = [];
33
+ const previousWindow = global.window;
34
+ global.window = {addEventListener() {}};
35
+ try {
36
+ const state = component.setup({...defaults(), loadDataAtInit: false, ...overrides}, {
37
+ slots: {}, expose() {}, attrs: {columns}, emit: (...args) => events.push(args),
38
+ });
39
+ await flush();
40
+ return {state, events};
41
+ } finally {global.window = previousWindow;}
42
+ }
43
+
44
+ test('export skips hidden presentation fields without a dataIndex', async () => {
45
+ const {state} = await table([
46
+ {key: 'company', dataIndex: 'company', title: 'Company'},
47
+ {key: 'extra_1', exportHidden: true, title: 'Attachment', customRender: () => {throw new Error('must not render');}},
48
+ ]);
49
+ assert.deepEqual(state.exportColumnsTitle.value, {company: 'Company'});
50
+ state.handleExportData([{company: 'Company A'}]);
51
+ assert.deepEqual(state.exportResultData.value, [{company: 'Company A'}]);
52
+ });
53
+
54
+ test('built-in export snapshots selection and pagination without changing subsequent list queries', async () => {
55
+ const {state} = await table([]);
56
+ const original = {page: 3, pageSize: 20, filters: [{field: 'status', value: 0}]};
57
+ state.listParams.value = structuredClone(original);
58
+ state.selectedRowKeys.value = [1, 3];
59
+ state.handleExport();
60
+ assert.equal(state.isExport.value, true);
61
+ assert.deepEqual(state.exportParams.value.filters, [...original.filters, {field: 'ids', type: 'custom', value: [1, 3]}]);
62
+ state.exportParams.value.page = 1;
63
+ state.exportParams.value.pageSize = 500;
64
+ state.selectedRowKeys.value.push(9);
65
+ assert.deepEqual(state.exportParams.value.filters.at(-1).value, [1, 3]);
66
+ assert.deepEqual(state.listParams.value, original);
67
+ state.selectedRowKeys.value = [9];
68
+ state.handleExport();
69
+ assert.deepEqual(state.exportParams.value.filters.at(-1).value, [9]);
70
+ assert.equal(state.exportParams.value.filters.length, 2);
71
+ state.selectedRowKeys.value = [];
72
+ state.handleExport();
73
+ assert.deepEqual(state.exportParams.value, original);
74
+ });
75
+
76
+ test('custom export receives the same isolated selection snapshot', async () => {
77
+ let exported;
78
+ const {state} = await table([], {customExport: params => {exported = params;}});
79
+ state.listParams.value = {page: 2, filters: []};
80
+ state.selectedRowKeys.value = [5];
81
+ state.handleExport();
82
+ assert.deepEqual(exported.filters, [{field: 'ids', type: 'custom', value: [5]}]);
83
+ exported.page = 1;
84
+ assert.equal(state.listParams.value.page, 2);
85
+ assert.equal(state.isExport.value, false);
86
+ });
87
+
88
+ test('built-in complete and partial imports refresh the table and display partial errors', async () => {
89
+ const {state, events} = await table([], {requestInfo: {service: '/org', serviceUrl: '/company/orgBranch', serviceType: 'get'}});
90
+ state.importVisible.value = true;
91
+ await state.handleImportSuccess();
92
+ await flush();
93
+ assert.equal(state.importVisible.value, false);
94
+ assert.equal(events.filter(([type, event]) => type === 'request' && event.params.url === '/company/orgBranch').length, 1);
95
+ state.importVisible.value = true;
96
+ const result = {errorFileKey: 'partial', success: 2, error: 1};
97
+ state.handleImportrefresh(result);
98
+ await flush();
99
+ assert.equal(state.importVisible.value, false);
100
+ assert.equal(state.ImportResultes.value, true);
101
+ assert.deepEqual(state.result.value, result);
102
+ assert.equal(events.filter(([type, event]) => type === 'request' && event.params.url === '/company/orgBranch').length, 2);
103
+ });
104
+
105
+ test('existing action slots still trigger the business export transformation callback', async () => {
106
+ const {state, events} = await table([
107
+ {key: 'company', dataIndex: 'company', title: 'Company'},
108
+ {key: 'action', dataIndex: 'id', title: 'Action'},
109
+ ]);
110
+ state.columnSlots.value = ['action'];
111
+ state.handleExportData([{id: 1, company: 'Company A'}]);
112
+ assert.deepEqual(state.exportColumnsTitle.value, {company: 'Company'});
113
+ assert.deepEqual(events.find(([name]) => name === 'changeExportData')[1], [{id: 1, company: 'Company A'}]);
114
+ });