@hzab/group-user-selector 0.0.9 → 0.0.11-alpha.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/CHANGELOG.md +12 -0
- package/README.md +97 -90
- package/package.json +57 -52
- package/src/assets/imgs/department.png +0 -0
- package/src/assets/imgs/emptyIcon.png +0 -0
- package/src/assets/imgs/searchIcon.png +0 -0
- package/src/components/ItemRenter/index.jsx +73 -46
- package/src/components/ItemRenter/index.less +57 -33
- package/src/components/SearchRenter/index.jsx +119 -108
- package/src/components/SearchRenter/index.less +51 -36
- package/src/index.less +84 -28
- package/src/index.tsx +94 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
# @hzab/group-user-selector@0.1.0
|
|
2
|
+
|
|
3
|
+
feat: 新增 iconCustomFunc 自定义返回图片函数
|
|
4
|
+
feat: 新增 LableSlot 插槽
|
|
5
|
+
feat: 新增 ItemRender 列表 item 自定义渲染
|
|
6
|
+
feat: 新增 SelectItemRender 选中 item 自定义渲染
|
|
7
|
+
feat: 新增 modal 计算选中人数模式
|
|
8
|
+
|
|
9
|
+
# @hzab/group-user-selector@0.0.10
|
|
10
|
+
|
|
11
|
+
feat: 搜索情况下默认不展示下级
|
|
12
|
+
|
|
1
13
|
# @hzab/group-user-selector@0.0.9
|
|
2
14
|
|
|
3
15
|
feat: 增加一键清除 API
|
package/README.md
CHANGED
|
@@ -1,90 +1,97 @@
|
|
|
1
|
-
# @hzab/group-user-selector
|
|
2
|
-
|
|
3
|
-
组件模板
|
|
4
|
-
|
|
5
|
-
- node@16.16.0
|
|
6
|
-
|
|
7
|
-
- 注意:首次克隆先执行 npm run prepare 命令
|
|
8
|
-
|
|
9
|
-
# 组件
|
|
10
|
-
|
|
11
|
-
## 示例
|
|
12
|
-
|
|
13
|
-
```jsx
|
|
14
|
-
import Demo from "@hzab/group-user-selector";
|
|
15
|
-
|
|
16
|
-
<Demo />;
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## API
|
|
20
|
-
|
|
21
|
-
### InfoPanel Attributes
|
|
22
|
-
|
|
23
|
-
| 参数 | 类型
|
|
24
|
-
| ------------------- |
|
|
25
|
-
| value | Object
|
|
26
|
-
| model | Object
|
|
27
|
-
| modelGetType | string
|
|
28
|
-
| searchModel | Object
|
|
29
|
-
| queryKey | string
|
|
30
|
-
| searchQueryKey | string
|
|
31
|
-
| labelKey | string
|
|
32
|
-
| valueKey | string
|
|
33
|
-
|
|
|
34
|
-
|
|
|
35
|
-
|
|
|
36
|
-
|
|
|
37
|
-
|
|
|
38
|
-
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
-
|
|
44
|
-
|
|
45
|
-
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
-
|
|
50
|
-
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
-
|
|
65
|
-
|
|
66
|
-
-
|
|
67
|
-
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
-
|
|
80
|
-
npm
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
1
|
+
# @hzab/group-user-selector
|
|
2
|
+
|
|
3
|
+
组件模板
|
|
4
|
+
|
|
5
|
+
- node@16.16.0
|
|
6
|
+
|
|
7
|
+
- 注意:首次克隆先执行 npm run prepare 命令
|
|
8
|
+
|
|
9
|
+
# 组件
|
|
10
|
+
|
|
11
|
+
## 示例
|
|
12
|
+
|
|
13
|
+
```jsx
|
|
14
|
+
import Demo from "@hzab/group-user-selector";
|
|
15
|
+
|
|
16
|
+
<Demo />;
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## API
|
|
20
|
+
|
|
21
|
+
### InfoPanel Attributes
|
|
22
|
+
|
|
23
|
+
| 参数 | 类型 | 必填 | 默认值 | 说明 |
|
|
24
|
+
| ------------------- | -------- | ---- | ----------- | ----------------------------------- |
|
|
25
|
+
| value | Object | 否 | [] | 选中的人员数据 |
|
|
26
|
+
| model | Object | 否 | - | 列表的请求 model (getListApi) |
|
|
27
|
+
| modelGetType | string | 否 | getList | 列表的请求类型 |
|
|
28
|
+
| searchModel | Object | 否 | - | 搜索列表的请求 model (getListApi) |
|
|
29
|
+
| queryKey | string | 否 | parentId | 列表的请求 model 的入参 key |
|
|
30
|
+
| searchQueryKey | string | 否 | search | 搜索列表的请求 model 的入参 key |
|
|
31
|
+
| labelKey | string | 否 | label | labelKey |
|
|
32
|
+
| valueKey | string | 否 | value | valueKey |
|
|
33
|
+
| phoneKey | string | 否 | phoneNumber | phoneKey 电话 |
|
|
34
|
+
| totalKey | string | 否 | total | totalKey 选中总数人 |
|
|
35
|
+
| imgKey | string | 否 | img | imgKey 头像 |
|
|
36
|
+
| isUserKey | string | 否 | isUser | 区分部门和人员 |
|
|
37
|
+
| hasPagination | boolean | 否 | true | 列表是否分页 |
|
|
38
|
+
| hasSearch | boolean | 否 | true | 是否有搜索 |
|
|
39
|
+
| hasSearchPagination | boolean | 否 | true | 搜索列表是否分页 |
|
|
40
|
+
| searchPlaceholder | string | 否 | "搜索成员" | 搜索框的提示词 |
|
|
41
|
+
| modal | string | 否 | default | default:选中总数 other:选中人数 |
|
|
42
|
+
| iconCustomFunc | function | 否 | - | 图片的回调函数,入参 item,返回地址 |
|
|
43
|
+
| LableSlot | function | 否 | - | label 插槽,入参 item,返回 DOM |
|
|
44
|
+
| ItemRender | function | 否 | - | 整行 item 自定义渲染 |
|
|
45
|
+
| SelectItemRender | function | 否 | - | 选中后 item 自定义渲染 |
|
|
46
|
+
|
|
47
|
+
# 组件开发流程
|
|
48
|
+
|
|
49
|
+
- 在 config/webpack.config.js 中按需修改 library 配置的文件名
|
|
50
|
+
- 在 config/webpack.config.js 中按需修改 alias 配置的包名,便于本地调试
|
|
51
|
+
- 在 tsconfig.json 中按需修改 paths 配置的包名,解决 ts 报错问题
|
|
52
|
+
- npm run dev
|
|
53
|
+
|
|
54
|
+
## 文件目录
|
|
55
|
+
|
|
56
|
+
- example 本地开发测试代码
|
|
57
|
+
- src 组件源码
|
|
58
|
+
|
|
59
|
+
## 命令
|
|
60
|
+
|
|
61
|
+
- Mac 执行该命令,设置 pre-commit 为可执行文件
|
|
62
|
+
|
|
63
|
+
- npm run mac-chmod
|
|
64
|
+
- chmod +x .husky && chmod +x .husky/pre-commit
|
|
65
|
+
|
|
66
|
+
- 生成文档:npm run docs
|
|
67
|
+
- 本地运行:npm run dev
|
|
68
|
+
|
|
69
|
+
## 发布
|
|
70
|
+
|
|
71
|
+
- npm 源和云效源都需要发布
|
|
72
|
+
|
|
73
|
+
- 命令:npm publish --access public
|
|
74
|
+
- 发布目录:
|
|
75
|
+
- src
|
|
76
|
+
|
|
77
|
+
### nrm
|
|
78
|
+
|
|
79
|
+
- 安装
|
|
80
|
+
npm install -g nrm
|
|
81
|
+
- 增加源
|
|
82
|
+
nrm add aliyun https://packages.aliyun.com/62046985b3ead41b374a17f7/npm/npm-registry/
|
|
83
|
+
- 切换源
|
|
84
|
+
nrm use aliyun
|
|
85
|
+
nrm use npm
|
|
86
|
+
- 登录(账号密码在 https://packages.aliyun.com/npm/npm-registry/guide 查看)
|
|
87
|
+
npm login --registry=https://packages.aliyun.com/62046985b3ead41b374a17f7/npm/npm-registry/
|
|
88
|
+
|
|
89
|
+
## 配置
|
|
90
|
+
|
|
91
|
+
### 配置文件
|
|
92
|
+
|
|
93
|
+
- 本地配置文件:config/config.js
|
|
94
|
+
|
|
95
|
+
### webpack 配置文件
|
|
96
|
+
|
|
97
|
+
- config/webpack.config.js
|
package/package.json
CHANGED
|
@@ -1,52 +1,57 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@hzab/group-user-selector",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "",
|
|
5
|
-
"main": "src",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"dev": "webpack serve -c ./config/webpack.config.js --env local",
|
|
8
|
-
"build": "webpack -c ./config/webpack.config.js --env production",
|
|
9
|
-
"
|
|
10
|
-
"publish
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
"
|
|
18
|
-
"
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
},
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@hzab/group-user-selector",
|
|
3
|
+
"version": "0.0.11-alpha.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"main": "src",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "webpack serve -c ./config/webpack.config.js --env local",
|
|
8
|
+
"build": "webpack -c ./config/webpack.config.js --env production",
|
|
9
|
+
"version:alpha": "npm version prerelease --preid=alpha",
|
|
10
|
+
"publish:alpha": "npm publish --tag alpha",
|
|
11
|
+
"version:beta": "npm version prerelease --preid=beta",
|
|
12
|
+
"publish:beta": "npm publish --tag beta",
|
|
13
|
+
"version:patch": "npm version patch",
|
|
14
|
+
"version:minior": "npm version minor",
|
|
15
|
+
"version:major": "npm version major",
|
|
16
|
+
"publish:stable": "npm publish --access public",
|
|
17
|
+
"prepare": "husky install",
|
|
18
|
+
"mac-chmod": "chmod +x .husky && chmod +x .husky/pre-commit",
|
|
19
|
+
"docs": "typedoc"
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"src",
|
|
23
|
+
"CHANGELOG.md"
|
|
24
|
+
],
|
|
25
|
+
"keywords": [],
|
|
26
|
+
"author": "CaiYansong",
|
|
27
|
+
"license": "ISC",
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@hzab/permissions": "^1.0.0",
|
|
30
|
+
"@hzab/webpack-config": "^1.0.0",
|
|
31
|
+
"@types/react": "^17.0.62",
|
|
32
|
+
"@types/react-dom": "^17.0.20",
|
|
33
|
+
"antd": "^4.14.0",
|
|
34
|
+
"axios": "^1.4.0",
|
|
35
|
+
"eslint": "^8.30.0",
|
|
36
|
+
"less": "^4.1.3",
|
|
37
|
+
"mobx": "^6.7.0",
|
|
38
|
+
"mobx-react": "^7.6.0",
|
|
39
|
+
"react": "^17.0.2",
|
|
40
|
+
"react-dom": "^17.0.2",
|
|
41
|
+
"react-router-dom": "^6.14.1",
|
|
42
|
+
"typedoc": "^0.24.8",
|
|
43
|
+
"typescript": "^4.9.4"
|
|
44
|
+
},
|
|
45
|
+
"directories": {
|
|
46
|
+
"src": "src"
|
|
47
|
+
},
|
|
48
|
+
"lint-staged": {
|
|
49
|
+
"**.{js,jsx,ts,tsx,css,scss,less,json,html}": [
|
|
50
|
+
"prettier --write"
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@hzab/data-model": "^1.7.0",
|
|
55
|
+
"lodash": "^4.17.21"
|
|
56
|
+
}
|
|
57
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,46 +1,73 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Checkbox } from "antd";
|
|
3
|
-
|
|
4
|
-
import defaultAvatar from "../../assets/imgs/defaultAvatar.png";
|
|
5
|
-
import department from "../../assets/imgs/department.png";
|
|
6
|
-
|
|
7
|
-
import "./index.less";
|
|
8
|
-
|
|
9
|
-
function ItemRenter(props, ref) {
|
|
10
|
-
const {
|
|
11
|
-
labelKey = "label",
|
|
12
|
-
valueKey = "value",
|
|
13
|
-
isUserKey = "isUser",
|
|
14
|
-
imgKey = "img",
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
|
|
1
|
+
import { forwardRef } from "react";
|
|
2
|
+
import { Checkbox, Avatar } from "antd";
|
|
3
|
+
|
|
4
|
+
import defaultAvatar from "../../assets/imgs/defaultAvatar.png";
|
|
5
|
+
import department from "../../assets/imgs/department.png";
|
|
6
|
+
|
|
7
|
+
import "./index.less";
|
|
8
|
+
|
|
9
|
+
function ItemRenter(props, ref) {
|
|
10
|
+
const {
|
|
11
|
+
labelKey = "label",
|
|
12
|
+
valueKey = "value",
|
|
13
|
+
isUserKey = "isUser",
|
|
14
|
+
imgKey = "img",
|
|
15
|
+
phoneKey = "phoneNumber",
|
|
16
|
+
isCheck = false,
|
|
17
|
+
item,
|
|
18
|
+
handleClickItem,
|
|
19
|
+
handleCheckItem,
|
|
20
|
+
noNextLevel = false,
|
|
21
|
+
iconFunc,
|
|
22
|
+
LableSlot,
|
|
23
|
+
ItemRender,
|
|
24
|
+
} = props;
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<>
|
|
28
|
+
{ItemRender ? (
|
|
29
|
+
<ItemRender
|
|
30
|
+
key={item[valueKey]}
|
|
31
|
+
item={item}
|
|
32
|
+
handleCheckItem={() => handleCheckItem(item)}
|
|
33
|
+
handleClickItem={() => {
|
|
34
|
+
if (isCheck) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
handleClickItem(item);
|
|
38
|
+
}}
|
|
39
|
+
></ItemRender>
|
|
40
|
+
) : (
|
|
41
|
+
<div className="group-selection-list-item" key={item[valueKey]}>
|
|
42
|
+
<div className="avatar" onClick={() => handleCheckItem(item)}>
|
|
43
|
+
<Checkbox className="checkbox-item-box" checked={isCheck} />
|
|
44
|
+
<Avatar className="avatar-item" size={32} src={iconFunc(item)} />
|
|
45
|
+
{LableSlot ? (
|
|
46
|
+
<LableSlot item={item}></LableSlot>
|
|
47
|
+
) : (
|
|
48
|
+
<div className="label">
|
|
49
|
+
<div>{item[labelKey]}</div>
|
|
50
|
+
<div className="label-phone">{item[phoneKey]}</div>
|
|
51
|
+
</div>
|
|
52
|
+
)}
|
|
53
|
+
</div>
|
|
54
|
+
{item[isUserKey] || noNextLevel ? null : (
|
|
55
|
+
<div
|
|
56
|
+
className={`next ${isCheck ? "noNext" : ""}`}
|
|
57
|
+
onClick={() => {
|
|
58
|
+
if (isCheck) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
handleClickItem(item);
|
|
62
|
+
}}
|
|
63
|
+
>
|
|
64
|
+
下级
|
|
65
|
+
</div>
|
|
66
|
+
)}
|
|
67
|
+
</div>
|
|
68
|
+
)}
|
|
69
|
+
</>
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export default forwardRef(ItemRenter);
|
|
@@ -1,33 +1,57 @@
|
|
|
1
|
-
.group-selection-list-item {
|
|
2
|
-
display: flex;
|
|
3
|
-
align-items: center;
|
|
4
|
-
justify-content: space-between;
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
.avatar {
|
|
8
|
-
display: flex;
|
|
9
|
-
align-items: center;
|
|
10
|
-
cursor: pointer;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
1
|
+
.group-selection-list-item {
|
|
2
|
+
display: flex;
|
|
3
|
+
align-items: center;
|
|
4
|
+
justify-content: space-between;
|
|
5
|
+
padding: 8px 6px;
|
|
6
|
+
margin-bottom: 16px;
|
|
7
|
+
.avatar {
|
|
8
|
+
display: flex;
|
|
9
|
+
align-items: center;
|
|
10
|
+
cursor: pointer;
|
|
11
|
+
|
|
12
|
+
.label {
|
|
13
|
+
font-size: 16px;
|
|
14
|
+
color: #333333;
|
|
15
|
+
.label-phone {
|
|
16
|
+
font-size: 12px;
|
|
17
|
+
color: #999999;
|
|
18
|
+
line-height: 1;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.avatar-item {
|
|
23
|
+
margin: 0 6px;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
.next {
|
|
28
|
+
color: var(--ant-primary-color, rgb(64, 62, 245));
|
|
29
|
+
cursor: pointer;
|
|
30
|
+
flex-shrink: 0;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.noNext {
|
|
34
|
+
opacity: 0.5;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.checkbox-item-box {
|
|
38
|
+
.ant-checkbox-inner {
|
|
39
|
+
border-radius: 4px;
|
|
40
|
+
}
|
|
41
|
+
.ant-checkbox-checked:after {
|
|
42
|
+
border-radius: 4px;
|
|
43
|
+
}
|
|
44
|
+
// 选中状态:深蓝色底色
|
|
45
|
+
.ant-checkbox-checked {
|
|
46
|
+
.ant-checkbox-inner {
|
|
47
|
+
background-color: var(--ant-primary-color, rgb(64, 62, 245));
|
|
48
|
+
border-color: var(--ant-primary-color, rgb(64, 62, 245));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
&:hover {
|
|
54
|
+
background: #f7f7f7;
|
|
55
|
+
border-radius: 8px;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -1,108 +1,119 @@
|
|
|
1
|
-
import { useEffect, useState, forwardRef } from "react";
|
|
2
|
-
import { Input, message, Pagination } from "antd";
|
|
3
|
-
|
|
4
|
-
import "
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
const [
|
|
19
|
-
const [
|
|
20
|
-
const [
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
.
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
pageSize,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
{
|
|
84
|
-
<
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
|
|
1
|
+
import { useEffect, useState, forwardRef } from "react";
|
|
2
|
+
import { Input, message, Pagination } from "antd";
|
|
3
|
+
|
|
4
|
+
import SearchIcon from "../../assets/imgs/searchIcon.png";
|
|
5
|
+
import "./index.less";
|
|
6
|
+
|
|
7
|
+
function SearchRenter(props, ref) {
|
|
8
|
+
const {
|
|
9
|
+
searchModel,
|
|
10
|
+
searchQueryKey = "search",
|
|
11
|
+
searchPlaceholder = "搜索成员",
|
|
12
|
+
hasSearchPagination = true,
|
|
13
|
+
hasSearch = true,
|
|
14
|
+
ItemRenter,
|
|
15
|
+
setLoading = () => {},
|
|
16
|
+
} = props;
|
|
17
|
+
|
|
18
|
+
const [search, setSearch] = useState("");
|
|
19
|
+
const [searchList, setSearchList] = useState([]);
|
|
20
|
+
const [total, setTotal] = useState(0);
|
|
21
|
+
const [pageData, setPageData] = useState(
|
|
22
|
+
hasSearchPagination
|
|
23
|
+
? {
|
|
24
|
+
pageSize: 10,
|
|
25
|
+
pageNum: 1,
|
|
26
|
+
}
|
|
27
|
+
: {},
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const handleSearch = (data) => {
|
|
31
|
+
setLoading && setLoading(true);
|
|
32
|
+
searchModel &&
|
|
33
|
+
searchModel
|
|
34
|
+
.getList({ ...data })
|
|
35
|
+
.then((res) => {
|
|
36
|
+
setSearchList(res?.list || res || []);
|
|
37
|
+
setTotal(res?.pagination?.total || res?.total || 0);
|
|
38
|
+
})
|
|
39
|
+
.catch((err) => {
|
|
40
|
+
message.error(err._message || "未知错误");
|
|
41
|
+
})
|
|
42
|
+
.finally(() => {
|
|
43
|
+
setLoading && setLoading(false);
|
|
44
|
+
});
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const handleChangePage = (pageNum, pageSize) => {
|
|
48
|
+
const pages = {
|
|
49
|
+
pageNum: pageSize !== pageData?.pageSize ? 1 : pageNum,
|
|
50
|
+
pageSize,
|
|
51
|
+
};
|
|
52
|
+
setPageData({
|
|
53
|
+
...pages,
|
|
54
|
+
});
|
|
55
|
+
handleSearch({
|
|
56
|
+
[searchQueryKey]: search,
|
|
57
|
+
...pages,
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
const onSearch = (value) => {
|
|
62
|
+
setSearch(value);
|
|
63
|
+
if (!value) {
|
|
64
|
+
setPageData({
|
|
65
|
+
pageSize: 10,
|
|
66
|
+
pageNum: 1,
|
|
67
|
+
});
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const data = {
|
|
71
|
+
pageSize: pageData?.pageSize || 10,
|
|
72
|
+
pageNum: 1,
|
|
73
|
+
};
|
|
74
|
+
setPageData(data);
|
|
75
|
+
handleSearch({
|
|
76
|
+
[searchQueryKey]: value,
|
|
77
|
+
...data,
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<>
|
|
83
|
+
{hasSearch ? (
|
|
84
|
+
<Input.Search
|
|
85
|
+
className="group-selection-search-input"
|
|
86
|
+
prefix={<img className="group-selection-search-icon" src={SearchIcon}></img>}
|
|
87
|
+
onSearch={onSearch}
|
|
88
|
+
enterButton
|
|
89
|
+
placeholder={searchPlaceholder}
|
|
90
|
+
allowClear
|
|
91
|
+
/>
|
|
92
|
+
) : null}
|
|
93
|
+
|
|
94
|
+
{search ? (
|
|
95
|
+
<div className="group-selection-search-view">
|
|
96
|
+
<div className="group-selection-search-list">
|
|
97
|
+
{searchList.map((item, index) => {
|
|
98
|
+
return ItemRenter(item, true);
|
|
99
|
+
})}
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
{hasSearchPagination ? (
|
|
103
|
+
<div className="group-selection-search-pagination">
|
|
104
|
+
<Pagination
|
|
105
|
+
current={pageData?.pageNum}
|
|
106
|
+
total={total}
|
|
107
|
+
pageSize={pageData?.pageSize}
|
|
108
|
+
onChange={handleChangePage}
|
|
109
|
+
size="small"
|
|
110
|
+
/>
|
|
111
|
+
</div>
|
|
112
|
+
) : null}
|
|
113
|
+
</div>
|
|
114
|
+
) : null}
|
|
115
|
+
</>
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export default forwardRef(SearchRenter);
|
|
@@ -1,36 +1,51 @@
|
|
|
1
|
-
.group-selection-search-view {
|
|
2
|
-
display: flex;
|
|
3
|
-
flex-direction: column;
|
|
4
|
-
box-sizing: border-box;
|
|
5
|
-
position: absolute;
|
|
6
|
-
top: 56px;
|
|
7
|
-
left:
|
|
8
|
-
width: calc(100% -
|
|
9
|
-
height: calc(100% -
|
|
10
|
-
overflow-y: hidden;
|
|
11
|
-
z-index: 10;
|
|
12
|
-
background-color: #fff;
|
|
13
|
-
|
|
14
|
-
.group-selection-search-list {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
overflow-y: auto;
|
|
18
|
-
padding:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
1
|
+
.group-selection-search-view {
|
|
2
|
+
display: flex;
|
|
3
|
+
flex-direction: column;
|
|
4
|
+
box-sizing: border-box;
|
|
5
|
+
position: absolute;
|
|
6
|
+
top: 56px;
|
|
7
|
+
left: 14px;
|
|
8
|
+
width: calc(100% - 28px);
|
|
9
|
+
height: calc(100% - 60px);
|
|
10
|
+
overflow-y: hidden;
|
|
11
|
+
z-index: 10;
|
|
12
|
+
background-color: #fff;
|
|
13
|
+
|
|
14
|
+
.group-selection-search-list {
|
|
15
|
+
box-sizing: border-box;
|
|
16
|
+
flex: 1;
|
|
17
|
+
overflow-y: auto;
|
|
18
|
+
padding: 14px;
|
|
19
|
+
margin-bottom: 40px;
|
|
20
|
+
|
|
21
|
+
// &::-webkit-scrollbar {
|
|
22
|
+
// display: none;
|
|
23
|
+
// }
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.group-selection-search-pagination {
|
|
27
|
+
position: absolute;
|
|
28
|
+
left: 0;
|
|
29
|
+
bottom: 0;
|
|
30
|
+
width: 100%;
|
|
31
|
+
height: 40px;
|
|
32
|
+
display: flex;
|
|
33
|
+
align-items: center;
|
|
34
|
+
justify-content: center;
|
|
35
|
+
background-color: #fff;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
.group-selection-search-icon {
|
|
39
|
+
width: 16px;
|
|
40
|
+
height: auto;
|
|
41
|
+
margin-right: 6px;
|
|
42
|
+
}
|
|
43
|
+
.group-selection-search-input {
|
|
44
|
+
.ant-input-affix-wrapper {
|
|
45
|
+
border-radius: 8px !important;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.ant-input-group-addon {
|
|
49
|
+
display: none;
|
|
50
|
+
}
|
|
51
|
+
}
|
package/src/index.less
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
position: relative;
|
|
27
27
|
height: 100%;
|
|
28
28
|
overflow: hidden;
|
|
29
|
-
padding:
|
|
29
|
+
padding: 14px;
|
|
30
30
|
border-right: 1px solid #e8e8e8;
|
|
31
31
|
|
|
32
32
|
// .group-selection-search-view {
|
|
@@ -75,15 +75,33 @@
|
|
|
75
75
|
|
|
76
76
|
.group-selection-list-check {
|
|
77
77
|
margin: 12px 0;
|
|
78
|
+
|
|
79
|
+
.group-selection-all-checkbox-box {
|
|
80
|
+
margin-right: 6px;
|
|
81
|
+
|
|
82
|
+
.ant-checkbox-inner {
|
|
83
|
+
border-radius: 4px;
|
|
84
|
+
}
|
|
85
|
+
.ant-checkbox-checked:after {
|
|
86
|
+
border-radius: 4px;
|
|
87
|
+
}
|
|
88
|
+
// 选中状态:深蓝色底色
|
|
89
|
+
.ant-checkbox-checked {
|
|
90
|
+
.ant-checkbox-inner {
|
|
91
|
+
background-color: var(--ant-primary-color, rgb(64, 62, 245));
|
|
92
|
+
border-color: var(--ant-primary-color, rgb(64, 62, 245));
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
78
96
|
}
|
|
79
97
|
|
|
80
98
|
.group-selection-list-view {
|
|
81
99
|
flex: 1;
|
|
82
100
|
overflow: auto;
|
|
83
101
|
|
|
84
|
-
&::-webkit-scrollbar {
|
|
85
|
-
|
|
86
|
-
}
|
|
102
|
+
// &::-webkit-scrollbar {
|
|
103
|
+
// display: none;
|
|
104
|
+
// }
|
|
87
105
|
}
|
|
88
106
|
|
|
89
107
|
// .group-selection-list-item {
|
|
@@ -124,43 +142,81 @@
|
|
|
124
142
|
.group-selection-detail {
|
|
125
143
|
position: relative;
|
|
126
144
|
height: 100%;
|
|
127
|
-
|
|
145
|
+
display: flex;
|
|
146
|
+
flex-direction: column;
|
|
147
|
+
padding: 14px;
|
|
148
|
+
overflow: hidden;
|
|
149
|
+
|
|
150
|
+
// &::-webkit-scrollbar {
|
|
151
|
+
// display: none;
|
|
152
|
+
// }
|
|
128
153
|
|
|
129
|
-
|
|
130
|
-
|
|
154
|
+
.group-selection-detail-empty {
|
|
155
|
+
height: 100%;
|
|
156
|
+
display: flex;
|
|
157
|
+
flex-direction: column;
|
|
158
|
+
align-items: center;
|
|
159
|
+
justify-content: center;
|
|
160
|
+
.ant-empty-image {
|
|
161
|
+
margin-bottom: 24px;
|
|
162
|
+
}
|
|
163
|
+
.ant-empty-description {
|
|
164
|
+
font-size: 14px;
|
|
165
|
+
color: #777777;
|
|
166
|
+
}
|
|
131
167
|
}
|
|
168
|
+
|
|
132
169
|
.group-selection-detail-title {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
170
|
+
height: 36px;
|
|
171
|
+
display: flex;
|
|
172
|
+
align-items: center;
|
|
173
|
+
justify-content: space-between;
|
|
174
|
+
|
|
175
|
+
.group-selection-detail-close {
|
|
176
|
+
color: var(--ant-primary-color, rgb(64, 62, 245));
|
|
177
|
+
cursor: pointer;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.group-selection-detail-total {
|
|
181
|
+
font-weight: bold;
|
|
182
|
+
font-size: 14px;
|
|
183
|
+
color: #333333;
|
|
184
|
+
}
|
|
136
185
|
}
|
|
137
186
|
|
|
138
187
|
.group-selection-detail-list {
|
|
188
|
+
flex: 1;
|
|
139
189
|
display: flex;
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
190
|
+
flex-direction: column;
|
|
191
|
+
padding: 14px 0 24px 0;
|
|
192
|
+
overflow: auto;
|
|
143
193
|
|
|
144
194
|
.group-selection-detail-item {
|
|
145
195
|
flex-shrink: 0;
|
|
146
196
|
display: flex;
|
|
147
197
|
align-items: center;
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
198
|
+
justify-content: space-between;
|
|
199
|
+
padding: 8px 6px;
|
|
200
|
+
margin-bottom: 14px;
|
|
151
201
|
border-radius: 8px;
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
202
|
+
.avatar-text-box {
|
|
203
|
+
display: flex;
|
|
204
|
+
align-items: center;
|
|
205
|
+
|
|
206
|
+
.label {
|
|
207
|
+
font-size: 16px;
|
|
208
|
+
color: #333333;
|
|
209
|
+
margin-right: 12px;
|
|
210
|
+
.label-phone {
|
|
211
|
+
font-size: 12px;
|
|
212
|
+
color: #999999;
|
|
213
|
+
line-height: 1;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
.avatar-item {
|
|
218
|
+
margin-right: 7px;
|
|
219
|
+
}
|
|
164
220
|
}
|
|
165
221
|
}
|
|
166
222
|
}
|
package/src/index.tsx
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { useEffect, useState, useImperativeHandle, forwardRef, useReducer, useRef } from "react";
|
|
2
|
-
import { Input, Breadcrumb, Checkbox, message, Spin, Pagination, ConfigProvider } from "antd";
|
|
1
|
+
import { useEffect, useState, useImperativeHandle, forwardRef, useReducer, useRef, useMemo } from "react";
|
|
2
|
+
import { Input, Breadcrumb, Checkbox, message, Spin, Pagination, ConfigProvider, Empty, Avatar } from "antd";
|
|
3
3
|
import zhCN from "antd/es/locale/zh_CN";
|
|
4
|
-
import {
|
|
4
|
+
import { CloseOutlined } from "@ant-design/icons";
|
|
5
5
|
import "moment/locale/zh-cn";
|
|
6
6
|
import _ from "lodash";
|
|
7
7
|
|
|
8
8
|
import defaultAvatar from "./assets/imgs/defaultAvatar.png";
|
|
9
9
|
import department from "./assets/imgs/department.png";
|
|
10
|
+
import EmptyIcon from "./assets/imgs/emptyIcon.png";
|
|
10
11
|
import SearchRenter from "./components/SearchRenter";
|
|
11
12
|
import ItemRenter from "./components/ItemRenter";
|
|
12
13
|
|
|
@@ -20,10 +21,27 @@ function GroupSelection(props, ref) {
|
|
|
20
21
|
labelKey = "label",
|
|
21
22
|
valueKey = "value",
|
|
22
23
|
isUserKey = "isUser",
|
|
24
|
+
/** 手机号字段 */
|
|
25
|
+
phoneKey = "phoneNumber",
|
|
26
|
+
/** 选中总数人字段 */
|
|
27
|
+
totalKey = "total",
|
|
28
|
+
/** default:选中总数,other:根据 totalKey计算人数 */
|
|
29
|
+
modal = "default",
|
|
23
30
|
imgKey = "img",
|
|
24
31
|
hasPagination = true,
|
|
25
32
|
modelGetType = "getList",
|
|
26
33
|
allowClear = false,
|
|
34
|
+
unit = "人",
|
|
35
|
+
/** icon自定义 */
|
|
36
|
+
iconCustomFunc,
|
|
37
|
+
/** label插槽 */
|
|
38
|
+
LableSlot,
|
|
39
|
+
/** 列表item自定义渲染 */
|
|
40
|
+
ItemRender,
|
|
41
|
+
/** 选中item自定义渲染 */
|
|
42
|
+
SelectItemRender,
|
|
43
|
+
/** 选中文案自定义 */
|
|
44
|
+
SelectTitleRender,
|
|
27
45
|
} = props;
|
|
28
46
|
const [breadcrumb, setBreadcrumb] = useState([
|
|
29
47
|
{
|
|
@@ -79,6 +97,12 @@ function GroupSelection(props, ref) {
|
|
|
79
97
|
});
|
|
80
98
|
};
|
|
81
99
|
|
|
100
|
+
const totalSum = useMemo(() => {
|
|
101
|
+
return selectedList?.reduce((pre, cur) => {
|
|
102
|
+
return pre + (cur?.[totalKey] || 0);
|
|
103
|
+
}, 0);
|
|
104
|
+
}, [selectedList]);
|
|
105
|
+
|
|
82
106
|
useEffect(() => {
|
|
83
107
|
getTreeData();
|
|
84
108
|
}, []);
|
|
@@ -149,16 +173,29 @@ function GroupSelection(props, ref) {
|
|
|
149
173
|
return is;
|
|
150
174
|
};
|
|
151
175
|
|
|
152
|
-
const
|
|
176
|
+
const iconFunc = (item) => {
|
|
177
|
+
// 优先执行自定义函数,拿到结果
|
|
178
|
+
const customResult = iconCustomFunc?.(item);
|
|
179
|
+
// 自定义有返回值直接用,否则走默认逻辑
|
|
180
|
+
if (customResult) return customResult;
|
|
181
|
+
// 默认图片逻辑
|
|
182
|
+
return item[imgKey] ? item[imgKey] : item[isUserKey] ? defaultAvatar : department;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const Renter = (item, noNextLevel) => {
|
|
153
186
|
const isCheck = handleCheck(item);
|
|
154
187
|
return (
|
|
155
188
|
<ItemRenter
|
|
156
189
|
{...props}
|
|
157
190
|
item={item}
|
|
191
|
+
iconFunc={iconFunc}
|
|
158
192
|
isCheck={isCheck}
|
|
159
193
|
handleCheckItem={handleCheckItem}
|
|
160
194
|
handleCheckDelete={handleCheckDelete}
|
|
161
195
|
handleClickItem={handleClickItem}
|
|
196
|
+
noNextLevel={noNextLevel}
|
|
197
|
+
LableSlot={LableSlot}
|
|
198
|
+
ItemRender={ItemRender}
|
|
162
199
|
/>
|
|
163
200
|
);
|
|
164
201
|
};
|
|
@@ -187,11 +224,16 @@ function GroupSelection(props, ref) {
|
|
|
187
224
|
})}
|
|
188
225
|
</Breadcrumb>
|
|
189
226
|
<div className="group-selection-list-check">
|
|
190
|
-
<Checkbox
|
|
227
|
+
<Checkbox
|
|
228
|
+
className="group-selection-all-checkbox-box"
|
|
229
|
+
onChange={handleCheckAll}
|
|
230
|
+
checked={checkAll && !!selectList.length}
|
|
231
|
+
/>
|
|
232
|
+
全选
|
|
191
233
|
</div>
|
|
192
234
|
<div className="group-selection-list-view">
|
|
193
235
|
{selectList.map((item, index) => {
|
|
194
|
-
return Renter(item);
|
|
236
|
+
return Renter(item, false);
|
|
195
237
|
})}
|
|
196
238
|
</div>
|
|
197
239
|
{hasPagination ? (
|
|
@@ -208,18 +250,58 @@ function GroupSelection(props, ref) {
|
|
|
208
250
|
</div>
|
|
209
251
|
<div className="group-selection-detail">
|
|
210
252
|
{allowClear ? (
|
|
211
|
-
<div className="group-selection-detail-title"
|
|
212
|
-
|
|
253
|
+
<div className="group-selection-detail-title">
|
|
254
|
+
<div className="group-selection-detail-total">
|
|
255
|
+
{SelectTitleRender ? (
|
|
256
|
+
<SelectTitleRender value={modal === "default" ? selectedList?.length : totalSum}></SelectTitleRender>
|
|
257
|
+
) : (
|
|
258
|
+
` 已选:${modal === "default" ? selectedList?.length : totalSum}
|
|
259
|
+
${unit}`
|
|
260
|
+
)}
|
|
261
|
+
</div>
|
|
262
|
+
<div className="group-selection-detail-close" onClick={handleAllowClear}>
|
|
263
|
+
清空
|
|
264
|
+
</div>
|
|
213
265
|
</div>
|
|
214
266
|
) : null}
|
|
267
|
+
{!selectedList?.length && (
|
|
268
|
+
<div className="group-selection-detail-empty">
|
|
269
|
+
<Empty
|
|
270
|
+
description={"请选择部门或人员"}
|
|
271
|
+
image={EmptyIcon}
|
|
272
|
+
imageStyle={{
|
|
273
|
+
width: "250px",
|
|
274
|
+
height: "99px",
|
|
275
|
+
}}
|
|
276
|
+
></Empty>
|
|
277
|
+
</div>
|
|
278
|
+
)}
|
|
215
279
|
|
|
216
280
|
<div className="group-selection-detail-list">
|
|
217
281
|
{selectedList.map((item, index) => {
|
|
218
|
-
return (
|
|
282
|
+
return SelectItemRender ? (
|
|
283
|
+
<SelectItemRender
|
|
284
|
+
key={item[valueKey]}
|
|
285
|
+
item={item}
|
|
286
|
+
handleCheckDelete={() => handleCheckDelete(item)}
|
|
287
|
+
></SelectItemRender>
|
|
288
|
+
) : (
|
|
219
289
|
<div className="group-selection-detail-item" key={item[valueKey]}>
|
|
220
|
-
<
|
|
221
|
-
|
|
222
|
-
|
|
290
|
+
<div className="avatar-text-box">
|
|
291
|
+
<Avatar className="avatar-item" size={32} src={iconFunc(item)} />
|
|
292
|
+
{LableSlot ? (
|
|
293
|
+
<LableSlot item={item}></LableSlot>
|
|
294
|
+
) : (
|
|
295
|
+
<div className="label">
|
|
296
|
+
<div>{item[labelKey]}</div>
|
|
297
|
+
<div className="label-phone">{item[phoneKey]}</div>
|
|
298
|
+
</div>
|
|
299
|
+
)}
|
|
300
|
+
</div>
|
|
301
|
+
<CloseOutlined
|
|
302
|
+
style={{ cursor: "pointer", color: "#6a6a6a" }}
|
|
303
|
+
onClick={() => handleCheckDelete(item)}
|
|
304
|
+
/>
|
|
223
305
|
</div>
|
|
224
306
|
);
|
|
225
307
|
})}
|