@qmlight/web-platform-components 1.0.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.
Files changed (52) hide show
  1. package/AsyncExe/index.tsx +9 -0
  2. package/AsyncExe/src/index.tsx +118 -0
  3. package/AsyncExe/src/lang/en.tsx +11 -0
  4. package/AsyncExe/src/lang/index.tsx +21 -0
  5. package/AsyncExe/src/lang/zh-cn.tsx +11 -0
  6. package/Demo/index.module.less +11 -0
  7. package/Demo/index.tsx +32 -0
  8. package/LICENSE +21 -0
  9. package/README.md +9 -0
  10. package/SearchAssistanceSelect/index.tsx +3 -0
  11. package/SearchAssistanceSelect/src/SearchAssistanceComponent/AdvancedSearch/api/index.js +6 -0
  12. package/SearchAssistanceSelect/src/SearchAssistanceComponent/AdvancedSearch/api/server.js +14 -0
  13. package/SearchAssistanceSelect/src/SearchAssistanceComponent/AdvancedSearch/index.less +23 -0
  14. package/SearchAssistanceSelect/src/SearchAssistanceComponent/AdvancedSearch/index.tsx +115 -0
  15. package/SearchAssistanceSelect/src/SearchAssistanceComponent/AdvancedSearch/popover.tsx +42 -0
  16. package/SearchAssistanceSelect/src/SearchAssistanceComponent/AdvancedSearch/searchboard.tsx +359 -0
  17. package/SearchAssistanceSelect/src/SearchAssistanceComponent/api/server.js +15 -0
  18. package/SearchAssistanceSelect/src/SearchAssistanceComponent/api/tabList/index.js +55 -0
  19. package/SearchAssistanceSelect/src/SearchAssistanceComponent/api/treeData/index.js +26 -0
  20. package/SearchAssistanceSelect/src/SearchAssistanceComponent/component/customNode/index.tsx +62 -0
  21. package/SearchAssistanceSelect/src/SearchAssistanceComponent/component/customNode/style.less +9 -0
  22. package/SearchAssistanceSelect/src/SearchAssistanceComponent/component/customOrg/customModal.tsx +234 -0
  23. package/SearchAssistanceSelect/src/SearchAssistanceComponent/component/customOrg/index.tsx +245 -0
  24. package/SearchAssistanceSelect/src/SearchAssistanceComponent/component/customOrg/style.less +27 -0
  25. package/SearchAssistanceSelect/src/SearchAssistanceComponent/component/dept/index.tsx +104 -0
  26. package/SearchAssistanceSelect/src/SearchAssistanceComponent/component/dept/style.less +9 -0
  27. package/SearchAssistanceSelect/src/SearchAssistanceComponent/component/dropdownList/index.tsx +74 -0
  28. package/SearchAssistanceSelect/src/SearchAssistanceComponent/component/dropdownList/style.less +19 -0
  29. package/SearchAssistanceSelect/src/SearchAssistanceComponent/component/recently/index.tsx +86 -0
  30. package/SearchAssistanceSelect/src/SearchAssistanceComponent/component/roleList/index.tsx +61 -0
  31. package/SearchAssistanceSelect/src/SearchAssistanceComponent/component/search/index.tsx +109 -0
  32. package/SearchAssistanceSelect/src/SearchAssistanceComponent/component/subordinate/index.tsx +64 -0
  33. package/SearchAssistanceSelect/src/SearchAssistanceComponent/component/tabList/index.tsx +99 -0
  34. package/SearchAssistanceSelect/src/SearchAssistanceComponent/component/tabList/style.less +86 -0
  35. package/SearchAssistanceSelect/src/SearchAssistanceComponent/index.tsx +298 -0
  36. package/SearchAssistanceSelect/src/SearchAssistanceComponent/searchModal.tsx +109 -0
  37. package/SearchAssistanceSelect/src/SearchAssistanceComponent/searchTabs.tsx +153 -0
  38. package/SearchAssistanceSelect/src/SearchAssistanceComponent/style.less +41 -0
  39. package/SearchAssistanceSelect/src/SearchAssistanceComponent/transfer/index.tsx +211 -0
  40. package/SearchAssistanceSelect/src/SearchAssistanceComponent/transfer/searchTransferRight.tsx +93 -0
  41. package/SearchAssistanceSelect/src/SearchAssistanceComponent/transfer/style.less +69 -0
  42. package/SearchAssistanceSelect/src/SearchAssistanceComponent/treeData/index.tsx +407 -0
  43. package/SearchAssistanceSelect/src/SearchAssistanceComponent/treeData/style.less +9 -0
  44. package/SearchAssistanceSelect/src/index.tsx +73 -0
  45. package/SearchAssistanceSelect/src/style.less +29 -0
  46. package/UploadFileMenu/download.ts +15 -0
  47. package/UploadFileMenu/index.tsx +3 -0
  48. package/UploadFileMenu/src/api/index.js +44 -0
  49. package/UploadFileMenu/src/api/server.js +9 -0
  50. package/UploadFileMenu/src/index.tsx +256 -0
  51. package/index.js +10 -0
  52. package/package.json +22 -0
@@ -0,0 +1,298 @@
1
+ import React, { useState, useMemo, useRef, useEffect } from 'react';
2
+ import { Select, Spin, Tooltip } from 'dcp-design-react';
3
+ import { SearchOutlined, CloseCircleFilled } from '@/icons';
4
+ import debounce from 'lodash-es/debounce';
5
+ import './style.less';
6
+ import SearchAssistanceModel from './searchModal';
7
+ import isEmpty from 'lodash-es/isEmpty';
8
+ import { getUsersByConditions } from './api/tabList';
9
+ const debounceTimeout = 800;
10
+ type SeachProps = {
11
+ value?: any;
12
+ fetchOptions: (search: any) => Promise<any>;
13
+ onChange?: (a) => void;
14
+ mode?: 'multiple' | 'tags' | undefined;
15
+ params?: any;
16
+ items?: itemsProps[];
17
+ $$form?: any;
18
+ option?: any;
19
+ modalVisible?: boolean;
20
+ type: string | undefined;
21
+ title?: string;
22
+ customData?: any[];
23
+ };
24
+ type itemsProps = {
25
+ label: string;
26
+ key: string;
27
+ type?: string;
28
+ };
29
+ const { Option } = Select;
30
+ const SearchAssistanceSelectSelect: React.FC<SeachProps> = ({
31
+ fetchOptions = getUsersByConditions,
32
+ onChange: onValueChange,
33
+ value: data,
34
+ mode,
35
+ params,
36
+ items,
37
+ option,
38
+ $$form,
39
+ modalVisible = false,
40
+ type,
41
+ title,
42
+ customData = [],
43
+ }) => {
44
+ const [value, setValue] = useState<any>(mode ? [] : undefined);
45
+ const [options, setOptions] = useState<any[]>([]);
46
+ const [fetching, setFetching] = useState(false);
47
+ const fetchRef = useRef(0);
48
+ const [visible, setVisible] = useState<boolean>(false);
49
+ const dataValue = useRef<any>(mode ? [] : {});
50
+ const [status, setStatus] = useState(false);
51
+ const pages = useRef<any>(0);
52
+ const currentPage = useRef<number>(1);
53
+ const [loading, setLoading] = useState(false);
54
+ const [searchValue, setSearchValue] = useState('');
55
+ const searchData = useRef([]);
56
+ useEffect(() => {
57
+ setValue(data);
58
+ // eslint-disable-next-line react-hooks/exhaustive-deps
59
+ }, [data]);
60
+ useEffect(() => {
61
+ setVisible(modalVisible);
62
+ }, [modalVisible]);
63
+ const debounceFetcher = useMemo(() => {
64
+ const loadOptions = async (info) => {
65
+ fetchRef.current += 1;
66
+ const fetchId = fetchRef.current;
67
+ setFetching(true);
68
+ if (currentPage.current === 1) {
69
+ setOptions([]);
70
+ }
71
+ let parm: any = { ...info };
72
+ // if (params) {
73
+ // parm = {
74
+ // ...parm,
75
+ // ...params,
76
+ // };
77
+ // }
78
+ if (type === 'org') {
79
+ parm = {
80
+ ...parm,
81
+ currentPage: currentPage.current,
82
+ pageSize: 20,
83
+ };
84
+ }
85
+ const res = await fetchOptions(parm);
86
+ if (fetchId !== fetchRef.current) {
87
+ // for fetch callback order
88
+ return;
89
+ }
90
+ if (res.code === 200) {
91
+ if (type === 'org') {
92
+ const list = res.data.list.map((item) => {
93
+ return {
94
+ ...item,
95
+ label: item.name,
96
+ value: item.id,
97
+ orgName: item.parentOrgName,
98
+ };
99
+ });
100
+ searchData.current = currentPage.current === 1 ? list : searchData.current.concat(list);
101
+ setOptions(searchData.current);
102
+ setLoading(false);
103
+ pages.current = res.data.total;
104
+ setFetching(false);
105
+ return;
106
+ } else {
107
+ setOptions(
108
+ res.data.map((item) => {
109
+ return {
110
+ ...item,
111
+ label: item.userName || item.name,
112
+ value: item.id,
113
+ deptName: item.departmentName,
114
+ };
115
+ })
116
+ );
117
+ setLoading(false);
118
+ setFetching(false);
119
+ }
120
+ }
121
+ };
122
+
123
+ return debounce(loadOptions, debounceTimeout);
124
+ // eslint-disable-next-line react-hooks/exhaustive-deps
125
+ }, [fetchOptions, debounceTimeout]);
126
+ const onModalDataChange = (value) => {
127
+ dataValue.current = value;
128
+ onDataChange && onDataChange(value);
129
+ setValue(value);
130
+ };
131
+ const onDataChange = (value) => {
132
+ onValueChange && onValueChange(value);
133
+ option?.onChange && option.onChange(value);
134
+ };
135
+ console.log(items);
136
+ return (
137
+ <div className="search-select-page">
138
+ <Select
139
+ // mode="tags"
140
+ mode={mode}
141
+ size="middle"
142
+ showSearch
143
+ showArrow
144
+ getPopupContainer={(trigger) => trigger}
145
+ searchValue={searchValue}
146
+ disabled={option?.readOnly || option?.disabled || $$form?.props?.formType === 'onlyShow'}
147
+ onPopupScroll={(event: any) => {
148
+ if (type !== 'org') {
149
+ return;
150
+ }
151
+ const nodeClient = event.target?.firstChild?.clientHeight || 0;
152
+ const scrollHeight = event.target.scrollTop;
153
+ if (
154
+ nodeClient - scrollHeight - 256 < 10 &&
155
+ currentPage.current * 20 <= pages.current &&
156
+ !loading
157
+ ) {
158
+ setLoading(true);
159
+ currentPage.current++;
160
+ debounceFetcher({ name: searchValue });
161
+ }
162
+ // console.log(event.target.scrollTop);
163
+ }}
164
+ dropdownRender={(menu) => {
165
+ return (
166
+ <>
167
+ {menu}
168
+ {loading ? <Spin tip="加载中..." /> : <></>}
169
+ </>
170
+ );
171
+ }}
172
+ suffixIcon={
173
+ <>
174
+ {/* {!isEmpty(value) && (
175
+ <CloseCircleFilled
176
+ className={`${!status ? 'search-clear' : 'active-search-clear'}`}
177
+ onClick={() => {
178
+ // setStatus(false);
179
+ if (!mode) {
180
+ dataValue.current = {};
181
+ setValue(dataValue.current);
182
+ return;
183
+ }
184
+ dataValue.current = [];
185
+ onDataChange && onDataChange(dataValue.current);
186
+ setValue(dataValue.current);
187
+ }}
188
+ />
189
+ )} */}
190
+ <SearchOutlined
191
+ onClick={(e) => {
192
+ e.stopPropagation();
193
+ if (
194
+ option?.readOnly ||
195
+ option?.disabled ||
196
+ $$form?.props?.formType === 'onlyShow'
197
+ ) {
198
+ return;
199
+ }
200
+ setVisible(true);
201
+ }}
202
+ />
203
+ </>
204
+ }
205
+ labelInValue
206
+ filterOption={false}
207
+ // onChange={(values) => {
208
+ // console.log(dataValue.current);
209
+ // setStatus(!isEmpty(values));
210
+ // }}
211
+ // options={options}
212
+ value={isEmpty(value) ? (mode ? [] : undefined) : value}
213
+ loading={fetching}
214
+ onSelect={(value: any) => {
215
+ const field = options.find((item) => item.value === value?.value);
216
+ if (!mode) {
217
+ dataValue.current = field;
218
+ onDataChange && onDataChange(dataValue.current);
219
+ setValue(dataValue.current);
220
+ return;
221
+ }
222
+ const oldField = dataValue.current.find((item) => item.value === value.value);
223
+ if (!oldField && field) {
224
+ dataValue.current = dataValue.current.concat([field]);
225
+ onDataChange && onDataChange(dataValue.current);
226
+ setValue(dataValue.current);
227
+ }
228
+ }}
229
+ onDeselect={(value: any) => {
230
+ if (!mode) {
231
+ dataValue.current = {};
232
+ setValue(dataValue.current);
233
+ return;
234
+ }
235
+ dataValue.current = dataValue.current.filter((item) => item.value !== value.value);
236
+ onDataChange && onDataChange(dataValue.current);
237
+ setValue(dataValue.current);
238
+ }}
239
+ onFocus={() => {
240
+ setStatus(true);
241
+ }}
242
+ onBlur={() => {
243
+ setStatus(false);
244
+ }}
245
+ notFoundContent={fetching ? <Spin size="small" /> : null}
246
+ onSearch={(value) => {
247
+ if (type === 'doc' || type === 'customNode') {
248
+ return;
249
+ }
250
+ if (type === 'org') {
251
+ currentPage.current = 1;
252
+ }
253
+ setSearchValue(value);
254
+
255
+ debounceFetcher({ name: value });
256
+ }}
257
+ >
258
+ {options.map((item) => {
259
+ return (
260
+ <Option key={item.value} value={item.value} label={item.label}>
261
+ <Tooltip
262
+ placement="right"
263
+ title={
264
+ <div>
265
+ {item.userName
266
+ ? `${item.label}|${item.jobName || 'DEFAULT'}|${item.orgName}|${
267
+ item.deptName
268
+ }`
269
+ : type === 'org'
270
+ ? `${item.label}|${item.orgName}
271
+ `
272
+ : item.label}
273
+ </div>
274
+ }
275
+ >
276
+ <div>{item.label}</div>
277
+ </Tooltip>
278
+ </Option>
279
+ );
280
+ })}
281
+ </Select>
282
+
283
+ <SearchAssistanceModel
284
+ data={value}
285
+ mode={mode}
286
+ items={items}
287
+ type={type}
288
+ onChange={onModalDataChange}
289
+ onClose={() => setVisible(false)}
290
+ visible={visible}
291
+ title={title || '人力资源'}
292
+ customData={customData}
293
+ />
294
+ </div>
295
+ );
296
+ };
297
+ SearchAssistanceSelectSelect.displayName = 'SearchAssistanceSelectSelect';
298
+ export default SearchAssistanceSelectSelect;
@@ -0,0 +1,109 @@
1
+ import React, { useEffect, useState } from 'react';
2
+ import { DcpModal, QmButton, QmSpace } from 'dcp-design-react';
3
+ import SearchTabs from './searchTabs';
4
+ import { cloneDeep } from '@/utils';
5
+ import isEmpty from 'lodash-es/isEmpty';
6
+
7
+ type ModalProps = {
8
+ visible: boolean;
9
+ title: string;
10
+ data: any;
11
+ onChange?: (a) => void;
12
+ onClose: () => void;
13
+ mode?: string | boolean | undefined;
14
+ items?: itemsProps[];
15
+ type: string | undefined;
16
+ customData?: any[];
17
+ };
18
+ type itemsProps = {
19
+ label: string;
20
+ key: string;
21
+ type?: string;
22
+ };
23
+ const SearchAssistanceModel: React.FC<ModalProps> = (props) => {
24
+ const { title, visible, onClose, data, mode, onChange, items, type, customData = [] } = props;
25
+ const [newData, setNewData] = useState<any>(mode ? [] : {});
26
+
27
+ const onDataChange = (value) => {
28
+ setNewData(cloneDeep(value));
29
+ if (!mode) {
30
+ onChange && onChange({ ...value, value: value.id, label: value.title });
31
+ onClose();
32
+ }
33
+ };
34
+ useEffect(() => {
35
+ if (isEmpty(data)) {
36
+ return;
37
+ }
38
+ if (mode === 'multiple') {
39
+ setNewData(
40
+ data.map((item) => {
41
+ return {
42
+ ...item,
43
+ title: item.label || item.text || item.title,
44
+ key: item.value,
45
+ id: item.value,
46
+ };
47
+ }) || []
48
+ );
49
+ } else {
50
+ setNewData({
51
+ ...data,
52
+ title: data.label || data.text || data.title,
53
+ key: data.value,
54
+ id: data.value,
55
+ });
56
+ }
57
+ // eslint-disable-next-line react-hooks/exhaustive-deps
58
+ }, [data]);
59
+ return (
60
+ <DcpModal
61
+ width={800}
62
+ height={540}
63
+ onClose={onClose}
64
+ bodyStyle={{
65
+ padding: 0,
66
+ }}
67
+ title={title}
68
+ visible={visible}
69
+ showFullScreen={false}
70
+ wrapClassName={'search-assistance-modal'}
71
+ >
72
+ <SearchTabs
73
+ data={newData}
74
+ items={items}
75
+ mode={mode}
76
+ onClose={onClose}
77
+ onDataChange={onDataChange}
78
+ customData={customData}
79
+ type={type}
80
+ />
81
+ {mode === 'multiple' ? (
82
+ <QmSpace className="action-footer">
83
+ <QmButton
84
+ type="primary"
85
+ onClick={() => {
86
+ onChange &&
87
+ onChange(
88
+ newData.map((item) => {
89
+ return {
90
+ ...item,
91
+ value: item.id,
92
+ label: item.title,
93
+ };
94
+ })
95
+ );
96
+ onClose();
97
+ }}
98
+ >
99
+ 确定{`(${newData.length})`}
100
+ </QmButton>
101
+ <QmButton onClick={() => onClose()}>取消</QmButton>
102
+ </QmSpace>
103
+ ) : (
104
+ <></>
105
+ )}
106
+ </DcpModal>
107
+ );
108
+ };
109
+ export default SearchAssistanceModel;
@@ -0,0 +1,153 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import { QmTabs, Input } from 'dcp-design-react';
3
+ import TreeData from './treeData';
4
+ import TransferIndex from './transfer';
5
+ import DeptPageIndex from './component/dept';
6
+ import SubordinateIndex from './component/subordinate';
7
+ import RecentlyPageIndex from './component/recently';
8
+ import SearchPageIndex from './component/search';
9
+ import AdvancedSearch from './AdvancedSearch';
10
+ import RoleListPage from './component/roleList';
11
+ import CustomOrg from './component/customOrg';
12
+ import CustomNode from './component/customNode';
13
+ import './style.less';
14
+ const { Search } = Input;
15
+ const componentList = {
16
+ '1': <RecentlyPageIndex />,
17
+ '2': <DeptPageIndex />,
18
+ '3': <SubordinateIndex />,
19
+ '4': <TreeData />,
20
+ '5': <SearchPageIndex />,
21
+ '6': <RoleListPage />,
22
+ '7': <CustomOrg />,
23
+ '8': <CustomNode />,
24
+ };
25
+ const item = [
26
+ {
27
+ label: '常用组',
28
+ key: '1',
29
+ },
30
+ // {
31
+ // label: '同部门',
32
+ // key: '2',
33
+ // },
34
+ // {
35
+ // label: '我的下属',
36
+ // key: '3',
37
+ // },
38
+ {
39
+ label: '组织结构',
40
+ key: '4',
41
+ type: 'default',
42
+ },
43
+ {
44
+ label: '自定义组',
45
+ key: '7',
46
+ type: 'customOrg',
47
+ },
48
+ ];
49
+ const SearchTabs = (props) => {
50
+ const { data, onClose, onDataChange, mode, items, customData } = props;
51
+ const [itemsList, setItemsList] = useState(item);
52
+ const [fetchParams, setFetchParams] = useState({});
53
+
54
+ const [activeKey, setActiveKey] = useState('1');
55
+ const prevActiveKey = useRef('1');
56
+ const onValueChange = (value) => {
57
+ onDataChange && onDataChange(value);
58
+ };
59
+ const tabChange = (value) => {
60
+ setActiveKey(value);
61
+ prevActiveKey.current = value;
62
+ };
63
+ const tabSearchChange = (params) => {
64
+ fetchHandle(params);
65
+ };
66
+ useEffect(() => {
67
+ if (items?.length) {
68
+ setActiveKey(items[0]?.key);
69
+ setItemsList(items);
70
+ }
71
+ }, [items]);
72
+ const fetchHandle = (field) => {
73
+ const { type, name } = field;
74
+ if (name === '') {
75
+ setActiveKey(prevActiveKey.current);
76
+ return;
77
+ }
78
+ if (type === 'default') {
79
+ const data = {
80
+ name,
81
+ // orgIdList: params.orgIdList?.map((item) => item.value),
82
+ // roleId: params.roleId?.value,
83
+ orgTypeCode: 'def',
84
+ };
85
+ setActiveKey('5');
86
+ setFetchParams(data);
87
+ }
88
+ if (type === 'role') {
89
+ setFetchParams({ name });
90
+ }
91
+ if (type === 'org') {
92
+ setFetchParams({
93
+ name,
94
+ });
95
+ }
96
+ };
97
+ const onSearch = (e) => {
98
+ setActiveKey('5');
99
+ setFetchParams({ name: e, orgTypeCode: 'def' });
100
+ };
101
+ return (
102
+ <div className="search-assistance-tabs">
103
+ <QmTabs
104
+ size="small"
105
+ activeKey={activeKey}
106
+ items={itemsList}
107
+ onChange={tabChange}
108
+ tabBarExtraContent={
109
+ mode ||
110
+ (itemsList.find((item) => item.key === activeKey)?.type === 'org' && activeKey === '4') ||
111
+ activeKey === '8' ? (
112
+ <></>
113
+ ) : (
114
+ <Search
115
+ // bordered={false}
116
+ // value={value}
117
+ // onChange={onSearchChange}
118
+ onSearch={onSearch}
119
+ allowClear
120
+ />
121
+ )
122
+ }
123
+ />
124
+ <div className={'search-assistance-tabs-content'}>
125
+ {mode === 'multiple' ? (
126
+ <TransferIndex
127
+ data={data || []}
128
+ customData={customData}
129
+ leftChildren={
130
+ componentList[activeKey] ? React.cloneElement(componentList[activeKey]) : <></>
131
+ }
132
+ onValueChange={onValueChange}
133
+ onTabChange={tabSearchChange}
134
+ params={fetchParams}
135
+ type={itemsList.find((item) => item.key === activeKey)?.type || 'default'}
136
+ />
137
+ ) : (
138
+ componentList[activeKey] &&
139
+ React.cloneElement(componentList[activeKey], {
140
+ mode,
141
+ selectedKeys: data?.value ? [data.value] : [],
142
+ onValueChange,
143
+ customData,
144
+ targetKeys: [],
145
+ params: fetchParams,
146
+ type: itemsList.find((item) => item.key === activeKey)?.type || 'default',
147
+ })
148
+ )}
149
+ </div>
150
+ </div>
151
+ );
152
+ };
153
+ export default SearchTabs;
@@ -0,0 +1,41 @@
1
+ .search-assistance-tabs{
2
+ .qm-tabs .ant-tabs-nav{
3
+ padding: 10px 10px 0px 10px;
4
+ margin-bottom: 0px;
5
+ }
6
+ flex: 1;
7
+ max-height: 100%;
8
+ &-content{
9
+ height:calc(100% - 50px)
10
+ }
11
+
12
+ }
13
+ .search-select-page{
14
+ .ant-select-dropdown > div:first-child{
15
+ height: 100%;
16
+ .ant-spin-spinning{
17
+ width: 100%;
18
+ height: 100%;
19
+ display: flex;
20
+ justify-content: center;
21
+ align-items: center;
22
+ }
23
+ .ant-breadcrumb-link{
24
+ cursor: pointer;
25
+ }
26
+ }
27
+ }
28
+
29
+ .search-assistance-modal{
30
+ .ant-modal-body{
31
+ display: flex;
32
+ flex-direction: column;
33
+ }
34
+
35
+ .action-footer{
36
+ padding: 10px;
37
+ border-top: 1px solid #f0f0f0;
38
+ justify-content: end;
39
+
40
+ }
41
+ }