@nokecy/qc-ui 1.1.88 → 1.1.90

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.
@@ -43,7 +43,7 @@ var _requestParams = require("./utils/requestParams");
43
43
  var _errors = require("./errors");
44
44
  var _logger = require("./utils/logger");
45
45
  var _entityExtensionColumns = require("./utils/entityExtensionColumns");
46
- var _excluded = ["style", "loading", "params", "request", "dataSource", "treeKeyName", "treeParentName", "rowData", "gridRef", "headerTitle", "toolBarRender", "search", "hideTool", "onGridReady", "gridKey", "children", "defaultSearchExpand", "overlayNoRowsTemplateText", "queryDefaultRows", "onSelectedRowsChange", "emptyState", "accessible", "enableClickSelection", "rowSelection", "useNativeTreeFilter", "entityType", "valueEnumContrast"];
46
+ var _excluded = ["style", "loading", "params", "request", "dataSource", "treeKeyName", "treeParentName", "rowData", "gridRef", "headerTitle", "toolBarRender", "search", "hideTool", "onGridReady", "gridKey", "children", "defaultSearchExpand", "overlayNoRowsTemplateText", "queryDefaultRows", "onSelectedRowsChange", "onQueryValuesChange", "emptyState", "accessible", "enableClickSelection", "rowSelection", "useNativeTreeFilter", "entityType", "valueEnumContrast"];
47
47
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
48
48
  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); }
49
49
  function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
@@ -109,6 +109,7 @@ function AgGridPlus(props) {
109
109
  overlayNoRowsTemplateText = props.overlayNoRowsTemplateText,
110
110
  queryDefaultRows = props.queryDefaultRows,
111
111
  onSelectedRowsChange = props.onSelectedRowsChange,
112
+ onQueryValuesChange = props.onQueryValuesChange,
112
113
  emptyState = props.emptyState,
113
114
  _props$accessible = props.accessible,
114
115
  accessible = _props$accessible === void 0 ? true : _props$accessible,
@@ -1161,6 +1162,7 @@ function AgGridPlus(props) {
1161
1162
  columnStates: (_ref = derivedColumnState !== null && derivedColumnState !== void 0 ? derivedColumnState : columnState) !== null && _ref !== void 0 ? _ref : [],
1162
1163
  defaultExpand: defaultSearchExpand,
1163
1164
  gridApi: apiRef.current,
1165
+ onValuesChange: onQueryValuesChange,
1164
1166
  onQuery: function onQuery(formValues) {
1165
1167
  // 优先使用高级搜索:如果存在高级搜索条件,忽略简单查询
1166
1168
  if (advancedQueryRules.children.length > 0) {
@@ -85,6 +85,12 @@ interface GridProps extends AgGridReactProps {
85
85
  * 选中行变化回调函数
86
86
  */
87
87
  onSelectedRowsChange?: (selectedRows: any[]) => void;
88
+ /**
89
+ * 查询区条件值变化时回调(输入、默认值落位、重置都会触发),参数为当前条件快照,以查询字段名为键。
90
+ * 只通知、不发起查询;宿主可据此与上次查询用的条件比较,提示「条件已变更,请查询」。
91
+ * @author nokecy
92
+ */
93
+ onQueryValuesChange?: (values: Record<string, any>) => void;
88
94
  /**
89
95
  * 错误处理回调函数
90
96
  * 当组件发生错误时调用,可用于自定义错误处理逻辑
@@ -1,6 +1,8 @@
1
1
  import { ColDef, ColumnState, GridApi } from 'ag-grid-community';
2
2
  import React from 'react';
3
3
  import './index.less';
4
+ /** 查询区初始化兜底:requestAnimationFrame 迟迟不触发时,最迟这么久后通知首查(毫秒)。@author nokecy */
5
+ export declare const INIT_FALLBACK_DELAY = 300;
4
6
  declare const FormRender: (props: {
5
7
  className?: any;
6
8
  gridApi?: GridApi<any> | undefined;
@@ -12,5 +14,7 @@ declare const FormRender: (props: {
12
14
  defaultRows?: number | undefined;
13
15
  onQuery: (formValue: any) => void;
14
16
  onInit?: ((defaultValues: any) => void) | undefined;
17
+ /** 查询条件值变化(输入、默认值落位、重置)时回调,参数为当前条件快照;不触发查询。@author nokecy */
18
+ onValuesChange?: ((values: Record<string, any>) => void) | undefined;
15
19
  }) => React.JSX.Element;
16
20
  export default FormRender;
@@ -4,7 +4,7 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" ==
4
4
  Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
- exports.default = void 0;
7
+ exports.default = exports.INIT_FALLBACK_DELAY = void 0;
8
8
  var _antdV = require("@formily/antd-v5");
9
9
  var _core = require("@formily/core");
10
10
  var _react = require("@formily/react");
@@ -30,6 +30,8 @@ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o =
30
30
  function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
31
31
  function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
32
32
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } // @author nokecy
33
+ /** 查询区初始化兜底:requestAnimationFrame 迟迟不触发时,最迟这么久后通知首查(毫秒)。@author nokecy */
34
+ var INIT_FALLBACK_DELAY = exports.INIT_FALLBACK_DELAY = 300;
33
35
  var FormRender = function FormRender(props) {
34
36
  var className = props.className,
35
37
  colDefs = props.colDefs,
@@ -55,6 +57,20 @@ var FormRender = function FormRender(props) {
55
57
  var form = (0, _react2.useMemo)(function () {
56
58
  return (0, _core.createForm)();
57
59
  }, []);
60
+
61
+ // 条件变化只通知宿主(如提示「条件已变更」),回调走 ref,宿主每次渲染传新函数也不重复订阅。@author nokecy
62
+ var onValuesChangeRef = (0, _react2.useRef)(props.onValuesChange);
63
+ onValuesChangeRef.current = props.onValuesChange;
64
+ (0, _react2.useEffect)(function () {
65
+ var id = form.subscribe(function (_ref) {
66
+ var _onValuesChangeRef$cu;
67
+ var type = _ref.type;
68
+ if (type === _core.LifeCycleTypes.ON_FORM_VALUES_CHANGE) (_onValuesChangeRef$cu = onValuesChangeRef.current) === null || _onValuesChangeRef$cu === void 0 || _onValuesChangeRef$cu.call(onValuesChangeRef, _objectSpread({}, form.values));
69
+ });
70
+ return function () {
71
+ return form.unsubscribe(id);
72
+ };
73
+ }, [form]);
58
74
  var SchemaField = (0, _react2.useMemo)(function () {
59
75
  return (0, _react.createSchemaField)({
60
76
  components: {
@@ -196,10 +212,10 @@ var FormRender = function FormRender(props) {
196
212
  previousFieldsRef.current = Object.keys(fieldSchemas);
197
213
  setSchema(new_schema);
198
214
  // 已有字段同步元数据,不触碰仍有效字段的查询值,也不触发查询。@author nokecy
199
- Object.entries(fieldSchemas).forEach(function (_ref) {
200
- var _ref2 = _slicedToArray(_ref, 2),
201
- name = _ref2[0],
202
- fieldSchema = _ref2[1];
215
+ Object.entries(fieldSchemas).forEach(function (_ref2) {
216
+ var _ref3 = _slicedToArray(_ref2, 2),
217
+ name = _ref3[0],
218
+ fieldSchema = _ref3[1];
203
219
  form.query(name).take(function (field) {
204
220
  var _fieldSchema$enum;
205
221
  field.title = fieldSchema.title;
@@ -222,11 +238,18 @@ var FormRender = function FormRender(props) {
222
238
  if (!initializedRef.current) {
223
239
  initializedRef.current = true;
224
240
  // 使用 requestAnimationFrame + setTimeout 确保默认值已应用
241
+ // 后台标签页或浏览器繁忙时 requestAnimationFrame 可能迟迟不触发,列表首查就一直不发,
242
+ // 只能手动点「查询」;另设一个定时兜底,两条路先到先执行、只执行一次。@author nokecy
243
+ var initialized = false;
244
+ var notifyInit = function notifyInit() {
245
+ if (initialized) return;
246
+ initialized = true;
247
+ props.onInit && props.onInit(form.values);
248
+ };
225
249
  requestAnimationFrame(function () {
226
- setTimeout(function () {
227
- props.onInit && props.onInit(form.values);
228
- }, 0);
250
+ setTimeout(notifyInit, 0);
229
251
  });
252
+ setTimeout(notifyInit, INIT_FALLBACK_DELAY);
230
253
  }
231
254
  }, [schemaKey, defaultRows, props.defaultExpand]);
232
255
  return /*#__PURE__*/_react2.default.createElement("div", {
@@ -28,6 +28,13 @@ export interface GridEmptyContextValue {
28
28
  onRetry?: () => void;
29
29
  }
30
30
  export declare const GridEmptyContext: React.Context<GridEmptyContextValue>;
31
+ /**
32
+ * 403 是否真的是「没有权限」。ABP 的业务异常(BusinessException)默认也按 403 返回,
33
+ * 例如「工厂日历缺少所选年周」;这类有业务错误码的 403 要显示后端原因并允许重试,
34
+ * 不能说成没权限,否则用户会去找管理员授权而真因在数据。
35
+ * 授权失败的错误码以 Volo.Authorization 开头,或没有错误码。@author nokecy
36
+ */
37
+ export declare const isPermissionDenied: (status?: number, code?: string) => boolean;
31
38
  export declare const GridEmptyState: React.FC;
32
39
  /**
33
40
  * 判断请求 filter 是否带生效条件(任意叶子值非空即算有筛选)。
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.hasActiveFilter = exports.GridEmptyState = exports.GridEmptyContext = void 0;
6
+ exports.isPermissionDenied = exports.hasActiveFilter = exports.GridEmptyState = exports.GridEmptyContext = void 0;
7
7
  var _react = _interopRequireDefault(require("react"));
8
8
  var _antd = require("antd");
9
9
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -31,6 +31,16 @@ var httpStatusOf = function httpStatusOf(error) {
31
31
  var _response$status, _error$context, _error$originalError;
32
32
  return (_response$status = error === null || error === void 0 || (_error$context = error.context) === null || _error$context === void 0 || (_error$context = _error$context.originalError) === null || _error$context === void 0 || (_error$context = _error$context.response) === null || _error$context === void 0 ? void 0 : _error$context.status) !== null && _response$status !== void 0 ? _response$status : error === null || error === void 0 || (_error$originalError = error.originalError) === null || _error$originalError === void 0 || (_error$originalError = _error$originalError.response) === null || _error$originalError === void 0 ? void 0 : _error$originalError.status;
33
33
  };
34
+
35
+ /**
36
+ * 403 是否真的是「没有权限」。ABP 的业务异常(BusinessException)默认也按 403 返回,
37
+ * 例如「工厂日历缺少所选年周」;这类有业务错误码的 403 要显示后端原因并允许重试,
38
+ * 不能说成没权限,否则用户会去找管理员授权而真因在数据。
39
+ * 授权失败的错误码以 Volo.Authorization 开头,或没有错误码。@author nokecy
40
+ */
41
+ var isPermissionDenied = exports.isPermissionDenied = function isPermissionDenied(status, code) {
42
+ return status === 403 && (!code || code.startsWith('Volo.Authorization'));
43
+ };
34
44
  var GridEmptyState = exports.GridEmptyState = function GridEmptyState() {
35
45
  var _React$useContext = _react.default.useContext(GridEmptyContext),
36
46
  error = _React$useContext.error,
@@ -48,8 +58,8 @@ var GridEmptyState = exports.GridEmptyState = function GridEmptyState() {
48
58
  });
49
59
  }
50
60
 
51
- // 分支 1:无权限(403)——说明原因,不给任何入口
52
- if (error && httpStatusOf(error) === 403) {
61
+ // 分支 1:无权限(403 且不是业务异常)——说明原因,不给任何入口
62
+ if (error && isPermissionDenied(httpStatusOf(error), remoteError === null || remoteError === void 0 ? void 0 : remoteError.code)) {
53
63
  return /*#__PURE__*/_react.default.createElement(_antd.Empty, {
54
64
  image: _antd.Empty.PRESENTED_IMAGE_SIMPLE,
55
65
  description: "\u6CA1\u6709\u6743\u9650\u67E5\u770B\u6B64\u5217\u8868\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u5F00\u901A"
@@ -59,8 +69,10 @@ var GridEmptyState = exports.GridEmptyState = function GridEmptyState() {
59
69
  // 分支 2:加载失败——给重试
60
70
  if (error) {
61
71
  return /*#__PURE__*/_react.default.createElement(_antd.Empty, {
62
- image: _antd.Empty.PRESENTED_IMAGE_SIMPLE,
63
- description: "\u52A0\u8F7D\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5"
72
+ image: _antd.Empty.PRESENTED_IMAGE_SIMPLE
73
+ // 后端给了业务原因(如数据未维护)时直接显示原因,告诉用户下一步。@author nokecy
74
+ ,
75
+ description: remoteError !== null && remoteError !== void 0 && remoteError.code && remoteError.message ? remoteError.message : '加载失败,请检查后重试'
64
76
  }, onRetry && /*#__PURE__*/_react.default.createElement(_antd.Button, {
65
77
  size: "small",
66
78
  type: "primary",
@@ -6,7 +6,7 @@
6
6
  */
7
7
  export { StandardAgGridColumn, StandardAgGridPlus } from './StandardAgGridPlus';
8
8
  export type { AppGridColumn, StandardListPolicy } from './StandardAgGridPlus';
9
- export { GridEmptyContext, GridEmptyState, hasActiveFilter } from './emptyState';
9
+ export { GridEmptyContext, GridEmptyState, hasActiveFilter, isPermissionDenied } from './emptyState';
10
10
  export type { GridEmptyContextValue } from './emptyState';
11
11
  export { applyColDefSort, detachLiveSortFromColumnDefs, firstGridSorter } from './gridColumnDefs';
12
12
  export { compositeClasses, getCompositeColumnEdges, withCompositeGroupHeader, withCompositeLeafHeader } from './groupedHeaders';
@@ -111,6 +111,12 @@ Object.defineProperty(exports, "inferListDefaultSort", {
111
111
  return _listDefaultSort.inferListDefaultSort;
112
112
  }
113
113
  });
114
+ Object.defineProperty(exports, "isPermissionDenied", {
115
+ enumerable: true,
116
+ get: function get() {
117
+ return _emptyState.isPermissionDenied;
118
+ }
119
+ });
114
120
  Object.defineProperty(exports, "normalizeExtendedDateColumn", {
115
121
  enumerable: true,
116
122
  get: function get() {
@@ -1,4 +1,4 @@
1
- var _excluded = ["style", "loading", "params", "request", "dataSource", "treeKeyName", "treeParentName", "rowData", "gridRef", "headerTitle", "toolBarRender", "search", "hideTool", "onGridReady", "gridKey", "children", "defaultSearchExpand", "overlayNoRowsTemplateText", "queryDefaultRows", "onSelectedRowsChange", "emptyState", "accessible", "enableClickSelection", "rowSelection", "useNativeTreeFilter", "entityType", "valueEnumContrast"];
1
+ var _excluded = ["style", "loading", "params", "request", "dataSource", "treeKeyName", "treeParentName", "rowData", "gridRef", "headerTitle", "toolBarRender", "search", "hideTool", "onGridReady", "gridKey", "children", "defaultSearchExpand", "overlayNoRowsTemplateText", "queryDefaultRows", "onSelectedRowsChange", "onQueryValuesChange", "emptyState", "accessible", "enableClickSelection", "rowSelection", "useNativeTreeFilter", "entityType", "valueEnumContrast"];
2
2
  function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
3
3
  function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
4
4
  function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
@@ -101,6 +101,7 @@ function AgGridPlus(props) {
101
101
  overlayNoRowsTemplateText = props.overlayNoRowsTemplateText,
102
102
  queryDefaultRows = props.queryDefaultRows,
103
103
  onSelectedRowsChange = props.onSelectedRowsChange,
104
+ onQueryValuesChange = props.onQueryValuesChange,
104
105
  emptyState = props.emptyState,
105
106
  _props$accessible = props.accessible,
106
107
  accessible = _props$accessible === void 0 ? true : _props$accessible,
@@ -1153,6 +1154,7 @@ function AgGridPlus(props) {
1153
1154
  columnStates: (_ref = derivedColumnState !== null && derivedColumnState !== void 0 ? derivedColumnState : columnState) !== null && _ref !== void 0 ? _ref : [],
1154
1155
  defaultExpand: defaultSearchExpand,
1155
1156
  gridApi: apiRef.current,
1157
+ onValuesChange: onQueryValuesChange,
1156
1158
  onQuery: function onQuery(formValues) {
1157
1159
  // 优先使用高级搜索:如果存在高级搜索条件,忽略简单查询
1158
1160
  if (advancedQueryRules.children.length > 0) {
@@ -85,6 +85,12 @@ interface GridProps extends AgGridReactProps {
85
85
  * 选中行变化回调函数
86
86
  */
87
87
  onSelectedRowsChange?: (selectedRows: any[]) => void;
88
+ /**
89
+ * 查询区条件值变化时回调(输入、默认值落位、重置都会触发),参数为当前条件快照,以查询字段名为键。
90
+ * 只通知、不发起查询;宿主可据此与上次查询用的条件比较,提示「条件已变更,请查询」。
91
+ * @author nokecy
92
+ */
93
+ onQueryValuesChange?: (values: Record<string, any>) => void;
88
94
  /**
89
95
  * 错误处理回调函数
90
96
  * 当组件发生错误时调用,可用于自定义错误处理逻辑
@@ -1,6 +1,8 @@
1
1
  import { ColDef, ColumnState, GridApi } from 'ag-grid-community';
2
2
  import React from 'react';
3
3
  import './index.less';
4
+ /** 查询区初始化兜底:requestAnimationFrame 迟迟不触发时,最迟这么久后通知首查(毫秒)。@author nokecy */
5
+ export declare const INIT_FALLBACK_DELAY = 300;
4
6
  declare const FormRender: (props: {
5
7
  className?: any;
6
8
  gridApi?: GridApi<any> | undefined;
@@ -12,5 +14,7 @@ declare const FormRender: (props: {
12
14
  defaultRows?: number | undefined;
13
15
  onQuery: (formValue: any) => void;
14
16
  onInit?: ((defaultValues: any) => void) | undefined;
17
+ /** 查询条件值变化(输入、默认值落位、重置)时回调,参数为当前条件快照;不触发查询。@author nokecy */
18
+ onValuesChange?: ((values: Record<string, any>) => void) | undefined;
15
19
  }) => React.JSX.Element;
16
20
  export default FormRender;
@@ -11,7 +11,7 @@ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len
11
11
  function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
12
12
  function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
13
13
  import { DatePicker, FormButtonGroup, FormGrid, FormItem, Form, Input, Select, Submit } from '@formily/antd-v5'; // @author nokecy
14
- import { createForm } from '@formily/core';
14
+ import { createForm, LifeCycleTypes } from '@formily/core';
15
15
  import { createSchemaField } from '@formily/react';
16
16
  import { Button, theme } from 'antd';
17
17
  import classNames from 'classnames';
@@ -21,6 +21,9 @@ import { queryFormSchemaKey } from "./schemaKey";
21
21
  import { resolveQueryColumns } from "./queryColumns";
22
22
  import BoolSelect from "../_utils/boolSelect";
23
23
  import "./index.less";
24
+
25
+ /** 查询区初始化兜底:requestAnimationFrame 迟迟不触发时,最迟这么久后通知首查(毫秒)。@author nokecy */
26
+ export var INIT_FALLBACK_DELAY = 300;
24
27
  var FormRender = function FormRender(props) {
25
28
  var className = props.className,
26
29
  colDefs = props.colDefs,
@@ -46,6 +49,20 @@ var FormRender = function FormRender(props) {
46
49
  var form = useMemo(function () {
47
50
  return createForm();
48
51
  }, []);
52
+
53
+ // 条件变化只通知宿主(如提示「条件已变更」),回调走 ref,宿主每次渲染传新函数也不重复订阅。@author nokecy
54
+ var onValuesChangeRef = useRef(props.onValuesChange);
55
+ onValuesChangeRef.current = props.onValuesChange;
56
+ useEffect(function () {
57
+ var id = form.subscribe(function (_ref) {
58
+ var _onValuesChangeRef$cu;
59
+ var type = _ref.type;
60
+ if (type === LifeCycleTypes.ON_FORM_VALUES_CHANGE) (_onValuesChangeRef$cu = onValuesChangeRef.current) === null || _onValuesChangeRef$cu === void 0 || _onValuesChangeRef$cu.call(onValuesChangeRef, _objectSpread({}, form.values));
61
+ });
62
+ return function () {
63
+ return form.unsubscribe(id);
64
+ };
65
+ }, [form]);
49
66
  var SchemaField = useMemo(function () {
50
67
  return createSchemaField({
51
68
  components: {
@@ -187,10 +204,10 @@ var FormRender = function FormRender(props) {
187
204
  previousFieldsRef.current = Object.keys(fieldSchemas);
188
205
  setSchema(new_schema);
189
206
  // 已有字段同步元数据,不触碰仍有效字段的查询值,也不触发查询。@author nokecy
190
- Object.entries(fieldSchemas).forEach(function (_ref) {
191
- var _ref2 = _slicedToArray(_ref, 2),
192
- name = _ref2[0],
193
- fieldSchema = _ref2[1];
207
+ Object.entries(fieldSchemas).forEach(function (_ref2) {
208
+ var _ref3 = _slicedToArray(_ref2, 2),
209
+ name = _ref3[0],
210
+ fieldSchema = _ref3[1];
194
211
  form.query(name).take(function (field) {
195
212
  var _fieldSchema$enum;
196
213
  field.title = fieldSchema.title;
@@ -213,11 +230,18 @@ var FormRender = function FormRender(props) {
213
230
  if (!initializedRef.current) {
214
231
  initializedRef.current = true;
215
232
  // 使用 requestAnimationFrame + setTimeout 确保默认值已应用
233
+ // 后台标签页或浏览器繁忙时 requestAnimationFrame 可能迟迟不触发,列表首查就一直不发,
234
+ // 只能手动点「查询」;另设一个定时兜底,两条路先到先执行、只执行一次。@author nokecy
235
+ var initialized = false;
236
+ var notifyInit = function notifyInit() {
237
+ if (initialized) return;
238
+ initialized = true;
239
+ props.onInit && props.onInit(form.values);
240
+ };
216
241
  requestAnimationFrame(function () {
217
- setTimeout(function () {
218
- props.onInit && props.onInit(form.values);
219
- }, 0);
242
+ setTimeout(notifyInit, 0);
220
243
  });
244
+ setTimeout(notifyInit, INIT_FALLBACK_DELAY);
221
245
  }
222
246
  }, [schemaKey, defaultRows, props.defaultExpand]);
223
247
  return /*#__PURE__*/React.createElement("div", {
@@ -28,6 +28,13 @@ export interface GridEmptyContextValue {
28
28
  onRetry?: () => void;
29
29
  }
30
30
  export declare const GridEmptyContext: React.Context<GridEmptyContextValue>;
31
+ /**
32
+ * 403 是否真的是「没有权限」。ABP 的业务异常(BusinessException)默认也按 403 返回,
33
+ * 例如「工厂日历缺少所选年周」;这类有业务错误码的 403 要显示后端原因并允许重试,
34
+ * 不能说成没权限,否则用户会去找管理员授权而真因在数据。
35
+ * 授权失败的错误码以 Volo.Authorization 开头,或没有错误码。@author nokecy
36
+ */
37
+ export declare const isPermissionDenied: (status?: number, code?: string) => boolean;
31
38
  export declare const GridEmptyState: React.FC;
32
39
  /**
33
40
  * 判断请求 filter 是否带生效条件(任意叶子值非空即算有筛选)。
@@ -25,6 +25,16 @@ var httpStatusOf = function httpStatusOf(error) {
25
25
  var _response$status, _error$context, _error$originalError;
26
26
  return (_response$status = error === null || error === void 0 || (_error$context = error.context) === null || _error$context === void 0 || (_error$context = _error$context.originalError) === null || _error$context === void 0 || (_error$context = _error$context.response) === null || _error$context === void 0 ? void 0 : _error$context.status) !== null && _response$status !== void 0 ? _response$status : error === null || error === void 0 || (_error$originalError = error.originalError) === null || _error$originalError === void 0 || (_error$originalError = _error$originalError.response) === null || _error$originalError === void 0 ? void 0 : _error$originalError.status;
27
27
  };
28
+
29
+ /**
30
+ * 403 是否真的是「没有权限」。ABP 的业务异常(BusinessException)默认也按 403 返回,
31
+ * 例如「工厂日历缺少所选年周」;这类有业务错误码的 403 要显示后端原因并允许重试,
32
+ * 不能说成没权限,否则用户会去找管理员授权而真因在数据。
33
+ * 授权失败的错误码以 Volo.Authorization 开头,或没有错误码。@author nokecy
34
+ */
35
+ export var isPermissionDenied = function isPermissionDenied(status, code) {
36
+ return status === 403 && (!code || code.startsWith('Volo.Authorization'));
37
+ };
28
38
  export var GridEmptyState = function GridEmptyState() {
29
39
  var _React$useContext = React.useContext(GridEmptyContext),
30
40
  error = _React$useContext.error,
@@ -42,8 +52,8 @@ export var GridEmptyState = function GridEmptyState() {
42
52
  });
43
53
  }
44
54
 
45
- // 分支 1:无权限(403)——说明原因,不给任何入口
46
- if (error && httpStatusOf(error) === 403) {
55
+ // 分支 1:无权限(403 且不是业务异常)——说明原因,不给任何入口
56
+ if (error && isPermissionDenied(httpStatusOf(error), remoteError === null || remoteError === void 0 ? void 0 : remoteError.code)) {
47
57
  return /*#__PURE__*/React.createElement(Empty, {
48
58
  image: Empty.PRESENTED_IMAGE_SIMPLE,
49
59
  description: "\u6CA1\u6709\u6743\u9650\u67E5\u770B\u6B64\u5217\u8868\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u5F00\u901A"
@@ -53,8 +63,10 @@ export var GridEmptyState = function GridEmptyState() {
53
63
  // 分支 2:加载失败——给重试
54
64
  if (error) {
55
65
  return /*#__PURE__*/React.createElement(Empty, {
56
- image: Empty.PRESENTED_IMAGE_SIMPLE,
57
- description: "\u52A0\u8F7D\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u540E\u91CD\u8BD5"
66
+ image: Empty.PRESENTED_IMAGE_SIMPLE
67
+ // 后端给了业务原因(如数据未维护)时直接显示原因,告诉用户下一步。@author nokecy
68
+ ,
69
+ description: remoteError !== null && remoteError !== void 0 && remoteError.code && remoteError.message ? remoteError.message : '加载失败,请检查后重试'
58
70
  }, onRetry && /*#__PURE__*/React.createElement(Button, {
59
71
  size: "small",
60
72
  type: "primary",
@@ -6,7 +6,7 @@
6
6
  */
7
7
  export { StandardAgGridColumn, StandardAgGridPlus } from './StandardAgGridPlus';
8
8
  export type { AppGridColumn, StandardListPolicy } from './StandardAgGridPlus';
9
- export { GridEmptyContext, GridEmptyState, hasActiveFilter } from './emptyState';
9
+ export { GridEmptyContext, GridEmptyState, hasActiveFilter, isPermissionDenied } from './emptyState';
10
10
  export type { GridEmptyContextValue } from './emptyState';
11
11
  export { applyColDefSort, detachLiveSortFromColumnDefs, firstGridSorter } from './gridColumnDefs';
12
12
  export { compositeClasses, getCompositeColumnEdges, withCompositeGroupHeader, withCompositeLeafHeader } from './groupedHeaders';
@@ -5,7 +5,7 @@
5
5
  * @author nokecy
6
6
  */
7
7
  export { StandardAgGridColumn, StandardAgGridPlus } from "./StandardAgGridPlus";
8
- export { GridEmptyContext, GridEmptyState, hasActiveFilter } from "./emptyState";
8
+ export { GridEmptyContext, GridEmptyState, hasActiveFilter, isPermissionDenied } from "./emptyState";
9
9
  export { applyColDefSort, detachLiveSortFromColumnDefs, firstGridSorter } from "./gridColumnDefs";
10
10
  export { compositeClasses, getCompositeColumnEdges, withCompositeGroupHeader, withCompositeLeafHeader } from "./groupedHeaders";
11
11
  export { getListDateType, normalizeExtendedDateColumn, normalizeListDateColumn } from "./listDateDisplay";