@qmlight/web-platform-components 1.0.2 → 1.0.5

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.
@@ -12,4 +12,5 @@ export default {
12
12
  QFC_PUBLIC: `${prefix}/dcp-base-public`,
13
13
  QFC_AUTH: `${prefix}/dcp-base-auth`,
14
14
  GWGL_SERVICE: `/gwgl-service`,
15
+ FT_FLOAT: `${prefix}/ft-oa-service`,
15
16
  };
@@ -11,7 +11,7 @@ export const getOrgsByConditions = (params) => {
11
11
  return axios.post(`${SERVER.QFC_BASE}/lowcode/getOrgsByConditions`, params);
12
12
  };
13
13
  export const recentUserPage = (params) => {
14
- return axios.post(`${SERVER.QFC_BASE}/custom/getCommonGroup`, params);
14
+ return axios.post(`${SERVER.FT_FLOAT}/customGroup/getCustomGroup`, params);
15
15
  };
16
16
 
17
17
  export const getUsersByConditions = (params) => {
@@ -0,0 +1,325 @@
1
+ import React, { useEffect, useRef, useState, useImperativeHandle } from 'react';
2
+ import { message, QmSearchTree } from 'dcp-design-react';
3
+ import {
4
+ getAllCustomGroups,
5
+ createCustomGroups,
6
+ deleteCustomGroup,
7
+ getUsersByCustomGroup,
8
+ } from '../../api/tabList';
9
+ import isEmpty from 'lodash-es/isEmpty';
10
+ import { UserOutlined, FolderOutlined, EditOutlined, DeleteOutlined } from '@/icons';
11
+ import './style.less';
12
+
13
+ const MultipleTree = React.forwardRef((props: any, ref) => {
14
+ const {
15
+ mode,
16
+ onDataChange,
17
+ selectedKeys = [],
18
+ targetKeys = [],
19
+ onItemSelectAll,
20
+ onValueChange,
21
+ type = 'default',
22
+ onDoubleClickChange,
23
+ actionHandle,
24
+ } = props;
25
+ const [fetchParams, setFetchParams] = useState<any>({});
26
+ const treeData = useRef<any[]>([]);
27
+ const searchTreeRef = useRef<any>();
28
+ const [itemKeys, setItemKeys] = useState<any[]>([]);
29
+ const timer = useRef<any>(null);
30
+ useEffect(() => {
31
+ if (selectedKeys) {
32
+ const treeList = getTreeList(treeData.current, []);
33
+ const newList = treeList
34
+ .filter((item) => selectedKeys.includes(item.id))
35
+ .map((item) => item.newId);
36
+ setItemKeys(newList || []);
37
+ }
38
+
39
+ // eslint-disable-next-line react-hooks/exhaustive-deps
40
+ }, [selectedKeys]);
41
+ const onRefreshChange = (id?) => {
42
+ if (id) {
43
+ setFetchParams({ newId: id, refesh: true });
44
+ return;
45
+ }
46
+ setFetchParams({});
47
+ };
48
+ useImperativeHandle(ref, () => {
49
+ return {
50
+ onRefresh: onRefreshChange,
51
+ };
52
+ });
53
+ const updateTreeData = (list, key, children) =>
54
+ list.map((node) => {
55
+ if (node.id === key) {
56
+ return {
57
+ ...node,
58
+ children,
59
+ };
60
+ }
61
+ if (node.children) {
62
+ return {
63
+ ...node,
64
+ children: updateTreeData(node.children, key, children),
65
+ };
66
+ }
67
+ return node;
68
+ });
69
+ const getNodeData = (data, id, field) => {
70
+ for (let i = 0; i < data.length; i++) {
71
+ if (data[i].id === id) {
72
+ return data[i];
73
+ }
74
+ if (!isEmpty(data[i].children)) {
75
+ return getNodeData(data[i].children, id, field);
76
+ }
77
+ }
78
+ return field;
79
+ };
80
+ const getIsLeft = (a1, a2) => {
81
+ if (type === 'default' || type === 'customOrg') {
82
+ return !a1;
83
+ }
84
+ return !a2;
85
+ };
86
+ const getCheckAble = (item) => {
87
+ if (type === 'default' || type === 'org') {
88
+ return !(targetKeys.includes(item.id) || targetKeys.includes(item.parentId));
89
+ }
90
+ if (type === 'customOrg') {
91
+ return (
92
+ !item.orgtype &&
93
+ item.orgtype !== 0 &&
94
+ !(targetKeys.includes(item.id) || targetKeys.includes(item.parentId))
95
+ );
96
+ }
97
+ if (type === 'doc') {
98
+ return !(targetKeys.includes(item.id) || targetKeys.includes(item.parentId));
99
+ }
100
+ return (
101
+ item.orgtype === 2 &&
102
+ !(
103
+ targetKeys.includes(item.id) ||
104
+ targetKeys.includes(item.parentId) ||
105
+ targetKeys.includes(`${item.parentId}_${item.id}`)
106
+ )
107
+ );
108
+ };
109
+
110
+ const getData = async (params) => {
111
+ params.id = params.newId;
112
+ const treeList = getTreeList(treeData.current, []);
113
+ const field = treeList.find((item) => item.id === params['id']) || {
114
+ hasChildren: true,
115
+ };
116
+ const { newId, refesh, ...newParams } = params;
117
+ const res = await (!params?.id
118
+ ? getAllCustomGroups({})
119
+ : getUsersByCustomGroup({ ids: [params.id] }));
120
+ if (res.code === 200) {
121
+ if (!params['id']) {
122
+ // const list = getNodeData(res.data, !hasChildren);
123
+ const list = res.data.map((item) => {
124
+ return {
125
+ ...item,
126
+ checkable: getCheckAble(item),
127
+ name: item.title,
128
+ newId: item.id,
129
+ orgtype: 2,
130
+ isLeaf: false,
131
+ };
132
+ });
133
+ console.log(list);
134
+ treeData.current = list;
135
+ const treeList = getTreeList(list, []);
136
+ onDataChange &&
137
+ onDataChange(
138
+ treeList.map((item) => {
139
+ return {
140
+ ...item,
141
+ key: item.id,
142
+ title: item.name,
143
+ };
144
+ })
145
+ );
146
+
147
+ return {
148
+ ...res,
149
+ data: list,
150
+ };
151
+ } else {
152
+ const { userList } = res.data[0] || {};
153
+ const list = userList.map((item) => {
154
+ return {
155
+ ...item,
156
+ isLeaf: true,
157
+ id: item.loginName,
158
+ parentId: params.id,
159
+ newId: `${params.id}_${item.loginName}`,
160
+ name: item.userName,
161
+ checkable: getCheckAble({ ...item, id: item.loginName }),
162
+ };
163
+ });
164
+
165
+ treeData.current = updateTreeData(treeData.current, params.id, list);
166
+ const treeList = getTreeList(treeData.current, []);
167
+ onDataChange &&
168
+ onDataChange(
169
+ treeList.map((item) => {
170
+ return {
171
+ ...item,
172
+ key: item.id,
173
+ title: item.name,
174
+ };
175
+ })
176
+ );
177
+ if (refesh) {
178
+ return {
179
+ ...res,
180
+ data: treeData.current,
181
+ };
182
+ }
183
+ return {
184
+ ...res,
185
+ data: list,
186
+ };
187
+ }
188
+ }
189
+ onRefreshChange(false);
190
+ return res;
191
+ };
192
+ const getTreeList = (treeData, list) => {
193
+ treeData.forEach((item) => {
194
+ list.push(item);
195
+ if (item.children) {
196
+ getTreeList(item.children, list);
197
+ }
198
+ });
199
+ return list;
200
+ };
201
+
202
+ const onItemChange = async (node) => {
203
+ if (node.length > 0) {
204
+ onItemSelectAll(
205
+ node.map((item) => item.id),
206
+ true
207
+ );
208
+ if (selectedKeys.length) {
209
+ return;
210
+ }
211
+ } else {
212
+ onItemSelectAll(selectedKeys, false);
213
+ }
214
+ };
215
+ useEffect(() => {
216
+ if (searchTreeRef.current) {
217
+ const treeList = getTreeList(treeData.current, []);
218
+ treeList.forEach((item) => {
219
+ if (item.orgtype === 0) {
220
+ searchTreeRef.current.UPDATE_RECORD(item.id, {
221
+ checkable: false,
222
+ });
223
+ } else {
224
+ searchTreeRef.current.UPDATE_RECORD(item.newId, {
225
+ checkable: getCheckAble(item),
226
+ });
227
+ }
228
+ });
229
+ }
230
+ // eslint-disable-next-line react-hooks/exhaustive-deps
231
+ }, [targetKeys]);
232
+
233
+ return (
234
+ <div className="search-tree-page">
235
+ {/* {type !== 'doc' && <DropDownList onDataChange={onDropDataChange} />} */}
236
+
237
+ <div className="search-tree-page-content">
238
+ <QmSearchTree
239
+ ref={searchTreeRef}
240
+ filterable={false}
241
+ showCollapse={false}
242
+ asyncLoad={true}
243
+ multiple={mode === 'multiple'}
244
+ fetch={{
245
+ api: getData,
246
+ params: fetchParams,
247
+ }}
248
+ // checkStrictly={true}
249
+ value={itemKeys}
250
+ checkStrategy={'SHOW_CHILD'}
251
+ onCheckChange={(node: any) => {
252
+ clearTimeout(timer.current);
253
+ timer.current = setTimeout(async () => {
254
+ await onItemSelectAll(selectedKeys, false);
255
+ onItemChange(node);
256
+ }, 300);
257
+ }}
258
+ onSelectChange={(node: any) => {
259
+ if (!mode) {
260
+ if (
261
+ (!node?.orgtype && node.orgtype !== 0) ||
262
+ (type === 'org' && node.orgtype !== 0)
263
+ ) {
264
+ setItemKeys([node.id]);
265
+ onValueChange && onValueChange({ ...node, value: node.id, title: node.name });
266
+ }
267
+ }
268
+ }}
269
+ titleRender={(node) => {
270
+ return node.orgtype === 2 ? (
271
+ <span
272
+ className="tree-header-multip"
273
+ onDoubleClick={(e) => {
274
+ if (!node?.checkable) {
275
+ return;
276
+ }
277
+ clearTimeout(timer.current);
278
+ if (!targetKeys?.includes(node.id)) {
279
+ onDoubleClickChange(node.id);
280
+ }
281
+ }}
282
+ >
283
+ <span>
284
+ <FolderOutlined /> {node.name}
285
+ </span>
286
+ <div className="item-action">
287
+ <EditOutlined
288
+ onClick={(e) => actionHandle(e, 'edit', node)}
289
+ style={{ marginRight: 8, fontSize: 14 }}
290
+ />
291
+ <DeleteOutlined
292
+ onClick={(e) => actionHandle(e, 'del', node)}
293
+ style={{ marginRight: 8, fontSize: 14 }}
294
+ />
295
+ </div>
296
+ </span>
297
+ ) : (
298
+ <span
299
+ onDoubleClick={(e) => {
300
+ if (!node?.checkable) {
301
+ return;
302
+ }
303
+ clearTimeout(timer.current);
304
+ if (!targetKeys?.includes(node.id)) {
305
+ onDoubleClickChange(node.id);
306
+ }
307
+ }}
308
+ >
309
+ <UserOutlined /> {node.name}
310
+ </span>
311
+ );
312
+ }}
313
+ fieldsDefine={{
314
+ valueKey: 'newId',
315
+ textKey: 'name',
316
+ }}
317
+ showSearchBar={false}
318
+ // dataSource={treeData}
319
+ />
320
+ </div>
321
+ </div>
322
+ );
323
+ });
324
+ MultipleTree.displayName = 'MultipleTree';
325
+ export default MultipleTree;
@@ -93,7 +93,7 @@ const CustomModal = ({ actionInfo, onClose, setAcitonInfo, mode }) => {
93
93
  }
94
94
  const field = {
95
95
  ...data,
96
- userIds: userList.map((item) => item.key),
96
+ userIds: userList.map((item) => item.oldId || item.key),
97
97
  };
98
98
  const res = await (!data?.id
99
99
  ? createCustomGroups(field)
@@ -197,7 +197,7 @@ const CustomModal = ({ actionInfo, onClose, setAcitonInfo, mode }) => {
197
197
  <></>
198
198
  )}
199
199
 
200
- <QmButton onClick={() => onClose()}>取消</QmButton>
200
+ <QmButton onClick={() => onClose('noRefesh')}>取消</QmButton>
201
201
  </QmSpace>
202
202
 
203
203
  <SearchAssistanceModel
@@ -219,7 +219,6 @@ const CustomModal = ({ actionInfo, onClose, setAcitonInfo, mode }) => {
219
219
  {
220
220
  label: '组织结构',
221
221
  key: '4',
222
- type: 'customOrg',
223
222
  },
224
223
  ]}
225
224
  type={'customOrg'}
@@ -12,6 +12,7 @@ import './style.less';
12
12
  import { Message } from '@/utils';
13
13
  import CustomModal from './customModal';
14
14
  import { EditOutlined, DeleteOutlined } from '@/icons';
15
+ import MultipleTree from './MultipleTree';
15
16
  const { Panel } = Collapse;
16
17
  const CustomOrg = (props) => {
17
18
  const {
@@ -22,6 +23,7 @@ const CustomOrg = (props) => {
22
23
  onItemSelect,
23
24
  onValueChange,
24
25
  onDataChange,
26
+ onItemSelectAll,
25
27
  } = props;
26
28
  const [dataSource, setData] = useState<any>([]);
27
29
  const [itemKeys, setItemKeys] = useState<any[]>([]);
@@ -30,6 +32,7 @@ const CustomOrg = (props) => {
30
32
  visible: false,
31
33
  });
32
34
  const [fetchParams, setFetchParams] = useState({});
35
+ const multipleTreeRef = useRef<any>();
33
36
 
34
37
  const [moveKey, setMoveKey] = useState<string | null>(null);
35
38
  const [activeKeys, setActiveKeys] = useState<string[]>([]);
@@ -53,6 +56,9 @@ const CustomOrg = (props) => {
53
56
 
54
57
  if (mode) {
55
58
  userList.current = list;
59
+
60
+ dataList.current = list;
61
+ setData(list);
56
62
  onDataChange && onDataChange(list);
57
63
  return;
58
64
  }
@@ -111,7 +117,10 @@ const CustomOrg = (props) => {
111
117
  };
112
118
 
113
119
  useEffect(() => {
114
- getData();
120
+ if (mode !== 'multiple') {
121
+ getData();
122
+ }
123
+
115
124
  // onDataChange && onDataChange(dataSource);
116
125
  // eslint-disable-next-line react-hooks/exhaustive-deps
117
126
  }, []);
@@ -144,7 +153,9 @@ const CustomOrg = (props) => {
144
153
  const res = await deleteCustomGroup({ id: item.id });
145
154
  if (res.code === 200) {
146
155
  Message('删除成功', 'success');
147
-
156
+ if (mode === 'multiple') {
157
+ multipleTreeRef?.current?.onRefresh();
158
+ }
148
159
  getData(true);
149
160
  }
150
161
  }
@@ -159,7 +170,7 @@ const CustomOrg = (props) => {
159
170
  getUserData(id);
160
171
  return;
161
172
  }
162
- getData(true);
173
+ multipleTreeRef?.current?.onRefresh(id);
163
174
  };
164
175
  const actionHandle = (e, flag, info) => {
165
176
  e.stopPropagation();
@@ -237,13 +248,18 @@ const CustomOrg = (props) => {
237
248
  )}
238
249
  {mode === 'multiple' && (
239
250
  <div className="custom-org-page-list">
240
- <TabList
251
+ <MultipleTree
241
252
  onDoubleClickChange={onDoubleClickChange}
242
- onItemSelect={itemSelect}
243
- selectedKeys={itemKeys}
244
- type={'edit'}
245
- onItemAction={onItemAction}
246
- dataSource={dataSource.filter((item) => !targetKeys.includes(item.id))}
253
+ targetKeys={targetKeys}
254
+ selectedKeys={selectedKeys}
255
+ mode={'multiple'}
256
+ onItemSelect={onItemSelect}
257
+ onValueChange={onValueChange}
258
+ onDataChange={onDataChange}
259
+ onItemSelectAll={onItemSelectAll}
260
+ type="default"
261
+ ref={multipleTreeRef}
262
+ actionHandle={actionHandle}
247
263
  />
248
264
  </div>
249
265
  )}
@@ -262,7 +278,16 @@ const CustomOrg = (props) => {
262
278
  >
263
279
  <CustomModal
264
280
  actionInfo={actionInfo}
265
- onClose={onClose}
281
+ onClose={(flag) => {
282
+ if (flag === 'noRefesh') {
283
+ setAcitonInfo({
284
+ type: 'add',
285
+ visible: false,
286
+ });
287
+ return;
288
+ }
289
+ onClose(flag);
290
+ }}
266
291
  mode={mode}
267
292
  setAcitonInfo={setAcitonInfo}
268
293
  />
@@ -6,6 +6,17 @@
6
6
  height:100%;
7
7
  }
8
8
  }
9
+ .ant-tree .ant-tree-treenode{
10
+ width: 100%;
11
+ }
12
+ .ant-tree .ant-tree-node-content-wrapper{
13
+ display: inline-block;
14
+ flex: 1;
15
+ }
16
+ .tree-header-multip{
17
+ display: flex;
18
+ justify-content: space-between;
19
+ }
9
20
  .ant-collapse-content-box{
10
21
  padding: 0px;
11
22
  }
@@ -0,0 +1,112 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import TabList from '../tabList';
3
+ import { getUsersByConditions, getOrgsByConditions } from '../../api/tabList';
4
+ import { Pagination } from 'dcp-design-react';
5
+
6
+ const OrgPageIndex = (props) => {
7
+ const {
8
+ mode,
9
+ selectedKeys,
10
+ targetKeys,
11
+ onDataChange,
12
+ onValueChange,
13
+ onItemSelect,
14
+ searchValue,
15
+ params = {},
16
+ onDoubleClickChange,
17
+ type,
18
+ } = props;
19
+ const [dataSource, setDataSource] = useState<any[]>([]);
20
+ const [itemKeys, setItemKeys] = useState<any[]>([]);
21
+ const [total, setTotal] = useState(0);
22
+ const [page, setPage] = useState(1);
23
+ const [fetchParams, setFetchParams] = useState<any>({});
24
+ const [loading, setLoading] = useState<boolean>(false);
25
+ const dataList = useRef<any[]>([]);
26
+ useEffect(() => {
27
+ setItemKeys(selectedKeys || []);
28
+ }, [selectedKeys]);
29
+ const itemSelect = (value, checked) => {
30
+ if (mode === 'multiple') {
31
+ onItemSelect && onItemSelect(value, checked);
32
+ return;
33
+ }
34
+ setItemKeys([value]);
35
+ const field = dataSource.find((item) => item.id === value);
36
+ onValueChange && onValueChange({ ...field, value: field.id, label: field.userName });
37
+ };
38
+ const fetchHandleApi = async (params) => {
39
+ if (type !== 'org') {
40
+ return getUsersByConditions(params);
41
+ }
42
+ return getOrgsByConditions(params);
43
+ };
44
+ const getData = async (params) => {
45
+ setLoading(true);
46
+ const res = await fetchHandleApi(params).finally(() => {
47
+ setLoading(false);
48
+ });
49
+
50
+ if (res.code === 200) {
51
+ const data = res.data?.records || res.data?.list;
52
+ const list = data.map((item) => {
53
+ return {
54
+ ...item,
55
+ id: item.loginName || item.id,
56
+ key: item.loginName || item.id,
57
+ oldId: item.id,
58
+ title: item.userName || item.name,
59
+
60
+ // deptName: item.departmentName | item.parentOrgName,
61
+ };
62
+ });
63
+ setDataSource(list || []);
64
+ list.forEach((item) => {
65
+ if (!dataList.current.find((items) => items.id === item.id)) {
66
+ dataList.current.push(item);
67
+ }
68
+ });
69
+ onDataChange && onDataChange(dataList.current);
70
+ setTotal(res.data.total);
71
+ }
72
+ };
73
+ const pageChange = (page, pageSize) => {
74
+ setPage(page);
75
+ setFetchParams({ ...fetchParams, currentPage: page });
76
+ };
77
+ useEffect(() => {
78
+ if (fetchParams.currentPage) {
79
+ getData({ ...fetchParams });
80
+ }
81
+
82
+ // eslint-disable-next-line react-hooks/exhaustive-deps
83
+ }, [fetchParams]);
84
+ useEffect(() => {
85
+ setFetchParams({ pageSize: 10, currentPage: 1 });
86
+ }, []);
87
+ // const ondrownChange = (field) => {
88
+ // setFetchParams({ pageSize: 10, currentPage: 1, orgTypeCode: field.key });
89
+ // };
90
+ return (
91
+ <div className="recetly-page-index search-page-list">
92
+ {/* <DropDownList onDataChange={ondrownChange} /> */}
93
+ <TabList
94
+ onItemSelect={itemSelect}
95
+ loading={loading}
96
+ onDoubleClickChange={onDoubleClickChange}
97
+ selectedKeys={itemKeys}
98
+ dataSource={dataSource.filter((item) => !targetKeys.includes(item.id))}
99
+ />
100
+ <Pagination
101
+ simple
102
+ size="small"
103
+ current={page}
104
+ defaultCurrent={1}
105
+ showTotal={(total) => `共 ${total} 条`}
106
+ total={total}
107
+ onChange={pageChange}
108
+ />
109
+ </div>
110
+ );
111
+ };
112
+ export default OrgPageIndex;