@nokecy/qc-ui 1.1.64 → 1.1.66

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.
@@ -12,6 +12,7 @@ var _antd = require("antd");
12
12
  var _classnames = _interopRequireDefault(require("classnames"));
13
13
  var _react2 = _interopRequireWildcard(require("react"));
14
14
  var _queryForm = _interopRequireDefault(require("./queryForm"));
15
+ var _schemaKey = require("./schemaKey");
15
16
  var _boolSelect = _interopRequireDefault(require("../_utils/boolSelect"));
16
17
  require("./index.less");
17
18
  function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
@@ -203,8 +204,19 @@ var FormRender = function FormRender(props) {
203
204
  // 【新增】用于追踪是否已完成首次初始化
204
205
  var initializedRef = (0, _react2.useRef)(false);
205
206
  (0, _react2.useEffect)(function () {
207
+ var _new_schema$propertie, _new_schema$propertie2;
206
208
  var new_schema = getSchema(onReset);
207
209
  setSchema(new_schema);
210
+ // Formily 只在字段首次创建时读取 schema:已有查询项要把新标题、组件属性(如下拉选项)写回字段。@author nokecy
211
+ Object.entries((_new_schema$propertie = (_new_schema$propertie2 = new_schema.properties) === null || _new_schema$propertie2 === void 0 || (_new_schema$propertie2 = _new_schema$propertie2.queryForm) === null || _new_schema$propertie2 === void 0 ? void 0 : _new_schema$propertie2.properties) !== null && _new_schema$propertie !== void 0 ? _new_schema$propertie : {}).forEach(function (_ref) {
212
+ var _ref2 = _slicedToArray(_ref, 2),
213
+ name = _ref2[0],
214
+ fieldSchema = _ref2[1];
215
+ form.query(name).take(function (field) {
216
+ field.title = fieldSchema.title;
217
+ field.setComponentProps(fieldSchema['x-component-props']);
218
+ });
219
+ });
208
220
 
209
221
  // 【修复】在 schema 设置完成后调用 onInit
210
222
  // 使用 setTimeout 确保 Formily 有时间处理 schema 并应用默认值
@@ -217,11 +229,7 @@ var FormRender = function FormRender(props) {
217
229
  }, 0);
218
230
  });
219
231
  }
220
- }, [columnStates === null || columnStates === void 0 ? void 0 : columnStates.map(function (c) {
221
- return c.colId;
222
- }).join('|'), colDefs === null || colDefs === void 0 ? void 0 : colDefs.map(function (c) {
223
- return "".concat(c.field, "|").concat(c.headerName);
224
- }).join('|')]);
232
+ }, [(0, _schemaKey.queryFormSchemaKey)(columnStates, colDefs)]);
225
233
  return /*#__PURE__*/_react2.default.createElement("div", {
226
234
  className: (0, _classnames.default)(className, "ag-grid-table-search ag-grid-table-search-query-filter"),
227
235
  style: {
@@ -0,0 +1,20 @@
1
+ type ColumnStateLike = {
2
+ colId?: string | null;
3
+ };
4
+ type QueryColumnLike = {
5
+ field?: string;
6
+ headerName?: string;
7
+ searchComponentProps?: {
8
+ options?: readonly {
9
+ value?: unknown;
10
+ label?: unknown;
11
+ }[];
12
+ };
13
+ };
14
+ /**
15
+ * 查询区 schema 的重建键:列(id、字段、标题)或下拉选项变了才重建。
16
+ * 下拉选项常在首帧之后才到(如从基础资料接口取名称),只看列与标题时选项停在首帧。
17
+ * @author nokecy
18
+ */
19
+ export declare const queryFormSchemaKey: (columnStates?: readonly ColumnStateLike[] | null, colDefs?: readonly QueryColumnLike[] | null) => string;
20
+ export {};
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.queryFormSchemaKey = void 0;
7
+ var optionsSignature = function optionsSignature(options) {
8
+ return Array.isArray(options) ? options.map(function (option) {
9
+ return "".concat(String(option === null || option === void 0 ? void 0 : option.value), "=").concat(String(option === null || option === void 0 ? void 0 : option.label));
10
+ }).join(',') : '';
11
+ };
12
+
13
+ /**
14
+ * 查询区 schema 的重建键:列(id、字段、标题)或下拉选项变了才重建。
15
+ * 下拉选项常在首帧之后才到(如从基础资料接口取名称),只看列与标题时选项停在首帧。
16
+ * @author nokecy
17
+ */
18
+ var queryFormSchemaKey = exports.queryFormSchemaKey = function queryFormSchemaKey(columnStates, colDefs) {
19
+ return [columnStates === null || columnStates === void 0 ? void 0 : columnStates.map(function (column) {
20
+ return column.colId;
21
+ }).join('|'), colDefs === null || colDefs === void 0 ? void 0 : colDefs.map(function (column) {
22
+ var _column$searchCompone;
23
+ return "".concat(column.field, "|").concat(column.headerName, "|").concat(optionsSignature((_column$searchCompone = column.searchComponentProps) === null || _column$searchCompone === void 0 ? void 0 : _column$searchCompone.options));
24
+ }).join('|')].join('#');
25
+ };
@@ -27,6 +27,8 @@ interface ConfigurableToolbarProps {
27
27
  import?: string;
28
28
  export?: string;
29
29
  };
30
+ /** 当前用户已授予的权限,见 GeneratedListPageConfig.access */
31
+ access?: Record<string, boolean>;
30
32
  }
31
33
  /**
32
34
  * 配置化工具栏组件
@@ -40,9 +40,10 @@ var ConfigurableToolbar = function ConfigurableToolbar(_ref) {
40
40
  _ref$exportFileName = _ref.exportFileName,
41
41
  exportFileName = _ref$exportFileName === void 0 ? 'export.xlsx' : _ref$exportFileName,
42
42
  filter = _ref.filter,
43
- permissions = _ref.permissions;
43
+ permissions = _ref.permissions,
44
+ access = _ref.access;
44
45
  // 使用统一的权限检查 Hook
45
- var _usePermissionCheck = (0, _usePermissionCheck2.usePermissionCheck)(permissions || {}),
46
+ var _usePermissionCheck = (0, _usePermissionCheck2.usePermissionCheck)(permissions || {}, access),
46
47
  canCreate = _usePermissionCheck.canCreate,
47
48
  canImport = _usePermissionCheck.canImport,
48
49
  canExport = _usePermissionCheck.canExport,
@@ -92,7 +92,11 @@ var GeneratedListPage = function GeneratedListPage(config) {
92
92
  } : _config$paginationCon,
93
93
  externalGridRef = config.gridRef,
94
94
  externalOnRefresh = config.onRefresh,
95
- pagedApiAdapter = config.pagedApiAdapter;
95
+ pagedApiAdapter = config.pagedApiAdapter,
96
+ gridComponent = config.gridComponent,
97
+ access = config.access,
98
+ deleteConfirm = config.deleteConfirm;
99
+ var Grid = gridComponent || _agGridPlus.AgGridPlus;
96
100
 
97
101
  // 内部Grid引用
98
102
  var internalGridRef = (0, _react.useRef)();
@@ -165,11 +169,13 @@ var GeneratedListPage = function GeneratedListPage(config) {
165
169
  permissions: permissions,
166
170
  formDialog: formDialog,
167
171
  deleteApi: apiConfig.delete,
168
- useErrorHandler: errorConfig.useErrorHandler
172
+ useErrorHandler: errorConfig.useErrorHandler,
173
+ access: access,
174
+ deleteConfirm: deleteConfirm
169
175
  }
170
176
  };
171
177
  return [].concat(_toConsumableArray(columnDefs), [operationColumn]);
172
- }, [columnDefs, formDialog, apiConfig.delete, permissions, onRefresh, OptionsColumnComponent, errorConfig.useErrorHandler]);
178
+ }, [columnDefs, formDialog, apiConfig.delete, permissions, onRefresh, OptionsColumnComponent, errorConfig.useErrorHandler, access, deleteConfirm]);
173
179
 
174
180
  /**
175
181
  * 从扁平数据构建树形结构
@@ -413,9 +419,10 @@ var GeneratedListPage = function GeneratedListPage(config) {
413
419
  importConfig: importConfig,
414
420
  exportFileName: exportFileName,
415
421
  filter: filter,
416
- permissions: permissions
422
+ permissions: permissions,
423
+ access: access
417
424
  }))];
418
- }, [enableImportExport, toolbarActions, formDialog, apiConfig, onRefresh, importConfig, exportFileName, permissions]);
425
+ }, [enableImportExport, toolbarActions, formDialog, apiConfig, onRefresh, importConfig, exportFileName, permissions, access]);
419
426
 
420
427
  // AgGridPlus属性配置
421
428
  var agGridProps = _objectSpread({
@@ -476,7 +483,7 @@ var GeneratedListPage = function GeneratedListPage(config) {
476
483
  position: 'relative',
477
484
  height: '100%'
478
485
  }
479
- }, /*#__PURE__*/_react.default.createElement(_agGridPlus.AgGridPlus, agGridProps), /*#__PURE__*/_react.default.createElement(_PerformanceMonitor.PerformanceDevTools, {
486
+ }, /*#__PURE__*/_react.default.createElement(Grid, agGridProps), /*#__PURE__*/_react.default.createElement(_PerformanceMonitor.PerformanceDevTools, {
480
487
  componentName: "GeneratedListPage-".concat(title),
481
488
  metrics: metrics,
482
489
  onGetReport: getPerformanceReport
@@ -32,10 +32,12 @@ var OptionsColumn = function OptionsColumn(props) {
32
32
  formDialog = props.formDialog,
33
33
  deleteApi = props.deleteApi,
34
34
  _props$useErrorHandle = props.useErrorHandler,
35
- useErrorHandler = _props$useErrorHandle === void 0 ? true : _props$useErrorHandle;
35
+ useErrorHandler = _props$useErrorHandle === void 0 ? true : _props$useErrorHandle,
36
+ access = props.access,
37
+ deleteConfirm = props.deleteConfirm;
36
38
 
37
39
  // 使用权限检查 Hook
38
- var _usePermissionCheck = (0, _usePermissionCheck2.usePermissionCheck)(permissions),
40
+ var _usePermissionCheck = (0, _usePermissionCheck2.usePermissionCheck)(permissions, access),
39
41
  canUpdate = _usePermissionCheck.canUpdate,
40
42
  canDelete = _usePermissionCheck.canDelete,
41
43
  hasPermission = _usePermissionCheck.hasPermission;
@@ -90,13 +92,24 @@ var OptionsColumn = function OptionsColumn(props) {
90
92
  return null;
91
93
  }
92
94
  var FormDialogComponent = formDialog === null || formDialog === void 0 ? void 0 : formDialog.component;
95
+
96
+ // 确认框要说清删的是哪一条:页面没给标题时取该行的名称或编码。@author nokecy
97
+ var record = data;
98
+ var recordLabel = (record === null || record === void 0 ? void 0 : record.name) || (record === null || record === void 0 ? void 0 : record.displayName) || (record === null || record === void 0 ? void 0 : record.code);
99
+ var resolveText = function resolveText(value, fallback) {
100
+ return typeof value === 'function' ? value(data) : value !== null && value !== void 0 ? value : fallback;
101
+ };
102
+ var deleteTitle = resolveText(deleteConfirm === null || deleteConfirm === void 0 ? void 0 : deleteConfirm.title, recordLabel ? "\u786E\u5B9A\u5220\u9664\u300C".concat(recordLabel, "\u300D\uFF1F") : '确定删除?');
103
+ var deleteContent = resolveText(deleteConfirm === null || deleteConfirm === void 0 ? void 0 : deleteConfirm.content, '删除后无法恢复。');
93
104
  return /*#__PURE__*/_react.default.createElement(_antd.Space, {
94
105
  onClick: function onClick(event) {
95
106
  event.stopPropagation();
96
107
  }
97
108
  }, showEditButton && FormDialogComponent && /*#__PURE__*/_react.default.createElement(Access, {
98
109
  accessible: canUpdate
99
- }, /*#__PURE__*/_react.default.createElement(FormDialogComponent, {
110
+ }, /*#__PURE__*/_react.default.createElement(_antd.Tooltip, {
111
+ title: "\u7F16\u8F91"
112
+ }, /*#__PURE__*/_react.default.createElement("span", null, /*#__PURE__*/_react.default.createElement(FormDialogComponent, {
100
113
  buttonProps: {
101
114
  size: "small",
102
115
  type: "link",
@@ -104,17 +117,19 @@ var OptionsColumn = function OptionsColumn(props) {
104
117
  style: {
105
118
  fontSize: 14
106
119
  }
107
- })
120
+ }),
121
+ 'aria-label': '编辑'
108
122
  },
109
123
  key: data.id,
110
124
  title: formDialog.editTitle || '编辑',
111
125
  entityId: data.id,
112
126
  onAfterSubmit: refresh
113
- })), showDeleteButton && /*#__PURE__*/_react.default.createElement(Access, {
127
+ })))), showDeleteButton && /*#__PURE__*/_react.default.createElement(Access, {
114
128
  accessible: canDelete
115
129
  }, /*#__PURE__*/_react.default.createElement(_deleteConfirm.default, {
116
- title: "\u786E\u5B9A\u5220\u9664?",
117
- content: "\u6B64\u64CD\u4F5C\u5C06\u6C38\u4E45\u5220\u9664\u8BE5\u6570\u636E\uFF0C\u4E14\u65E0\u6CD5\u6062\u590D",
130
+ title: deleteTitle,
131
+ content: deleteContent,
132
+ okText: "\u5220\u9664",
118
133
  onConfirm: /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2() {
119
134
  return _regeneratorRuntime().wrap(function _callee2$(_context2) {
120
135
  while (1) switch (_context2.prev = _context2.next) {
@@ -127,11 +142,13 @@ var OptionsColumn = function OptionsColumn(props) {
127
142
  }
128
143
  }, _callee2);
129
144
  }))
145
+ }, /*#__PURE__*/_react.default.createElement(_antd.Tooltip, {
146
+ title: "\u5220\u9664"
130
147
  }, /*#__PURE__*/_react.default.createElement(_antd.Button, {
131
148
  size: "small",
132
149
  icon: /*#__PURE__*/_react.default.createElement(_icons.DeleteOutlined, null),
133
150
  type: "link",
134
- title: "\u5220\u9664"
135
- }))));
151
+ "aria-label": "\u5220\u9664"
152
+ })))));
136
153
  };
137
154
  var _default = exports.default = OptionsColumn;
@@ -12,7 +12,7 @@ export { default } from './GeneratedListPage';
12
12
  export { default as GeneratedListPage } from './GeneratedListPage';
13
13
  export { default as ConfigurableToolbar } from './ConfigurableToolbar';
14
14
  export { default as OptionsColumn } from './OptionsColumn';
15
- export type { GeneratedListPageConfig, PermissionConfig, ApiConfig, ListParams, PagedResult, DeleteParams, ExportParams, ToolbarActionConfig, FormDialogConfig, TreeDataConfig, OptionsComponentProps } from './types';
15
+ export type { GeneratedListPageConfig, PermissionConfig, ApiConfig, ListParams, PagedResult, DeleteParams, ExportParams, ToolbarActionConfig, FormDialogConfig, TreeDataConfig, OptionsComponentProps, DeleteConfirmConfig } from './types';
16
16
  export { usePermissionCheck, PermissionChecker } from './usePermissionCheck';
17
17
  export { usePerformanceMonitor, PerformanceDevTools } from './PerformanceMonitor';
18
18
  export { useRequestManager } from './useRequestManager';
@@ -1,7 +1,7 @@
1
- /// <reference types="react" />
2
1
  import { GridRef } from "../ag-grid-plus/interface";
3
2
  import { ColDef } from "ag-grid-community";
4
3
  import { ButtonProps } from "antd";
4
+ import { ReactNode } from "react";
5
5
  import { PagedApiAdapter } from '../adapters';
6
6
  /**
7
7
  * 权限配置接口
@@ -203,6 +203,27 @@ export interface GeneratedListPageConfig<T = any> {
203
203
  onRefresh?: () => void;
204
204
  /** 分页 API 适配器(默认 ABP);非 ABP 后端可注入。@author nokecy */
205
205
  pagedApiAdapter?: PagedApiAdapter;
206
+ /**
207
+ * 表格组件,默认用包内 AgGridPlus。
208
+ * 宿主可注入自己的表格基座(属性与 AgGridPlus 相同),让序号、默认复选、编码列收起、
209
+ * 内部字段隐藏等列表规范在通用列表页上同样生效。@author nokecy
210
+ */
211
+ gridComponent?: React.ComponentType<any>;
212
+ /**
213
+ * 当前用户已授予的权限(权限名 → 是否授予),通常传 umi 的 useAccess()。
214
+ * 不传时工具栏与操作列不做权限过滤——没有权限的人也会看到新建、编辑、删除,点了才报 403。@author nokecy
215
+ */
216
+ access?: Record<string, boolean>;
217
+ /** 删除确认框;title、content 可按行生成 */
218
+ deleteConfirm?: DeleteConfirmConfig<T>;
219
+ }
220
+ /**
221
+ * 删除确认框配置。
222
+ * 不传 title 时标题带上该行的名称或编码,让用户看清删的是哪一条;不传 content 时说明删除后无法恢复。@author nokecy
223
+ */
224
+ export interface DeleteConfirmConfig<T = any> {
225
+ title?: ReactNode | ((record: T) => ReactNode);
226
+ content?: ReactNode | ((record: T) => ReactNode);
206
227
  }
207
228
  /**
208
229
  * 操作列组件属性接口
@@ -221,4 +242,8 @@ export interface OptionsComponentProps<T = any> {
221
242
  deleteApi?: (params: DeleteParams) => Promise<void>;
222
243
  /** 是否使用统一错误处理 */
223
244
  useErrorHandler?: boolean;
245
+ /** 当前用户已授予的权限,见 GeneratedListPageConfig.access */
246
+ access?: Record<string, boolean>;
247
+ /** 删除确认框配置 */
248
+ deleteConfirm?: DeleteConfirmConfig<T>;
224
249
  }
@@ -18,6 +18,7 @@ import { Button, theme } from 'antd';
18
18
  import classNames from 'classnames';
19
19
  import React, { useEffect, useMemo, useRef, useState } from 'react';
20
20
  import QueryForm from "./queryForm";
21
+ import { queryFormSchemaKey } from "./schemaKey";
21
22
  import BoolSelect from "../_utils/boolSelect";
22
23
  import "./index.less";
23
24
  var FormRender = function FormRender(props) {
@@ -195,8 +196,19 @@ var FormRender = function FormRender(props) {
195
196
  // 【新增】用于追踪是否已完成首次初始化
196
197
  var initializedRef = useRef(false);
197
198
  useEffect(function () {
199
+ var _new_schema$propertie, _new_schema$propertie2;
198
200
  var new_schema = getSchema(onReset);
199
201
  setSchema(new_schema);
202
+ // Formily 只在字段首次创建时读取 schema:已有查询项要把新标题、组件属性(如下拉选项)写回字段。@author nokecy
203
+ Object.entries((_new_schema$propertie = (_new_schema$propertie2 = new_schema.properties) === null || _new_schema$propertie2 === void 0 || (_new_schema$propertie2 = _new_schema$propertie2.queryForm) === null || _new_schema$propertie2 === void 0 ? void 0 : _new_schema$propertie2.properties) !== null && _new_schema$propertie !== void 0 ? _new_schema$propertie : {}).forEach(function (_ref) {
204
+ var _ref2 = _slicedToArray(_ref, 2),
205
+ name = _ref2[0],
206
+ fieldSchema = _ref2[1];
207
+ form.query(name).take(function (field) {
208
+ field.title = fieldSchema.title;
209
+ field.setComponentProps(fieldSchema['x-component-props']);
210
+ });
211
+ });
200
212
 
201
213
  // 【修复】在 schema 设置完成后调用 onInit
202
214
  // 使用 setTimeout 确保 Formily 有时间处理 schema 并应用默认值
@@ -209,11 +221,7 @@ var FormRender = function FormRender(props) {
209
221
  }, 0);
210
222
  });
211
223
  }
212
- }, [columnStates === null || columnStates === void 0 ? void 0 : columnStates.map(function (c) {
213
- return c.colId;
214
- }).join('|'), colDefs === null || colDefs === void 0 ? void 0 : colDefs.map(function (c) {
215
- return "".concat(c.field, "|").concat(c.headerName);
216
- }).join('|')]);
224
+ }, [queryFormSchemaKey(columnStates, colDefs)]);
217
225
  return /*#__PURE__*/React.createElement("div", {
218
226
  className: classNames(className, "ag-grid-table-search ag-grid-table-search-query-filter"),
219
227
  style: {
@@ -0,0 +1,20 @@
1
+ type ColumnStateLike = {
2
+ colId?: string | null;
3
+ };
4
+ type QueryColumnLike = {
5
+ field?: string;
6
+ headerName?: string;
7
+ searchComponentProps?: {
8
+ options?: readonly {
9
+ value?: unknown;
10
+ label?: unknown;
11
+ }[];
12
+ };
13
+ };
14
+ /**
15
+ * 查询区 schema 的重建键:列(id、字段、标题)或下拉选项变了才重建。
16
+ * 下拉选项常在首帧之后才到(如从基础资料接口取名称),只看列与标题时选项停在首帧。
17
+ * @author nokecy
18
+ */
19
+ export declare const queryFormSchemaKey: (columnStates?: readonly ColumnStateLike[] | null, colDefs?: readonly QueryColumnLike[] | null) => string;
20
+ export {};
@@ -0,0 +1,19 @@
1
+ var optionsSignature = function optionsSignature(options) {
2
+ return Array.isArray(options) ? options.map(function (option) {
3
+ return "".concat(String(option === null || option === void 0 ? void 0 : option.value), "=").concat(String(option === null || option === void 0 ? void 0 : option.label));
4
+ }).join(',') : '';
5
+ };
6
+
7
+ /**
8
+ * 查询区 schema 的重建键:列(id、字段、标题)或下拉选项变了才重建。
9
+ * 下拉选项常在首帧之后才到(如从基础资料接口取名称),只看列与标题时选项停在首帧。
10
+ * @author nokecy
11
+ */
12
+ export var queryFormSchemaKey = function queryFormSchemaKey(columnStates, colDefs) {
13
+ return [columnStates === null || columnStates === void 0 ? void 0 : columnStates.map(function (column) {
14
+ return column.colId;
15
+ }).join('|'), colDefs === null || colDefs === void 0 ? void 0 : colDefs.map(function (column) {
16
+ var _column$searchCompone;
17
+ return "".concat(column.field, "|").concat(column.headerName, "|").concat(optionsSignature((_column$searchCompone = column.searchComponentProps) === null || _column$searchCompone === void 0 ? void 0 : _column$searchCompone.options));
18
+ }).join('|')].join('#');
19
+ };
@@ -27,6 +27,8 @@ interface ConfigurableToolbarProps {
27
27
  import?: string;
28
28
  export?: string;
29
29
  };
30
+ /** 当前用户已授予的权限,见 GeneratedListPageConfig.access */
31
+ access?: Record<string, boolean>;
30
32
  }
31
33
  /**
32
34
  * 配置化工具栏组件
@@ -32,9 +32,10 @@ var ConfigurableToolbar = function ConfigurableToolbar(_ref) {
32
32
  _ref$exportFileName = _ref.exportFileName,
33
33
  exportFileName = _ref$exportFileName === void 0 ? 'export.xlsx' : _ref$exportFileName,
34
34
  filter = _ref.filter,
35
- permissions = _ref.permissions;
35
+ permissions = _ref.permissions,
36
+ access = _ref.access;
36
37
  // 使用统一的权限检查 Hook
37
- var _usePermissionCheck = usePermissionCheck(permissions || {}),
38
+ var _usePermissionCheck = usePermissionCheck(permissions || {}, access),
38
39
  canCreate = _usePermissionCheck.canCreate,
39
40
  canImport = _usePermissionCheck.canImport,
40
41
  canExport = _usePermissionCheck.canExport,
@@ -82,7 +82,11 @@ var GeneratedListPage = function GeneratedListPage(config) {
82
82
  } : _config$paginationCon,
83
83
  externalGridRef = config.gridRef,
84
84
  externalOnRefresh = config.onRefresh,
85
- pagedApiAdapter = config.pagedApiAdapter;
85
+ pagedApiAdapter = config.pagedApiAdapter,
86
+ gridComponent = config.gridComponent,
87
+ access = config.access,
88
+ deleteConfirm = config.deleteConfirm;
89
+ var Grid = gridComponent || AgGridPlus;
86
90
 
87
91
  // 内部Grid引用
88
92
  var internalGridRef = useRef();
@@ -155,11 +159,13 @@ var GeneratedListPage = function GeneratedListPage(config) {
155
159
  permissions: permissions,
156
160
  formDialog: formDialog,
157
161
  deleteApi: apiConfig.delete,
158
- useErrorHandler: errorConfig.useErrorHandler
162
+ useErrorHandler: errorConfig.useErrorHandler,
163
+ access: access,
164
+ deleteConfirm: deleteConfirm
159
165
  }
160
166
  };
161
167
  return [].concat(_toConsumableArray(columnDefs), [operationColumn]);
162
- }, [columnDefs, formDialog, apiConfig.delete, permissions, onRefresh, OptionsColumnComponent, errorConfig.useErrorHandler]);
168
+ }, [columnDefs, formDialog, apiConfig.delete, permissions, onRefresh, OptionsColumnComponent, errorConfig.useErrorHandler, access, deleteConfirm]);
163
169
 
164
170
  /**
165
171
  * 从扁平数据构建树形结构
@@ -403,9 +409,10 @@ var GeneratedListPage = function GeneratedListPage(config) {
403
409
  importConfig: importConfig,
404
410
  exportFileName: exportFileName,
405
411
  filter: filter,
406
- permissions: permissions
412
+ permissions: permissions,
413
+ access: access
407
414
  }))];
408
- }, [enableImportExport, toolbarActions, formDialog, apiConfig, onRefresh, importConfig, exportFileName, permissions]);
415
+ }, [enableImportExport, toolbarActions, formDialog, apiConfig, onRefresh, importConfig, exportFileName, permissions, access]);
409
416
 
410
417
  // AgGridPlus属性配置
411
418
  var agGridProps = _objectSpread({
@@ -466,7 +473,7 @@ var GeneratedListPage = function GeneratedListPage(config) {
466
473
  position: 'relative',
467
474
  height: '100%'
468
475
  }
469
- }, /*#__PURE__*/React.createElement(AgGridPlus, agGridProps), /*#__PURE__*/React.createElement(PerformanceDevTools, {
476
+ }, /*#__PURE__*/React.createElement(Grid, agGridProps), /*#__PURE__*/React.createElement(PerformanceDevTools, {
470
477
  componentName: "GeneratedListPage-".concat(title),
471
478
  metrics: metrics,
472
479
  onGetReport: getPerformanceReport
@@ -3,7 +3,7 @@ function _regeneratorRuntime() { "use strict"; /*! regenerator-runtime -- Copyri
3
3
  function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
4
4
  function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
5
5
  import React, { useMemo } from 'react';
6
- import { Space, Button } from 'antd';
6
+ import { Space, Button, Tooltip } from 'antd';
7
7
  import { EditOutlined, DeleteOutlined } from '@ant-design/icons';
8
8
  import AccessWrapper from "./_utils/AccessWrapper";
9
9
  import { defaultHandleDelete } from "./_utils/defaultHandlers";
@@ -24,10 +24,12 @@ var OptionsColumn = function OptionsColumn(props) {
24
24
  formDialog = props.formDialog,
25
25
  deleteApi = props.deleteApi,
26
26
  _props$useErrorHandle = props.useErrorHandler,
27
- useErrorHandler = _props$useErrorHandle === void 0 ? true : _props$useErrorHandle;
27
+ useErrorHandler = _props$useErrorHandle === void 0 ? true : _props$useErrorHandle,
28
+ access = props.access,
29
+ deleteConfirm = props.deleteConfirm;
28
30
 
29
31
  // 使用权限检查 Hook
30
- var _usePermissionCheck = usePermissionCheck(permissions),
32
+ var _usePermissionCheck = usePermissionCheck(permissions, access),
31
33
  canUpdate = _usePermissionCheck.canUpdate,
32
34
  canDelete = _usePermissionCheck.canDelete,
33
35
  hasPermission = _usePermissionCheck.hasPermission;
@@ -82,13 +84,24 @@ var OptionsColumn = function OptionsColumn(props) {
82
84
  return null;
83
85
  }
84
86
  var FormDialogComponent = formDialog === null || formDialog === void 0 ? void 0 : formDialog.component;
87
+
88
+ // 确认框要说清删的是哪一条:页面没给标题时取该行的名称或编码。@author nokecy
89
+ var record = data;
90
+ var recordLabel = (record === null || record === void 0 ? void 0 : record.name) || (record === null || record === void 0 ? void 0 : record.displayName) || (record === null || record === void 0 ? void 0 : record.code);
91
+ var resolveText = function resolveText(value, fallback) {
92
+ return typeof value === 'function' ? value(data) : value !== null && value !== void 0 ? value : fallback;
93
+ };
94
+ var deleteTitle = resolveText(deleteConfirm === null || deleteConfirm === void 0 ? void 0 : deleteConfirm.title, recordLabel ? "\u786E\u5B9A\u5220\u9664\u300C".concat(recordLabel, "\u300D\uFF1F") : '确定删除?');
95
+ var deleteContent = resolveText(deleteConfirm === null || deleteConfirm === void 0 ? void 0 : deleteConfirm.content, '删除后无法恢复。');
85
96
  return /*#__PURE__*/React.createElement(Space, {
86
97
  onClick: function onClick(event) {
87
98
  event.stopPropagation();
88
99
  }
89
100
  }, showEditButton && FormDialogComponent && /*#__PURE__*/React.createElement(Access, {
90
101
  accessible: canUpdate
91
- }, /*#__PURE__*/React.createElement(FormDialogComponent, {
102
+ }, /*#__PURE__*/React.createElement(Tooltip, {
103
+ title: "\u7F16\u8F91"
104
+ }, /*#__PURE__*/React.createElement("span", null, /*#__PURE__*/React.createElement(FormDialogComponent, {
92
105
  buttonProps: {
93
106
  size: "small",
94
107
  type: "link",
@@ -96,17 +109,19 @@ var OptionsColumn = function OptionsColumn(props) {
96
109
  style: {
97
110
  fontSize: 14
98
111
  }
99
- })
112
+ }),
113
+ 'aria-label': '编辑'
100
114
  },
101
115
  key: data.id,
102
116
  title: formDialog.editTitle || '编辑',
103
117
  entityId: data.id,
104
118
  onAfterSubmit: refresh
105
- })), showDeleteButton && /*#__PURE__*/React.createElement(Access, {
119
+ })))), showDeleteButton && /*#__PURE__*/React.createElement(Access, {
106
120
  accessible: canDelete
107
121
  }, /*#__PURE__*/React.createElement(DeleteConfirm, {
108
- title: "\u786E\u5B9A\u5220\u9664?",
109
- content: "\u6B64\u64CD\u4F5C\u5C06\u6C38\u4E45\u5220\u9664\u8BE5\u6570\u636E\uFF0C\u4E14\u65E0\u6CD5\u6062\u590D",
122
+ title: deleteTitle,
123
+ content: deleteContent,
124
+ okText: "\u5220\u9664",
110
125
  onConfirm: /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2() {
111
126
  return _regeneratorRuntime().wrap(function _callee2$(_context2) {
112
127
  while (1) switch (_context2.prev = _context2.next) {
@@ -119,11 +134,13 @@ var OptionsColumn = function OptionsColumn(props) {
119
134
  }
120
135
  }, _callee2);
121
136
  }))
137
+ }, /*#__PURE__*/React.createElement(Tooltip, {
138
+ title: "\u5220\u9664"
122
139
  }, /*#__PURE__*/React.createElement(Button, {
123
140
  size: "small",
124
141
  icon: /*#__PURE__*/React.createElement(DeleteOutlined, null),
125
142
  type: "link",
126
- title: "\u5220\u9664"
127
- }))));
143
+ "aria-label": "\u5220\u9664"
144
+ })))));
128
145
  };
129
146
  export default OptionsColumn;
@@ -12,7 +12,7 @@ export { default } from './GeneratedListPage';
12
12
  export { default as GeneratedListPage } from './GeneratedListPage';
13
13
  export { default as ConfigurableToolbar } from './ConfigurableToolbar';
14
14
  export { default as OptionsColumn } from './OptionsColumn';
15
- export type { GeneratedListPageConfig, PermissionConfig, ApiConfig, ListParams, PagedResult, DeleteParams, ExportParams, ToolbarActionConfig, FormDialogConfig, TreeDataConfig, OptionsComponentProps } from './types';
15
+ export type { GeneratedListPageConfig, PermissionConfig, ApiConfig, ListParams, PagedResult, DeleteParams, ExportParams, ToolbarActionConfig, FormDialogConfig, TreeDataConfig, OptionsComponentProps, DeleteConfirmConfig } from './types';
16
16
  export { usePermissionCheck, PermissionChecker } from './usePermissionCheck';
17
17
  export { usePerformanceMonitor, PerformanceDevTools } from './PerformanceMonitor';
18
18
  export { useRequestManager } from './useRequestManager';
@@ -1,7 +1,7 @@
1
- /// <reference types="react" />
2
1
  import { GridRef } from "../ag-grid-plus/interface";
3
2
  import { ColDef } from "ag-grid-community";
4
3
  import { ButtonProps } from "antd";
4
+ import { ReactNode } from "react";
5
5
  import { PagedApiAdapter } from '../adapters';
6
6
  /**
7
7
  * 权限配置接口
@@ -203,6 +203,27 @@ export interface GeneratedListPageConfig<T = any> {
203
203
  onRefresh?: () => void;
204
204
  /** 分页 API 适配器(默认 ABP);非 ABP 后端可注入。@author nokecy */
205
205
  pagedApiAdapter?: PagedApiAdapter;
206
+ /**
207
+ * 表格组件,默认用包内 AgGridPlus。
208
+ * 宿主可注入自己的表格基座(属性与 AgGridPlus 相同),让序号、默认复选、编码列收起、
209
+ * 内部字段隐藏等列表规范在通用列表页上同样生效。@author nokecy
210
+ */
211
+ gridComponent?: React.ComponentType<any>;
212
+ /**
213
+ * 当前用户已授予的权限(权限名 → 是否授予),通常传 umi 的 useAccess()。
214
+ * 不传时工具栏与操作列不做权限过滤——没有权限的人也会看到新建、编辑、删除,点了才报 403。@author nokecy
215
+ */
216
+ access?: Record<string, boolean>;
217
+ /** 删除确认框;title、content 可按行生成 */
218
+ deleteConfirm?: DeleteConfirmConfig<T>;
219
+ }
220
+ /**
221
+ * 删除确认框配置。
222
+ * 不传 title 时标题带上该行的名称或编码,让用户看清删的是哪一条;不传 content 时说明删除后无法恢复。@author nokecy
223
+ */
224
+ export interface DeleteConfirmConfig<T = any> {
225
+ title?: ReactNode | ((record: T) => ReactNode);
226
+ content?: ReactNode | ((record: T) => ReactNode);
206
227
  }
207
228
  /**
208
229
  * 操作列组件属性接口
@@ -221,4 +242,8 @@ export interface OptionsComponentProps<T = any> {
221
242
  deleteApi?: (params: DeleteParams) => Promise<void>;
222
243
  /** 是否使用统一错误处理 */
223
244
  useErrorHandler?: boolean;
245
+ /** 当前用户已授予的权限,见 GeneratedListPageConfig.access */
246
+ access?: Record<string, boolean>;
247
+ /** 删除确认框配置 */
248
+ deleteConfirm?: DeleteConfirmConfig<T>;
224
249
  }