@hzab/flowlong-designer 0.0.1 → 0.0.3

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 CHANGED
@@ -1,2 +1,5 @@
1
+ # @hzab/flowlong-designer@0.0.2
2
+ 重构人员选择
3
+
1
4
  # @hzab/flowlong-designer@0.0.1
2
- 组件初始化
5
+ 组件初始化
package/README.md CHANGED
@@ -20,9 +20,32 @@ import Demo from "@hzab/flowlong-designer";
20
20
 
21
21
  ### InfoPanel Attributes
22
22
 
23
+ | 参数 | 类型 | 必填 | 默认值 | 说明 |
24
+ | ------ | ------ | ---- | ------ | ----------------- |
25
+ | value | Object | 否 | - | 数据信息的 schema |
26
+ | listConfig | Object | 否 | - | 人员选择的 config |
27
+ | roleListConfig | Object | 否 | - | 角色选择的 config |
28
+ | initiatorListConfig | Object | 否 | - | 发起人选择的 config |
29
+
30
+
31
+
32
+ ### InfoPanel listConfig|roleListConfig | initiatorListConfig
33
+
23
34
  | 参数 | 类型 | 必填 | 默认值 | 说明 |
24
35
  | ------ | ------ | ---- | ------ | ----------------- |
25
- | schema | Object | | - | 数据信息的 schema |
36
+ | value | Object | | [] | 选中的人员数据 |
37
+ | model | Object | 否 | - | 列表的请求 model (getListApi) |
38
+ | searchModel | Object | 否 | - | 搜索列表的请求 model (getListApi) |
39
+ | queryKey | string | 否 | parentId | 列表的请求 model 的入参 key |
40
+ | searchQueryKey | string | 否 | search | 搜索列表的请求 model 的入参 key |
41
+ | labelKey | string | 否 | label | labelKey |
42
+ | valueKey | string | 否 | value | valueKey |
43
+ | imgKey | string | 否 | img | imgKey 头像 |
44
+ | isUserKey | string | 否 | isUser | 区分部门和人员 |
45
+ | hasPagination | boolean | 否 | true | 列表是否分页 |
46
+ | hasSearch | boolean | 否 | true | 是否有搜索 |
47
+ | hasSearchPagination | boolean | 否 | true | 搜索列表是否分页 |
48
+
26
49
 
27
50
  # 组件开发流程
28
51
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hzab/flowlong-designer",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "自定义审批流配置组件",
5
5
  "main": "src",
6
6
  "scripts": {
@@ -46,6 +46,9 @@
46
46
  ]
47
47
  },
48
48
  "dependencies": {
49
+ "@hzab/data-model": "^1.7.0",
50
+ "@hzab/deep-list": "^0.0.2",
51
+ "@hzab/group-user-selector": "^0.0.4",
49
52
  "nanoid": "^3.3.7"
50
53
  }
51
54
  }
@@ -51,7 +51,7 @@ export const Approver = (props) => {
51
51
  return false;
52
52
  }
53
53
  } else if (nodeConf.setType == 2) {
54
- return nodeConf.examineLevel == 1 ? "直接主管" : `发起人的第${nodeConf.examineLevel}级主管`;
54
+ return nodeConf.examineLevel == 1 ? "直接部门经理" : `发起人的第${nodeConf.examineLevel}级部门经理`;
55
55
  } else if (nodeConf.setType == 3) {
56
56
  if (nodeConf.nodeAssigneeList && nodeConf.nodeAssigneeList.length > 0) {
57
57
  const roles = nodeConf.nodeAssigneeList.map((item) => item.name).join("、");
@@ -65,6 +65,8 @@ export const Approver = (props) => {
65
65
  return "发起人自己";
66
66
  } else if (nodeConf.setType == 7) {
67
67
  return "连续多级主管";
68
+ } else if (nodeConf.setType == 9) {
69
+ return "驻点队长";
68
70
  }
69
71
  }
70
72
 
@@ -193,13 +195,18 @@ export const Approver = (props) => {
193
195
  type="primary"
194
196
  icon={<PlusOutlined />}
195
197
  onClick={() =>
196
- selectorCtx.setSelectHandler(1, form.nodeAssigneeList, (selected) => {
197
- setForm((f) => {
198
- // 设置 人员、角色 列表数组
199
- f.nodeAssigneeList = selected;
200
- return { ...f };
201
- });
202
- })
198
+ selectorCtx.setSelectHandler(
199
+ 1,
200
+ form.nodeAssigneeList,
201
+ (selected) => {
202
+ setForm((f) => {
203
+ // 设置 人员、角色 列表数组
204
+ f.nodeAssigneeList = selected;
205
+ return { ...f };
206
+ });
207
+ },
208
+ 2,
209
+ )
203
210
  }
204
211
  >
205
212
  选择人员
@@ -223,7 +230,7 @@ export const Approver = (props) => {
223
230
  </Form.Item>
224
231
  ) : null}
225
232
 
226
- {form.setType === 2 ? (
233
+ {/* {form.setType === 2 ? (
227
234
  <Form.Item label="指定主管" name="aaa">
228
235
  发起人的第
229
236
  <InputNumber
@@ -238,7 +245,7 @@ export const Approver = (props) => {
238
245
  />
239
246
  级主管
240
247
  </Form.Item>
241
- ) : null}
248
+ ) : null} */}
242
249
 
243
250
  {form.setType === 3 ? (
244
251
  <Form.Item label="选择角色" name="nodeAssigneeList">
@@ -246,13 +253,18 @@ export const Approver = (props) => {
246
253
  type="primary"
247
254
  icon={<PlusOutlined />}
248
255
  onClick={() =>
249
- selectorCtx.setSelectHandler(2, form.nodeAssigneeList, (selected) => {
250
- setForm((f) => {
251
- // 设置 人员、角色 列表数组
252
- f.nodeAssigneeList = selected;
253
- return { ...f };
254
- });
255
- })
256
+ selectorCtx.setSelectHandler(
257
+ 2,
258
+ form.nodeAssigneeList,
259
+ (selected) => {
260
+ setForm((f) => {
261
+ // 设置 人员、角色 列表数组
262
+ f.nodeAssigneeList = selected;
263
+ return { ...f };
264
+ });
265
+ },
266
+ 2,
267
+ )
256
268
  }
257
269
  >
258
270
  选择角色
@@ -276,7 +288,7 @@ export const Approver = (props) => {
276
288
  </Form.Item>
277
289
  ) : null}
278
290
 
279
- {form.setType === 4 ? (
291
+ {/* {form.setType === 4 ? (
280
292
  <Form.Item label="指定主管" name="selectMode">
281
293
  <Radio.Group
282
294
  options={selectModeOptions}
@@ -318,7 +330,7 @@ export const Approver = (props) => {
318
330
  });
319
331
  }}
320
332
  />{" "}
321
- 级主管
333
+ 级主管级主管
322
334
  </Form.Item>
323
335
  ) : null}
324
336
 
@@ -374,7 +386,7 @@ export const Approver = (props) => {
374
386
  });
375
387
  }}
376
388
  />
377
- </Form.Item>
389
+ </Form.Item> */}
378
390
  </Form>
379
391
  </Drawer>
380
392
  </div>
@@ -3,11 +3,12 @@
3
3
  */
4
4
  export const setTypeOptions = [
5
5
  { label: "指定成员", value: 1 },
6
- { label: "主管", value: 2 },
6
+ { label: "部门经理", value: 2 },
7
7
  { label: "角色", value: 3 },
8
- { label: "发起人自选", value: 4 },
9
- { label: "发起人自己", value: 5 },
10
- { label: "连续多级主管", value: 7 },
8
+ // { label: "发起人自选", value: 4 },
9
+ // { label: "发起人自己", value: 5 },
10
+ // { label: "连续多级主管", value: 7 },
11
+ { label: "驻点队长", value: 9 },
11
12
  ];
12
13
 
13
14
  /**
@@ -0,0 +1,30 @@
1
+ import { Input, InputNumber } from "antd";
2
+ import GroupUserSelectorModal from "../GroupUserSelectorModal";
3
+
4
+ interface FormMapProps {
5
+ type: string;
6
+ onChange?: (v: any) => void;
7
+ value?: any;
8
+ }
9
+ const Field = (props: FormMapProps) => {
10
+ const { type, onChange, value } = props;
11
+
12
+ return (
13
+ <>
14
+ {["day", "hour"].includes(type) && (
15
+ <Input
16
+ value={value}
17
+ placeholder="值"
18
+ type="number"
19
+ onChange={(e) => {
20
+ onChange(e.target.value);
21
+ }}
22
+ ></Input>
23
+ )}
24
+ {["dept", "useId"].includes(type) && (
25
+ <GroupUserSelectorModal type={type} onChange={onChange} value={value}></GroupUserSelectorModal>
26
+ )}
27
+ </>
28
+ );
29
+ };
30
+ export default Field;
@@ -0,0 +1,4 @@
1
+ .groupUserSelectorModal {
2
+ max-height: 500px;
3
+ overflow-y: auto;
4
+ }
@@ -0,0 +1,97 @@
1
+ import DataModel from "@hzab/data-model";
2
+ import GroupUserSelector from "@hzab/group-user-selector";
3
+ import { Input, Modal } from "antd";
4
+ import { useMemo, useRef, useState } from "react";
5
+ import "./index.less";
6
+ const fieldMap = {
7
+ dept: "deptList",
8
+ useId: "userNameVos",
9
+ };
10
+ const titleMap = {
11
+ dept: "部门",
12
+ useId: "用户",
13
+ };
14
+ const GroupUserSelectorModal = (props) => {
15
+ const { type, onChange, value = [] } = props;
16
+ const [open, setOpen] = useState(false);
17
+ const groupUserSelectorRef = useRef(null);
18
+ const deptModel = new DataModel({
19
+ getListApi: "/api/v1/sysOrg/getDeptList",
20
+ });
21
+ const userModel = new DataModel({
22
+ getListApi: "/api/v1/userinfo/userDetailListV2",
23
+ query: {
24
+ conditionStatus: 0,
25
+ },
26
+ getListMap(data) {
27
+ return {
28
+ ...data,
29
+ name: data.userName,
30
+ id: data.userId,
31
+ isUser: true,
32
+ };
33
+ },
34
+ });
35
+ const model = useMemo(() => {
36
+ if (type === "dept") {
37
+ return deptModel;
38
+ }
39
+ if (type === "useId") {
40
+ return userModel;
41
+ }
42
+ }, [type]);
43
+ const onOk = () => {
44
+ onChange(groupUserSelectorRef.current?.selectedList);
45
+ setOpen(false);
46
+ };
47
+
48
+ const inputValue = useMemo(() => {
49
+ if (type === "dept" && value) {
50
+ return value?.map((item) => item?.label)?.join(",");
51
+ }
52
+ if (type === "useId" && value) {
53
+ return value?.map((item) => item?.name)?.join(",");
54
+ }
55
+ }, [value, type]);
56
+ const userListConfig = {
57
+ searchQueryKey: "userName",
58
+ labelKey: "name",
59
+ valueKey: "id",
60
+ };
61
+ return (
62
+ <div>
63
+ <Input
64
+ value={inputValue}
65
+ readOnly
66
+ onClick={() => {
67
+ setOpen(true);
68
+ }}
69
+ placeholder="请点击编辑"
70
+ style={{ cursor: "pointer" }}
71
+ ></Input>
72
+ <Modal
73
+ title={titleMap[type]}
74
+ open={open}
75
+ onCancel={() => {
76
+ setOpen(false);
77
+ }}
78
+ width={800}
79
+ okText={"确认"}
80
+ cancelText={"取消"}
81
+ onOk={onOk}
82
+ centered
83
+ destroyOnClose
84
+ >
85
+ <div className="groupUserSelectorModal">
86
+ <GroupUserSelector
87
+ value={value || []}
88
+ ref={groupUserSelectorRef}
89
+ model={model}
90
+ {...(type === "useId" ? userListConfig : {})}
91
+ ></GroupUserSelector>
92
+ </div>
93
+ </Modal>
94
+ </div>
95
+ );
96
+ };
97
+ export default GroupUserSelectorModal;
@@ -2,10 +2,12 @@
2
2
  .branch-box .add-branch {
3
3
  background: var(--el-bg-color);
4
4
  }
5
+
5
6
  .branch-wrap {
6
7
  display: inline-flex;
7
8
  width: 100%;
8
9
  }
10
+
9
11
  .branch-box-wrap {
10
12
  display: flex;
11
13
  flex-flow: column wrap;
@@ -14,12 +16,14 @@
14
16
  width: 100%;
15
17
  flex-shrink: 0;
16
18
  }
19
+
17
20
  .col-box {
18
21
  display: inline-flex;
19
22
  flex-direction: column;
20
23
  align-items: center;
21
24
  position: relative;
22
25
  }
26
+
23
27
  .branch-box {
24
28
  display: flex;
25
29
  overflow: visible;
@@ -30,6 +34,7 @@
30
34
  position: relative;
31
35
  margin-top: 15px;
32
36
  }
37
+
33
38
  .branch-box .col-box::before {
34
39
  content: "";
35
40
  position: absolute;
@@ -43,11 +48,13 @@
43
48
  height: 100%;
44
49
  background-color: rgb(202, 202, 202);
45
50
  }
51
+
46
52
  .condition-node {
47
53
  display: inline-flex;
48
54
  flex-direction: column;
49
55
  min-height: 220px;
50
56
  }
57
+
51
58
  .condition-node-box {
52
59
  padding-top: 30px;
53
60
  padding-right: 50px;
@@ -59,6 +66,7 @@
59
66
  display: inline-flex;
60
67
  flex-direction: column;
61
68
  }
69
+
62
70
  .condition-node-box::before {
63
71
  content: "";
64
72
  position: absolute;
@@ -71,6 +79,7 @@
71
79
  height: 100%;
72
80
  background-color: rgb(202, 202, 202);
73
81
  }
82
+
74
83
  .auto-judge {
75
84
  position: relative;
76
85
  width: 220px;
@@ -81,6 +90,7 @@
81
90
  cursor: pointer;
82
91
  box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.1);
83
92
  }
93
+
84
94
  .auto-judge::before {
85
95
  content: "";
86
96
  position: absolute;
@@ -93,12 +103,15 @@
93
103
  border-color: rgb(202, 202, 202) transparent transparent;
94
104
  background: rgb(239, 239, 239);
95
105
  }
106
+
96
107
  .auto-judge .title {
97
108
  line-height: 16px;
98
109
  }
110
+
99
111
  .auto-judge .title .node-title {
100
112
  color: #15bc83;
101
113
  }
114
+
102
115
  .auto-judge .title .delete-btn {
103
116
  font-size: 15px;
104
117
  position: absolute;
@@ -107,35 +120,43 @@
107
120
  color: #999;
108
121
  display: none;
109
122
  }
123
+
110
124
  .auto-judge .title .priority-title {
111
125
  position: absolute;
112
126
  top: 15px;
113
127
  right: 15px;
114
128
  color: #999;
115
129
  }
130
+
116
131
  .auto-judge .content {
117
132
  position: relative;
118
133
  padding-top: 15px;
119
134
  }
135
+
120
136
  .auto-judge .content .placeholder {
121
137
  color: #999;
122
138
  }
139
+
123
140
  .auto-judge:hover {
124
141
  .delete-btn {
125
142
  display: block;
126
143
  }
144
+
127
145
  .priority-title {
128
146
  display: none;
129
147
  }
130
148
  }
149
+
131
150
  .auto-judge:hover {
132
151
  .sort-left {
133
152
  display: flex;
134
153
  }
154
+
135
155
  .sort-right {
136
156
  display: flex;
137
157
  }
138
158
  }
159
+
139
160
  .auto-judge .sort-left {
140
161
  position: absolute;
141
162
  top: 0;
@@ -147,6 +168,7 @@
147
168
  align-items: center;
148
169
  flex-direction: column;
149
170
  }
171
+
150
172
  .auto-judge .sort-right {
151
173
  position: absolute;
152
174
  top: 0;
@@ -158,10 +180,12 @@
158
180
  align-items: center;
159
181
  flex-direction: column;
160
182
  }
183
+
161
184
  .auto-judge .sort-left:hover,
162
185
  .auto-judge .sort-right:hover {
163
186
  background: #eee;
164
187
  }
188
+
165
189
  .auto-judge:after {
166
190
  pointer-events: none;
167
191
  content: "";
@@ -174,10 +198,12 @@
174
198
  border-radius: 4px;
175
199
  transition: all 0.1s;
176
200
  }
201
+
177
202
  .auto-judge:hover:after {
178
203
  border: 1px solid #3296fa;
179
204
  box-shadow: 0 0 6px 0 rgba(50, 150, 250, 0.3);
180
205
  }
206
+
181
207
  .top-left-cover-line,
182
208
  .top-right-cover-line {
183
209
  position: absolute;
@@ -186,6 +212,7 @@
186
212
  background-color: #fff;
187
213
  top: -2px;
188
214
  }
215
+
189
216
  .bottom-left-cover-line,
190
217
  .bottom-right-cover-line {
191
218
  position: absolute;
@@ -194,15 +221,19 @@
194
221
  background-color: #fff;
195
222
  bottom: -2px;
196
223
  }
224
+
197
225
  .top-left-cover-line {
198
226
  left: -1px;
199
227
  }
228
+
200
229
  .top-right-cover-line {
201
230
  right: -1px;
202
231
  }
232
+
203
233
  .bottom-left-cover-line {
204
234
  left: -1px;
205
235
  }
236
+
206
237
  .bottom-right-cover-line {
207
238
  right: -1px;
208
239
  }
@@ -271,7 +302,12 @@
271
302
  }
272
303
 
273
304
  div:not(:first-child) {
274
- margin-left: 16px;
305
+ // margin-left: 16px;
306
+ }
307
+
308
+ .condition-content-box-item {
309
+ margin-right: 16px;
310
+
275
311
  }
276
312
  }
277
313
 
@@ -311,9 +347,10 @@
311
347
  padding: 12px;
312
348
  }
313
349
  }
350
+
314
351
  .ant-drawer-footer {
315
- .ant-btn + .ant-btn {
352
+ .ant-btn+.ant-btn {
316
353
  margin-left: 12px;
317
354
  }
318
355
  }
319
- }
356
+ }
@@ -5,6 +5,7 @@ import { LeftOutlined, DeleteOutlined, RightOutlined, EditOutlined } from "@ant-
5
5
  import AddNode from "../AddNode";
6
6
 
7
7
  import "./index.less";
8
+ import Field from "./components/Field";
8
9
 
9
10
  /**
10
11
  * 操作符选项列表
@@ -19,6 +20,13 @@ export const operatorOptions = [
19
20
  { label: "包含", value: "include" },
20
21
  { label: "不包含", value: "notinclude" },
21
22
  ];
23
+ /**条件字段下拉数据 */
24
+ const conditionOption = [
25
+ { label: "天", value: "day" },
26
+ { label: "小时", value: "hour" },
27
+ { label: "部门", value: "dept" },
28
+ { label: "用户id", value: "useId" },
29
+ ];
22
30
 
23
31
  export const Branch = (props) => {
24
32
  const { modelValue: nodeConfig, onChange, ItemSlot } = props;
@@ -89,7 +97,17 @@ export const Branch = (props) => {
89
97
  var { conditionList } = nodeConfig.conditionNodes[idx];
90
98
  if (conditionList && conditionList.length == 1) {
91
99
  const text = conditionList
92
- .map((conditionGroup) => conditionGroup.map((item) => `${item.label}${item.operator}${item.value}`))
100
+ .map((conditionGroup) =>
101
+ conditionGroup.map((item) => {
102
+ if (item?.field === "dept") {
103
+ return `${item.label}${item.operator}${item.value?.map((el) => el?.label)}`;
104
+ }
105
+ if (item?.field === "useId") {
106
+ return `${item.label}${item.operator}${item.value?.map((el) => el?.userName)}`;
107
+ }
108
+ return `${item.label}${item.operator}${item.value}`;
109
+ }),
110
+ )
93
111
  .join(" 和 ");
94
112
  return text;
95
113
  } else if (conditionList && conditionList.length > 1) {
@@ -142,7 +160,7 @@ export const Branch = (props) => {
142
160
  function onConditionAdd(conditionList) {
143
161
  conditionList.push({
144
162
  label: "",
145
- field: "",
163
+ field: "day",
146
164
  operator: "=",
147
165
  value: "",
148
166
  });
@@ -264,7 +282,7 @@ export const Branch = (props) => {
264
282
  onClose={onDrawerClose}
265
283
  destroyOnClose
266
284
  getContainer="body"
267
- width={600}
285
+ width={800}
268
286
  title={
269
287
  <div className="node-wrap-drawer-title">
270
288
  {isEditTitle ? (
@@ -336,33 +354,40 @@ export const Branch = (props) => {
336
354
  setForm((f) => ({ ...f }));
337
355
  }}
338
356
  placeholder="描述"
357
+ className="condition-content-box-item"
339
358
  />
340
- <Input
359
+ <Select
360
+ options={conditionOption}
341
361
  value={condition.field}
342
362
  onChange={(e) => {
343
- condition.field = e.target.value;
363
+ condition.field = e;
364
+ condition.value = null;
344
365
  // 更新数据
345
366
  setForm((f) => ({ ...f }));
346
367
  }}
368
+ className="condition-content-box-item"
347
369
  placeholder="条件字段"
348
370
  />
349
371
  <Select
350
372
  value={condition.operator}
351
373
  onChange={(val) => {
352
374
  condition.operator = val;
375
+ // 更新数据
376
+ setForm((f) => ({ ...f }));
353
377
  }}
354
378
  placeholder="请选择"
355
379
  options={operatorOptions}
380
+ className="condition-content-box-item"
356
381
  ></Select>
357
- <Input
382
+ <Field
358
383
  value={condition.value}
384
+ type={condition.field}
359
385
  onChange={(e) => {
360
- condition.value = e.target.value;
386
+ condition.value = e;
361
387
  // 更新数据
362
388
  setForm((f) => ({ ...f }));
363
389
  }}
364
- placeholder="值"
365
- />
390
+ ></Field>
366
391
  </div>
367
392
  </div>
368
393
  </div>
@@ -143,10 +143,10 @@ export const Promoter = (props) => {
143
143
  f.nodeAssigneeList = selected;
144
144
  return { ...f };
145
145
  });
146
- })
146
+ }, 1)
147
147
  }
148
148
  >
149
- 选择角色
149
+ 选择人员
150
150
  </Button>
151
151
  <div className="tags-list">
152
152
  {form.nodeAssigneeList?.map((it, idx) => {
@@ -5,3 +5,6 @@
5
5
  }
6
6
  }
7
7
  }
8
+ .send-title {
9
+ background-color: #3296fa;
10
+ }