@nokecy/qc-ui-business 2.0.0-beta.0 → 2.0.0-beta.1
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/dist/cjs/standardFormDialog/StandardFormDialog.js +31 -3
- package/dist/cjs/standardFormDialog/types.d.ts +16 -1
- package/dist/cjs/standardList/StandardAgGridPlus.js +5 -2
- package/dist/cjs/standardList/dateFormat.d.ts +3 -2
- package/dist/cjs/standardList/dateFormat.js +4 -2
- package/dist/cjs/standardList/emptyState.d.ts +6 -1
- package/dist/cjs/standardList/emptyState.js +41 -16
- package/dist/cjs/standardList/enumColumns.d.ts +1 -0
- package/dist/cjs/standardList/enumColumns.js +6 -2
- package/dist/cjs/standardList/listDateDisplay.js +6 -3
- package/dist/esm/standardFormDialog/StandardFormDialog.js +32 -4
- package/dist/esm/standardFormDialog/types.d.ts +16 -1
- package/dist/esm/standardList/StandardAgGridPlus.js +5 -2
- package/dist/esm/standardList/dateFormat.d.ts +3 -2
- package/dist/esm/standardList/dateFormat.js +4 -2
- package/dist/esm/standardList/emptyState.d.ts +6 -1
- package/dist/esm/standardList/emptyState.js +41 -16
- package/dist/esm/standardList/enumColumns.d.ts +1 -0
- package/dist/esm/standardList/enumColumns.js +6 -2
- package/dist/esm/standardList/listDateDisplay.js +6 -3
- package/package.json +3 -3
|
@@ -10,6 +10,7 @@ var _formilyCore = require("@nokecy/formily-core");
|
|
|
10
10
|
var _antd = require("antd");
|
|
11
11
|
var _PortalManager = _interopRequireDefault(require("./PortalManager"));
|
|
12
12
|
var _formilyReact = require("@nokecy/formily-react");
|
|
13
|
+
var _index = _interopRequireDefault(require("@nokecy/qc-ui-components/draggableModal/index"));
|
|
13
14
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
14
15
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
15
16
|
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); }
|
|
@@ -46,6 +47,13 @@ var SchemaFieldComponents = (0, _formilyReact.createSchemaField)({
|
|
|
46
47
|
}
|
|
47
48
|
});
|
|
48
49
|
|
|
50
|
+
/** 表单弹窗的可缩放壳:最小宽度取规范最小一档 560,避免缩到字段挤压。 */
|
|
51
|
+
var ResizableFormModal = function ResizableFormModal(modalProps) {
|
|
52
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_index.default, _objectSpread({
|
|
53
|
+
minWidth: 560
|
|
54
|
+
}, modalProps));
|
|
55
|
+
};
|
|
56
|
+
|
|
49
57
|
/**
|
|
50
58
|
* 默认的 useFormSchema hook - 直接返回schema配置
|
|
51
59
|
*/
|
|
@@ -83,7 +91,7 @@ var StandardFormDialog = function StandardFormDialog(props) {
|
|
|
83
91
|
directFormSchema = props.formSchema,
|
|
84
92
|
apiConfig = props.apiConfig,
|
|
85
93
|
_props$width = props.width,
|
|
86
|
-
width = _props$width === void 0 ?
|
|
94
|
+
width = _props$width === void 0 ? 720 : _props$width,
|
|
87
95
|
entityId = props.entityId,
|
|
88
96
|
_props$title = props.title,
|
|
89
97
|
title = _props$title === void 0 ? '表单' : _props$title,
|
|
@@ -99,6 +107,12 @@ var StandardFormDialog = function StandardFormDialog(props) {
|
|
|
99
107
|
customSubmitHandler = props.customSubmitHandler,
|
|
100
108
|
_props$useUnifiedErro = props.useUnifiedErrorHandling,
|
|
101
109
|
useUnifiedErrorHandling = _props$useUnifiedErro === void 0 ? true : _props$useUnifiedErro,
|
|
110
|
+
_props$locateFirstErr = props.locateFirstError,
|
|
111
|
+
locateFirstError = _props$locateFirstErr === void 0 ? true : _props$locateFirstErr,
|
|
112
|
+
_props$confirmOnDirty = props.confirmOnDirtyClose,
|
|
113
|
+
confirmOnDirtyClose = _props$confirmOnDirty === void 0 ? true : _props$confirmOnDirty,
|
|
114
|
+
_props$resizable = props.resizable,
|
|
115
|
+
resizable = _props$resizable === void 0 ? true : _props$resizable,
|
|
102
116
|
_props$useFormSchema = props.useFormSchema,
|
|
103
117
|
useFormSchemaHook = _props$useFormSchema === void 0 ? defaultUseFormSchema : _props$useFormSchema,
|
|
104
118
|
_props$useSchemaField = props.useSchemaField,
|
|
@@ -245,6 +259,18 @@ var StandardFormDialog = function StandardFormDialog(props) {
|
|
|
245
259
|
|
|
246
260
|
// 表单验证失败回调
|
|
247
261
|
var handleValidationFailed = (0, _react.useCallback)(function (form) {
|
|
262
|
+
if (locateFirstError) {
|
|
263
|
+
// 提示里直接写出所在页签与字段,不再拼字段名串(DESIGN.md §6.4)。
|
|
264
|
+
// 只在最上层弹窗内找,避免定位到弹窗下面页面里的字段。
|
|
265
|
+
void (0, _formilyAntd.focusFirstError)(form, {
|
|
266
|
+
root: function root() {
|
|
267
|
+
var _modals;
|
|
268
|
+
var modals = document.querySelectorAll('.ant-modal');
|
|
269
|
+
return (_modals = modals[modals.length - 1]) !== null && _modals !== void 0 ? _modals : document;
|
|
270
|
+
}
|
|
271
|
+
});
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
248
274
|
var errors = form.errors;
|
|
249
275
|
var errorFields = Object.keys(errors);
|
|
250
276
|
if (errorFields.length > 0) {
|
|
@@ -276,7 +302,7 @@ var StandardFormDialog = function StandardFormDialog(props) {
|
|
|
276
302
|
errors: errors
|
|
277
303
|
});
|
|
278
304
|
}
|
|
279
|
-
}, []);
|
|
305
|
+
}, [locateFirstError]);
|
|
280
306
|
|
|
281
307
|
// 表单属性配置
|
|
282
308
|
var formProps = (0, _react.useMemo)(function () {
|
|
@@ -417,6 +443,8 @@ var StandardFormDialog = function StandardFormDialog(props) {
|
|
|
417
443
|
// 不设置静态 loading,使用 FormDialog 自带的 form.submitting。
|
|
418
444
|
// @author nokecy
|
|
419
445
|
maskClosable: false,
|
|
446
|
+
confirmOnDirtyClose: confirmOnDirtyClose,
|
|
447
|
+
modalComponent: resizable ? ResizableFormModal : undefined,
|
|
420
448
|
onOk: function onOk() {
|
|
421
449
|
if (confirmingRef.current || loadingRef.current) return false;
|
|
422
450
|
confirmingRef.current = true;
|
|
@@ -458,7 +486,7 @@ var StandardFormDialog = function StandardFormDialog(props) {
|
|
|
458
486
|
});
|
|
459
487
|
});
|
|
460
488
|
formDialog.forConfirm(handleSubmit).open(formProps);
|
|
461
|
-
}, [title, width, portalId, schema, SchemaField, formProps, handleSubmit]);
|
|
489
|
+
}, [title, width, portalId, schema, SchemaField, formProps, handleSubmit, confirmOnDirtyClose, resizable]);
|
|
462
490
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_formilyAntd.FormDialog.Portal, {
|
|
463
491
|
id: portalId,
|
|
464
492
|
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_antd.Button, _objectSpread(_objectSpread({
|
|
@@ -44,8 +44,23 @@ export interface StandardFormDialogConfig {
|
|
|
44
44
|
schemaConfig: FormSchemaConfig;
|
|
45
45
|
/** API配置 */
|
|
46
46
|
apiConfig: FormApiConfig;
|
|
47
|
-
/**
|
|
47
|
+
/** 对话框宽度,默认 720;规范只取 560 / 720 / 960 三档。 */
|
|
48
48
|
width?: number;
|
|
49
|
+
/**
|
|
50
|
+
* 校验失败时定位首个错误字段(切页签、展开折叠、滚动并聚焦)并给出带位置的提示,默认 true。
|
|
51
|
+
* 传 false 回到旧行为:只弹出「请检查表单错误:字段名…」的汇总提示。
|
|
52
|
+
*/
|
|
53
|
+
locateFirstError?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* 表单被改过时,关闭(叉、Esc、取消按钮)先弹「继续编辑 / 放弃修改」确认,默认 true(DESIGN.md §6.6)。
|
|
56
|
+
* 判据为 form.modified;提交成功后的关闭不确认。传 false 恢复直接关闭。
|
|
57
|
+
*/
|
|
58
|
+
confirmOnDirtyClose?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* 弹窗可拖动标题移动、拖边框缩放,默认 true(表单字段多时需要放大;宽度默认仍按 width,缩放不持久化)。
|
|
61
|
+
* 最小 560 x 300,且不超过视口 95%。传 false 回到固定尺寸。
|
|
62
|
+
*/
|
|
63
|
+
resizable?: boolean;
|
|
49
64
|
/** 实体ID(编辑时) */
|
|
50
65
|
entityId?: string | number;
|
|
51
66
|
/** 标题 */
|
|
@@ -565,9 +565,12 @@ var StandardAgGridPlus = exports.StandardAgGridPlus = function StandardAgGridPlu
|
|
|
565
565
|
hasFilter: hasFilter || !!filterActive,
|
|
566
566
|
actions: emptyActions,
|
|
567
567
|
clearFilterAction: clearFilterAction,
|
|
568
|
-
onRetry: onRetry
|
|
568
|
+
onRetry: onRetry,
|
|
569
|
+
// 文案可定制:与基座同名 prop 同一语义(§7.8「『包材』下暂无物料」)
|
|
570
|
+
overrideText: props.overlayNoRowsTemplateText,
|
|
571
|
+
texts: props.emptyState
|
|
569
572
|
};
|
|
570
|
-
}, [lastError, hasFilter, filterActive, emptyActions, clearFilterAction, onRetry]);
|
|
573
|
+
}, [lastError, hasFilter, filterActive, emptyActions, clearFilterAction, onRetry, props.overlayNoRowsTemplateText, props.emptyState]);
|
|
571
574
|
var onGridReady = (0, _react.useCallback)(function (event) {
|
|
572
575
|
var _restProps$onGridRead;
|
|
573
576
|
var api = event.api;
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 列表日期显示格式:日期 `YYYY-MM-DD
|
|
2
|
+
* 列表日期显示格式:日期 `YYYY-MM-DD`,日期时间默认 `YYYY-MM-DD HH:mm:ss`(列表传 'minute' 到分钟),按浏览器本地时区。
|
|
3
3
|
* @author nokecy
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
6
|
* 将时间格式化为 yyyy-MM-dd HH:mm:ss 格式
|
|
7
7
|
* @param value 时间值(字符串、Date对象或null/undefined)
|
|
8
|
+
* @param precision 'second'(默认)带秒;'minute' 到分钟,列表默认用它(DESIGN.md §7.7:列表到分钟,日志与审计到秒)
|
|
8
9
|
* @returns 格式化后的时间字符串,如果输入无效则返回空字符串
|
|
9
10
|
*/
|
|
10
|
-
export declare const formatDateTime: (value: string | Date | null | undefined) => string;
|
|
11
|
+
export declare const formatDateTime: (value: string | Date | null | undefined, precision?: 'minute' | 'second') => string;
|
|
11
12
|
/**
|
|
12
13
|
* 将时间格式化为 yyyy-MM-dd 格式
|
|
13
14
|
* @param value 时间值(字符串、Date对象或null/undefined)
|
|
@@ -5,7 +5,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.formatDateTime = exports.formatDate = void 0;
|
|
7
7
|
/**
|
|
8
|
-
* 列表日期显示格式:日期 `YYYY-MM-DD
|
|
8
|
+
* 列表日期显示格式:日期 `YYYY-MM-DD`,日期时间默认 `YYYY-MM-DD HH:mm:ss`(列表传 'minute' 到分钟),按浏览器本地时区。
|
|
9
9
|
* @author nokecy
|
|
10
10
|
*/
|
|
11
11
|
|
|
@@ -17,9 +17,11 @@ var parseDate = function parseDate(value) {
|
|
|
17
17
|
/**
|
|
18
18
|
* 将时间格式化为 yyyy-MM-dd HH:mm:ss 格式
|
|
19
19
|
* @param value 时间值(字符串、Date对象或null/undefined)
|
|
20
|
+
* @param precision 'second'(默认)带秒;'minute' 到分钟,列表默认用它(DESIGN.md §7.7:列表到分钟,日志与审计到秒)
|
|
20
21
|
* @returns 格式化后的时间字符串,如果输入无效则返回空字符串
|
|
21
22
|
*/
|
|
22
23
|
var formatDateTime = exports.formatDateTime = function formatDateTime(value) {
|
|
24
|
+
var precision = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'second';
|
|
23
25
|
if (!value) return '';
|
|
24
26
|
try {
|
|
25
27
|
var date = parseDate(value);
|
|
@@ -30,7 +32,7 @@ var formatDateTime = exports.formatDateTime = function formatDateTime(value) {
|
|
|
30
32
|
var hours = String(date.getHours()).padStart(2, '0');
|
|
31
33
|
var minutes = String(date.getMinutes()).padStart(2, '0');
|
|
32
34
|
var seconds = String(date.getSeconds()).padStart(2, '0');
|
|
33
|
-
return "".concat(year, "-").concat(month, "-").concat(day, " ").concat(hours, ":").concat(minutes, ":").concat(seconds);
|
|
35
|
+
return precision === 'minute' ? "".concat(year, "-").concat(month, "-").concat(day, " ").concat(hours, ":").concat(minutes) : "".concat(year, "-").concat(month, "-").concat(day, " ").concat(hours, ":").concat(minutes, ":").concat(seconds);
|
|
34
36
|
} catch (error) {
|
|
35
37
|
return '';
|
|
36
38
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { GridPlusError } from '@nokecy/qc-ui-components/ag-grid-plus/errors/index';
|
|
3
|
+
import type { EmptyStateTexts } from '@nokecy/qc-ui-components/ag-grid-plus/utils/emptyState';
|
|
3
4
|
/**
|
|
4
5
|
* 列表空态四分支(U2)。
|
|
5
6
|
*
|
|
@@ -7,7 +8,7 @@ import type { GridPlusError } from '@nokecy/qc-ui-components/ag-grid-plus/errors
|
|
|
7
8
|
* 1. **无权限**(请求 403)→ 说明缺权限,不给新建入口;
|
|
8
9
|
* 2. **加载失败** → 给「重新加载」按钮;
|
|
9
10
|
* 3. **筛选无结果**(最近一次请求带条件)→ 引导调整/清空筛选;
|
|
10
|
-
* 4. **无数据** →
|
|
11
|
+
* 4. **无数据** → 「还没有数据」+ 业务页注入的操作(通常是 Access 包裹的新建按钮)。
|
|
11
12
|
*
|
|
12
13
|
* 渲染方式:作为 AG-Grid 的 `noRowsOverlayComponent` 挂在标准列表基座上(见 ./StandardAgGridPlus.tsx)。
|
|
13
14
|
* ag-grid-react 的 overlay 组件经 portal 渲染、仍在 React 树内,所以用 context 传动态状态,
|
|
@@ -26,6 +27,10 @@ export interface GridEmptyContextValue {
|
|
|
26
27
|
clearFilterAction?: React.ReactNode;
|
|
27
28
|
/** 重试(= 重新请求) */
|
|
28
29
|
onRetry?: () => void;
|
|
30
|
+
/** 四分支文案覆盖(对应基座的 emptyState prop) */
|
|
31
|
+
texts?: EmptyStateTexts;
|
|
32
|
+
/** 对应基座的 overlayNoRowsTemplateText:只替换「无数据」「无结果」两支的文案 */
|
|
33
|
+
overrideText?: string;
|
|
29
34
|
}
|
|
30
35
|
export declare const GridEmptyContext: React.Context<GridEmptyContextValue>;
|
|
31
36
|
/**
|
|
@@ -6,6 +6,8 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
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
|
+
var _EmptyIllustration = _interopRequireDefault(require("@nokecy/qc-ui-components/ag-grid-plus/shared/EmptyIllustration"));
|
|
10
|
+
var _emptyState = require("@nokecy/qc-ui-components/ag-grid-plus/utils/emptyState");
|
|
9
11
|
var _jsxRuntime = require("react/jsx-runtime");
|
|
10
12
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
11
13
|
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); } /**
|
|
@@ -15,7 +17,7 @@ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" ==
|
|
|
15
17
|
* 1. **无权限**(请求 403)→ 说明缺权限,不给新建入口;
|
|
16
18
|
* 2. **加载失败** → 给「重新加载」按钮;
|
|
17
19
|
* 3. **筛选无结果**(最近一次请求带条件)→ 引导调整/清空筛选;
|
|
18
|
-
* 4. **无数据** →
|
|
20
|
+
* 4. **无数据** → 「还没有数据」+ 业务页注入的操作(通常是 Access 包裹的新建按钮)。
|
|
19
21
|
*
|
|
20
22
|
* 渲染方式:作为 AG-Grid 的 `noRowsOverlayComponent` 挂在标准列表基座上(见 ./StandardAgGridPlus.tsx)。
|
|
21
23
|
* ag-grid-react 的 overlay 组件经 portal 渲染、仍在 React 树内,所以用 context 传动态状态,
|
|
@@ -41,37 +43,56 @@ var isPermissionDenied = exports.isPermissionDenied = function isPermissionDenie
|
|
|
41
43
|
return status === 403 && (!code || code.startsWith('Volo.Authorization'));
|
|
42
44
|
};
|
|
43
45
|
var GridEmptyState = exports.GridEmptyState = function GridEmptyState() {
|
|
46
|
+
var _texts$noData;
|
|
44
47
|
var _React$useContext = _react.default.useContext(GridEmptyContext),
|
|
45
48
|
error = _React$useContext.error,
|
|
46
49
|
hasFilter = _React$useContext.hasFilter,
|
|
47
50
|
actions = _React$useContext.actions,
|
|
48
51
|
clearFilterAction = _React$useContext.clearFilterAction,
|
|
49
|
-
onRetry = _React$useContext.onRetry
|
|
52
|
+
onRetry = _React$useContext.onRetry,
|
|
53
|
+
texts = _React$useContext.texts,
|
|
54
|
+
overrideText = _React$useContext.overrideText;
|
|
50
55
|
var remoteError = error === null || error === void 0 ? void 0 : error.getRemoteServiceError();
|
|
56
|
+
// 插画随分支变化,统一 1.5px 描边(DESIGN.md §10)
|
|
57
|
+
var image = function image(kind) {
|
|
58
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_EmptyIllustration.default, {
|
|
59
|
+
kind: kind
|
|
60
|
+
});
|
|
61
|
+
};
|
|
62
|
+
var imageStyles = {
|
|
63
|
+
image: {
|
|
64
|
+
height: 64
|
|
65
|
+
}
|
|
66
|
+
};
|
|
51
67
|
|
|
52
68
|
// 组织上下文校验失败不是列表权限配置错误,应提示用户重新选择组织。
|
|
53
69
|
if ((remoteError === null || remoteError === void 0 ? void 0 : remoteError.code) === 'FactoryManagement:OrganizationNotAvailable') {
|
|
54
70
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_antd.Empty, {
|
|
55
|
-
image:
|
|
71
|
+
image: image('error'),
|
|
72
|
+
styles: imageStyles,
|
|
56
73
|
description: remoteError.message || '所选组织不可用或未获得访问权限,请重新选择。'
|
|
57
74
|
});
|
|
58
75
|
}
|
|
59
76
|
|
|
60
|
-
//
|
|
77
|
+
// 分支:无权限(403 且不是业务异常)——说明原因,不给任何入口
|
|
61
78
|
if (error && isPermissionDenied(httpStatusOf(error), remoteError === null || remoteError === void 0 ? void 0 : remoteError.code)) {
|
|
79
|
+
var _texts$noPermission;
|
|
62
80
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_antd.Empty, {
|
|
63
|
-
image:
|
|
64
|
-
|
|
81
|
+
image: image('noPermission'),
|
|
82
|
+
styles: imageStyles,
|
|
83
|
+
description: (_texts$noPermission = texts === null || texts === void 0 ? void 0 : texts.noPermission) !== null && _texts$noPermission !== void 0 ? _texts$noPermission : _emptyState.DEFAULT_EMPTY_TEXTS.noPermission
|
|
65
84
|
});
|
|
66
85
|
}
|
|
67
86
|
|
|
68
|
-
//
|
|
87
|
+
// 分支:加载失败——给重试
|
|
69
88
|
if (error) {
|
|
89
|
+
var _texts$error;
|
|
70
90
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_antd.Empty, {
|
|
71
|
-
image:
|
|
72
|
-
|
|
91
|
+
image: image('error'),
|
|
92
|
+
styles: imageStyles
|
|
93
|
+
// 后端给了原因就写「加载失败,原因:…」,告诉用户下一步;页面自定义文案优先。@author nokecy
|
|
73
94
|
,
|
|
74
|
-
description:
|
|
95
|
+
description: (_texts$error = texts === null || texts === void 0 ? void 0 : texts.error) !== null && _texts$error !== void 0 ? _texts$error : remoteError !== null && remoteError !== void 0 && remoteError.message ? "\u52A0\u8F7D\u5931\u8D25\uFF0C\u539F\u56E0\uFF1A".concat(remoteError.message) : '加载失败,请检查后重试',
|
|
75
96
|
children: onRetry && /*#__PURE__*/(0, _jsxRuntime.jsx)(_antd.Button, {
|
|
76
97
|
size: "small",
|
|
77
98
|
type: "primary",
|
|
@@ -81,19 +102,23 @@ var GridEmptyState = exports.GridEmptyState = function GridEmptyState() {
|
|
|
81
102
|
});
|
|
82
103
|
}
|
|
83
104
|
|
|
84
|
-
//
|
|
105
|
+
// 分支:筛选无结果——引导调整条件,并可提供一键清空入口
|
|
85
106
|
if (hasFilter) {
|
|
107
|
+
var _texts$noResult;
|
|
86
108
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_antd.Empty, {
|
|
87
|
-
image:
|
|
88
|
-
|
|
109
|
+
image: image('noResult'),
|
|
110
|
+
styles: imageStyles,
|
|
111
|
+
description: overrideText || ((_texts$noResult = texts === null || texts === void 0 ? void 0 : texts.noResult) !== null && _texts$noResult !== void 0 ? _texts$noResult : _emptyState.DEFAULT_EMPTY_TEXTS.noResult),
|
|
89
112
|
children: clearFilterAction
|
|
90
113
|
});
|
|
91
114
|
}
|
|
92
115
|
|
|
93
|
-
//
|
|
116
|
+
// 分支:无数据——业务页可注入新建入口。
|
|
117
|
+
// overrideText(overlayNoRowsTemplateText)只作用于这两支「空」:失败与无权限不能被一句业务文案盖掉。
|
|
94
118
|
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_antd.Empty, {
|
|
95
|
-
image:
|
|
96
|
-
|
|
119
|
+
image: image('noData'),
|
|
120
|
+
styles: imageStyles,
|
|
121
|
+
description: overrideText || ((_texts$noData = texts === null || texts === void 0 ? void 0 : texts.noData) !== null && _texts$noData !== void 0 ? _texts$noData : _emptyState.DEFAULT_EMPTY_TEXTS.noData),
|
|
97
122
|
children: actions
|
|
98
123
|
});
|
|
99
124
|
};
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.createNormalizedEnumFallbackRenderer = exports.applyNormalizedEnumFallbacksToColumns = exports.applyGridValueEnumToColumns = void 0;
|
|
7
7
|
var _react = require("react");
|
|
8
8
|
var _valueEnumColor = require("@nokecy/qc-ui-components/ag-grid-plus/utils/valueEnumColor");
|
|
9
|
+
var _statusPill = require("@nokecy/qc-ui-components/ag-grid-plus/utils/statusPill");
|
|
9
10
|
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); }
|
|
10
11
|
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
11
12
|
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
@@ -58,12 +59,15 @@ var createNormalizedEnumFallbackRenderer = exports.createNormalizedEnumFallbackR
|
|
|
58
59
|
return item.value !== params.value && normalizeEnumCode(item.value) === normalizedValue;
|
|
59
60
|
});
|
|
60
61
|
if (matched) {
|
|
61
|
-
var _matched$label;
|
|
62
|
+
var _matched$label, _matched$label2;
|
|
63
|
+
if ((0, _statusPill.isStatusKey)(matched.status)) return /*#__PURE__*/(0, _react.createElement)(_statusPill.StatusPill, {
|
|
64
|
+
status: matched.status
|
|
65
|
+
}, (_matched$label = matched.label) !== null && _matched$label !== void 0 ? _matched$label : '');
|
|
62
66
|
return /*#__PURE__*/(0, _react.createElement)('span', {
|
|
63
67
|
style: {
|
|
64
68
|
color: matched.color || 'inherit'
|
|
65
69
|
}
|
|
66
|
-
}, (_matched$
|
|
70
|
+
}, (_matched$label2 = matched.label) !== null && _matched$label2 !== void 0 ? _matched$label2 : '');
|
|
67
71
|
}
|
|
68
72
|
}
|
|
69
73
|
return fallback ? fallback(params) : params.value;
|
|
@@ -11,6 +11,7 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
|
|
|
11
11
|
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
12
12
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
|
|
13
13
|
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
14
|
+
var EMPTY_DATE = '—';
|
|
14
15
|
/** 从日期类型、字段及标题识别日历日期与操作时间,排除耗时和工时。@author nokecy */
|
|
15
16
|
var getListDateType = exports.getListDateType = function getListDateType(column) {
|
|
16
17
|
var _column$field, _column$headerName;
|
|
@@ -34,13 +35,15 @@ var getListDateType = exports.getListDateType = function getListDateType(column)
|
|
|
34
35
|
|
|
35
36
|
/** 列表只格式化展示值,保留数据源中的日期供排序、筛选及提交使用。@author nokecy */
|
|
36
37
|
var normalizeListDateColumn = exports.normalizeListDateColumn = function normalizeListDateColumn(column) {
|
|
37
|
-
var _column$type, _column$cellRenderer;
|
|
38
|
+
var _column$valueFormatte, _column$type, _column$cellRenderer;
|
|
38
39
|
var dateType = getListDateType(column);
|
|
39
40
|
if (!dateType) return column;
|
|
40
|
-
|
|
41
|
+
// 列表日期到分钟、空值显示「—」(DESIGN.md §7.7);页面自己传 valueFormatter(如审计列要秒)即覆盖
|
|
42
|
+
var defaultFormatter = function defaultFormatter(_ref) {
|
|
41
43
|
var value = _ref.value;
|
|
42
|
-
return dateType === 'dateTimeColumn' ? (0, _dateFormat.formatDateTime)(value) : (0, _dateFormat.formatDate)(value);
|
|
44
|
+
return (dateType === 'dateTimeColumn' ? (0, _dateFormat.formatDateTime)(value, 'minute') : (0, _dateFormat.formatDate)(value)) || EMPTY_DATE;
|
|
43
45
|
};
|
|
46
|
+
var formatter = (_column$valueFormatte = column.valueFormatter) !== null && _column$valueFormatte !== void 0 ? _column$valueFormatte : defaultFormatter;
|
|
44
47
|
return _objectSpread(_objectSpread({}, column), {}, {
|
|
45
48
|
type: (_column$type = column.type) !== null && _column$type !== void 0 ? _column$type : dateType,
|
|
46
49
|
valueFormatter: formatter,
|
|
@@ -18,11 +18,12 @@ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key i
|
|
|
18
18
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
|
|
19
19
|
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
20
20
|
import React, { useCallback, useMemo, useRef, useEffect } from 'react';
|
|
21
|
-
import { FormDialog, FormLayout, FormItem, FormGrid, Input, Select, DatePicker, NumberPicker, Switch } from '@nokecy/formily-antd';
|
|
21
|
+
import { FormDialog, FormLayout, FormItem, FormGrid, Input, Select, DatePicker, NumberPicker, Switch, focusFirstError } from '@nokecy/formily-antd';
|
|
22
22
|
import { onFormInit, onFormValidateFailed, onFormSubmitEnd } from '@nokecy/formily-core';
|
|
23
23
|
import { Button, ConfigProvider, message, Spin } from 'antd';
|
|
24
24
|
import portalManager from "./PortalManager";
|
|
25
25
|
import { createSchemaField, Observer } from '@nokecy/formily-react';
|
|
26
|
+
import DraggableModal from '@nokecy/qc-ui-components/draggableModal/index';
|
|
26
27
|
|
|
27
28
|
// 创建默认的 SchemaField,包含基本组件和装饰器
|
|
28
29
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
@@ -40,6 +41,13 @@ var SchemaFieldComponents = createSchemaField({
|
|
|
40
41
|
}
|
|
41
42
|
});
|
|
42
43
|
|
|
44
|
+
/** 表单弹窗的可缩放壳:最小宽度取规范最小一档 560,避免缩到字段挤压。 */
|
|
45
|
+
var ResizableFormModal = function ResizableFormModal(modalProps) {
|
|
46
|
+
return /*#__PURE__*/_jsx(DraggableModal, _objectSpread({
|
|
47
|
+
minWidth: 560
|
|
48
|
+
}, modalProps));
|
|
49
|
+
};
|
|
50
|
+
|
|
43
51
|
/**
|
|
44
52
|
* 默认的 useFormSchema hook - 直接返回schema配置
|
|
45
53
|
*/
|
|
@@ -77,7 +85,7 @@ var StandardFormDialog = function StandardFormDialog(props) {
|
|
|
77
85
|
directFormSchema = props.formSchema,
|
|
78
86
|
apiConfig = props.apiConfig,
|
|
79
87
|
_props$width = props.width,
|
|
80
|
-
width = _props$width === void 0 ?
|
|
88
|
+
width = _props$width === void 0 ? 720 : _props$width,
|
|
81
89
|
entityId = props.entityId,
|
|
82
90
|
_props$title = props.title,
|
|
83
91
|
title = _props$title === void 0 ? '表单' : _props$title,
|
|
@@ -93,6 +101,12 @@ var StandardFormDialog = function StandardFormDialog(props) {
|
|
|
93
101
|
customSubmitHandler = props.customSubmitHandler,
|
|
94
102
|
_props$useUnifiedErro = props.useUnifiedErrorHandling,
|
|
95
103
|
useUnifiedErrorHandling = _props$useUnifiedErro === void 0 ? true : _props$useUnifiedErro,
|
|
104
|
+
_props$locateFirstErr = props.locateFirstError,
|
|
105
|
+
locateFirstError = _props$locateFirstErr === void 0 ? true : _props$locateFirstErr,
|
|
106
|
+
_props$confirmOnDirty = props.confirmOnDirtyClose,
|
|
107
|
+
confirmOnDirtyClose = _props$confirmOnDirty === void 0 ? true : _props$confirmOnDirty,
|
|
108
|
+
_props$resizable = props.resizable,
|
|
109
|
+
resizable = _props$resizable === void 0 ? true : _props$resizable,
|
|
96
110
|
_props$useFormSchema = props.useFormSchema,
|
|
97
111
|
useFormSchemaHook = _props$useFormSchema === void 0 ? defaultUseFormSchema : _props$useFormSchema,
|
|
98
112
|
_props$useSchemaField = props.useSchemaField,
|
|
@@ -239,6 +253,18 @@ var StandardFormDialog = function StandardFormDialog(props) {
|
|
|
239
253
|
|
|
240
254
|
// 表单验证失败回调
|
|
241
255
|
var handleValidationFailed = useCallback(function (form) {
|
|
256
|
+
if (locateFirstError) {
|
|
257
|
+
// 提示里直接写出所在页签与字段,不再拼字段名串(DESIGN.md §6.4)。
|
|
258
|
+
// 只在最上层弹窗内找,避免定位到弹窗下面页面里的字段。
|
|
259
|
+
void focusFirstError(form, {
|
|
260
|
+
root: function root() {
|
|
261
|
+
var _modals;
|
|
262
|
+
var modals = document.querySelectorAll('.ant-modal');
|
|
263
|
+
return (_modals = modals[modals.length - 1]) !== null && _modals !== void 0 ? _modals : document;
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
242
268
|
var errors = form.errors;
|
|
243
269
|
var errorFields = Object.keys(errors);
|
|
244
270
|
if (errorFields.length > 0) {
|
|
@@ -270,7 +296,7 @@ var StandardFormDialog = function StandardFormDialog(props) {
|
|
|
270
296
|
errors: errors
|
|
271
297
|
});
|
|
272
298
|
}
|
|
273
|
-
}, []);
|
|
299
|
+
}, [locateFirstError]);
|
|
274
300
|
|
|
275
301
|
// 表单属性配置
|
|
276
302
|
var formProps = useMemo(function () {
|
|
@@ -411,6 +437,8 @@ var StandardFormDialog = function StandardFormDialog(props) {
|
|
|
411
437
|
// 不设置静态 loading,使用 FormDialog 自带的 form.submitting。
|
|
412
438
|
// @author nokecy
|
|
413
439
|
maskClosable: false,
|
|
440
|
+
confirmOnDirtyClose: confirmOnDirtyClose,
|
|
441
|
+
modalComponent: resizable ? ResizableFormModal : undefined,
|
|
414
442
|
onOk: function onOk() {
|
|
415
443
|
if (confirmingRef.current || loadingRef.current) return false;
|
|
416
444
|
confirmingRef.current = true;
|
|
@@ -452,7 +480,7 @@ var StandardFormDialog = function StandardFormDialog(props) {
|
|
|
452
480
|
});
|
|
453
481
|
});
|
|
454
482
|
formDialog.forConfirm(handleSubmit).open(formProps);
|
|
455
|
-
}, [title, width, portalId, schema, SchemaField, formProps, handleSubmit]);
|
|
483
|
+
}, [title, width, portalId, schema, SchemaField, formProps, handleSubmit, confirmOnDirtyClose, resizable]);
|
|
456
484
|
return /*#__PURE__*/_jsx(FormDialog.Portal, {
|
|
457
485
|
id: portalId,
|
|
458
486
|
children: /*#__PURE__*/_jsx(Button, _objectSpread(_objectSpread({
|
|
@@ -44,8 +44,23 @@ export interface StandardFormDialogConfig {
|
|
|
44
44
|
schemaConfig: FormSchemaConfig;
|
|
45
45
|
/** API配置 */
|
|
46
46
|
apiConfig: FormApiConfig;
|
|
47
|
-
/**
|
|
47
|
+
/** 对话框宽度,默认 720;规范只取 560 / 720 / 960 三档。 */
|
|
48
48
|
width?: number;
|
|
49
|
+
/**
|
|
50
|
+
* 校验失败时定位首个错误字段(切页签、展开折叠、滚动并聚焦)并给出带位置的提示,默认 true。
|
|
51
|
+
* 传 false 回到旧行为:只弹出「请检查表单错误:字段名…」的汇总提示。
|
|
52
|
+
*/
|
|
53
|
+
locateFirstError?: boolean;
|
|
54
|
+
/**
|
|
55
|
+
* 表单被改过时,关闭(叉、Esc、取消按钮)先弹「继续编辑 / 放弃修改」确认,默认 true(DESIGN.md §6.6)。
|
|
56
|
+
* 判据为 form.modified;提交成功后的关闭不确认。传 false 恢复直接关闭。
|
|
57
|
+
*/
|
|
58
|
+
confirmOnDirtyClose?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* 弹窗可拖动标题移动、拖边框缩放,默认 true(表单字段多时需要放大;宽度默认仍按 width,缩放不持久化)。
|
|
61
|
+
* 最小 560 x 300,且不超过视口 95%。传 false 回到固定尺寸。
|
|
62
|
+
*/
|
|
63
|
+
resizable?: boolean;
|
|
49
64
|
/** 实体ID(编辑时) */
|
|
50
65
|
entityId?: string | number;
|
|
51
66
|
/** 标题 */
|
|
@@ -561,9 +561,12 @@ var StandardAgGridPlus = function StandardAgGridPlus(props) {
|
|
|
561
561
|
hasFilter: hasFilter || !!filterActive,
|
|
562
562
|
actions: emptyActions,
|
|
563
563
|
clearFilterAction: clearFilterAction,
|
|
564
|
-
onRetry: onRetry
|
|
564
|
+
onRetry: onRetry,
|
|
565
|
+
// 文案可定制:与基座同名 prop 同一语义(§7.8「『包材』下暂无物料」)
|
|
566
|
+
overrideText: props.overlayNoRowsTemplateText,
|
|
567
|
+
texts: props.emptyState
|
|
565
568
|
};
|
|
566
|
-
}, [lastError, hasFilter, filterActive, emptyActions, clearFilterAction, onRetry]);
|
|
569
|
+
}, [lastError, hasFilter, filterActive, emptyActions, clearFilterAction, onRetry, props.overlayNoRowsTemplateText, props.emptyState]);
|
|
567
570
|
var onGridReady = useCallback(function (event) {
|
|
568
571
|
var _restProps$onGridRead;
|
|
569
572
|
var api = event.api;
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 列表日期显示格式:日期 `YYYY-MM-DD
|
|
2
|
+
* 列表日期显示格式:日期 `YYYY-MM-DD`,日期时间默认 `YYYY-MM-DD HH:mm:ss`(列表传 'minute' 到分钟),按浏览器本地时区。
|
|
3
3
|
* @author nokecy
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
6
|
* 将时间格式化为 yyyy-MM-dd HH:mm:ss 格式
|
|
7
7
|
* @param value 时间值(字符串、Date对象或null/undefined)
|
|
8
|
+
* @param precision 'second'(默认)带秒;'minute' 到分钟,列表默认用它(DESIGN.md §7.7:列表到分钟,日志与审计到秒)
|
|
8
9
|
* @returns 格式化后的时间字符串,如果输入无效则返回空字符串
|
|
9
10
|
*/
|
|
10
|
-
export declare const formatDateTime: (value: string | Date | null | undefined) => string;
|
|
11
|
+
export declare const formatDateTime: (value: string | Date | null | undefined, precision?: 'minute' | 'second') => string;
|
|
11
12
|
/**
|
|
12
13
|
* 将时间格式化为 yyyy-MM-dd 格式
|
|
13
14
|
* @param value 时间值(字符串、Date对象或null/undefined)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 列表日期显示格式:日期 `YYYY-MM-DD
|
|
2
|
+
* 列表日期显示格式:日期 `YYYY-MM-DD`,日期时间默认 `YYYY-MM-DD HH:mm:ss`(列表传 'minute' 到分钟),按浏览器本地时区。
|
|
3
3
|
* @author nokecy
|
|
4
4
|
*/
|
|
5
5
|
|
|
@@ -11,9 +11,11 @@ var parseDate = function parseDate(value) {
|
|
|
11
11
|
/**
|
|
12
12
|
* 将时间格式化为 yyyy-MM-dd HH:mm:ss 格式
|
|
13
13
|
* @param value 时间值(字符串、Date对象或null/undefined)
|
|
14
|
+
* @param precision 'second'(默认)带秒;'minute' 到分钟,列表默认用它(DESIGN.md §7.7:列表到分钟,日志与审计到秒)
|
|
14
15
|
* @returns 格式化后的时间字符串,如果输入无效则返回空字符串
|
|
15
16
|
*/
|
|
16
17
|
export var formatDateTime = function formatDateTime(value) {
|
|
18
|
+
var precision = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'second';
|
|
17
19
|
if (!value) return '';
|
|
18
20
|
try {
|
|
19
21
|
var date = parseDate(value);
|
|
@@ -24,7 +26,7 @@ export var formatDateTime = function formatDateTime(value) {
|
|
|
24
26
|
var hours = String(date.getHours()).padStart(2, '0');
|
|
25
27
|
var minutes = String(date.getMinutes()).padStart(2, '0');
|
|
26
28
|
var seconds = String(date.getSeconds()).padStart(2, '0');
|
|
27
|
-
return "".concat(year, "-").concat(month, "-").concat(day, " ").concat(hours, ":").concat(minutes, ":").concat(seconds);
|
|
29
|
+
return precision === 'minute' ? "".concat(year, "-").concat(month, "-").concat(day, " ").concat(hours, ":").concat(minutes) : "".concat(year, "-").concat(month, "-").concat(day, " ").concat(hours, ":").concat(minutes, ":").concat(seconds);
|
|
28
30
|
} catch (error) {
|
|
29
31
|
return '';
|
|
30
32
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { GridPlusError } from '@nokecy/qc-ui-components/ag-grid-plus/errors/index';
|
|
3
|
+
import type { EmptyStateTexts } from '@nokecy/qc-ui-components/ag-grid-plus/utils/emptyState';
|
|
3
4
|
/**
|
|
4
5
|
* 列表空态四分支(U2)。
|
|
5
6
|
*
|
|
@@ -7,7 +8,7 @@ import type { GridPlusError } from '@nokecy/qc-ui-components/ag-grid-plus/errors
|
|
|
7
8
|
* 1. **无权限**(请求 403)→ 说明缺权限,不给新建入口;
|
|
8
9
|
* 2. **加载失败** → 给「重新加载」按钮;
|
|
9
10
|
* 3. **筛选无结果**(最近一次请求带条件)→ 引导调整/清空筛选;
|
|
10
|
-
* 4. **无数据** →
|
|
11
|
+
* 4. **无数据** → 「还没有数据」+ 业务页注入的操作(通常是 Access 包裹的新建按钮)。
|
|
11
12
|
*
|
|
12
13
|
* 渲染方式:作为 AG-Grid 的 `noRowsOverlayComponent` 挂在标准列表基座上(见 ./StandardAgGridPlus.tsx)。
|
|
13
14
|
* ag-grid-react 的 overlay 组件经 portal 渲染、仍在 React 树内,所以用 context 传动态状态,
|
|
@@ -26,6 +27,10 @@ export interface GridEmptyContextValue {
|
|
|
26
27
|
clearFilterAction?: React.ReactNode;
|
|
27
28
|
/** 重试(= 重新请求) */
|
|
28
29
|
onRetry?: () => void;
|
|
30
|
+
/** 四分支文案覆盖(对应基座的 emptyState prop) */
|
|
31
|
+
texts?: EmptyStateTexts;
|
|
32
|
+
/** 对应基座的 overlayNoRowsTemplateText:只替换「无数据」「无结果」两支的文案 */
|
|
33
|
+
overrideText?: string;
|
|
29
34
|
}
|
|
30
35
|
export declare const GridEmptyContext: React.Context<GridEmptyContextValue>;
|
|
31
36
|
/**
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
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); }
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { Button, Empty } from 'antd';
|
|
4
|
+
import EmptyIllustration from '@nokecy/qc-ui-components/ag-grid-plus/shared/EmptyIllustration';
|
|
5
|
+
import { DEFAULT_EMPTY_TEXTS } from '@nokecy/qc-ui-components/ag-grid-plus/utils/emptyState';
|
|
4
6
|
|
|
5
7
|
/**
|
|
6
8
|
* 列表空态四分支(U2)。
|
|
@@ -9,7 +11,7 @@ import { Button, Empty } from 'antd';
|
|
|
9
11
|
* 1. **无权限**(请求 403)→ 说明缺权限,不给新建入口;
|
|
10
12
|
* 2. **加载失败** → 给「重新加载」按钮;
|
|
11
13
|
* 3. **筛选无结果**(最近一次请求带条件)→ 引导调整/清空筛选;
|
|
12
|
-
* 4. **无数据** →
|
|
14
|
+
* 4. **无数据** → 「还没有数据」+ 业务页注入的操作(通常是 Access 包裹的新建按钮)。
|
|
13
15
|
*
|
|
14
16
|
* 渲染方式:作为 AG-Grid 的 `noRowsOverlayComponent` 挂在标准列表基座上(见 ./StandardAgGridPlus.tsx)。
|
|
15
17
|
* ag-grid-react 的 overlay 组件经 portal 渲染、仍在 React 树内,所以用 context 传动态状态,
|
|
@@ -36,37 +38,56 @@ export var isPermissionDenied = function isPermissionDenied(status, code) {
|
|
|
36
38
|
return status === 403 && (!code || code.startsWith('Volo.Authorization'));
|
|
37
39
|
};
|
|
38
40
|
export var GridEmptyState = function GridEmptyState() {
|
|
41
|
+
var _texts$noData;
|
|
39
42
|
var _React$useContext = React.useContext(GridEmptyContext),
|
|
40
43
|
error = _React$useContext.error,
|
|
41
44
|
hasFilter = _React$useContext.hasFilter,
|
|
42
45
|
actions = _React$useContext.actions,
|
|
43
46
|
clearFilterAction = _React$useContext.clearFilterAction,
|
|
44
|
-
onRetry = _React$useContext.onRetry
|
|
47
|
+
onRetry = _React$useContext.onRetry,
|
|
48
|
+
texts = _React$useContext.texts,
|
|
49
|
+
overrideText = _React$useContext.overrideText;
|
|
45
50
|
var remoteError = error === null || error === void 0 ? void 0 : error.getRemoteServiceError();
|
|
51
|
+
// 插画随分支变化,统一 1.5px 描边(DESIGN.md §10)
|
|
52
|
+
var image = function image(kind) {
|
|
53
|
+
return /*#__PURE__*/_jsx(EmptyIllustration, {
|
|
54
|
+
kind: kind
|
|
55
|
+
});
|
|
56
|
+
};
|
|
57
|
+
var imageStyles = {
|
|
58
|
+
image: {
|
|
59
|
+
height: 64
|
|
60
|
+
}
|
|
61
|
+
};
|
|
46
62
|
|
|
47
63
|
// 组织上下文校验失败不是列表权限配置错误,应提示用户重新选择组织。
|
|
48
64
|
if ((remoteError === null || remoteError === void 0 ? void 0 : remoteError.code) === 'FactoryManagement:OrganizationNotAvailable') {
|
|
49
65
|
return /*#__PURE__*/_jsx(Empty, {
|
|
50
|
-
image:
|
|
66
|
+
image: image('error'),
|
|
67
|
+
styles: imageStyles,
|
|
51
68
|
description: remoteError.message || '所选组织不可用或未获得访问权限,请重新选择。'
|
|
52
69
|
});
|
|
53
70
|
}
|
|
54
71
|
|
|
55
|
-
//
|
|
72
|
+
// 分支:无权限(403 且不是业务异常)——说明原因,不给任何入口
|
|
56
73
|
if (error && isPermissionDenied(httpStatusOf(error), remoteError === null || remoteError === void 0 ? void 0 : remoteError.code)) {
|
|
74
|
+
var _texts$noPermission;
|
|
57
75
|
return /*#__PURE__*/_jsx(Empty, {
|
|
58
|
-
image:
|
|
59
|
-
|
|
76
|
+
image: image('noPermission'),
|
|
77
|
+
styles: imageStyles,
|
|
78
|
+
description: (_texts$noPermission = texts === null || texts === void 0 ? void 0 : texts.noPermission) !== null && _texts$noPermission !== void 0 ? _texts$noPermission : DEFAULT_EMPTY_TEXTS.noPermission
|
|
60
79
|
});
|
|
61
80
|
}
|
|
62
81
|
|
|
63
|
-
//
|
|
82
|
+
// 分支:加载失败——给重试
|
|
64
83
|
if (error) {
|
|
84
|
+
var _texts$error;
|
|
65
85
|
return /*#__PURE__*/_jsx(Empty, {
|
|
66
|
-
image:
|
|
67
|
-
|
|
86
|
+
image: image('error'),
|
|
87
|
+
styles: imageStyles
|
|
88
|
+
// 后端给了原因就写「加载失败,原因:…」,告诉用户下一步;页面自定义文案优先。@author nokecy
|
|
68
89
|
,
|
|
69
|
-
description:
|
|
90
|
+
description: (_texts$error = texts === null || texts === void 0 ? void 0 : texts.error) !== null && _texts$error !== void 0 ? _texts$error : remoteError !== null && remoteError !== void 0 && remoteError.message ? "\u52A0\u8F7D\u5931\u8D25\uFF0C\u539F\u56E0\uFF1A".concat(remoteError.message) : '加载失败,请检查后重试',
|
|
70
91
|
children: onRetry && /*#__PURE__*/_jsx(Button, {
|
|
71
92
|
size: "small",
|
|
72
93
|
type: "primary",
|
|
@@ -76,19 +97,23 @@ export var GridEmptyState = function GridEmptyState() {
|
|
|
76
97
|
});
|
|
77
98
|
}
|
|
78
99
|
|
|
79
|
-
//
|
|
100
|
+
// 分支:筛选无结果——引导调整条件,并可提供一键清空入口
|
|
80
101
|
if (hasFilter) {
|
|
102
|
+
var _texts$noResult;
|
|
81
103
|
return /*#__PURE__*/_jsx(Empty, {
|
|
82
|
-
image:
|
|
83
|
-
|
|
104
|
+
image: image('noResult'),
|
|
105
|
+
styles: imageStyles,
|
|
106
|
+
description: overrideText || ((_texts$noResult = texts === null || texts === void 0 ? void 0 : texts.noResult) !== null && _texts$noResult !== void 0 ? _texts$noResult : DEFAULT_EMPTY_TEXTS.noResult),
|
|
84
107
|
children: clearFilterAction
|
|
85
108
|
});
|
|
86
109
|
}
|
|
87
110
|
|
|
88
|
-
//
|
|
111
|
+
// 分支:无数据——业务页可注入新建入口。
|
|
112
|
+
// overrideText(overlayNoRowsTemplateText)只作用于这两支「空」:失败与无权限不能被一句业务文案盖掉。
|
|
89
113
|
return /*#__PURE__*/_jsx(Empty, {
|
|
90
|
-
image:
|
|
91
|
-
|
|
114
|
+
image: image('noData'),
|
|
115
|
+
styles: imageStyles,
|
|
116
|
+
description: overrideText || ((_texts$noData = texts === null || texts === void 0 ? void 0 : texts.noData) !== null && _texts$noData !== void 0 ? _texts$noData : DEFAULT_EMPTY_TEXTS.noData),
|
|
92
117
|
children: actions
|
|
93
118
|
});
|
|
94
119
|
};
|
|
@@ -14,6 +14,7 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
|
|
|
14
14
|
*/
|
|
15
15
|
import { createElement } from 'react';
|
|
16
16
|
import { gridValueEnum } from '@nokecy/qc-ui-components/ag-grid-plus/utils/valueEnumColor';
|
|
17
|
+
import { isStatusKey, StatusPill } from '@nokecy/qc-ui-components/ag-grid-plus/utils/statusPill';
|
|
17
18
|
/**
|
|
18
19
|
* 递归给 columnDefs / 列组 children 的 valueEnum 套上 `gridValueEnum`,并补默认未知值显示。
|
|
19
20
|
* 没有 valueEnum 且没有 children 的列保持原引用。
|
|
@@ -53,12 +54,15 @@ export var createNormalizedEnumFallbackRenderer = function createNormalizedEnumF
|
|
|
53
54
|
return item.value !== params.value && normalizeEnumCode(item.value) === normalizedValue;
|
|
54
55
|
});
|
|
55
56
|
if (matched) {
|
|
56
|
-
var _matched$label;
|
|
57
|
+
var _matched$label, _matched$label2;
|
|
58
|
+
if (isStatusKey(matched.status)) return /*#__PURE__*/createElement(StatusPill, {
|
|
59
|
+
status: matched.status
|
|
60
|
+
}, (_matched$label = matched.label) !== null && _matched$label !== void 0 ? _matched$label : '');
|
|
57
61
|
return /*#__PURE__*/createElement('span', {
|
|
58
62
|
style: {
|
|
59
63
|
color: matched.color || 'inherit'
|
|
60
64
|
}
|
|
61
|
-
}, (_matched$
|
|
65
|
+
}, (_matched$label2 = matched.label) !== null && _matched$label2 !== void 0 ? _matched$label2 : '');
|
|
62
66
|
}
|
|
63
67
|
}
|
|
64
68
|
return fallback ? fallback(params) : params.value;
|
|
@@ -5,6 +5,7 @@ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key i
|
|
|
5
5
|
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
|
|
6
6
|
function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
7
7
|
import { formatDate, formatDateTime } from "./dateFormat";
|
|
8
|
+
var EMPTY_DATE = '—';
|
|
8
9
|
/** 从日期类型、字段及标题识别日历日期与操作时间,排除耗时和工时。@author nokecy */
|
|
9
10
|
export var getListDateType = function getListDateType(column) {
|
|
10
11
|
var _column$field, _column$headerName;
|
|
@@ -28,13 +29,15 @@ export var getListDateType = function getListDateType(column) {
|
|
|
28
29
|
|
|
29
30
|
/** 列表只格式化展示值,保留数据源中的日期供排序、筛选及提交使用。@author nokecy */
|
|
30
31
|
export var normalizeListDateColumn = function normalizeListDateColumn(column) {
|
|
31
|
-
var _column$type, _column$cellRenderer;
|
|
32
|
+
var _column$valueFormatte, _column$type, _column$cellRenderer;
|
|
32
33
|
var dateType = getListDateType(column);
|
|
33
34
|
if (!dateType) return column;
|
|
34
|
-
|
|
35
|
+
// 列表日期到分钟、空值显示「—」(DESIGN.md §7.7);页面自己传 valueFormatter(如审计列要秒)即覆盖
|
|
36
|
+
var defaultFormatter = function defaultFormatter(_ref) {
|
|
35
37
|
var value = _ref.value;
|
|
36
|
-
return dateType === 'dateTimeColumn' ? formatDateTime(value) : formatDate(value);
|
|
38
|
+
return (dateType === 'dateTimeColumn' ? formatDateTime(value, 'minute') : formatDate(value)) || EMPTY_DATE;
|
|
37
39
|
};
|
|
40
|
+
var formatter = (_column$valueFormatte = column.valueFormatter) !== null && _column$valueFormatte !== void 0 ? _column$valueFormatte : defaultFormatter;
|
|
38
41
|
return _objectSpread(_objectSpread({}, column), {}, {
|
|
39
42
|
type: (_column$type = column.type) !== null && _column$type !== void 0 ? _column$type : dateType,
|
|
40
43
|
valueFormatter: formatter,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nokecy/qc-ui-business",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.1",
|
|
4
4
|
"description": "QC_UI business components and ABP adapters",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
|
@@ -45,10 +45,10 @@
|
|
|
45
45
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@nokecy/formily-antd": "1.2.
|
|
48
|
+
"@nokecy/formily-antd": "1.2.5",
|
|
49
49
|
"@nokecy/formily-core": "2.3.7",
|
|
50
50
|
"@nokecy/formily-react": "2.3.7",
|
|
51
|
-
"@nokecy/qc-ui-components": "2.0.0-beta.
|
|
51
|
+
"@nokecy/qc-ui-components": "2.0.0-beta.1",
|
|
52
52
|
"ahooks": "3.10.0"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|