@bchr/bchr-front-lib 0.5.9 → 0.5.10

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.
@@ -0,0 +1,144 @@
1
+ import React, {Fragment} from "react";
2
+ import InputRefAddonBtn from "./InputRefAddonBtn";
3
+ import {Form, Input} from "antd";
4
+ import {Values} from "../utils";
5
+ import Strings from "../utils/Strings";
6
+ import lodash from "lodash";
7
+
8
+ class FormRefInput extends React.Component {
9
+ constructor(props) {
10
+ super(props);
11
+ this.modalRef = React.createRef();
12
+ }
13
+
14
+ buildHiddenFieldNames = (field) => {
15
+ if (Values.isBlankString(field)) {
16
+ throw new Error("参照输入控件缺少【field】关键属性");
17
+ }
18
+
19
+ if (field.endsWith("_ext_name")) {
20
+ let index = field.indexOf("_ext_name");
21
+ let fieldPrefix = field.substring(0, index)
22
+ return [fieldPrefix + "_pk", fieldPrefix + "_ext_code"];
23
+ }
24
+ else if (field.endsWith("_name")) {
25
+ let index = field.indexOf("_name");
26
+ let fieldPrefix = field.substring(0, index)
27
+ return [fieldPrefix + "_pk", fieldPrefix + "_code"];
28
+ }
29
+ else if (field.endsWith("_ext_names")) {
30
+ let index = field.indexOf("_ext_names");
31
+ let fieldPrefix = field.substring(0, index)
32
+ return [fieldPrefix + "_pks", fieldPrefix + "_codes"];
33
+ }
34
+ else {
35
+ throw new Error("参照输入控件缺少【field】关键属性的名称需要以【_ext_name】结尾");
36
+ }
37
+ }
38
+
39
+ onOk = (selectedData) => {
40
+ const {multiple, field, formRef, okCallback} = this.props;
41
+
42
+ if (formRef && formRef.current) {
43
+ let [field_pk, field_code] = this.buildHiddenFieldNames(field);
44
+ const {setFieldsValue, resetFields} = formRef.current;
45
+
46
+ resetFields([field]);
47
+
48
+ if (!multiple) {
49
+ setFieldsValue(field, selectedData[0].name);
50
+ setFieldsValue(field_pk, selectedData[0].pk);
51
+ setFieldsValue(field_code, selectedData[0].code);
52
+ } else {
53
+ let fieldNameData = [];
54
+ let fieldPkData = [];
55
+ let fieldCodeData = [];
56
+
57
+ selectedData.forEach(item => {
58
+ fieldNameData.push(item.name);
59
+ fieldPkData.push(item.pk);
60
+ fieldCodeData.push(item.code);
61
+ })
62
+
63
+ setFieldsValue(field_pk, fieldPkData.join(','));
64
+ setFieldsValue(field_code, fieldCodeData.join(','));
65
+ setFieldsValue(field, fieldNameData.join(','));
66
+ }
67
+ }
68
+
69
+ if (okCallback && typeof okCallback === 'function') {
70
+ if (!multiple) {
71
+ okCallback(selectedData[0]);
72
+ } else {
73
+ okCallback(selectedData);
74
+ }
75
+ }
76
+ }
77
+
78
+ onClear = () => {
79
+ const {field, formRef, clearCallback} = this.props;
80
+ const {setFieldsValue} = formRef.current;
81
+ let [field_pk, field_code] = this.buildHiddenFieldNames(field);
82
+
83
+ setFieldsValue(field_pk, null);
84
+ setFieldsValue(field_code, null);
85
+ setFieldsValue(field, null);
86
+
87
+ if (clearCallback && typeof clearCallback === 'function') {
88
+ clearCallback(null);
89
+ }
90
+ }
91
+
92
+ render() {
93
+ let inputProps = {...this.props};
94
+ let {
95
+ disabled, refCode, refDialogWidth,refDialogClassName,
96
+ refDialogHeight, field, multiple,
97
+ isNotData, customGridData, customRefUIConfig,
98
+ onBeforeClick
99
+ } = inputProps;
100
+
101
+ delete inputProps.addonAfter;
102
+ delete inputProps.refCode;
103
+ delete inputProps.refDialogWidth;
104
+ delete inputProps.refDialogHeight;
105
+ delete inputProps.refDialogClassName;
106
+ delete inputProps.formRef;
107
+ delete inputProps.multiple;
108
+ delete inputProps.okCallback;
109
+ delete inputProps.isNotData;
110
+ delete inputProps.customGridData;
111
+ delete inputProps.customRefUIConfig;
112
+ delete inputProps.onBeforeClick;
113
+
114
+ if (lodash.isPlainObject(refCode) && Strings.isNotBlankString(refCode.dictCode)) {
115
+ refCode = refCode.dictCode
116
+ }
117
+
118
+ let [field_pk, field_code] = this.buildHiddenFieldNames(field);
119
+
120
+ return <Fragment>
121
+ {field_pk && <input type={"hidden"} name={field_pk}></input>}
122
+ {field_code && <input type={"hidden"} name={field_code}></input>}
123
+ <Form.Item {...inputProps} className={`form-ref-input ${inputProps.className || ''}`}>
124
+ <Input readOnly={true}
125
+ allowClear={true}
126
+ onChange={this.onClear}
127
+ addonAfter={!disabled && <InputRefAddonBtn ref={this.modalRef}
128
+ isNotData={isNotData}
129
+ customGridData={customGridData}
130
+ customRefUIConfig={customRefUIConfig}
131
+ refCode={refCode}
132
+ multiple={multiple}
133
+ onOk={this.onOk}
134
+ onBeforeClick={onBeforeClick}
135
+ refDialogClassName={refDialogClassName}
136
+ refDialogWidth={refDialogWidth}
137
+ refDialogHeight={refDialogHeight}/>}/>
138
+ </Form.Item>
139
+ </Fragment>
140
+ }
141
+
142
+ }
143
+
144
+ export default FormRefInput;
@@ -0,0 +1,329 @@
1
+ import React from "react";
2
+ import {Checkbox, Empty, Modal, Radio, Spin} from "antd";
3
+ import {Grid, GridColumn} from "@progress/kendo-react-grid";
4
+ import lodash from "lodash";
5
+ import {process} from "@progress/kendo-data-query";
6
+ import {KendoGridFilterCellRender, KendoGridRowNumberCellRender} from "./KendoGridCellRenders";
7
+ import Values from "../utils/Values";
8
+ import {buildQueryParameters} from "../utils/TableDataProcessors";
9
+ import {loadingTips} from "../BaseAppUtils";
10
+ import http from "../../services/http";
11
+
12
+ class GridSelectModal extends React.Component {
13
+ constructor(props) {
14
+ super(props);
15
+ let {refUIConfig, refCode} = props;
16
+ this.state = {
17
+ visible: false,
18
+ loading: true,
19
+ gridColumns: refUIConfig?.gridColumns,
20
+ gridData: [],
21
+ total: 0,
22
+ gridSelectedData: [],
23
+ checkedAll: false,
24
+ checkedIndeterminate: false,
25
+ gridOperator: {
26
+ skip: 0,
27
+ take: 20
28
+ }
29
+ }
30
+ this.showModal = this.showModal.bind(this);
31
+ this.hideModal = this.hideModal.bind(this);
32
+ this.queryRefData = this.queryRefData.bind(this);
33
+ }
34
+
35
+ componentDidMount() {
36
+ this.queryRefData();
37
+ }
38
+
39
+ async queryRefData() {
40
+ try {
41
+ let {refCode, isNotData, customGridData, refUIConfig} = this.props;
42
+ let {gridOperator} = this.state;
43
+
44
+ if (isNotData) {
45
+ this.setState({
46
+ gridData: customGridData || []
47
+ })
48
+ } else {
49
+ let pageQueryParameters = buildQueryParameters(gridOperator);
50
+
51
+ let result = await http.postJSON('queryRefData?ref_code=' + refCode, pageQueryParameters);
52
+
53
+ let gridData;
54
+ let total;
55
+ if (refUIConfig.pageable) {
56
+ gridData = result.data || [];
57
+ total = result.total || 0;
58
+ } else {
59
+ gridData = result || [];
60
+ total = result.length;
61
+ }
62
+
63
+ this.setState({
64
+ gridData,
65
+ total
66
+ })
67
+ }
68
+ } catch (e) {
69
+ this.dealAjaxException(e);
70
+ } finally {
71
+ this.setState({
72
+ loading: false
73
+ })
74
+ }
75
+ }
76
+
77
+ showModal() {
78
+ this.setState({
79
+ visible: true
80
+ })
81
+ }
82
+
83
+ hideModal() {
84
+ this.setState({
85
+ visible: false
86
+ })
87
+ }
88
+
89
+ onGridSelectModalOk = () => {
90
+ let {onOk} = this.props;
91
+ let {gridSelectedData} = this.state;
92
+ if (onOk && typeof onOk === 'function') {
93
+ onOk(gridSelectedData)
94
+ }
95
+ }
96
+
97
+ onDataStateChange(e) {
98
+ let {refUIConfig} = this.props;
99
+ let {gridData, total, loading} = this.state;
100
+
101
+ let pageable = refUIConfig?.pageable;
102
+ if (pageable) {
103
+ gridData = [];
104
+ total = 0;
105
+ loading = true;
106
+ }
107
+
108
+ this.setState({
109
+ gridData,
110
+ total,
111
+ loading,
112
+ gridOperator: e.dataState,
113
+ }, () => {
114
+ if (refUIConfig.pageable) {
115
+ this.queryRefData();
116
+ }
117
+ });
118
+ }
119
+
120
+ onGridHeaderSelectionChange = (e) => {
121
+ let {checkedAll, gridSelectedData} = this.state;
122
+ const checked = !!e.target.checked;
123
+ let gridData = this.state.gridData;
124
+
125
+ if (gridData && gridData.length > 0) {
126
+ gridData.forEach(dataItem => dataItem.selected = checked);
127
+ gridSelectedData = [...gridData.filter(dataItem => dataItem.selected)];
128
+ checkedAll = gridData.length === gridSelectedData.length;
129
+ } else {
130
+ checkedAll = true;
131
+ }
132
+
133
+ this.setState({
134
+ gridData,
135
+ gridSelectedData,
136
+ checkedAll,
137
+ checkedIndeterminate: false,
138
+ })
139
+ }
140
+
141
+ onGridRowSelectionChange = (e) => {
142
+ let {checkedAll, checkedIndeterminate, gridSelectedData} = this.state;
143
+ let selectedRowData = e.dataItem;
144
+ selectedRowData.selected = !selectedRowData.selected;
145
+ let gridData = this.state.gridData;
146
+
147
+ if (gridData && gridData.length > 0) {
148
+ gridData.forEach(dataItem => {
149
+ if (dataItem.pk === selectedRowData.pk) {
150
+ dataItem.selected = selectedRowData.selected;
151
+ }
152
+ });
153
+ gridSelectedData = [...gridData.filter(dataItem => dataItem.selected)];
154
+ checkedAll = gridData.length === gridSelectedData.length;
155
+ checkedIndeterminate = gridSelectedData.length && gridData.length !== gridSelectedData.length;
156
+ } else {
157
+ checkedAll = false;
158
+ checkedIndeterminate = false;
159
+ }
160
+
161
+ this.setState({
162
+ gridData,
163
+ gridSelectedData,
164
+ checkedAll,
165
+ checkedIndeterminate,
166
+ })
167
+ }
168
+
169
+ onRadioGridRowSelectionChange(state, e) {
170
+ let event = null;
171
+ let gridSelectedData = [];
172
+ if (lodash.isObject(state)) {
173
+ event = state;
174
+ } else {
175
+ event = e;
176
+ }
177
+
178
+ let selectedRowData = event.dataItem;
179
+ selectedRowData.selected = !selectedRowData.selected;
180
+ let gridData = this.state.gridData;
181
+
182
+ if (gridData && gridData.length > 0) {
183
+ gridData.forEach(dataItem => {
184
+ dataItem.selected = dataItem.pk === selectedRowData.pk;
185
+ })
186
+ gridSelectedData = [...gridData.filter(dataItem => dataItem.selected)];
187
+ }
188
+
189
+ this.setState({
190
+ gridData,
191
+ gridSelectedData
192
+ }, () => {
193
+ if (state && !lodash.isObject(state)) {
194
+ let {onOk} = this.props;
195
+ if (onOk && typeof onOk === 'function') {
196
+ onOk(gridSelectedData)
197
+ }
198
+ }
199
+ })
200
+ }
201
+
202
+ buildGridColumns = (gridColumns) => {
203
+ if (!gridColumns || !gridColumns.length) {
204
+ return <Empty image={<span className="iconfont icon-personal-empty"/>} description={"暂无数据"}/>
205
+ }
206
+ return gridColumns.map(column => {
207
+ if (column.show) {
208
+ return <GridColumn key={`grid_select_modal_column_${column.code}`}
209
+ className={'text-center'}
210
+ headerClassName={'text-center'}
211
+ width={column.width}
212
+ title={column.name}
213
+ field={column.code}/>
214
+ }
215
+ return null;
216
+ })
217
+ }
218
+
219
+ render() {
220
+ let {
221
+ refUIConfig,
222
+ className,
223
+ multiple,
224
+ title,
225
+ children,
226
+ visible,
227
+ onCancel
228
+ } = this.props;
229
+
230
+ let {
231
+ loading,
232
+ checkedAll,
233
+ checkedIndeterminate,
234
+ gridData,
235
+ total,
236
+ gridOperator,
237
+ gridColumns
238
+ } = this.state;
239
+
240
+ let modalTitle = refUIConfig?.refTitle;
241
+ if (Values.isNotBlankString(title)) {
242
+ modalTitle = title;
243
+ }
244
+ if (Values.isBlankString(modalTitle)) {
245
+ modalTitle = "请选择";
246
+ }
247
+
248
+ let pageable = refUIConfig?.pageable;
249
+ if (pageable) {
250
+ pageable = {pageSizes: [20, 50, 100, 200], type: 'numeric'};
251
+ }
252
+
253
+ let {width= 600, height=300} = this.props;
254
+
255
+
256
+ return <Modal className={`grid-select-modal ${className || ''}`}
257
+ title={modalTitle}
258
+ visible={visible}
259
+ width={width}
260
+ height={height+102}
261
+ style={{minHeight: `${height+102}px`}}
262
+ onOk={this.onGridSelectModalOk}
263
+ onCancel={onCancel}>
264
+ <div className="grid-select-content" style={{height: `${height}px`}}>
265
+ <Spin spinning={loading} tip={loadingTips.loading}>
266
+ <Grid data={pageable ? gridData : process(gridData, {filter: gridOperator.filter})}
267
+ {...(pageable ? gridOperator : {filter: gridOperator.filter})}
268
+ filterable={true}
269
+ pageable={pageable}
270
+ sortable={true}
271
+ resizable={true}
272
+ reorderable={false}
273
+ total={total}
274
+ selectable={{mode: "single"}}
275
+ selectedField="selected"
276
+ onDataStateChange={this.onDataStateChange.bind(this)}
277
+ onRowClick={this.onRadioGridRowSelectionChange.bind(this)}
278
+ onRowDoubleClick={this.onRadioGridRowSelectionChange.bind(this, true)}>
279
+ <GridColumn field="selected"
280
+ className={'text-center'}
281
+ title={"选择"}
282
+ width="60px"
283
+ headerClassName={"text-center"}
284
+ locked={true}
285
+ headerCell={props => {
286
+ if (multiple) {
287
+ return <Checkbox.Group>
288
+ <Checkbox defaultChecked={false}
289
+ checked={checkedAll}
290
+ indeterminate={checkedIndeterminate}
291
+ onChange={this.onGridHeaderSelectionChange.bind(this)}/>
292
+ </Checkbox.Group>
293
+ }
294
+ return <span>选择</span>
295
+ }}
296
+ filterCell={KendoGridFilterCellRender}
297
+ cell={props => {
298
+ let {className, dataItem, style} = props;
299
+ return <td className={className} style={style}>
300
+ {!multiple && <Radio checked={dataItem.selected}
301
+ onChange={this.onRadioGridRowSelectionChange.bind(this, props)}/>}
302
+ {multiple && <Checkbox checked={dataItem.selected}
303
+ onChange={this.onGridRowSelectionChange.bind(this, props)}/>}
304
+ </td>
305
+ }}/>
306
+ <GridColumn headerClassName={"text-center"}
307
+ title="序号"
308
+ editable={false}
309
+ filterable={false}
310
+ locked={true}
311
+ className={"text-center"}
312
+ width="60px"
313
+ cell={KendoGridRowNumberCellRender}/>
314
+ {this.buildGridColumns(gridColumns)}
315
+ <GridColumn headerClassName={"text-center"}
316
+ title=""
317
+ filterable={false}
318
+ editable={false}
319
+ className={"text-center"}
320
+ />
321
+ </Grid>
322
+ </Spin>
323
+ </div>
324
+ {children}
325
+ </Modal>
326
+ }
327
+ }
328
+
329
+ export default GridSelectModal;
@@ -0,0 +1,120 @@
1
+ import React, {Fragment} from "react";
2
+ import lodash from "lodash";
3
+ import http from "../../services/http";
4
+ import GridSelectModal from "./GridSelectModal";
5
+ import {message} from "antd";
6
+ import uuid from "react-uuid";
7
+
8
+ class InputRefAddonBtn extends React.Component {
9
+ constructor(props) {
10
+ super(props);
11
+ let {refCode, isNotData} = props;
12
+ if (!isNotData && (refCode === null || refCode === void 0)) {
13
+ throw new Error("Not provide refCode prop.");
14
+ }
15
+
16
+ this.state = {
17
+ refUIConfig: null,
18
+ showGridSelectModal: false
19
+ }
20
+ }
21
+
22
+ showRefDialog = async () => {
23
+ let {
24
+ refCode, isNotData, customRefUIConfig,
25
+ onBeforeClick
26
+ } = this.props;
27
+
28
+ if (lodash.isFunction(onBeforeClick)) {
29
+ onBeforeClick(async (beforeCustomGridData) => {
30
+ try {
31
+ let {refUIConfig} = this.state;
32
+ if (refUIConfig == null) {
33
+ if (isNotData) {
34
+ refUIConfig = customRefUIConfig;
35
+ } else {
36
+ refUIConfig = await http.getJSON("queryRefUIConfig?ref_code=" + refCode);
37
+ }
38
+ if (refUIConfig == null) {
39
+ throw new Error("参照[refCode=]" + refCode + "未定义.");
40
+ }
41
+ }
42
+
43
+ let showGridSelectModal = true;
44
+ this.setState({refUIConfig, showGridSelectModal, beforeCustomGridData});
45
+ }
46
+ catch (e) {
47
+ http.dealAjaxException(e);
48
+ }
49
+ })
50
+ } else {
51
+ try {
52
+ let {refUIConfig} = this.state;
53
+ if (refUIConfig == null) {
54
+ if (isNotData) {
55
+ refUIConfig = customRefUIConfig;
56
+ } else {
57
+ refUIConfig = await http.getJSON("queryRefUIConfig?ref_code=" + refCode);
58
+ }
59
+ if (refUIConfig == null) {
60
+ throw new Error("参照[refCode=]" + refCode + "未定义.");
61
+ }
62
+ }
63
+
64
+ let showGridSelectModal = true;
65
+ this.setState({refUIConfig, showGridSelectModal});
66
+ }
67
+ catch (e) {
68
+ http.dealAjaxException(e);
69
+ }
70
+ }
71
+ }
72
+
73
+ onOkGridSelectModal = (selectedData) => {
74
+ if (!selectedData || !selectedData.length) {
75
+ let {refUIConfig} = this.state;
76
+ message.warning(`未选择${refUIConfig.refTitle || '参照'}`)
77
+ return false
78
+ }
79
+ let {rules, multiple} = this.props;
80
+ if (rules && rules.test(multiple ? selectedData : selectedData[0])) {
81
+ message.warning(`${rules.message}`)
82
+ return false
83
+ }
84
+ this.props.onOk(selectedData);
85
+ this.setState({showGridSelectModal: false});
86
+ }
87
+
88
+ closeGridSelectModal = () => {
89
+ this.setState({showGridSelectModal: false})
90
+ }
91
+
92
+ render() {
93
+ let {refCode, refDialogWidth, refDialogHeight,refDialogClassName, multiple, isNotData, customGridData, isNotIcon, icon, btnText} = this.props;
94
+ let {refUIConfig, beforeCustomGridData, showGridSelectModal} = this.state;
95
+
96
+ return <Fragment>
97
+ <div className="form-input-control" onClick={this.showRefDialog}>
98
+ {!isNotIcon && <span className="iconfont icon-personal-search"/>}
99
+ {btnText}
100
+ </div>
101
+ {showGridSelectModal && <GridSelectModal
102
+ key={`grid_select_modal_${uuid()}`}
103
+ multiple={multiple}
104
+ isNotData={isNotData}
105
+ customGridData={beforeCustomGridData || customGridData}
106
+ refUIConfig={refUIConfig}
107
+ refCode={refCode}
108
+ onOk={this.onOkGridSelectModal}
109
+ onCancel={this.closeGridSelectModal}
110
+ width={refDialogWidth}
111
+ className={refDialogClassName}
112
+ height={refDialogHeight}
113
+ visible={showGridSelectModal}/>}
114
+ </Fragment>
115
+ }
116
+
117
+ }
118
+
119
+
120
+ export default InputRefAddonBtn;