lu-lowcode-package-form 0.1.0
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/.babelrc +4 -0
- package/.eslintrc.js +11 -0
- package/README.md +70 -0
- package/dist/index.js +2 -0
- package/dist/index.js.LICENSE.txt +62 -0
- package/package.json +57 -0
- package/postcss.config.js +6 -0
- package/public/favicon.ico +0 -0
- package/public/index.html +43 -0
- package/public/logo192.png +0 -0
- package/public/logo512.png +0 -0
- package/public/manifest.json +25 -0
- package/public/robots.txt +3 -0
- package/src/App.css +3 -0
- package/src/App.js +41 -0
- package/src/App.test.js +8 -0
- package/src/components/field/base.jsx +16 -0
- package/src/components/field/checkbox/checkbox-tree.jsx +130 -0
- package/src/components/field/checkbox/index.jsx +14 -0
- package/src/components/field/custom/index.jsx +20 -0
- package/src/components/field/input/index.jsx +51 -0
- package/src/components/field/radio/index.jsx +13 -0
- package/src/components/field/select/index.jsx +2 -0
- package/src/components/field/select/select-props.jsx +14 -0
- package/src/components/field/select/select.jsx +39 -0
- package/src/components/field/select/tree-select.jsx +42 -0
- package/src/components/form-container/index.jsx +191 -0
- package/src/components/index.jsx +21 -0
- package/src/index.css +13 -0
- package/src/index.js +17 -0
- package/src/logo.svg +1 -0
- package/src/reportWebVitals.js +13 -0
- package/src/setupTests.js +5 -0
- package/src/utils/column-mapping.js +27 -0
- package/src/utils/index.js +186 -0
- package/tailwind.config.js +17 -0
- package/webpack.config.js +41 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import React, { forwardRef, useEffect } from "react";
|
|
2
|
+
|
|
3
|
+
import { Form, Row, Col } from "antd";
|
|
4
|
+
|
|
5
|
+
function debounce(func, wait) {
|
|
6
|
+
let timeout;
|
|
7
|
+
return function(...args) {
|
|
8
|
+
clearTimeout(timeout);
|
|
9
|
+
timeout = setTimeout(() => func.apply(this, args), wait);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function groupArray(array, groupLength) {
|
|
13
|
+
console.log("groupArray array", array.length)
|
|
14
|
+
const newArray = [];
|
|
15
|
+
let tmpArray = [];
|
|
16
|
+
|
|
17
|
+
const fillReactElement = (groupLength, array) => {
|
|
18
|
+
const diff = groupLength - array.length;
|
|
19
|
+
array.push(...new Array(diff).fill(React.createElement('div')));
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
for (const currNode of array) {
|
|
23
|
+
const { cols = 1 } = currNode?.props || {};
|
|
24
|
+
tmpArray.push(currNode);
|
|
25
|
+
|
|
26
|
+
if (tmpArray.length === groupLength) {
|
|
27
|
+
newArray.push(tmpArray);
|
|
28
|
+
tmpArray = [];
|
|
29
|
+
} else if (tmpArray.length > groupLength) {
|
|
30
|
+
fillReactElement(groupLength, tmpArray);
|
|
31
|
+
newArray.push(tmpArray);
|
|
32
|
+
tmpArray = [currNode];
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (tmpArray.length > 0) {
|
|
37
|
+
fillReactElement(groupLength, tmpArray);
|
|
38
|
+
newArray.push(tmpArray);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return newArray;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
const FormContainer = forwardRef(({ cols, children }, ref) => {
|
|
46
|
+
cols = cols ? cols : 1
|
|
47
|
+
const [form] = Form.useForm();
|
|
48
|
+
const [formContent, setFormContent] = React.useState(null);
|
|
49
|
+
const withMap = React.useRef(null);
|
|
50
|
+
React.useImperativeHandle(ref, () => {
|
|
51
|
+
return {
|
|
52
|
+
formRef: form,
|
|
53
|
+
initFieldsShow: initFieldsShow,
|
|
54
|
+
}
|
|
55
|
+
}, [])
|
|
56
|
+
|
|
57
|
+
useEffect(() => {
|
|
58
|
+
},[form])
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
initWithMap()
|
|
62
|
+
setFormContent(getChildren())
|
|
63
|
+
}, [])
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
const initWithMap = () => {
|
|
67
|
+
withMap.current = new Map();
|
|
68
|
+
let childrenArray = React.Children.toArray(children);
|
|
69
|
+
for (let i = 0; i < childrenArray.length; i++) {
|
|
70
|
+
const { componentId, __id, _componentName, ...props } = childrenArray[i].props;
|
|
71
|
+
const name = componentId || __id;
|
|
72
|
+
withMap.current.set(name, {
|
|
73
|
+
children: childrenArray.filter((item) => {
|
|
74
|
+
return item.props.__withId == name || item.props.__withIds?.includes(name)
|
|
75
|
+
}),
|
|
76
|
+
show: true
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
initFieldsShow();
|
|
81
|
+
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// 初始化字段的显示状态
|
|
85
|
+
const initFieldsShow = (reloadFields = false) => {
|
|
86
|
+
const fieldsValues = form.getFieldsValue();
|
|
87
|
+
withMap.current.keys().forEach(function (key) {
|
|
88
|
+
computeNeedShow(key,fieldsValues)
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
if (reloadFields) setFormContent(getChildren())
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 计算是否显示
|
|
95
|
+
const computeNeedShow = (name,fieldsValues) => {
|
|
96
|
+
let needRefresh = false;
|
|
97
|
+
if (withMap.current.has(name)) {
|
|
98
|
+
let withChildrens = withMap.current.get(name).children
|
|
99
|
+
withChildrens.forEach((item) => {
|
|
100
|
+
if (item.props.__withFunc && typeof item.props.__withFunc === 'function') {
|
|
101
|
+
let childrenShow = item.props.__withFunc(fieldsValues);
|
|
102
|
+
const name = item.props.componentId || item.props.__id;
|
|
103
|
+
if (withMap.current.has(name)) {
|
|
104
|
+
let childrenItem = withMap.current.get(name)
|
|
105
|
+
if (childrenItem.show != childrenShow) {
|
|
106
|
+
childrenItem.show = childrenShow
|
|
107
|
+
withMap.current.set(name, childrenItem)
|
|
108
|
+
needRefresh = true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
})
|
|
113
|
+
}
|
|
114
|
+
return needRefresh
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const handleFieldsChange = debounce((changedFields, allFields) => {
|
|
118
|
+
// 获得所有字段值
|
|
119
|
+
const fieldsValues = form.getFieldsValue();
|
|
120
|
+
let needRefresh = false;
|
|
121
|
+
for (let index = 0; index < changedFields.length; index++) {
|
|
122
|
+
const element = changedFields[index];
|
|
123
|
+
if (element.name && element.name.length > 0 )
|
|
124
|
+
needRefresh = computeNeedShow(element.name[0],fieldsValues)
|
|
125
|
+
}
|
|
126
|
+
if (needRefresh) {
|
|
127
|
+
setFormContent(getChildren())
|
|
128
|
+
}
|
|
129
|
+
}, 100); // 字段变化时会调用三次此函数,使用 100 毫秒的防抖时间
|
|
130
|
+
|
|
131
|
+
const getChildren = () => {
|
|
132
|
+
let childrenArray = React.Children.toArray(children);
|
|
133
|
+
const newArray = groupArray(childrenArray.filter((item) => {
|
|
134
|
+
const name = item.props.componentId || item.props.__id
|
|
135
|
+
return withMap.current.has(name) && withMap.current.get(name).show
|
|
136
|
+
}), cols);
|
|
137
|
+
console.log("newArray", newArray)
|
|
138
|
+
const result = newArray.map((childs) => {
|
|
139
|
+
return (
|
|
140
|
+
<Row
|
|
141
|
+
key={childs?.[0]?.key}
|
|
142
|
+
gutter={[24, 24]}
|
|
143
|
+
>
|
|
144
|
+
{childs.map((child) => {
|
|
145
|
+
const { componentId, __id, _componentName, onChange, ...props } = child.props;
|
|
146
|
+
const name = componentId || __id;
|
|
147
|
+
const componentName = _componentName;
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
// 占整行内容
|
|
151
|
+
if (['FieldLayout', 'FieldSubTable'].includes(componentName)) {
|
|
152
|
+
// console.log('q=>child', child);
|
|
153
|
+
return (
|
|
154
|
+
<Col key={name} span={24} style={{ marginBottom: 0 }} >
|
|
155
|
+
{child}
|
|
156
|
+
</Col>
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
// console.log('child', child)
|
|
160
|
+
return (
|
|
161
|
+
<Col key={name} span={24 / childs.length} >
|
|
162
|
+
{name && (
|
|
163
|
+
<Form.Item
|
|
164
|
+
style={{ marginBottom: 0 }}
|
|
165
|
+
label=""
|
|
166
|
+
name={name}
|
|
167
|
+
rules={[{ required: props.isRequired, message: `${props.title}不能为空!` }]}
|
|
168
|
+
>
|
|
169
|
+
|
|
170
|
+
{child}
|
|
171
|
+
</Form.Item>
|
|
172
|
+
)}
|
|
173
|
+
</Col>
|
|
174
|
+
);
|
|
175
|
+
})}
|
|
176
|
+
</Row>
|
|
177
|
+
);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
console.log("result", newArray)
|
|
181
|
+
return result;
|
|
182
|
+
};
|
|
183
|
+
return (
|
|
184
|
+
<Form form={form} className="form-container p-6 w-full h-full box-border overflow-auto" onFieldsChange={handleFieldsChange}>
|
|
185
|
+
{formContent}
|
|
186
|
+
</Form>
|
|
187
|
+
)
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
export default FormContainer;
|
|
191
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Input, TextArea, Password, Search ,CodeMachine} from './field/input/index.jsx'
|
|
2
|
+
import { TreeSelect, Select } from './field/select/index.jsx'
|
|
3
|
+
import Custom from './field/custom/index.jsx'
|
|
4
|
+
import { default as FormContainer } from './form-container/index.jsx'
|
|
5
|
+
import { Checkbox ,CheckboxTree } from './field/checkbox/index.jsx'
|
|
6
|
+
import { default as RadioGrop } from './field/radio/index.jsx'
|
|
7
|
+
const Field = {
|
|
8
|
+
Input,
|
|
9
|
+
TextArea,
|
|
10
|
+
Password,
|
|
11
|
+
Search,
|
|
12
|
+
TreeSelect,
|
|
13
|
+
Select,
|
|
14
|
+
CodeMachine,
|
|
15
|
+
Checkbox,
|
|
16
|
+
CheckboxTree,
|
|
17
|
+
RadioGrop,
|
|
18
|
+
Custom,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export { FormContainer, Field }
|
package/src/index.css
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
body {
|
|
2
|
+
margin: 0;
|
|
3
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
4
|
+
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
|
5
|
+
sans-serif;
|
|
6
|
+
-webkit-font-smoothing: antialiased;
|
|
7
|
+
-moz-osx-font-smoothing: grayscale;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
code {
|
|
11
|
+
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
|
12
|
+
monospace;
|
|
13
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import ReactDOM from 'react-dom/client';
|
|
3
|
+
import './index.css';
|
|
4
|
+
import App from './App';
|
|
5
|
+
import reportWebVitals from './reportWebVitals';
|
|
6
|
+
|
|
7
|
+
const root = ReactDOM.createRoot(document.getElementById('root'));
|
|
8
|
+
root.render(
|
|
9
|
+
<React.StrictMode>
|
|
10
|
+
<App />
|
|
11
|
+
</React.StrictMode>
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
// If you want to start measuring performance in your app, pass a function
|
|
15
|
+
// to log results (for example: reportWebVitals(console.log))
|
|
16
|
+
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
|
|
17
|
+
reportWebVitals();
|
package/src/logo.svg
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 841.9 595.3"><g fill="#61DAFB"><path d="M666.3 296.5c0-32.5-40.7-63.3-103.1-82.4 14.4-63.6 8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6 0 8.3.9 11.4 2.6 13.6 7.8 19.5 37.5 14.9 75.7-1.1 9.4-2.9 19.3-5.1 29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50 32.6-30.3 63.2-46.9 84-46.9V78c-27.5 0-63.5 19.6-99.9 53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7 0 51.4 16.5 84 46.6-14 14.7-28 31.4-41.3 49.9-22.6 2.4-44 6.1-63.6 11-2.3-10-4-19.7-5.2-29-4.7-38.2 1.1-67.9 14.6-75.8 3-1.8 6.9-2.6 11.5-2.6V78.5c-8.4 0-16 1.8-22.6 5.6-28.1 16.2-34.4 66.7-19.9 130.1-62.2 19.2-102.7 49.9-102.7 82.3 0 32.5 40.7 63.3 103.1 82.4-14.4 63.6-8 114.2 20.2 130.4 6.5 3.8 14.1 5.6 22.5 5.6 27.5 0 63.5-19.6 99.9-53.6 36.4 33.8 72.4 53.2 99.9 53.2 8.4 0 16-1.8 22.6-5.6 28.1-16.2 34.4-66.7 19.9-130.1 62-19.1 102.5-49.9 102.5-82.3zm-130.2-66.7c-3.7 12.9-8.3 26.2-13.5 39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4 14.2 2.1 27.9 4.7 41 7.9zm-45.8 106.5c-7.8 13.5-15.8 26.3-24.1 38.2-14.9 1.3-30 2-45.2 2-15.1 0-30.2-.7-45-1.9-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8 6.2-13.4 13.2-26.8 20.7-39.9 7.8-13.5 15.8-26.3 24.1-38.2 14.9-1.3 30-2 45.2-2 15.1 0 30.2.7 45 1.9 8.3 11.9 16.4 24.6 24.2 38 7.6 13.1 14.5 26.4 20.8 39.8-6.3 13.4-13.2 26.8-20.7 39.9zm32.3-13c5.4 13.4 10 26.8 13.8 39.8-13.1 3.2-26.9 5.9-41.2 8 4.9-7.7 9.8-15.6 14.4-23.7 4.6-8 8.9-16.1 13-24.1zM421.2 430c-9.3-9.6-18.6-20.3-27.8-32 9 .4 18.2.7 27.5.7 9.4 0 18.7-.2 27.8-.7-9 11.7-18.3 22.4-27.5 32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9 3.7-12.9 8.3-26.2 13.5-39.5 4.1 8 8.4 16 13.1 24 4.7 8 9.5 15.8 14.4 23.4zM420.7 163c9.3 9.6 18.6 20.3 27.8 32-9-.4-18.2-.7-27.5-.7-9.4 0-18.7.2-27.8.7 9-11.7 18.3-22.4 27.5-32zm-74 58.9c-4.9 7.7-9.8 15.6-14.4 23.7-4.6 8-8.9 16-13 24-5.4-13.4-10-26.8-13.8-39.8 13.1-3.1 26.9-5.8 41.2-7.9zm-90.5 125.2c-35.4-15.1-58.3-34.9-58.3-50.6 0-15.7 22.9-35.6 58.3-50.6 8.6-3.7 18-7 27.7-10.1 5.7 19.6 13.2 40 22.5 60.9-9.2 20.8-16.6 41.1-22.2 60.6-9.9-3.1-19.3-6.5-28-10.2zM310 490c-13.6-7.8-19.5-37.5-14.9-75.7 1.1-9.4 2.9-19.3 5.1-29.4 19.6 4.8 41 8.5 63.5 10.9 13.5 18.5 27.5 35.3 41.6 50-32.6 30.3-63.2 46.9-84 46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7 38.2-1.1 67.9-14.6 75.8-3 1.8-6.9 2.6-11.5 2.6-20.7 0-51.4-16.5-84-46.6 14-14.7 28-31.4 41.3-49.9 22.6-2.4 44-6.1 63.6-11 2.3 10.1 4.1 19.8 5.2 29.1zm38.5-66.7c-8.6 3.7-18 7-27.7 10.1-5.7-19.6-13.2-40-22.5-60.9 9.2-20.8 16.6-41.1 22.2-60.6 9.9 3.1 19.3 6.5 28.1 10.2 35.4 15.1 58.3 34.9 58.3 50.6-.1 15.7-23 35.6-58.4 50.6zM320.8 78.4z"/><circle cx="420.9" cy="296.5" r="45.7"/><path d="M520.5 78.1z"/></g></svg>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const reportWebVitals = onPerfEntry => {
|
|
2
|
+
if (onPerfEntry && onPerfEntry instanceof Function) {
|
|
3
|
+
import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
|
|
4
|
+
getCLS(onPerfEntry);
|
|
5
|
+
getFID(onPerfEntry);
|
|
6
|
+
getFCP(onPerfEntry);
|
|
7
|
+
getLCP(onPerfEntry);
|
|
8
|
+
getTTFB(onPerfEntry);
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export default reportWebVitals;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const columnMapping = {
|
|
2
|
+
"varchar" : {
|
|
3
|
+
valueType : "text",
|
|
4
|
+
searchForm: "input"
|
|
5
|
+
}
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const findColumnType = (columnType, property) => {
|
|
9
|
+
for (const key in columnMapping) {
|
|
10
|
+
if (columnType.startsWith(key)) {
|
|
11
|
+
return columnMapping[key][property];
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return null;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const GetValueType = (columnType) => {
|
|
18
|
+
const valueType = columnMapping[columnType]?.valueType || findColumnType(columnType, "valueType");
|
|
19
|
+
return valueType || "text";
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const GetSearchForm = (columnType) => {
|
|
23
|
+
const searchForm = columnMapping[columnType]?.searchForm || findColumnType(columnType, "searchForm");
|
|
24
|
+
return searchForm || "input";
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
export { GetValueType, GetSearchForm };
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import { DeleteFilled, EditFilled, FileAddFilled } from "@ant-design/icons";
|
|
2
|
+
import { Tooltip } from "antd";
|
|
3
|
+
|
|
4
|
+
export const createPromiseWrapper = () => {
|
|
5
|
+
let resolve, reject;
|
|
6
|
+
|
|
7
|
+
const promise = new Promise((res, rej) => {
|
|
8
|
+
resolve = res;
|
|
9
|
+
reject = rej;
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
return { promise, resolve, reject };
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 构造树型结构的菜单
|
|
17
|
+
* @param {*} data 数据源
|
|
18
|
+
*/
|
|
19
|
+
export function handleTreeMenu(data) {
|
|
20
|
+
return constructTree(
|
|
21
|
+
data,
|
|
22
|
+
"id",
|
|
23
|
+
"title",
|
|
24
|
+
"parentId",
|
|
25
|
+
"routes",
|
|
26
|
+
0,
|
|
27
|
+
(item) => ({
|
|
28
|
+
path: item.route || "/",
|
|
29
|
+
name: item.title,
|
|
30
|
+
icon: item.icon,
|
|
31
|
+
})
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* 构造树型结构数据
|
|
37
|
+
* @param {*} data 数据源
|
|
38
|
+
* @param {*} id id字段 默认 'id'
|
|
39
|
+
* @param {*} title 显示字段 默认 'title'
|
|
40
|
+
* @param {*} parentId 父节点字段 默认 'parentId'
|
|
41
|
+
* @param {*} children 孩子节点字段 默认 'children'
|
|
42
|
+
* @param {*} rootId 根Id 默认 0
|
|
43
|
+
* @param {*} disabledValue 禁用的节点值 默认 0
|
|
44
|
+
*/
|
|
45
|
+
export function handleTree(
|
|
46
|
+
data,
|
|
47
|
+
id = "id",
|
|
48
|
+
title = "title",
|
|
49
|
+
parentId = "parentId",
|
|
50
|
+
children = "children",
|
|
51
|
+
rootId = 0,
|
|
52
|
+
disabledValue = 0
|
|
53
|
+
) {
|
|
54
|
+
return constructTree(
|
|
55
|
+
data,
|
|
56
|
+
id,
|
|
57
|
+
title,
|
|
58
|
+
parentId,
|
|
59
|
+
children,
|
|
60
|
+
rootId,
|
|
61
|
+
(item) => ({
|
|
62
|
+
value: item[id],
|
|
63
|
+
title: item[title],
|
|
64
|
+
key: item[id],
|
|
65
|
+
disabled: item[id] === disabledValue,
|
|
66
|
+
})
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* 构造树型结构编辑数据
|
|
72
|
+
* @param {*} data 数据源
|
|
73
|
+
* @param {*} id id字段
|
|
74
|
+
* @param {*} parentId 父节点字段
|
|
75
|
+
* @param {*} children 孩子节点字段
|
|
76
|
+
* @param {*} title 显示字段
|
|
77
|
+
* @param {*} rootId 根Id
|
|
78
|
+
* @param {*} handle 处理函数
|
|
79
|
+
* @param {*} moduleName 模块名称
|
|
80
|
+
*/
|
|
81
|
+
export function handleTreeEdit(
|
|
82
|
+
data,
|
|
83
|
+
id,
|
|
84
|
+
parentId,
|
|
85
|
+
children,
|
|
86
|
+
title,
|
|
87
|
+
rootId,
|
|
88
|
+
handle = { New: () => {}, Edit: () => {}, Del: () => {} },
|
|
89
|
+
moduleName = "节点"
|
|
90
|
+
) {
|
|
91
|
+
const newNode = (node) => ({
|
|
92
|
+
title: (
|
|
93
|
+
<div
|
|
94
|
+
className="flex items-center text-[#1890ff]"
|
|
95
|
+
onClick={(event) => handle.New(event, node)}
|
|
96
|
+
>
|
|
97
|
+
<FileAddFilled className="mr-2" /> 添加子{moduleName}
|
|
98
|
+
</div>
|
|
99
|
+
),
|
|
100
|
+
key: `${node ? node[id] : 0}-add`,
|
|
101
|
+
selectable: false,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
const processNode = (item) => {
|
|
105
|
+
item.__original = { ...item };
|
|
106
|
+
item.__label = item[title];
|
|
107
|
+
item.__value = item[id];
|
|
108
|
+
return item;
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const renderTitle = (child) => (
|
|
112
|
+
<div className="flex items-center">
|
|
113
|
+
{child.__label}
|
|
114
|
+
<Tooltip title={`编辑${moduleName}`} color="#666">
|
|
115
|
+
<EditFilled
|
|
116
|
+
className="ml-4 text-gray-200 hover:text-[#1890ff]"
|
|
117
|
+
onClick={(event) => handle.Edit(event, child)}
|
|
118
|
+
/>
|
|
119
|
+
</Tooltip>
|
|
120
|
+
<Tooltip title={`删除${moduleName}`} color="red">
|
|
121
|
+
<DeleteFilled
|
|
122
|
+
className="ml-2 text-gray-200 hover:text-red-500"
|
|
123
|
+
onClick={(event) => handle.Del(event, child)}
|
|
124
|
+
/>
|
|
125
|
+
</Tooltip>
|
|
126
|
+
<Tooltip title={`添加子${moduleName}`} color="#666">
|
|
127
|
+
<FileAddFilled
|
|
128
|
+
className="ml-2 text-gray-200 hover:text-[#1890ff]"
|
|
129
|
+
onClick={(event) => handle.New(event, child)}
|
|
130
|
+
/>
|
|
131
|
+
</Tooltip>
|
|
132
|
+
</div>
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
const treeData = constructTree(
|
|
136
|
+
data,
|
|
137
|
+
id,
|
|
138
|
+
title,
|
|
139
|
+
parentId,
|
|
140
|
+
children,
|
|
141
|
+
rootId,
|
|
142
|
+
processNode
|
|
143
|
+
).map((item) => {
|
|
144
|
+
item.title = renderTitle(item);
|
|
145
|
+
item.key = `node-${item[id]}`;
|
|
146
|
+
return item;
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
treeData.push(newNode());
|
|
150
|
+
return treeData;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* 构造树型结构的通用函数
|
|
155
|
+
* @param {*} data 数据源
|
|
156
|
+
* @param {*} id id字段
|
|
157
|
+
* @param {*} title 显示字段
|
|
158
|
+
* @param {*} parentId 父节点字段
|
|
159
|
+
* @param {*} children 孩子节点字段
|
|
160
|
+
* @param {*} rootId 根Id
|
|
161
|
+
* @param {*} processItem 处理每个节点的函数
|
|
162
|
+
*/
|
|
163
|
+
function constructTree(
|
|
164
|
+
data,
|
|
165
|
+
id,
|
|
166
|
+
title,
|
|
167
|
+
parentId,
|
|
168
|
+
children,
|
|
169
|
+
rootId,
|
|
170
|
+
processItem
|
|
171
|
+
) {
|
|
172
|
+
if (!Array.isArray(data) || data.length === 0) return [];
|
|
173
|
+
|
|
174
|
+
const cloneData = data.map((item) => ({
|
|
175
|
+
...item,
|
|
176
|
+
...processItem(item),
|
|
177
|
+
}));
|
|
178
|
+
|
|
179
|
+
return cloneData.filter((father) => {
|
|
180
|
+
const branchArr = cloneData.filter(
|
|
181
|
+
(child) => father[id] === child[parentId]
|
|
182
|
+
);
|
|
183
|
+
father[children] = branchArr.length > 0 ? branchArr : [];
|
|
184
|
+
return father[parentId] === rootId;
|
|
185
|
+
});
|
|
186
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
purge: [
|
|
3
|
+
'./src/**/*.html',
|
|
4
|
+
'./src/**/*.tsx',
|
|
5
|
+
'./src/**/*.jsx',
|
|
6
|
+
'./src/**/*.js',
|
|
7
|
+
],
|
|
8
|
+
darkMode: false, // or 'media' or 'class'
|
|
9
|
+
theme: {
|
|
10
|
+
extend: {},
|
|
11
|
+
},
|
|
12
|
+
variants: {
|
|
13
|
+
extend: {},
|
|
14
|
+
},
|
|
15
|
+
plugins: [],
|
|
16
|
+
}
|
|
17
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
mode: 'production',
|
|
5
|
+
entry: './src/components/index.jsx',
|
|
6
|
+
output: {
|
|
7
|
+
path: path.resolve(__dirname, 'dist'),
|
|
8
|
+
filename: 'index.js',
|
|
9
|
+
library: 'luLowcodePackageForm',
|
|
10
|
+
libraryTarget: 'umd',
|
|
11
|
+
globalObject: 'this',
|
|
12
|
+
},
|
|
13
|
+
resolve: {
|
|
14
|
+
extensions: ['.js', '.jsx'],
|
|
15
|
+
},
|
|
16
|
+
module: {
|
|
17
|
+
rules: [
|
|
18
|
+
{
|
|
19
|
+
test: /\.(js|jsx)$/,
|
|
20
|
+
exclude: /node_modules/,
|
|
21
|
+
use: {
|
|
22
|
+
loader: 'babel-loader',
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
externals: {
|
|
28
|
+
react: {
|
|
29
|
+
commonjs: 'react',
|
|
30
|
+
commonjs2: 'react',
|
|
31
|
+
amd: 'react',
|
|
32
|
+
root: 'React',
|
|
33
|
+
},
|
|
34
|
+
'react-dom': {
|
|
35
|
+
commonjs: 'react-dom',
|
|
36
|
+
commonjs2: 'react-dom',
|
|
37
|
+
amd: 'react-dom',
|
|
38
|
+
root: 'ReactDOM',
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
};
|