ztxkui 4.2.23-552 → 4.2.23-554
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/UI/Table/EditTable.js +29 -1
- package/dist/components/Input/AntInputModal.d.ts +8 -0
- package/dist/components/Input/AntInputModal.js +79 -0
- package/dist/components/Input/hooks/index.d.ts +2 -0
- package/dist/components/Input/hooks/index.js +1 -0
- package/dist/components/Input/hooks/useInputModal.d.ts +53 -0
- package/dist/components/Input/hooks/useInputModal.js +105 -0
- package/dist/components/Input/input.js +29 -10
- package/dist/components/Table/hooks/useCtrl.d.ts +5 -0
- package/dist/components/Table/hooks/useCtrl.js +31 -0
- package/dist/components/Table/hooks/useDropRef.js +10 -1
- package/dist/components/Table/hooks/useSelectSubtotal.js +83 -20
- package/dist/components/Table/table-enhance-cell.d.ts +6 -0
- package/dist/components/Table/table-enhance-cell.js +55 -5
- package/package.json +1 -1
|
@@ -90,7 +90,35 @@ function useColumns(tableHandleRef) {
|
|
|
90
90
|
dataIndex: 'test1',
|
|
91
91
|
key: 'test1',
|
|
92
92
|
render: function (text, record, index) {
|
|
93
|
-
return (React.createElement(Input, { value: text,
|
|
93
|
+
return (React.createElement(Input, { value: text, onChange: function (e) {
|
|
94
|
+
var _a;
|
|
95
|
+
var newRecord = {
|
|
96
|
+
test1: e.target.value,
|
|
97
|
+
};
|
|
98
|
+
(_a = tableHandleRef.current) === null || _a === void 0 ? void 0 : _a.onEditableSaveHandle(newRecord, index);
|
|
99
|
+
}, onPaste: function (e) {
|
|
100
|
+
var _a;
|
|
101
|
+
(_a = tableHandleRef.current) === null || _a === void 0 ? void 0 : _a.onPasteHandle(e, {
|
|
102
|
+
index: index,
|
|
103
|
+
dataIndex: 'test1',
|
|
104
|
+
record: record,
|
|
105
|
+
});
|
|
106
|
+
} }));
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
title: i18next.t('测试列11122'),
|
|
111
|
+
width: 100,
|
|
112
|
+
dataIndex: 'test111122',
|
|
113
|
+
key: 'test111122',
|
|
114
|
+
render: function (text, record, index) {
|
|
115
|
+
return (React.createElement(Input.TextArea, { value: text, onChange: function (e) {
|
|
116
|
+
var _a;
|
|
117
|
+
var newRecord = {
|
|
118
|
+
test111122: e.target.value,
|
|
119
|
+
};
|
|
120
|
+
(_a = tableHandleRef.current) === null || _a === void 0 ? void 0 : _a.onEditableSaveHandle(newRecord, index);
|
|
121
|
+
}, onPaste: function (e) {
|
|
94
122
|
var _a;
|
|
95
123
|
(_a = tableHandleRef.current) === null || _a === void 0 ? void 0 : _a.onPasteHandle(e, {
|
|
96
124
|
index: index,
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { InputProps } from 'antd';
|
|
3
|
+
interface InputModalProps extends Omit<InputProps, 'onChange' | 'onBlur'> {
|
|
4
|
+
onChange?: InputProps['onChange'];
|
|
5
|
+
onBlur?: InputProps['onBlur'];
|
|
6
|
+
}
|
|
7
|
+
declare const InputModal: React.FC<InputModalProps>;
|
|
8
|
+
export default InputModal;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
13
|
+
var t = {};
|
|
14
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
15
|
+
t[p] = s[p];
|
|
16
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
17
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
18
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
19
|
+
t[p[i]] = s[p[i]];
|
|
20
|
+
}
|
|
21
|
+
return t;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* 这里重构一份的原因是 因为Table组件里面的编辑列使用的是 AntInput的组件
|
|
25
|
+
* 担心会有问题,这里用Antd的Input组件来代替
|
|
26
|
+
*/
|
|
27
|
+
import i18next from 'ztxkutils/dist/i18next';
|
|
28
|
+
import React from 'react';
|
|
29
|
+
import { Modal, Button } from '../../index.build';
|
|
30
|
+
import { Input } from 'antd';
|
|
31
|
+
var InputModal = function (_a) {
|
|
32
|
+
var onDoubleClick = _a.onDoubleClick, onChange = _a.onChange, onBlur = _a.onBlur, props = __rest(_a, ["onDoubleClick", "onChange", "onBlur"]);
|
|
33
|
+
var isDoubleClick = React.useRef(false);
|
|
34
|
+
var _b = React.useState(false), visible = _b[0], setVisible = _b[1];
|
|
35
|
+
var _c = React.useState(''), modalValue = _c[0], setModalValue = _c[1];
|
|
36
|
+
var isModalDisabled = React.useMemo(function () {
|
|
37
|
+
return props.disabled || props.readOnly;
|
|
38
|
+
}, [props.disabled, props.readOnly]);
|
|
39
|
+
var handleDoubleClick = function (e) {
|
|
40
|
+
if (onDoubleClick) {
|
|
41
|
+
onDoubleClick(e);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
isDoubleClick.current = true;
|
|
45
|
+
setVisible(true);
|
|
46
|
+
setModalValue(props.value);
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
var close = function () {
|
|
50
|
+
setVisible(false);
|
|
51
|
+
isDoubleClick.current = false;
|
|
52
|
+
};
|
|
53
|
+
var handleSure = function () {
|
|
54
|
+
// 模拟结构
|
|
55
|
+
var e = {
|
|
56
|
+
target: {
|
|
57
|
+
value: modalValue,
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
onChange && onChange(e);
|
|
61
|
+
onBlur && onBlur(e);
|
|
62
|
+
close();
|
|
63
|
+
};
|
|
64
|
+
var handleClear = function () {
|
|
65
|
+
setModalValue('');
|
|
66
|
+
};
|
|
67
|
+
var handleBlur = function (e) {
|
|
68
|
+
if (isDoubleClick.current)
|
|
69
|
+
return;
|
|
70
|
+
onBlur && onBlur(e.target.value);
|
|
71
|
+
};
|
|
72
|
+
return (React.createElement(React.Fragment, null,
|
|
73
|
+
React.createElement(Input, __assign({}, props, { onBlur: handleBlur, onDoubleClick: handleDoubleClick, onChange: function (e) { return onChange && onChange(e); } })),
|
|
74
|
+
React.createElement(Modal, { title: isModalDisabled ? i18next.t('内容') : i18next.t('请输入内容'), visible: visible, loading: false, destroyOnClose: true, onCancel: close, footer: isModalDisabled ? undefined : (React.createElement(React.Fragment, null,
|
|
75
|
+
React.createElement(Button, { onClick: handleClear }, i18next.t('清空内容')),
|
|
76
|
+
React.createElement(Button, { type: "primary", onClick: handleSure }, i18next.t('确认')))) },
|
|
77
|
+
React.createElement(Input.TextArea, { value: modalValue, readOnly: isModalDisabled, autoFocus: true, autoSize: { minRows: 10, maxRows: 50 }, onChange: function (e) { return setModalValue(e.target.value); } }))));
|
|
78
|
+
};
|
|
79
|
+
export default InputModal;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as useInputModal } from './useInputModal';
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface UseInputModalOptions {
|
|
3
|
+
/** 确认时的回调 */
|
|
4
|
+
onConfirm?: (value: string, event?: {
|
|
5
|
+
target: {
|
|
6
|
+
value: string;
|
|
7
|
+
};
|
|
8
|
+
}) => void;
|
|
9
|
+
/** 取消时的回调 */
|
|
10
|
+
onCancel?: () => void;
|
|
11
|
+
/** 是否禁用(只读模式) */
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
/** Modal 标题 */
|
|
14
|
+
title?: string;
|
|
15
|
+
/** TextArea 最小行数 */
|
|
16
|
+
minRows?: number;
|
|
17
|
+
/** TextArea 最大行数 */
|
|
18
|
+
maxRows?: number;
|
|
19
|
+
/** 是否使用事件模式(antd 风格,回调参数为 { target: { value } }) */
|
|
20
|
+
eventMode?: boolean;
|
|
21
|
+
}
|
|
22
|
+
export interface UseInputModalReturn {
|
|
23
|
+
/** 是否显示 Modal */
|
|
24
|
+
visible: boolean;
|
|
25
|
+
/** 当前 Modal 中的值 */
|
|
26
|
+
modalValue: string;
|
|
27
|
+
/** 是否为双击触发的打开(用于防止 onBlur 重复触发) */
|
|
28
|
+
isDoubleClick: React.MutableRefObject<boolean>;
|
|
29
|
+
/** 打开 Modal */
|
|
30
|
+
open: (initialValue?: string) => void;
|
|
31
|
+
/** 关闭 Modal */
|
|
32
|
+
close: () => void;
|
|
33
|
+
/** 设置 Modal 值 */
|
|
34
|
+
setModalValue: React.Dispatch<React.SetStateAction<string>>;
|
|
35
|
+
/** 清空 Modal 值 */
|
|
36
|
+
clearValue: () => void;
|
|
37
|
+
/** 确认操作 */
|
|
38
|
+
confirm: () => void;
|
|
39
|
+
/** 处理双击事件 */
|
|
40
|
+
handleDoubleClick: (e: React.MouseEvent, currentValue?: string) => void;
|
|
41
|
+
/** 处理失焦事件(自动跳过双击触发的情况) */
|
|
42
|
+
handleBlur: (e: React.FocusEvent | any, originalHandler?: (value: string | any) => void) => void;
|
|
43
|
+
/** 渲染 Modal 组件 */
|
|
44
|
+
renderModal: () => React.ReactNode;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* 输入弹窗 Hook
|
|
48
|
+
* @description 封装双击输入框弹出 Modal 编辑的功能
|
|
49
|
+
* @param options 配置选项
|
|
50
|
+
* @returns Modal 状态和操作方法
|
|
51
|
+
*/
|
|
52
|
+
declare function useInputModal(options?: UseInputModalOptions): UseInputModalReturn;
|
|
53
|
+
export default useInputModal;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import i18next from 'ztxkutils/dist/i18next';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Modal, Button, Input } from '../../../index.build';
|
|
4
|
+
/**
|
|
5
|
+
* 输入弹窗 Hook
|
|
6
|
+
* @description 封装双击输入框弹出 Modal 编辑的功能
|
|
7
|
+
* @param options 配置选项
|
|
8
|
+
* @returns Modal 状态和操作方法
|
|
9
|
+
*/
|
|
10
|
+
function useInputModal(options) {
|
|
11
|
+
if (options === void 0) { options = {}; }
|
|
12
|
+
var onConfirm = options.onConfirm, onCancel = options.onCancel, _a = options.disabled, disabled = _a === void 0 ? false : _a, title = options.title, _b = options.minRows, minRows = _b === void 0 ? 10 : _b, _c = options.maxRows, maxRows = _c === void 0 ? 50 : _c, _d = options.eventMode, eventMode = _d === void 0 ? false : _d;
|
|
13
|
+
var _e = React.useState(false), visible = _e[0], setVisible = _e[1];
|
|
14
|
+
var _f = React.useState(''), modalValue = _f[0], setModalValue = _f[1];
|
|
15
|
+
var isDoubleClick = React.useRef(false);
|
|
16
|
+
var open = React.useCallback(function (initialValue) {
|
|
17
|
+
setModalValue(initialValue !== null && initialValue !== void 0 ? initialValue : '');
|
|
18
|
+
isDoubleClick.current = true;
|
|
19
|
+
setVisible(true);
|
|
20
|
+
}, []);
|
|
21
|
+
var close = React.useCallback(function () {
|
|
22
|
+
setVisible(false);
|
|
23
|
+
isDoubleClick.current = false;
|
|
24
|
+
onCancel === null || onCancel === void 0 ? void 0 : onCancel();
|
|
25
|
+
}, [onCancel]);
|
|
26
|
+
var clearValue = React.useCallback(function () {
|
|
27
|
+
setModalValue('');
|
|
28
|
+
}, []);
|
|
29
|
+
var confirm = React.useCallback(function () {
|
|
30
|
+
if (eventMode) {
|
|
31
|
+
// 事件模式:模拟 antd 的 event 对象
|
|
32
|
+
var event_1 = {
|
|
33
|
+
target: {
|
|
34
|
+
value: modalValue,
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
onConfirm === null || onConfirm === void 0 ? void 0 : onConfirm(modalValue, event_1);
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
// 值模式:直接传递值
|
|
41
|
+
onConfirm === null || onConfirm === void 0 ? void 0 : onConfirm(modalValue);
|
|
42
|
+
}
|
|
43
|
+
setVisible(false);
|
|
44
|
+
}, [modalValue, onConfirm, eventMode]);
|
|
45
|
+
/**
|
|
46
|
+
* 处理双击事件
|
|
47
|
+
* @param e 鼠标事件
|
|
48
|
+
* @param currentValue 当前输入框的值
|
|
49
|
+
* @param originalHandler 原始的双击处理函数(如果存在则调用,否则打开 Modal)
|
|
50
|
+
*/
|
|
51
|
+
var handleDoubleClick = React.useCallback(function (e, currentValue) {
|
|
52
|
+
open(currentValue);
|
|
53
|
+
}, [open]);
|
|
54
|
+
/**
|
|
55
|
+
* 处理失焦事件
|
|
56
|
+
* @description 自动跳过双击触发的情况,避免 Modal 打开时触发失焦
|
|
57
|
+
* @param e 事件对象
|
|
58
|
+
* @param originalHandler 原始的失焦处理函数
|
|
59
|
+
*/
|
|
60
|
+
var handleBlur = React.useCallback(function (e, originalHandler) {
|
|
61
|
+
var _a;
|
|
62
|
+
// 如果是双击触发的打开,跳过 onBlur
|
|
63
|
+
if (isDoubleClick.current)
|
|
64
|
+
return;
|
|
65
|
+
if (originalHandler) {
|
|
66
|
+
// 根据事件模式决定传递的参数格式
|
|
67
|
+
if (eventMode) {
|
|
68
|
+
originalHandler(e);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
originalHandler((_a = e.target) === null || _a === void 0 ? void 0 : _a.value);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}, [eventMode]);
|
|
75
|
+
var renderModal = React.useCallback(function () {
|
|
76
|
+
return (React.createElement(Modal, { title: title !== null && title !== void 0 ? title : (disabled ? i18next.t('内容') : i18next.t('请输入内容')), visible: visible, loading: false, destroyOnClose: true, onCancel: close, footer: disabled ? undefined : (React.createElement(React.Fragment, null,
|
|
77
|
+
React.createElement(Button, { onClick: clearValue }, i18next.t('清空内容')),
|
|
78
|
+
React.createElement(Button, { type: "primary", onClick: confirm }, i18next.t('确认')))) },
|
|
79
|
+
React.createElement(Input.TextArea, { value: modalValue, readOnly: disabled, autoFocus: true, autoSize: { minRows: minRows, maxRows: maxRows }, onChange: function (e) { return setModalValue(e.target.value); } })));
|
|
80
|
+
}, [
|
|
81
|
+
visible,
|
|
82
|
+
modalValue,
|
|
83
|
+
disabled,
|
|
84
|
+
title,
|
|
85
|
+
minRows,
|
|
86
|
+
maxRows,
|
|
87
|
+
close,
|
|
88
|
+
clearValue,
|
|
89
|
+
confirm,
|
|
90
|
+
]);
|
|
91
|
+
return {
|
|
92
|
+
visible: visible,
|
|
93
|
+
modalValue: modalValue,
|
|
94
|
+
isDoubleClick: isDoubleClick,
|
|
95
|
+
open: open,
|
|
96
|
+
close: close,
|
|
97
|
+
setModalValue: setModalValue,
|
|
98
|
+
clearValue: clearValue,
|
|
99
|
+
confirm: confirm,
|
|
100
|
+
handleDoubleClick: handleDoubleClick,
|
|
101
|
+
handleBlur: handleBlur,
|
|
102
|
+
renderModal: renderModal,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
export default useInputModal;
|
|
@@ -29,8 +29,12 @@ import useLastest from '../utils/useLastest';
|
|
|
29
29
|
import InputQuill from './InputQuill';
|
|
30
30
|
import InputQuillRead from './InputQuillRead';
|
|
31
31
|
import InputModal from './InputModal';
|
|
32
|
+
import AntInputModal from './AntInputModal';
|
|
33
|
+
import { useTableContext } from '../Table/table-context';
|
|
34
|
+
import { useInputModal } from './hooks';
|
|
32
35
|
function Input(props) {
|
|
33
|
-
var doubleClickReadOnly = props.doubleClickReadOnly, onDoubleClick = props.onDoubleClick, onBlur = props.onBlur, isAsrInput = props.isAsrInput, asrCloseTime = props.asrCloseTime, _a = props.allowSpace, allowSpace = _a === void 0 ? false : _a, restProps = __rest(props, ["doubleClickReadOnly", "onDoubleClick", "onBlur", "isAsrInput", "asrCloseTime", "allowSpace"]);
|
|
36
|
+
var doubleClickReadOnly = props.doubleClickReadOnly, onDoubleClick = props.onDoubleClick, onBlur = props.onBlur, isAsrInput = props.isAsrInput, asrCloseTime = props.asrCloseTime, _a = props.allowSpace, allowSpace = _a === void 0 ? false : _a, isInputModal = props.isInputModal, restProps = __rest(props, ["doubleClickReadOnly", "onDoubleClick", "onBlur", "isAsrInput", "asrCloseTime", "allowSpace", "isInputModal"]);
|
|
37
|
+
var inTable = useTableContext().inTable;
|
|
34
38
|
var _b = useState(!!doubleClickReadOnly), readOnly = _b[0], setReadOnly = _b[1];
|
|
35
39
|
var onBlurHandle = function (e) {
|
|
36
40
|
if (doubleClickReadOnly) {
|
|
@@ -41,12 +45,6 @@ function Input(props) {
|
|
|
41
45
|
onBlur && onBlur(e);
|
|
42
46
|
props.onChange && props.onChange(e);
|
|
43
47
|
};
|
|
44
|
-
var onDoubleClickHandle = function (e) {
|
|
45
|
-
if (doubleClickReadOnly) {
|
|
46
|
-
setReadOnly(false);
|
|
47
|
-
}
|
|
48
|
-
onDoubleClick && onDoubleClick(e);
|
|
49
|
-
};
|
|
50
48
|
// 阻止在input设置allowClear后,在input外部鼠标点击,然后移入input框中松开鼠标时候,input框会聚焦
|
|
51
49
|
var onMouseUpHandle = function (e) {
|
|
52
50
|
e === null || e === void 0 ? void 0 : e.stopPropagation();
|
|
@@ -60,9 +58,29 @@ function Input(props) {
|
|
|
60
58
|
// 受控模式
|
|
61
59
|
onChangeLastest.current && onChangeLastest.current(e);
|
|
62
60
|
}, [onChangeLastest]);
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
61
|
+
var showInputModal = isInputModal || inTable;
|
|
62
|
+
var inputModal = useInputModal({
|
|
63
|
+
disabled: props.disabled || props.readOnly,
|
|
64
|
+
eventMode: true,
|
|
65
|
+
onConfirm: function (value, event) {
|
|
66
|
+
// 受控模式
|
|
67
|
+
onChangeLastest.current && onChangeLastest.current(event);
|
|
68
|
+
},
|
|
69
|
+
});
|
|
70
|
+
var onDoubleClickHandle = function (e) {
|
|
71
|
+
if (doubleClickReadOnly) {
|
|
72
|
+
setReadOnly(false);
|
|
73
|
+
}
|
|
74
|
+
if (showInputModal) {
|
|
75
|
+
inputModal.handleDoubleClick(e, props.value);
|
|
76
|
+
}
|
|
77
|
+
onDoubleClick && onDoubleClick(e);
|
|
78
|
+
};
|
|
79
|
+
return (React.createElement(React.Fragment, null,
|
|
80
|
+
isAsrInput && !props.readOnly && !props.disabled ? (React.createElement("div", { className: "asr-input", style: { display: 'inline-block' } },
|
|
81
|
+
React.createElement(Asr, { recordTextCallback: recordTextCallback, timeout: asrCloseTime, className: "asr-input--btn" }),
|
|
82
|
+
React.createElement(AntInput, __assign({ onMouseUp: onMouseUpHandle, onBlur: onBlurHandle, onDoubleClick: onDoubleClickHandle, readOnly: readOnly }, restProps)))) : (React.createElement(AntInput, __assign({ onMouseUp: onMouseUpHandle, onBlur: onBlurHandle, onDoubleClick: onDoubleClickHandle, readOnly: readOnly }, restProps))),
|
|
83
|
+
showInputModal && inputModal.renderModal()));
|
|
66
84
|
}
|
|
67
85
|
var TextArea = React.forwardRef(function (props, ref) {
|
|
68
86
|
var _a = props.handleSize, handleSize = _a === void 0 ? true : _a, _b = props.autoSize, autoSize = _b === void 0 ? true : _b, className = props.className, isAsrInput = props.isAsrInput, asrCloseTime = props.asrCloseTime, resetProps = __rest(props, ["handleSize", "autoSize", "className", "isAsrInput", "asrCloseTime"]);
|
|
@@ -125,4 +143,5 @@ Input.Password = AntInput.Password;
|
|
|
125
143
|
Input.Quill = InputQuill;
|
|
126
144
|
Input.QuillRead = InputQuillRead;
|
|
127
145
|
Input.Modal = InputModal;
|
|
146
|
+
Input.AntInputModal = AntInputModal;
|
|
128
147
|
export default Input;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// 监听是否摁下ctrl键
|
|
2
|
+
import { useRef, useEffect, useCallback } from 'react';
|
|
3
|
+
export default function useCtrl() {
|
|
4
|
+
var ctrlKeyPressedRef = useRef(false);
|
|
5
|
+
var getCtrlKeyPressed = useCallback(function (e) {
|
|
6
|
+
return e.ctrlKey || e.metaKey;
|
|
7
|
+
}, []);
|
|
8
|
+
// 监听 Ctrl 键状态
|
|
9
|
+
useEffect(function () {
|
|
10
|
+
var handleKeyDown = function (e) {
|
|
11
|
+
if (getCtrlKeyPressed(e)) {
|
|
12
|
+
ctrlKeyPressedRef.current = true;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
var handleKeyUp = function (e) {
|
|
16
|
+
if (!getCtrlKeyPressed(e)) {
|
|
17
|
+
ctrlKeyPressedRef.current = false;
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
21
|
+
document.addEventListener('keyup', handleKeyUp);
|
|
22
|
+
return function () {
|
|
23
|
+
document.removeEventListener('keydown', handleKeyDown);
|
|
24
|
+
document.removeEventListener('keyup', handleKeyUp);
|
|
25
|
+
};
|
|
26
|
+
}, []);
|
|
27
|
+
return {
|
|
28
|
+
ctrlKeyPressedRef: ctrlKeyPressedRef,
|
|
29
|
+
getCtrlKeyPressed: getCtrlKeyPressed,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -2,8 +2,10 @@ import i18next from 'ztxkutils/dist/i18next';
|
|
|
2
2
|
import { useRef } from 'react';
|
|
3
3
|
import { useDrag, useDrop } from 'react-dnd';
|
|
4
4
|
import { tableDragRowType } from '../constants';
|
|
5
|
+
import useCtrl from './useCtrl';
|
|
5
6
|
function useDropRef(index, moverow) {
|
|
6
7
|
var ref = useRef(null);
|
|
8
|
+
var ctrlKeyPressedRef = useCtrl().ctrlKeyPressedRef;
|
|
7
9
|
/**
|
|
8
10
|
* @description 定义拖拽项
|
|
9
11
|
*/
|
|
@@ -13,7 +15,14 @@ function useDropRef(index, moverow) {
|
|
|
13
15
|
collect: function (monitor) { return ({
|
|
14
16
|
isDragging: monitor.isDragging(),
|
|
15
17
|
}); },
|
|
16
|
-
canDrag: function (
|
|
18
|
+
canDrag: function () {
|
|
19
|
+
var _a;
|
|
20
|
+
// 如果摁下了ctrl键 不可以拖拽行
|
|
21
|
+
if (ctrlKeyPressedRef.current) {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
return !((_a = document.activeElement) === null || _a === void 0 ? void 0 : _a.tagName.toLowerCase().match(/input|textarea/));
|
|
25
|
+
},
|
|
17
26
|
}); }, [index]), drag = _a[1];
|
|
18
27
|
/**
|
|
19
28
|
* @description 定义可放置项
|
|
@@ -3,10 +3,12 @@ import { useRef, useEffect, useCallback } from 'react';
|
|
|
3
3
|
import { domFind, domParentsUntil } from '../utils/dom';
|
|
4
4
|
import { plus } from 'number-precision';
|
|
5
5
|
import { copyValueHandle } from '../../utils/index';
|
|
6
|
+
import useCtrl from './useCtrl';
|
|
6
7
|
export default function useSelectSubtotal(tableRef, props) {
|
|
7
8
|
var onMoveRow = props.onMoveRow, onEditableSave = props.onEditableSave;
|
|
8
9
|
var tipRef = useRef();
|
|
9
10
|
var rowResultRef = useRef();
|
|
11
|
+
var getCtrlKeyPressed = useCtrl().getCtrlKeyPressed;
|
|
10
12
|
// 找到每个单元格实际对应的坐标
|
|
11
13
|
var cellPosition = useCallback(function (container) {
|
|
12
14
|
console.time(i18next.t('开始计算耗时'));
|
|
@@ -88,9 +90,9 @@ export default function useSelectSubtotal(tableRef, props) {
|
|
|
88
90
|
// // eslint-disable-next-line react-hooks/exhaustive-deps
|
|
89
91
|
// }, [dataSource, cellPosition]);
|
|
90
92
|
useEffect(function () {
|
|
91
|
-
if (onMoveRow || onEditableSave) {
|
|
92
|
-
|
|
93
|
-
}
|
|
93
|
+
// if (onMoveRow || onEditableSave) {
|
|
94
|
+
// return;
|
|
95
|
+
// }
|
|
94
96
|
var tableContent = domFind(tableRef.current, '.ant-table-content');
|
|
95
97
|
if (!tableContent) {
|
|
96
98
|
tableContent = domFind(tableRef.current, '.ant-table-container');
|
|
@@ -108,13 +110,18 @@ export default function useSelectSubtotal(tableRef, props) {
|
|
|
108
110
|
}
|
|
109
111
|
var mousedownHandler = function (e) {
|
|
110
112
|
var _a;
|
|
113
|
+
// 当编辑模式时,需要摁下ctrl键才可以复制。
|
|
114
|
+
if ((onMoveRow || onEditableSave) && !getCtrlKeyPressed(e)) {
|
|
115
|
+
clearSelections(); // 清除之前的选择
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
111
118
|
// 这里要判断如果最上层是TD也行
|
|
112
119
|
var target = ((_a = e.target) === null || _a === void 0 ? void 0 : _a.tagName) === 'TD' ? e.target : domParentsUntil(e.target, 'td');
|
|
113
120
|
if ((target === null || target === void 0 ? void 0 : target.tagName) === 'TD') {
|
|
114
121
|
isDragging = true;
|
|
115
122
|
startCell = target;
|
|
116
123
|
// 是否按下ctrl键 可以选取多段内容
|
|
117
|
-
if (!e
|
|
124
|
+
if (!getCtrlKeyPressed(e)) {
|
|
118
125
|
clearSelections();
|
|
119
126
|
}
|
|
120
127
|
}
|
|
@@ -153,7 +160,7 @@ export default function useSelectSubtotal(tableRef, props) {
|
|
|
153
160
|
}
|
|
154
161
|
}
|
|
155
162
|
// 是否按下ctrl键
|
|
156
|
-
if (!e
|
|
163
|
+
if (!getCtrlKeyPressed(e)) {
|
|
157
164
|
container.classList.remove('table-select-none');
|
|
158
165
|
}
|
|
159
166
|
};
|
|
@@ -164,7 +171,7 @@ export default function useSelectSubtotal(tableRef, props) {
|
|
|
164
171
|
lastEndCell = e.target;
|
|
165
172
|
if (startCell !== lastEndCell) {
|
|
166
173
|
container.classList.add('table-select-none');
|
|
167
|
-
var isCtrl = e
|
|
174
|
+
var isCtrl = getCtrlKeyPressed(e);
|
|
168
175
|
selectCells(startCell, e.target, isCtrl); // 仅在必要时更新选择
|
|
169
176
|
}
|
|
170
177
|
}
|
|
@@ -172,7 +179,7 @@ export default function useSelectSubtotal(tableRef, props) {
|
|
|
172
179
|
};
|
|
173
180
|
container.addEventListener('mousemove', mousemoveHandler);
|
|
174
181
|
var selectCells = function (start, end, isCtrl) {
|
|
175
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
182
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
|
|
176
183
|
if (!isCtrl) {
|
|
177
184
|
clearSelections(); // 清除之前的选择
|
|
178
185
|
}
|
|
@@ -206,25 +213,31 @@ export default function useSelectSubtotal(tableRef, props) {
|
|
|
206
213
|
var lenRow = Math.max(startRow, endRow);
|
|
207
214
|
var initCell = Math.min(startCol, endCol);
|
|
208
215
|
var lenCell = Math.max(startCol, endCol);
|
|
216
|
+
// 标记当前选择区域的单元格为选中状态
|
|
209
217
|
for (var i = initRow; i <= lenRow; i++) {
|
|
210
|
-
var positionArr = [];
|
|
211
218
|
for (var j = initCell; j <= lenCell; j++) {
|
|
212
|
-
// const $td = container.rows[i]?.cells[j];
|
|
213
219
|
var $td = (_f = (_e = rowResult[i - 1]) === null || _e === void 0 ? void 0 : _e[j]) === null || _f === void 0 ? void 0 : _f.td;
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
220
|
+
(_g = $td === null || $td === void 0 ? void 0 : $td.classList) === null || _g === void 0 ? void 0 : _g.add('move-selected');
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
// 重新构建 textArr 和 textPositionArr(基于所有已选中的单元格)
|
|
224
|
+
textArr = [];
|
|
225
|
+
textPositionArr = [];
|
|
226
|
+
// 遍历所有单元格,按行组织已选中的单元格
|
|
227
|
+
var rowsCount = rowResult.length;
|
|
228
|
+
var colsCount = ((_h = rowResult[0]) === null || _h === void 0 ? void 0 : _h.length) || 0;
|
|
229
|
+
for (var i = 0; i < rowsCount; i++) {
|
|
230
|
+
var rowPositionArr = [];
|
|
231
|
+
for (var j = 0; j < colsCount; j++) {
|
|
232
|
+
var $td = (_k = (_j = rowResult[i]) === null || _j === void 0 ? void 0 : _j[j]) === null || _k === void 0 ? void 0 : _k.td;
|
|
233
|
+
if ($td && $td.classList.contains('move-selected')) {
|
|
234
|
+
var innerText = getCellValue($td);
|
|
221
235
|
textArr.push(innerText);
|
|
222
|
-
|
|
236
|
+
rowPositionArr.push(innerText);
|
|
223
237
|
}
|
|
224
|
-
(_g = $td === null || $td === void 0 ? void 0 : $td.classList) === null || _g === void 0 ? void 0 : _g.add('move-selected');
|
|
225
238
|
}
|
|
226
|
-
if (
|
|
227
|
-
textPositionArr.push(
|
|
239
|
+
if (rowPositionArr.length > 0) {
|
|
240
|
+
textPositionArr.push(rowPositionArr);
|
|
228
241
|
}
|
|
229
242
|
}
|
|
230
243
|
};
|
|
@@ -244,6 +257,7 @@ export default function useSelectSubtotal(tableRef, props) {
|
|
|
244
257
|
var isCtrlPressed = event.ctrlKey || event.metaKey;
|
|
245
258
|
// 如果同时按下了Ctrl/Cmd键和C键,则执行你的复制操作
|
|
246
259
|
if (isCtrlPressed && isCKey && textPositionArr.length > 0) {
|
|
260
|
+
console.log('复制文本textPositionArr', textPositionArr);
|
|
247
261
|
// 执行你的复制操作,例如将文本添加到剪贴板
|
|
248
262
|
var textToCopy = textPositionArr
|
|
249
263
|
.map(function (row) { return row.join('\t'); })
|
|
@@ -304,3 +318,52 @@ function sumArrayValues(arr) {
|
|
|
304
318
|
}
|
|
305
319
|
return sum;
|
|
306
320
|
}
|
|
321
|
+
/**
|
|
322
|
+
* 判断传入的dom元素中的值
|
|
323
|
+
* 一种情况就是直接通过innerText获取
|
|
324
|
+
* 另外一种就是通过输入框获取
|
|
325
|
+
* @param td 表格单元格元素
|
|
326
|
+
* @returns 单元格中的文本值
|
|
327
|
+
*/
|
|
328
|
+
function getCellValue(td) {
|
|
329
|
+
var _a, _b, _c, _d;
|
|
330
|
+
if (!td) {
|
|
331
|
+
return '';
|
|
332
|
+
}
|
|
333
|
+
try {
|
|
334
|
+
// 查找 antd Select 显示的值
|
|
335
|
+
var antdSelect = td.querySelector('.ant-select-selection-item');
|
|
336
|
+
if (antdSelect) {
|
|
337
|
+
return (_a = antdSelect.textContent) !== null && _a !== void 0 ? _a : '';
|
|
338
|
+
}
|
|
339
|
+
// 优先查找输入框元素的值
|
|
340
|
+
var inputElement = td.querySelector('input, textarea');
|
|
341
|
+
if (inputElement) {
|
|
342
|
+
return (_b = inputElement.value) !== null && _b !== void 0 ? _b : '';
|
|
343
|
+
}
|
|
344
|
+
// 查找带 contenteditable 属性的元素
|
|
345
|
+
var editableElement = td.querySelector('[contenteditable="true"]');
|
|
346
|
+
if (editableElement && editableElement.innerText !== undefined) {
|
|
347
|
+
return editableElement.innerText;
|
|
348
|
+
}
|
|
349
|
+
// 查找 antd 相关组件的输入值
|
|
350
|
+
var antdInput = td.querySelector('.ant-input, .ant-input-number-input');
|
|
351
|
+
if (antdInput) {
|
|
352
|
+
if ('value' in antdInput) {
|
|
353
|
+
return (_c = antdInput.value) !== null && _c !== void 0 ? _c : '';
|
|
354
|
+
}
|
|
355
|
+
return (_d = antdInput.textContent) !== null && _d !== void 0 ? _d : '';
|
|
356
|
+
}
|
|
357
|
+
// 默认通过 innerText 获取
|
|
358
|
+
var innerText = td.innerText;
|
|
359
|
+
if (innerText !== undefined && innerText !== null) {
|
|
360
|
+
// 去除 "复制" 等后缀文字
|
|
361
|
+
return innerText.replace(/\s+复制/g, '').trim();
|
|
362
|
+
}
|
|
363
|
+
return '';
|
|
364
|
+
}
|
|
365
|
+
catch (error) {
|
|
366
|
+
console.error(i18next.t('获取单元格值失败'), error);
|
|
367
|
+
return '';
|
|
368
|
+
}
|
|
369
|
+
}
|
|
@@ -31,6 +31,12 @@ export interface IEditableConfig {
|
|
|
31
31
|
precisionHandle?: (record: any) => number;
|
|
32
32
|
[props: string]: any;
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* 将带有千分符、货币符号、百分号的字符串转换成数字
|
|
36
|
+
* @param value 待转换的字符串,如 "14,855.00"、"$1,234.56"、"50%"
|
|
37
|
+
* @returns 转换后的数字,转换失败返回 NaN
|
|
38
|
+
*/
|
|
39
|
+
export declare function parseStringToNumber(value: string): number;
|
|
34
40
|
/**
|
|
35
41
|
* 数据转换 将粘贴过来的数据格式化处理
|
|
36
42
|
*/
|
|
@@ -65,11 +65,59 @@ import { ERROR_TD_CLASSNAME } from './index';
|
|
|
65
65
|
import { getInnerIndex } from './hooks/useInnerPagination';
|
|
66
66
|
import { exactRound } from 'ztxkutils/dist/tools';
|
|
67
67
|
import { INNER_PARENT_ROW_KEY_NO, INNER_PARENT_ROW_KEY } from './constants';
|
|
68
|
+
/**
|
|
69
|
+
* 将带有千分符、货币符号、百分号的字符串转换成数字
|
|
70
|
+
* @param value 待转换的字符串,如 "14,855.00"、"$1,234.56"、"50%"
|
|
71
|
+
* @returns 转换后的数字,转换失败返回 NaN
|
|
72
|
+
*/
|
|
73
|
+
export function parseStringToNumber(value) {
|
|
74
|
+
if (typeof value !== 'string') {
|
|
75
|
+
return NaN;
|
|
76
|
+
}
|
|
77
|
+
try {
|
|
78
|
+
// 去除首尾空格
|
|
79
|
+
var str = value.trim();
|
|
80
|
+
// 如果是空字符串,返回 NaN
|
|
81
|
+
if (!str) {
|
|
82
|
+
return NaN;
|
|
83
|
+
}
|
|
84
|
+
// 记录是否为百分比
|
|
85
|
+
var isPercent = false;
|
|
86
|
+
if (str.endsWith('%')) {
|
|
87
|
+
isPercent = true;
|
|
88
|
+
str = str.slice(0, -1).trim();
|
|
89
|
+
}
|
|
90
|
+
// 移除千分符(逗号)和货币符号
|
|
91
|
+
// 千分符的逗号只出现在数字之间,小数点前的逗号
|
|
92
|
+
str = str.replace(/,/g, '');
|
|
93
|
+
// 移除常见货币符号
|
|
94
|
+
str = str.replace(/^[¥$€£¥]+\s*/g, '');
|
|
95
|
+
// 移除可能存在的空格
|
|
96
|
+
str = str.trim();
|
|
97
|
+
// 尝试转换为数字
|
|
98
|
+
var num = parseFloat(str);
|
|
99
|
+
if (isNaN(num)) {
|
|
100
|
+
return NaN;
|
|
101
|
+
}
|
|
102
|
+
// 如果是百分比,需要除以 100
|
|
103
|
+
return isPercent ? num / 100 : num;
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
console.error(i18next.t('数字转换失败'), error);
|
|
107
|
+
return NaN;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
68
110
|
/**
|
|
69
111
|
* 数据转换 将粘贴过来的数据格式化处理
|
|
70
112
|
*/
|
|
71
113
|
export function transformData(data, config) {
|
|
72
114
|
var newData = data;
|
|
115
|
+
// 如果newData能转换成数字,就转换成数字
|
|
116
|
+
// 如果newData不能转换成数字,不做处理
|
|
117
|
+
var parsedNumber = parseStringToNumber(newData);
|
|
118
|
+
if (!isNaN(parsedNumber)) {
|
|
119
|
+
newData = parsedNumber;
|
|
120
|
+
}
|
|
73
121
|
if (!config) {
|
|
74
122
|
return newData;
|
|
75
123
|
}
|
|
@@ -296,7 +344,7 @@ var TableEnhanceCell = function (_a) {
|
|
|
296
344
|
return null;
|
|
297
345
|
}
|
|
298
346
|
if (!editableConfig) {
|
|
299
|
-
return (React.createElement(
|
|
347
|
+
return (React.createElement(ZtInput.AntInputModal, { autoComplete: "new-password", maxLength: 50, onPressEnter: save, onBlur: save, allowClear: true, onPaste: onPasteHandle, value: val, onMouseUp: function (e) {
|
|
300
348
|
e === null || e === void 0 ? void 0 : e.stopPropagation();
|
|
301
349
|
},
|
|
302
350
|
// draggable
|
|
@@ -306,11 +354,12 @@ var TableEnhanceCell = function (_a) {
|
|
|
306
354
|
// e?.nativeEvent?.stopImmediatePropagation?.();
|
|
307
355
|
// }}
|
|
308
356
|
onChange: function (e) {
|
|
357
|
+
var _a, _b;
|
|
309
358
|
setVal(e.target.value);
|
|
310
359
|
removeErrorClass();
|
|
311
360
|
valueRef.current[dataIndex] = e.target.value;
|
|
312
361
|
if (!e.target.value) {
|
|
313
|
-
e.target.focus();
|
|
362
|
+
(_b = (_a = e.target).focus) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
314
363
|
}
|
|
315
364
|
} }));
|
|
316
365
|
}
|
|
@@ -453,7 +502,7 @@ var TableEnhanceCell = function (_a) {
|
|
|
453
502
|
} })));
|
|
454
503
|
}
|
|
455
504
|
else {
|
|
456
|
-
return (React.createElement(
|
|
505
|
+
return (React.createElement(ZtInput.AntInputModal, __assign({ autoComplete: "new-password", maxLength: 50 }, editableProps, { disabled: disabledResult, onPressEnter: save, onBlur: save, allowClear: true, onPaste: onPasteHandle, value: val, onMouseUp: function (e) {
|
|
457
506
|
e === null || e === void 0 ? void 0 : e.stopPropagation();
|
|
458
507
|
},
|
|
459
508
|
// draggable
|
|
@@ -463,11 +512,12 @@ var TableEnhanceCell = function (_a) {
|
|
|
463
512
|
// e?.nativeEvent?.stopImmediatePropagation?.();
|
|
464
513
|
// }}
|
|
465
514
|
onChange: function (e) {
|
|
515
|
+
var _a, _b;
|
|
466
516
|
setVal(e.target.value);
|
|
467
517
|
valueRef.current[dataIndex] = e.target.value;
|
|
468
518
|
removeErrorClass();
|
|
469
|
-
if (!e.target.value) {
|
|
470
|
-
e.target.focus();
|
|
519
|
+
if (!e.target.value && e.target.focus) {
|
|
520
|
+
(_b = (_a = e.target).focus) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
471
521
|
}
|
|
472
522
|
} })));
|
|
473
523
|
}
|