@hzab/flowlong-designer 1.0.2 → 1.0.4

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,3 +1,13 @@
1
+ # @hzab/flowlong-designer@1.0.4
2
+
3
+ fix:@hzab/group-user-selector 版本更新;
4
+
5
+ # @hzab/flowlong-designer@1.0.3
6
+
7
+ fix:添加节点连接线优化;
8
+ feat:新增只读;
9
+ feat:新增可拖拽流程图
10
+
1
11
  # @hzab/flowlong-designer@1.0.2
2
12
 
3
13
  fix:修复条件节点删除
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hzab/flowlong-designer",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "自定义审批流配置组件",
5
5
  "main": "src",
6
6
  "scripts": {
@@ -23,7 +23,7 @@
23
23
  "devDependencies": {
24
24
  "@hzab/data-model": "^1.7.0",
25
25
  "@hzab/deep-list": "^0.0.2",
26
- "@hzab/group-user-selector": "^0.0.4",
26
+ "@hzab/group-user-selector": "^0.0.6",
27
27
  "@hzab/permissions": "0.1.1",
28
28
  "@hzab/webpack-config": "^0.7.1",
29
29
  "@types/react": "^17.0.62",
@@ -54,5 +54,8 @@
54
54
  "@hzab/deep-list": ">=0.0.2",
55
55
  "@hzab/group-user-selector": ">=0.0.4",
56
56
  "nanoid": "^3.3.7"
57
+ },
58
+ "dependencies": {
59
+ "react-draggable": "^4.5.0"
57
60
  }
58
61
  }
@@ -78,7 +78,7 @@ export function getNodeKey() {
78
78
  }
79
79
 
80
80
  export const AddNode = (props) => {
81
- const { modelValue, onChange, disable } = props;
81
+ const { modelValue, onChange, disable, readOnly } = props;
82
82
  /**重置nodeKey */
83
83
  const resetNodeKey = (item) => {
84
84
  if (item?.nodeKey) {
@@ -122,7 +122,7 @@ export const AddNode = (props) => {
122
122
  }
123
123
  >
124
124
  <Button
125
- disabled={disable}
125
+ disabled={disable || readOnly}
126
126
  className="add-node-btn"
127
127
  type="primary"
128
128
  shape="circle"
@@ -10,7 +10,7 @@ import { SelectContext } from "../../../Selector/SelectContext";
10
10
  import "./index.less";
11
11
 
12
12
  export const Approver = (props) => {
13
- const { modelValue = {}, onChange, disable } = props;
13
+ const { modelValue = {}, onChange, disable, readOnly } = props;
14
14
  const [form, setForm] = useState({
15
15
  nodeName: "",
16
16
  setType: undefined,
@@ -120,7 +120,7 @@ export const Approver = (props) => {
120
120
  <div className="title" style={{ background: "#ff943e" }}>
121
121
  <UserOutlined />
122
122
  <span>{modelValue?.nodeName}</span>
123
- {!disable && <DeleteOutlined className="node-close-btn" onClick={onNodeDel} />}
123
+ {!disable && !readOnly && <DeleteOutlined className="node-close-btn" onClick={onNodeDel} />}
124
124
  </div>
125
125
  <div className="content">
126
126
  {toText(modelValue) ? <span>{toText(modelValue)}</span> : <span className="placeholder">请选择</span>}
@@ -152,7 +152,9 @@ export const Approver = (props) => {
152
152
  ) : (
153
153
  <div className="drawer-title">
154
154
  {form.nodeName || "审批人设置"}
155
- {!disable && <EditOutlined className="node-wrap-drawer__title-edit" onClick={onEditTitle} />}
155
+ {!disable && !readOnly && (
156
+ <EditOutlined className="node-wrap-drawer__title-edit" onClick={onEditTitle} />
157
+ )}
156
158
  </div>
157
159
  )}
158
160
  </div>
@@ -162,12 +164,14 @@ export const Approver = (props) => {
162
164
  destroyOnClose
163
165
  getContainer="body"
164
166
  footer={
165
- <div className="approver-drawer-footer">
166
- <Button type="primary" onClick={onDrawerSave} disabled={disable}>
167
- 保存
168
- </Button>
169
- <Button onClick={onDrawerClose}>取消</Button>
170
- </div>
167
+ readOnly ? null : (
168
+ <div className="approver-drawer-footer">
169
+ <Button type="primary" onClick={onDrawerSave} disabled={disable}>
170
+ 保存
171
+ </Button>
172
+ <Button onClick={onDrawerClose}>取消</Button>
173
+ </div>
174
+ )
171
175
  }
172
176
  >
173
177
  <Form
@@ -181,6 +185,7 @@ export const Approver = (props) => {
181
185
  >
182
186
  <Form.Item label="审批人员类型" name="setType">
183
187
  <Select
188
+ disabled={readOnly}
184
189
  options={setTypeOptions}
185
190
  value={form.setType}
186
191
  onSelect={(val) => {
@@ -191,38 +196,42 @@ export const Approver = (props) => {
191
196
  return { ...f };
192
197
  });
193
198
  }}
199
+ className={`${readOnly ? "readonly-select" : ""}`}
194
200
  />
195
201
  </Form.Item>
196
202
 
197
203
  {form.setType === 1 ? (
198
204
  <Form.Item label="选择成员" name="nodeAssigneeList">
199
- <Button
200
- type="primary"
201
- icon={<PlusOutlined />}
202
- onClick={() =>
203
- selectorCtx.setSelectHandler(
204
- 1,
205
- form.nodeAssigneeList,
206
- (selected) => {
207
- setForm((f) => {
208
- // 设置 人员、角色 列表数组
209
- f.nodeAssigneeList = selected;
210
- return { ...f };
211
- });
212
- },
213
- 2,
214
- )
215
- }
216
- >
217
- 选择人员
218
- </Button>
205
+ {readOnly ? null : (
206
+ <Button
207
+ type="primary"
208
+ icon={<PlusOutlined />}
209
+ onClick={() =>
210
+ selectorCtx.setSelectHandler(
211
+ 1,
212
+ form.nodeAssigneeList,
213
+ (selected) => {
214
+ setForm((f) => {
215
+ // 设置 人员、角色 列表数组
216
+ f.nodeAssigneeList = selected;
217
+ return { ...f };
218
+ });
219
+ },
220
+ 2,
221
+ )
222
+ }
223
+ >
224
+ 选择人员
225
+ </Button>
226
+ )}
227
+
219
228
  <div className="tags-list">
220
229
  {form.nodeAssigneeList?.map((user, idx) => {
221
230
  return (
222
231
  <Tag
223
232
  key={user.id || idx}
224
233
  className="node-assignee-item"
225
- closable
234
+ closable={!readOnly}
226
235
  onClose={() => {
227
236
  onUserDel(idx);
228
237
  }}
@@ -254,33 +263,36 @@ export const Approver = (props) => {
254
263
 
255
264
  {form.setType === 3 ? (
256
265
  <Form.Item label="选择角色" name="nodeAssigneeList">
257
- <Button
258
- type="primary"
259
- icon={<PlusOutlined />}
260
- onClick={() =>
261
- selectorCtx.setSelectHandler(
262
- 2,
263
- form.nodeAssigneeList,
264
- (selected) => {
265
- setForm((f) => {
266
- // 设置 人员、角色 列表数组
267
- f.nodeAssigneeList = selected;
268
- return { ...f };
269
- });
270
- },
271
- 2,
272
- )
273
- }
274
- >
275
- 选择角色
276
- </Button>
266
+ {readOnly ? null : (
267
+ <Button
268
+ type="primary"
269
+ icon={<PlusOutlined />}
270
+ onClick={() =>
271
+ selectorCtx.setSelectHandler(
272
+ 2,
273
+ form.nodeAssigneeList,
274
+ (selected) => {
275
+ setForm((f) => {
276
+ // 设置 人员、角色 列表数组
277
+ f.nodeAssigneeList = selected;
278
+ return { ...f };
279
+ });
280
+ },
281
+ 2,
282
+ )
283
+ }
284
+ >
285
+ 选择角色
286
+ </Button>
287
+ )}
288
+
277
289
  <div className="tags-list">
278
290
  {form.nodeAssigneeList?.map((it, idx) => {
279
291
  return (
280
292
  <Tag
281
293
  key={it.id || idx}
282
294
  className="node-assignee-item"
283
- closable
295
+ closable={!readOnly}
284
296
  onClose={() => {
285
297
  onRoleDel(idx);
286
298
  }}
@@ -384,6 +396,7 @@ export const Approver = (props) => {
384
396
  <Radio.Group
385
397
  options={examineModeOptions}
386
398
  value={form.examineMode}
399
+ style={readOnly ? { pointerEvents: "none" } : {}}
387
400
  onChange={(e) => {
388
401
  setForm((f) => {
389
402
  form.examineMode = e.target.value;
@@ -6,13 +6,15 @@ interface FormMapProps {
6
6
  onChange?: (v: any) => void;
7
7
  value?: any;
8
8
  disabled?: boolean;
9
+ readOnly?: boolean;
9
10
  }
10
11
  const Field = (props: FormMapProps) => {
11
- const { type, onChange, value, disabled } = props;
12
+ const { type, onChange, value, disabled, readOnly } = props;
12
13
  return (
13
14
  <>
14
15
  {["day", "hour"].includes(type) && (
15
16
  <Input
17
+ readOnly={readOnly}
16
18
  disabled={disabled}
17
19
  value={value}
18
20
  placeholder="值"
@@ -28,6 +30,7 @@ const Field = (props: FormMapProps) => {
28
30
  onChange={onChange}
29
31
  value={value}
30
32
  disabled={disabled}
33
+ readOnly={readOnly}
31
34
  ></GroupUserSelectorModal>
32
35
  )}
33
36
  </>
@@ -12,7 +12,7 @@ const titleMap = {
12
12
  assignee: "用户",
13
13
  };
14
14
  const GroupUserSelectorModal = (props) => {
15
- const { type, onChange, value = [], disabled } = props;
15
+ const { type, onChange, value = [], disabled, readOnly } = props;
16
16
  const [open, setOpen] = useState(false);
17
17
  const groupUserSelectorRef = useRef(null);
18
18
  const deptModel = new DataModel({
@@ -94,12 +94,15 @@ const GroupUserSelectorModal = (props) => {
94
94
  <Input
95
95
  disabled={disabled}
96
96
  value={value?.deptUserLabel || null}
97
- readOnly
97
+ readOnly={readOnly}
98
98
  onClick={() => {
99
+ if (readOnly) {
100
+ return;
101
+ }
99
102
  setOpen(true);
100
103
  }}
101
104
  placeholder="请点击编辑"
102
- style={!disabled ? { cursor: "pointer" } : {}}
105
+ style={disabled || readOnly ? {} : { cursor: "pointer" }}
103
106
  ></Input>
104
107
  <Modal
105
108
  title={titleMap[type]}
@@ -121,6 +124,7 @@ const GroupUserSelectorModal = (props) => {
121
124
  model={model}
122
125
  searchModel={model}
123
126
  {...(type === "assignee" ? userListConfig : {})}
127
+ readOnly={readOnly}
124
128
  ></GroupUserSelector>
125
129
  </div>
126
130
  </Modal>
@@ -17,7 +17,8 @@
17
17
  flex-shrink: 0;
18
18
  }
19
19
 
20
- .col-box {
20
+ .col-box,
21
+ .col-box-custom {
21
22
  display: inline-flex;
22
23
  flex-direction: column;
23
24
  align-items: center;
@@ -49,6 +50,12 @@
49
50
  background-color: rgb(202, 202, 202);
50
51
  }
51
52
 
53
+ .branch-box .col-box-custom {
54
+ border-right: 2px solid #ffffff;
55
+ }
56
+
57
+
58
+
52
59
  .condition-node {
53
60
  display: inline-flex;
54
61
  flex-direction: column;
@@ -81,7 +88,8 @@
81
88
  }
82
89
 
83
90
  .auto-judge,
84
- .auto-judge-disable {
91
+ .auto-judge-disable,
92
+ .auto-judge-read-only {
85
93
  position: relative;
86
94
  width: 220px;
87
95
  min-height: 72px;
@@ -92,8 +100,11 @@
92
100
  box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.1);
93
101
  }
94
102
 
103
+
104
+
95
105
  .auto-judge::before,
96
- .auto-judge-disable::before {
106
+ .auto-judge-disable::before,
107
+ .auto-judge-read-only::before {
97
108
  content: "";
98
109
  position: absolute;
99
110
  top: -12px;
@@ -107,17 +118,20 @@
107
118
  }
108
119
 
109
120
  .auto-judge .title,
110
- .auto-judge-disable .title {
121
+ .auto-judge-disable .title,
122
+ .auto-judge-read-only .title {
111
123
  line-height: 16px;
112
124
  }
113
125
 
114
126
  .auto-judge .title .node-title,
115
- .auto-judge-disable .title .node-title {
127
+ .auto-judge-disable .title .node-title,
128
+ .auto-judge-read-only .title .node-title {
116
129
  color: #15bc83;
117
130
  }
118
131
 
119
132
  .auto-judge .title .delete-btn,
120
- .auto-judge-disable .title .delete-btn {
133
+ .auto-judge-disable .title .delete-btn,
134
+ .auto-judge-read-only .title .delete-btn {
121
135
  font-size: 15px;
122
136
  position: absolute;
123
137
  top: 15px;
@@ -127,7 +141,8 @@
127
141
  }
128
142
 
129
143
  .auto-judge .title .priority-title,
130
- .auto-judge-disable .title .priority-title {
144
+ .auto-judge-disable .title .priority-title,
145
+ .auto-judge-read-only .title .priority-title {
131
146
  position: absolute;
132
147
  top: 15px;
133
148
  right: 15px;
@@ -135,13 +150,15 @@
135
150
  }
136
151
 
137
152
  .auto-judge .content,
138
- .auto-judge-disable .content {
153
+ .auto-judge-disable .content,
154
+ .auto-judge-read-only .content {
139
155
  position: relative;
140
156
  padding-top: 15px;
141
157
  }
142
158
 
143
159
  .auto-judge .content .placeholder,
144
- .auto-judge-disable .content .placeholder {
160
+ .auto-judge-disable .content .placeholder,
161
+ .auto-judge-read-only .content .placeholder {
145
162
  color: #999;
146
163
  }
147
164
 
@@ -166,7 +183,8 @@
166
183
  }
167
184
 
168
185
  .auto-judge .sort-left,
169
- .auto-judge-disable .sort-left {
186
+ .auto-judge-disable .sort-left,
187
+ .auto-judge-read-only .sort-left {
170
188
  position: absolute;
171
189
  top: 0;
172
190
  bottom: 0;
@@ -179,7 +197,8 @@
179
197
  }
180
198
 
181
199
  .auto-judge .sort-right,
182
- .auto-judge-disable .sort-right {
200
+ .auto-judge-disable .sort-right,
201
+ .auto-judge-read-only .sort-right {
183
202
  position: absolute;
184
203
  top: 0;
185
204
  bottom: 0;
@@ -197,7 +216,8 @@
197
216
  }
198
217
 
199
218
  .auto-judge:after,
200
- .auto-judge-disable:after {
219
+ .auto-judge-disable:after,
220
+ .auto-judge-read-only:after {
201
221
  pointer-events: none;
202
222
  content: "";
203
223
  position: absolute;
@@ -210,15 +230,22 @@
210
230
  transition: all 0.1s;
211
231
  }
212
232
 
213
- .auto-judge:hover:after {
233
+ .auto-judge:hover:after,
234
+ .auto-judge-read-only:hover:after {
214
235
  border: 1px solid #3296fa;
215
236
  box-shadow: 0 0 6px 0 rgba(50, 150, 250, 0.3);
237
+
216
238
  }
217
239
 
218
240
  .auto-judge-disable {
219
241
  cursor: not-allowed;
220
242
  }
221
243
 
244
+ .auto-judge-read-only {
245
+ cursor: pointer;
246
+
247
+ }
248
+
222
249
  .top-left-cover-line,
223
250
  .top-right-cover-line {
224
251
  position: absolute;
@@ -37,7 +37,7 @@ const timeType = ["day", "hour"];
37
37
  /** 部门或用户 */
38
38
  const deptUserType = ["dept", "assignee"];
39
39
  export const Branch = (props) => {
40
- const { modelValue: nodeConfig, onChange, ItemSlot, disable } = props;
40
+ const { modelValue: nodeConfig, onChange, ItemSlot, disable, readOnly } = props;
41
41
  const [form, setForm] = useState({
42
42
  nodeName: "",
43
43
  setType: undefined,
@@ -67,6 +67,9 @@ export const Branch = (props) => {
67
67
  return arr;
68
68
  }
69
69
  function onTermAdd() {
70
+ if (readOnly) {
71
+ return;
72
+ }
70
73
  if (!nodeConfig.conditionNodes) {
71
74
  nodeConfig.conditionNodes = [];
72
75
  }
@@ -274,22 +277,42 @@ export const Branch = (props) => {
274
277
  operatorOptions,
275
278
  };
276
279
  };
280
+
281
+ const getEvenNumber = (number) => {
282
+ return number % 2 === 0;
283
+ };
284
+
277
285
  return (
278
286
  <div className="branch-wrap">
279
287
  <div className="branch-box-wrap">
280
288
  <div className="branch-box">
281
- <Button className="add-branch" onClick={onTermAdd} disabled={disable}>
289
+ <Button
290
+ className="add-branch"
291
+ onClick={onTermAdd}
292
+ disabled={disable}
293
+ style={readOnly ? { cursor: "default" } : {}}
294
+ >
282
295
  添加条件
283
296
  </Button>
284
297
  {nodeConfig?.conditionNodes?.map((item, idx) => {
285
298
  const conditionDisable = idx == nodeConfig.conditionNodes?.length - 1;
286
-
299
+ let num = 0;
300
+ let autoJudgeClassName = "auto-judge";
301
+ if (getEvenNumber(nodeConfig?.conditionNodes?.length)) {
302
+ num = nodeConfig?.conditionNodes?.length / 2;
303
+ }
304
+ if (conditionDisable) {
305
+ autoJudgeClassName = "auto-judge-disable";
306
+ }
307
+ if (readOnly) {
308
+ autoJudgeClassName = "auto-judge-read-only";
309
+ }
287
310
  return (
288
- <div className="col-box" key={idx}>
311
+ <div className={`col-box ${num - 1 === idx ? "col-box-custom" : ""}`} key={idx}>
289
312
  <div className="condition-node">
290
313
  <div className="condition-node-box">
291
314
  <div
292
- className={conditionDisable ? "auto-judge-disable" : "auto-judge"}
315
+ className={autoJudgeClassName}
293
316
  onClick={() => {
294
317
  if (!conditionDisable) {
295
318
  onShow(idx);
@@ -312,7 +335,7 @@ export const Branch = (props) => {
312
335
  <div className="title">
313
336
  <span className="node-title">{item.nodeName}</span>
314
337
  <span className="priority-title">优先级{item.priorityLevel}</span>
315
- {!conditionDisable && !disable && (
338
+ {!conditionDisable && !disable && !readOnly && (
316
339
  <DeleteOutlined
317
340
  className="delete-btn"
318
341
  onClick={(e) => {
@@ -403,17 +426,23 @@ export const Branch = (props) => {
403
426
  ) : (
404
427
  <div className="drawer-title">
405
428
  {form.nodeName || "条件设置"}
406
- {!disable && <EditOutlined className="node-wrap-drawer__title-edit" onClick={onEditTitle} />}
429
+ {!disable && !readOnly && (
430
+ <EditOutlined className="node-wrap-drawer__title-edit" onClick={onEditTitle} />
431
+ )}
407
432
  </div>
408
433
  )}
409
434
  </div>
410
435
  }
411
436
  footer={
412
437
  <>
413
- <Button type="primary" onClick={onDrawerSave} disabled={disable}>
414
- 保存
415
- </Button>
416
- <Button onClick={onDrawerClose}>取消</Button>
438
+ {readOnly ? null : (
439
+ <>
440
+ <Button type="primary" onClick={onDrawerSave} disabled={disable}>
441
+ 保存
442
+ </Button>
443
+ <Button onClick={onDrawerClose}>取消</Button>
444
+ </>
445
+ )}
417
446
  </>
418
447
  }
419
448
  >
@@ -425,16 +454,18 @@ export const Branch = (props) => {
425
454
  <div className="condition-group-editor">
426
455
  <div className="header">
427
456
  <span>条件组 {conditionGroupIdx + 1}</span>
428
- <div
429
- onClick={() => {
430
- if (disable) {
431
- return;
432
- }
433
- deleteConditionGroup(conditionGroupIdx);
434
- }}
435
- >
436
- <DeleteOutlined className={`branch-delete-icon ${disable ? "disable-delete-button" : ""}`} />
437
- </div>
457
+ {readOnly ? null : (
458
+ <div
459
+ onClick={() => {
460
+ if (disable) {
461
+ return;
462
+ }
463
+ deleteConditionGroup(conditionGroupIdx);
464
+ }}
465
+ >
466
+ <DeleteOutlined className={`branch-delete-icon ${disable ? "disable-delete-button" : ""}`} />
467
+ </div>
468
+ )}
438
469
  </div>
439
470
 
440
471
  <div className="main-content">
@@ -451,19 +482,21 @@ export const Branch = (props) => {
451
482
  <div className="condition-content" key={idx}>
452
483
  <div className="condition-relation">
453
484
  <span>{idx == 0 ? "当" : "且"}</span>
454
- <div onClick={() => deleteConditionList(conditionGroup, idx)}>
455
- <DeleteOutlined
456
- className={`branch-delete-icon ${disable ? "disable-delete-button" : ""}`}
457
- />
458
- </div>
485
+ {readOnly ? null : (
486
+ <div onClick={() => deleteConditionList(conditionGroup, idx)}>
487
+ <DeleteOutlined
488
+ className={`branch-delete-icon ${disable ? "disable-delete-button" : ""}`}
489
+ />
490
+ </div>
491
+ )}
459
492
  </div>
460
493
  <div className="condition-content">
461
494
  <div className="condition-content-box">
462
495
  <Select
463
- disabled={disable}
496
+ disabled={disable || readOnly}
464
497
  value={condition.label}
465
498
  options={descOption}
466
- className="condition-content-box-item"
499
+ className={`condition-content-box-item ${readOnly ? "readonly-select" : ""}`}
467
500
  onChange={(e) => {
468
501
  condition.label = e;
469
502
  if (e === "时长") {
@@ -479,7 +512,7 @@ export const Branch = (props) => {
479
512
  }}
480
513
  ></Select>
481
514
  <Select
482
- disabled={disable}
515
+ disabled={disable || readOnly}
483
516
  options={conditionOption}
484
517
  value={condition.field}
485
518
  onChange={(e) => {
@@ -491,11 +524,11 @@ export const Branch = (props) => {
491
524
  // 更新数据
492
525
  setForm((f) => ({ ...f }));
493
526
  }}
494
- className="condition-content-box-item"
527
+ className={`condition-content-box-item ${readOnly ? "readonly-select" : ""}`}
495
528
  placeholder="条件字段"
496
529
  />
497
530
  <Select
498
- disabled={disable}
531
+ disabled={disable || readOnly}
499
532
  value={condition.operator}
500
533
  onChange={(val) => {
501
534
  condition.operator = val;
@@ -504,9 +537,10 @@ export const Branch = (props) => {
504
537
  }}
505
538
  placeholder="请选择"
506
539
  options={operatorOptions}
507
- className="condition-content-box-item"
540
+ className={`condition-content-box-item ${readOnly ? "readonly-select" : ""}`}
508
541
  ></Select>
509
542
  <Field
543
+ readOnly={readOnly}
510
544
  disabled={disable}
511
545
  value={fieldValue}
512
546
  type={condition.field}
@@ -529,17 +563,21 @@ export const Branch = (props) => {
529
563
  })}
530
564
  </div>
531
565
  <div className="sub-content">
532
- <Button type="primary" onClick={() => onConditionAdd(conditionGroup)} disabled={disable}>
533
- 添加条件
534
- </Button>
566
+ {readOnly ? null : (
567
+ <Button type="primary" onClick={() => onConditionAdd(conditionGroup)} disabled={disable}>
568
+ 添加条件
569
+ </Button>
570
+ )}
535
571
  </div>
536
572
  </div>
537
573
  </div>
538
574
  );
539
575
  })}
540
- <Button onClick={onConditionGroupAdd} disabled={disable}>
541
- 添加条件组
542
- </Button>
576
+ {readOnly ? null : (
577
+ <Button onClick={onConditionGroupAdd} disabled={disable}>
578
+ 添加条件组
579
+ </Button>
580
+ )}
543
581
  </Drawer>
544
582
  </div>
545
583
  );
@@ -9,7 +9,7 @@ import "./index.less";
9
9
 
10
10
  export const Promoter = (props) => {
11
11
  const selectorCtx = useContext(SelectContext);
12
- const { modelValue: nodeConfig = {}, onChange, disable } = props;
12
+ const { modelValue: nodeConfig = {}, onChange, disable, readOnly } = props;
13
13
 
14
14
  const [drawer, setDrawer] = useState(false);
15
15
  const [isEditTitle, setIsEditTitle] = useState(false);
@@ -122,48 +122,55 @@ export const Promoter = (props) => {
122
122
  ) : (
123
123
  <div className="drawer-title">
124
124
  {form.nodeName || "发起人"}
125
- <EditOutlined className="node-wrap-drawer__title-edit" onClick={onEditTitle} />
125
+ {!disable && !readOnly && (
126
+ <EditOutlined className="node-wrap-drawer__title-edit" onClick={onEditTitle} />
127
+ )}
126
128
  </div>
127
129
  )}
128
130
  </div>
129
131
  }
130
132
  footer={
131
- <>
132
- <Button type="primary" onClick={onDrawerSave}>
133
- 保存
134
- </Button>
135
- <Button onClick={onDrawerClose}>取消</Button>
136
- </>
133
+ readOnly ? null : (
134
+ <>
135
+ <Button type="primary" onClick={onDrawerSave}>
136
+ 保存
137
+ </Button>
138
+ <Button onClick={onDrawerClose}>取消</Button>
139
+ </>
140
+ )
137
141
  }
138
142
  >
139
143
  <Form label-position="top" initialValues={form}>
140
144
  <Form.Item label="谁可以发起此审批">
141
- <Button
142
- type="primary"
143
- onClick={() =>
144
- selectorCtx.setSelectHandler(
145
- 2,
146
- form.nodeAssigneeList,
147
- (selected) => {
148
- setForm((f) => {
149
- // 设置 人员、角色 列表数组
150
- f.nodeAssigneeList = selected;
151
- return { ...f };
152
- });
153
- },
154
- 1,
155
- )
156
- }
157
- >
158
- 选择人员
159
- </Button>
145
+ {readOnly ? null : (
146
+ <Button
147
+ type="primary"
148
+ onClick={() =>
149
+ selectorCtx.setSelectHandler(
150
+ 2,
151
+ form.nodeAssigneeList,
152
+ (selected) => {
153
+ setForm((f) => {
154
+ // 设置 人员、角色 列表数组
155
+ f.nodeAssigneeList = selected;
156
+ return { ...f };
157
+ });
158
+ },
159
+ 1,
160
+ )
161
+ }
162
+ >
163
+ 选择人员
164
+ </Button>
165
+ )}
166
+
160
167
  <div className="tags-list">
161
168
  {form.nodeAssigneeList?.map((it, idx) => {
162
169
  return (
163
170
  <Tag
164
171
  key={idx}
165
172
  className="node-assignee-item"
166
- closable
173
+ closable={!readOnly}
167
174
  onClose={(e) => {
168
175
  e.preventDefault();
169
176
  onRoleDel(idx);
@@ -10,7 +10,7 @@ import { SelectContext } from "../../../Selector/SelectContext";
10
10
  import "./index.less";
11
11
 
12
12
  export const Approver = (props) => {
13
- const { modelValue = {}, onChange, disable } = props;
13
+ const { modelValue = {}, onChange, disable, readOnly } = props;
14
14
  const [form, setForm] = useState({
15
15
  nodeName: "",
16
16
  setType: undefined,
@@ -122,7 +122,7 @@ export const Approver = (props) => {
122
122
  <div className="title send-title">
123
123
  <UserOutlined />
124
124
  <span>{modelValue?.nodeName}</span>
125
- {!disable && <DeleteOutlined className="node-close-btn" onClick={onNodeDel} />}
125
+ {!disable && !readOnly && <DeleteOutlined className="node-close-btn" onClick={onNodeDel} />}
126
126
  </div>
127
127
  <div className="content">
128
128
  {toText(modelValue) ? <span>{toText(modelValue)}</span> : <span className="placeholder">请选择</span>}
@@ -154,7 +154,9 @@ export const Approver = (props) => {
154
154
  ) : (
155
155
  <div className="drawer-title">
156
156
  {form.nodeName || "审批人设置"}
157
- {!disable && <EditOutlined className="node-wrap-drawer__title-edit" onClick={onEditTitle} />}
157
+ {!disable && !readOnly && (
158
+ <EditOutlined className="node-wrap-drawer__title-edit" onClick={onEditTitle} />
159
+ )}
158
160
  </div>
159
161
  )}
160
162
  </div>
@@ -164,12 +166,14 @@ export const Approver = (props) => {
164
166
  destroyOnClose
165
167
  getContainer="body"
166
168
  footer={
167
- <div className="approver-drawer-footer">
168
- <Button type="primary" onClick={onDrawerSave} disabled={disable}>
169
- 保存
170
- </Button>
171
- <Button onClick={onDrawerClose}>取消</Button>
172
- </div>
169
+ readOnly ? null : (
170
+ <div className="approver-drawer-footer">
171
+ <Button type="primary" onClick={onDrawerSave} disabled={disable}>
172
+ 保存
173
+ </Button>
174
+ <Button onClick={onDrawerClose}>取消</Button>
175
+ </div>
176
+ )
173
177
  }
174
178
  >
175
179
  <Form
@@ -183,6 +187,8 @@ export const Approver = (props) => {
183
187
  >
184
188
  <Form.Item label="审批人员类型" name="setType">
185
189
  <Select
190
+ disabled={readOnly}
191
+ className={`${readOnly ? "readonly-select" : ""}`}
186
192
  options={setTypeOptions}
187
193
  value={form.setType}
188
194
  onSelect={(val) => {
@@ -198,33 +204,36 @@ export const Approver = (props) => {
198
204
 
199
205
  {form.setType === 1 ? (
200
206
  <Form.Item label="选择成员" name="nodeAssigneeList">
201
- <Button
202
- type="primary"
203
- icon={<PlusOutlined />}
204
- onClick={() =>
205
- selectorCtx.setSelectHandler(
206
- 1,
207
- form.nodeAssigneeList,
208
- (selected) => {
209
- setForm((f) => {
210
- // 设置 人员、角色 列表数组
211
- f.nodeAssigneeList = selected;
212
- return { ...f };
213
- });
214
- },
215
- 2,
216
- )
217
- }
218
- >
219
- 选择人员
220
- </Button>
207
+ {readOnly ? null : (
208
+ <Button
209
+ type="primary"
210
+ icon={<PlusOutlined />}
211
+ onClick={() =>
212
+ selectorCtx.setSelectHandler(
213
+ 1,
214
+ form.nodeAssigneeList,
215
+ (selected) => {
216
+ setForm((f) => {
217
+ // 设置 人员、角色 列表数组
218
+ f.nodeAssigneeList = selected;
219
+ return { ...f };
220
+ });
221
+ },
222
+ 2,
223
+ )
224
+ }
225
+ >
226
+ 选择人员
227
+ </Button>
228
+ )}
229
+
221
230
  <div className="tags-list">
222
231
  {form.nodeAssigneeList?.map((user, idx) => {
223
232
  return (
224
233
  <Tag
225
234
  key={user.id || idx}
226
235
  className="node-assignee-item"
227
- closable
236
+ closable={!readOnly}
228
237
  onClose={() => {
229
238
  onUserDel(idx);
230
239
  }}
@@ -256,33 +265,36 @@ export const Approver = (props) => {
256
265
 
257
266
  {form.setType === 3 ? (
258
267
  <Form.Item label="选择角色" name="nodeAssigneeList">
259
- <Button
260
- type="primary"
261
- icon={<PlusOutlined />}
262
- onClick={() =>
263
- selectorCtx.setSelectHandler(
264
- 2,
265
- form.nodeAssigneeList,
266
- (selected) => {
267
- setForm((f) => {
268
- // 设置 人员、角色 列表数组
269
- f.nodeAssigneeList = selected;
270
- return { ...f };
271
- });
272
- },
273
- 2,
274
- )
275
- }
276
- >
277
- 选择角色
278
- </Button>
268
+ {readOnly ? null : (
269
+ <Button
270
+ type="primary"
271
+ icon={<PlusOutlined />}
272
+ onClick={() =>
273
+ selectorCtx.setSelectHandler(
274
+ 2,
275
+ form.nodeAssigneeList,
276
+ (selected) => {
277
+ setForm((f) => {
278
+ // 设置 人员、角色 列表数组
279
+ f.nodeAssigneeList = selected;
280
+ return { ...f };
281
+ });
282
+ },
283
+ 2,
284
+ )
285
+ }
286
+ >
287
+ 选择角色
288
+ </Button>
289
+ )}
290
+
279
291
  <div className="tags-list">
280
292
  {form.nodeAssigneeList?.map((it, idx) => {
281
293
  return (
282
294
  <Tag
283
295
  key={it.id || idx}
284
296
  className="node-assignee-item"
285
- closable
297
+ closable={!readOnly}
286
298
  onClose={() => {
287
299
  onRoleDel(idx);
288
300
  }}
@@ -24,6 +24,7 @@ export const Selector = (props) => {
24
24
  function onModalClose() {
25
25
  selectorCtx.onClose();
26
26
  }
27
+ console.log(listConfig, "listConfig");
27
28
 
28
29
  return (
29
30
  <div className="selector">
package/src/index.less CHANGED
@@ -3,40 +3,7 @@
3
3
  /* 默认白色背景 */
4
4
  width: 100%;
5
5
 
6
- .designer-affix,
7
- .designer-affix-isShowJson {
8
- position: fixed;
9
- right: 20px;
10
- bottom: 20px;
11
- z-index: 9;
12
- // padding: 12px;
13
- // border: 1px solid #999;
14
- width: 132px;
15
- height: 48px;
16
- // background: url("./assets/img/control-bg.png") no-repeat;
17
- background-size: 100% 100%;
18
- display: flex;
19
- justify-content: center;
20
- align-items: center;
21
- background-position-x: 100%;
22
- background-position-y: 100%;
23
6
 
24
- .action-btn+.action-btn {
25
- margin-left: 12px;
26
- }
27
-
28
- .action-img {
29
- width: 28px;
30
- height: 28px;
31
- margin-right: 16px;
32
- cursor: pointer;
33
-
34
- }
35
-
36
- .action-img:last-child {
37
- margin-right: 0px;
38
- }
39
- }
40
7
 
41
8
  .designer-affix-isShowJson {
42
9
  width: 180px;
@@ -571,4 +538,43 @@
571
538
  .ant-btn+.ant-btn {
572
539
  margin-left: 12px;
573
540
  }
541
+ }
542
+
543
+
544
+ .readonly-select.ant-select:not(.ant-select-customize-input) .ant-select-selector {
545
+ background: none;
546
+ color: rgba(0, 0, 0, .85);
547
+ cursor: default
548
+ }
549
+
550
+ .designer-affix,
551
+ .designer-affix-isShowJson {
552
+ position: fixed;
553
+ right: 20px;
554
+ bottom: 20px;
555
+ z-index: 9;
556
+ width: 180px;
557
+ height: 48px;
558
+ background-size: 100% 100%;
559
+ display: flex;
560
+ justify-content: center;
561
+ align-items: center;
562
+ background-position-x: 100%;
563
+ background-position-y: 100%;
564
+
565
+ .action-btn+.action-btn {
566
+ margin-left: 12px;
567
+ }
568
+
569
+ .action-img {
570
+ width: 28px;
571
+ height: 28px;
572
+ margin-right: 16px;
573
+ cursor: pointer;
574
+
575
+ }
576
+
577
+ .action-img:last-child {
578
+ margin-right: 0px;
579
+ }
574
580
  }
package/src/index.tsx CHANGED
@@ -12,7 +12,7 @@ import subImg from "./assets/img/sub.png";
12
12
  import reloadImg from "./assets/img/reload.png";
13
13
  import checkJsonImg from "./assets/img/check-json.png";
14
14
  import controlBgImg from "./assets/img/control-bg.png";
15
-
15
+ import Draggable from "react-draggable";
16
16
  /**
17
17
  * 复制指定字符串
18
18
  * @param str
@@ -49,7 +49,7 @@ function copy(str) {
49
49
  }
50
50
 
51
51
  function FlowlongDesigner(props, ref) {
52
- const { value, flowName, roleListConfig, listConfig, initiatorListConfig, isShowJson, disable } = props;
52
+ const { value, flowName, roleListConfig, listConfig, initiatorListConfig, isShowJson, disable, readOnly } = props;
53
53
  const [drawer, setDrawer] = useState(false);
54
54
  const [zoom, setZoom] = useState(1);
55
55
  const [data, setData] = useState(Object.keys(value || {}).length > 0 ? value : getInitNodeData({ name: flowName }));
@@ -92,85 +92,90 @@ function FlowlongDesigner(props, ref) {
92
92
  };
93
93
 
94
94
  return (
95
- <div className="flowlong-designer">
96
- <SelectContext.Provider
97
- value={{
98
- selectHandler,
99
- setSelectHandler(type, value, onSave, drawerType) {
100
- setSelectHandler({
101
- open: true,
102
- type,
103
- drawerType,
104
- value,
105
- onSave,
106
- roleListConfig,
107
- listConfig,
108
- initiatorListConfig,
109
- });
110
- },
111
- onClose() {
112
- setSelectHandler({
113
- open: false,
114
- type: -1,
115
- drawerType: -1,
116
- value: [],
117
- onSave: (s) => {},
118
- roleListConfig,
119
- listConfig,
120
- initiatorListConfig,
121
- });
122
- },
123
- }}
124
- >
125
- <div
126
- className={isShowJson ? "designer-affix-isShowJson" : "designer-affix"}
127
- style={{
128
- backgroundImage: `url(${controlBgImg})`,
129
- }}
130
- >
131
- {isShowJson && (
132
- <Tooltip title={"查看 JSON"}>
133
- <img className="action-img" src={checkJsonImg} onClick={() => setDrawer(true)} alt="" />
134
- </Tooltip>
135
- )}
136
- <Tooltip title={"缩小"}>
137
- <img className="action-img" src={subImg} onClick={() => setZoom((z) => z - 0.1)} alt="" />
138
- </Tooltip>
139
- <Tooltip title={"放大"}>
140
- <img className="action-img" src={addImg} onClick={() => setZoom((z) => z + 0.1)} alt="" />
141
- </Tooltip>
142
- <Tooltip title={"重置"}>
143
- <img className="action-img" src={reloadImg} onClick={onReset} alt="" />
144
- </Tooltip>
145
- </div>
146
- <div className="affix-container" style={{ transformOrigin: "0 0", transform: `scale(${zoom})` }}>
147
- <ScWorkflow
148
- className="workflow"
149
- id="content-to-capture"
150
- modelValue={data.nodeConfig}
151
- disable={disable}
152
- onChange={(val) => {
153
- setData((d) => {
154
- d.nodeConfig = val;
155
- return { ...d };
156
- });
95
+ <>
96
+ <Draggable>
97
+ <div className="flowlong-designer">
98
+ <SelectContext.Provider
99
+ value={{
100
+ selectHandler,
101
+ setSelectHandler(type, value, onSave, drawerType) {
102
+ setSelectHandler({
103
+ open: true,
104
+ type,
105
+ drawerType,
106
+ value,
107
+ onSave,
108
+ roleListConfig,
109
+ listConfig,
110
+ initiatorListConfig,
111
+ });
112
+ },
113
+ onClose() {
114
+ setSelectHandler({
115
+ open: false,
116
+ type: -1,
117
+ drawerType: -1,
118
+ value: [],
119
+ onSave: (s) => {},
120
+ roleListConfig,
121
+ listConfig,
122
+ initiatorListConfig,
123
+ });
124
+ },
157
125
  }}
158
- />
159
- <Drawer className="drawer-wrapper" open={drawer} width={720} onClose={onDrawerClose}>
160
- <div>
161
- <div className="cp-parse-json-btn" onClick={copyParseJson}>
162
- 复制格式化后的 JSON
163
- </div>
164
- <div className="cp-json-btn" onClick={copyJson}>
165
- 复制压缩后的 JSON
166
- </div>
126
+ >
127
+ <div className="affix-container" style={{ transformOrigin: "0 0", transform: `scale(${zoom})` }}>
128
+ <ScWorkflow
129
+ className="workflow"
130
+ id="content-to-capture"
131
+ modelValue={data.nodeConfig}
132
+ disable={disable}
133
+ readOnly={readOnly}
134
+ onChange={(val) => {
135
+ setData((d) => {
136
+ d.nodeConfig = val;
137
+ return { ...d };
138
+ });
139
+ }}
140
+ />
141
+ <Drawer className="drawer-wrapper" open={drawer} width={720} onClose={onDrawerClose}>
142
+ <div>
143
+ <div className="cp-parse-json-btn" onClick={copyParseJson}>
144
+ 复制格式化后的 JSON
145
+ </div>
146
+ <div className="cp-json-btn" onClick={copyJson}>
147
+ 复制压缩后的 JSON
148
+ </div>
149
+ </div>
150
+ {/* <json-editor-vue className="editor" language="zh-CN" current-mode="view" v-model="data" /> */}
151
+ <pre className="json-viewer">{JSON.stringify(data, null, 2)}</pre>
152
+ </Drawer>
167
153
  </div>
168
- {/* <json-editor-vue className="editor" language="zh-CN" current-mode="view" v-model="data" /> */}
169
- <pre className="json-viewer">{JSON.stringify(data, null, 2)}</pre>
170
- </Drawer>
154
+ </SelectContext.Provider>
171
155
  </div>
172
- </SelectContext.Provider>
173
- </div>
156
+ </Draggable>
157
+ <div
158
+ className={isShowJson ? "designer-affix-isShowJson" : "designer-affix"}
159
+ style={{
160
+ backgroundImage: `url(${controlBgImg})`,
161
+ }}
162
+ >
163
+ {isShowJson && (
164
+ <Tooltip title={"查看 JSON"}>
165
+ <img className="action-img" src={checkJsonImg} onClick={() => setDrawer(true)} alt="" />
166
+ </Tooltip>
167
+ )}
168
+ <Tooltip title={"缩小"}>
169
+ <img className="action-img" src={subImg} onClick={() => setZoom((z) => z - 0.1)} alt="" />
170
+ </Tooltip>
171
+ <Tooltip title={"放大"}>
172
+ <img className="action-img" src={addImg} onClick={() => setZoom((z) => z + 0.1)} alt="" />
173
+ </Tooltip>
174
+ <Tooltip title={"重置"}>
175
+ <img className="action-img" src={reloadImg} onClick={onReset} alt="" />
176
+ </Tooltip>
177
+ </div>
178
+ </>
174
179
  );
175
180
  }
176
181