@hzab/flowlong-designer 0.0.1

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.
@@ -0,0 +1,319 @@
1
+ .branch-wrap {
2
+ .branch-box .add-branch {
3
+ background: var(--el-bg-color);
4
+ }
5
+ .branch-wrap {
6
+ display: inline-flex;
7
+ width: 100%;
8
+ }
9
+ .branch-box-wrap {
10
+ display: flex;
11
+ flex-flow: column wrap;
12
+ align-items: center;
13
+ min-height: 270px;
14
+ width: 100%;
15
+ flex-shrink: 0;
16
+ }
17
+ .col-box {
18
+ display: inline-flex;
19
+ flex-direction: column;
20
+ align-items: center;
21
+ position: relative;
22
+ }
23
+ .branch-box {
24
+ display: flex;
25
+ overflow: visible;
26
+ min-height: 180px;
27
+ height: auto;
28
+ border-bottom: 2px solid #ccc;
29
+ border-top: 2px solid #ccc;
30
+ position: relative;
31
+ margin-top: 15px;
32
+ }
33
+ .branch-box .col-box::before {
34
+ content: "";
35
+ position: absolute;
36
+ top: 0px;
37
+ left: 0px;
38
+ right: 0px;
39
+ bottom: 0px;
40
+ z-index: 0;
41
+ margin: auto;
42
+ width: 2px;
43
+ height: 100%;
44
+ background-color: rgb(202, 202, 202);
45
+ }
46
+ .condition-node {
47
+ display: inline-flex;
48
+ flex-direction: column;
49
+ min-height: 220px;
50
+ }
51
+ .condition-node-box {
52
+ padding-top: 30px;
53
+ padding-right: 50px;
54
+ padding-left: 50px;
55
+ justify-content: center;
56
+ align-items: center;
57
+ flex-grow: 1;
58
+ position: relative;
59
+ display: inline-flex;
60
+ flex-direction: column;
61
+ }
62
+ .condition-node-box::before {
63
+ content: "";
64
+ position: absolute;
65
+ top: 0px;
66
+ left: 0px;
67
+ right: 0px;
68
+ bottom: 0px;
69
+ margin: auto;
70
+ width: 2px;
71
+ height: 100%;
72
+ background-color: rgb(202, 202, 202);
73
+ }
74
+ .auto-judge {
75
+ position: relative;
76
+ width: 220px;
77
+ min-height: 72px;
78
+ background: rgb(255, 255, 255);
79
+ border-radius: 4px;
80
+ padding: 15px 15px;
81
+ cursor: pointer;
82
+ box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.1);
83
+ }
84
+ .auto-judge::before {
85
+ content: "";
86
+ position: absolute;
87
+ top: -12px;
88
+ left: 50%;
89
+ transform: translateX(-50%);
90
+ width: 0px;
91
+ border-style: solid;
92
+ border-width: 8px 6px 4px;
93
+ border-color: rgb(202, 202, 202) transparent transparent;
94
+ background: rgb(239, 239, 239);
95
+ }
96
+ .auto-judge .title {
97
+ line-height: 16px;
98
+ }
99
+ .auto-judge .title .node-title {
100
+ color: #15bc83;
101
+ }
102
+ .auto-judge .title .delete-btn {
103
+ font-size: 15px;
104
+ position: absolute;
105
+ top: 15px;
106
+ right: 15px;
107
+ color: #999;
108
+ display: none;
109
+ }
110
+ .auto-judge .title .priority-title {
111
+ position: absolute;
112
+ top: 15px;
113
+ right: 15px;
114
+ color: #999;
115
+ }
116
+ .auto-judge .content {
117
+ position: relative;
118
+ padding-top: 15px;
119
+ }
120
+ .auto-judge .content .placeholder {
121
+ color: #999;
122
+ }
123
+ .auto-judge:hover {
124
+ .delete-btn {
125
+ display: block;
126
+ }
127
+ .priority-title {
128
+ display: none;
129
+ }
130
+ }
131
+ .auto-judge:hover {
132
+ .sort-left {
133
+ display: flex;
134
+ }
135
+ .sort-right {
136
+ display: flex;
137
+ }
138
+ }
139
+ .auto-judge .sort-left {
140
+ position: absolute;
141
+ top: 0;
142
+ bottom: 0;
143
+ z-index: 1;
144
+ left: 0;
145
+ display: none;
146
+ justify-content: center;
147
+ align-items: center;
148
+ flex-direction: column;
149
+ }
150
+ .auto-judge .sort-right {
151
+ position: absolute;
152
+ top: 0;
153
+ bottom: 0;
154
+ z-index: 1;
155
+ right: 0;
156
+ display: none;
157
+ justify-content: center;
158
+ align-items: center;
159
+ flex-direction: column;
160
+ }
161
+ .auto-judge .sort-left:hover,
162
+ .auto-judge .sort-right:hover {
163
+ background: #eee;
164
+ }
165
+ .auto-judge:after {
166
+ pointer-events: none;
167
+ content: "";
168
+ position: absolute;
169
+ top: 0;
170
+ bottom: 0;
171
+ left: 0;
172
+ right: 0;
173
+ z-index: 2;
174
+ border-radius: 4px;
175
+ transition: all 0.1s;
176
+ }
177
+ .auto-judge:hover:after {
178
+ border: 1px solid #3296fa;
179
+ box-shadow: 0 0 6px 0 rgba(50, 150, 250, 0.3);
180
+ }
181
+ .top-left-cover-line,
182
+ .top-right-cover-line {
183
+ position: absolute;
184
+ height: 3px;
185
+ width: 50%;
186
+ background-color: #fff;
187
+ top: -2px;
188
+ }
189
+ .bottom-left-cover-line,
190
+ .bottom-right-cover-line {
191
+ position: absolute;
192
+ height: 3px;
193
+ width: 50%;
194
+ background-color: #fff;
195
+ bottom: -2px;
196
+ }
197
+ .top-left-cover-line {
198
+ left: -1px;
199
+ }
200
+ .top-right-cover-line {
201
+ right: -1px;
202
+ }
203
+ .bottom-left-cover-line {
204
+ left: -1px;
205
+ }
206
+ .bottom-right-cover-line {
207
+ right: -1px;
208
+ }
209
+ }
210
+
211
+ .branch-drawer {
212
+ .top-tips {
213
+ display: flex;
214
+ justify-content: space-between;
215
+ align-items: center;
216
+ margin-bottom: 12px;
217
+ color: #646a73;
218
+ }
219
+
220
+ .or-branch-link-tip {
221
+ margin: 10px 0;
222
+ color: #646a73;
223
+ }
224
+
225
+ .condition-group-editor {
226
+ user-select: none;
227
+ border-radius: 4px;
228
+ border: 1px solid #e4e5e7;
229
+ position: relative;
230
+ margin-bottom: 16px;
231
+
232
+ .branch-delete-icon {
233
+ font-size: 18px;
234
+ }
235
+
236
+ .header {
237
+ background-color: #f4f6f8;
238
+ padding: 0 12px;
239
+ font-size: 14px;
240
+ color: #171e31;
241
+ height: 36px;
242
+ display: flex;
243
+ align-items: center;
244
+
245
+ span {
246
+ flex: 1;
247
+ }
248
+ }
249
+
250
+ .main-content {
251
+ padding: 0 12px;
252
+
253
+ .condition-relation {
254
+ color: #9ca2a9;
255
+ display: flex;
256
+ align-items: center;
257
+ height: 36px;
258
+ display: flex;
259
+ justify-content: space-between;
260
+ padding: 0 2px;
261
+ }
262
+
263
+ .condition-content-box {
264
+ display: flex;
265
+ justify-content: space-between;
266
+ align-items: center;
267
+
268
+ div {
269
+ width: 100%;
270
+ min-width: 120px;
271
+ }
272
+
273
+ div:not(:first-child) {
274
+ margin-left: 16px;
275
+ }
276
+ }
277
+
278
+ .cell-box {
279
+ div {
280
+ padding: 16px 0;
281
+ width: 100%;
282
+ min-width: 120px;
283
+ color: #909399;
284
+ font-size: 14px;
285
+ font-weight: 600;
286
+ text-align: center;
287
+ }
288
+ }
289
+
290
+ .condition-content {
291
+ display: flex;
292
+ flex-direction: column;
293
+
294
+ :deep(.el-input__wrapper) {
295
+ border-top-left-radius: 0;
296
+ border-bottom-left-radius: 0;
297
+ }
298
+
299
+ .content {
300
+ flex: 1;
301
+ padding: 0 0 4px 0;
302
+ display: flex;
303
+ align-items: center;
304
+ min-height: 31.6px;
305
+ flex-wrap: wrap;
306
+ }
307
+ }
308
+ }
309
+
310
+ .sub-content {
311
+ padding: 12px;
312
+ }
313
+ }
314
+ .ant-drawer-footer {
315
+ .ant-btn + .ant-btn {
316
+ margin-left: 12px;
317
+ }
318
+ }
319
+ }
@@ -0,0 +1,387 @@
1
+ import { useRef, useState } from "react";
2
+ import { Drawer, Button, Input, Select } from "antd";
3
+ import { LeftOutlined, DeleteOutlined, RightOutlined, EditOutlined } from "@ant-design/icons";
4
+
5
+ import AddNode from "../AddNode";
6
+
7
+ import "./index.less";
8
+
9
+ /**
10
+ * 操作符选项列表
11
+ */
12
+ export const operatorOptions = [
13
+ { label: "等于", value: "==" },
14
+ { label: "不等于", value: "!=" },
15
+ { label: "大于", value: ">" },
16
+ { label: "大于等于", value: ">=" },
17
+ { label: "小于", value: "<" },
18
+ { label: "小于等于", value: "<=" },
19
+ { label: "包含", value: "include" },
20
+ { label: "不包含", value: "notinclude" },
21
+ ];
22
+
23
+ export const Branch = (props) => {
24
+ const { modelValue: nodeConfig, onChange, ItemSlot } = props;
25
+ const [form, setForm] = useState({
26
+ nodeName: "",
27
+ setType: undefined,
28
+ nodeAssigneeList: [],
29
+ directorMode: undefined,
30
+ termAuto: false,
31
+ examineLevel: undefined,
32
+ selectMode: undefined,
33
+ directorLevel: undefined,
34
+ term: undefined,
35
+ termMode: undefined,
36
+ examineMode: undefined,
37
+ conditionList: [],
38
+ });
39
+ const [drawer, setDrawer] = useState(false);
40
+ const [isEditTitle, setIsEditTitle] = useState(false);
41
+ const curIdxRef = useRef(-1);
42
+
43
+ const nodeTitleRef = useRef();
44
+
45
+ function onTermAdd() {
46
+ if (!nodeConfig.conditionNodes) {
47
+ nodeConfig.conditionNodes = [];
48
+ }
49
+ let len = nodeConfig.conditionNodes?.length + 1;
50
+ nodeConfig.conditionNodes?.push({
51
+ nodeName: "条件" + len,
52
+ type: 3,
53
+ priorityLevel: len,
54
+ conditionMode: 1,
55
+ conditionList: [],
56
+ });
57
+ onChange && onChange({ ...nodeConfig });
58
+ }
59
+ function onShow(idx) {
60
+ curIdxRef.current = idx;
61
+ setForm(JSON.parse(JSON.stringify(nodeConfig.conditionNodes[idx])));
62
+ setDrawer(true);
63
+ }
64
+ function arrTransfer(idx, type = 1) {
65
+ nodeConfig.conditionNodes[idx] = nodeConfig.conditionNodes?.splice(
66
+ idx + type,
67
+ 1,
68
+ nodeConfig.conditionNodes[idx],
69
+ )[0];
70
+ nodeConfig.conditionNodes?.map((item, index) => {
71
+ item.priorityLevel = index + 1;
72
+ });
73
+ onChange && onChange({ ...nodeConfig });
74
+ }
75
+ function onTermDel(idx) {
76
+ nodeConfig.conditionNodes?.splice(idx, 1);
77
+ if (nodeConfig.conditionNodes?.length == 1) {
78
+ if (nodeConfig.childNode) {
79
+ if (nodeConfig.conditionNodes[0].childNode) {
80
+ this.reData(nodeConfig.conditionNodes[0].childNode, nodeConfig.childNode);
81
+ } else {
82
+ nodeConfig.conditionNodes[0].childNode = nodeConfig.childNode;
83
+ }
84
+ }
85
+ onChange && onChange({ ...nodeConfig });
86
+ }
87
+ }
88
+ function toText(nodeConfig, idx) {
89
+ var { conditionList } = nodeConfig.conditionNodes[idx];
90
+ if (conditionList && conditionList.length == 1) {
91
+ const text = conditionList
92
+ .map((conditionGroup) => conditionGroup.map((item) => `${item.label}${item.operator}${item.value}`))
93
+ .join(" 和 ");
94
+ return text;
95
+ } else if (conditionList && conditionList.length > 1) {
96
+ return conditionList.length + "个条件,或满足";
97
+ } else {
98
+ if (idx == nodeConfig.conditionNodes?.length - 1) {
99
+ return "其他条件进入此流程";
100
+ } else {
101
+ return false;
102
+ }
103
+ }
104
+ }
105
+ function onDrawerClose() {
106
+ setDrawer(false);
107
+ }
108
+
109
+ function onEditTitle() {
110
+ setIsEditTitle(true);
111
+ if (nodeTitleRef.current) {
112
+ // @ts-ignore
113
+ nodeTitleRef.current?.focus();
114
+ }
115
+ }
116
+ function onSaveTitle(e) {
117
+ setForm((f) => {
118
+ // @ts-ignore
119
+ f.nodeName = nodeTitleRef.current?.input?.value;
120
+ return { ...f };
121
+ });
122
+ setIsEditTitle(false);
123
+ }
124
+
125
+ function onDrawerSave() {
126
+ nodeConfig.conditionNodes[curIdxRef.current] = form;
127
+ onChange && onChange({ ...nodeConfig });
128
+ onDrawerClose();
129
+ }
130
+
131
+ /**
132
+ * 添加条件组
133
+ */
134
+ function onConditionGroupAdd() {
135
+ onConditionAdd(form.conditionList[form.conditionList.push([]) - 1]);
136
+ }
137
+
138
+ /**
139
+ * 添加条件
140
+ * @param conditionList
141
+ */
142
+ function onConditionAdd(conditionList) {
143
+ conditionList.push({
144
+ label: "",
145
+ field: "",
146
+ operator: "=",
147
+ value: "",
148
+ });
149
+ // 更新数据
150
+ setForm((f) => ({ ...f }));
151
+ }
152
+
153
+ function deleteConditionGroup(idx) {
154
+ form.conditionList.splice(idx, 1);
155
+ setForm((f) => ({ ...f }));
156
+ }
157
+ function deleteConditionList(conditionList, idx) {
158
+ conditionList.splice(idx, 1);
159
+ setForm((f) => ({ ...f }));
160
+ }
161
+
162
+ return (
163
+ <div className="branch-wrap">
164
+ <div className="branch-box-wrap">
165
+ <div className="branch-box">
166
+ <Button className="add-branch" onClick={onTermAdd}>
167
+ 添加条件
168
+ </Button>
169
+ {nodeConfig?.conditionNodes?.map((item, idx) => {
170
+ return (
171
+ <div className="col-box" key={idx}>
172
+ <div className="condition-node">
173
+ <div className="condition-node-box">
174
+ <div
175
+ className="auto-judge"
176
+ onClick={() => {
177
+ onShow(idx);
178
+ }}
179
+ >
180
+ {idx != 0 ? (
181
+ <div
182
+ className="sort-left"
183
+ onClick={(e) => {
184
+ e.stopPropagation();
185
+ arrTransfer(idx, -1);
186
+ }}
187
+ >
188
+ <LeftOutlined />
189
+ </div>
190
+ ) : null}
191
+ <div className="title">
192
+ <span className="node-title">{item.nodeName}</span>
193
+ <span className="priority-title">优先级{item.priorityLevel}</span>
194
+
195
+ <DeleteOutlined
196
+ className="delete-btn"
197
+ onClick={(e) => {
198
+ e.stopPropagation();
199
+ onTermDel(idx);
200
+ }}
201
+ />
202
+ </div>
203
+ <div className="content">
204
+ {toText(nodeConfig, idx) ? (
205
+ <span>{toText(nodeConfig, idx)}</span>
206
+ ) : (
207
+ <span className="placeholder">请设置条件</span>
208
+ )}
209
+ </div>
210
+ {idx != nodeConfig.conditionNodes?.length - 1 ? (
211
+ <div
212
+ className="sort-right"
213
+ onClick={(e) => {
214
+ e.stopPropagation();
215
+ arrTransfer(idx);
216
+ }}
217
+ >
218
+ <RightOutlined />
219
+ </div>
220
+ ) : null}
221
+ </div>
222
+ <AddNode
223
+ modelValue={item.childNode}
224
+ onChange={(val) => {
225
+ item.childNode = val;
226
+ // 更新数据
227
+ setForm((f) => ({ ...f }));
228
+ }}
229
+ ></AddNode>
230
+ </div>
231
+ </div>
232
+ {item.childNode && ItemSlot ? (
233
+ <ItemSlot
234
+ modelValue={item}
235
+ onChange={(val) => {
236
+ // 数据保存到指定对象中
237
+ if (nodeConfig?.conditionNodes[idx]) {
238
+ nodeConfig.conditionNodes[idx].childNode = val?.childNode;
239
+ }
240
+ onChange && onChange({ ...nodeConfig });
241
+ }}
242
+ />
243
+ ) : null}
244
+ {idx == 0 ? <div className="top-left-cover-line"></div> : null}
245
+ {idx == 0 ? <div className="bottom-left-cover-line"></div> : null}
246
+ {idx == nodeConfig.conditionNodes?.length - 1 ? <div className="top-right-cover-line"></div> : null}
247
+ {idx == nodeConfig.conditionNodes?.length - 1 ? <div className="bottom-right-cover-line"></div> : null}
248
+ </div>
249
+ );
250
+ })}
251
+ </div>
252
+ <AddNode
253
+ modelValue={nodeConfig.childNode}
254
+ onChange={(val) => {
255
+ nodeConfig.childNode = val;
256
+ onChange && onChange({ ...nodeConfig });
257
+ }}
258
+ ></AddNode>
259
+ </div>
260
+
261
+ <Drawer
262
+ className={"branch-drawer"}
263
+ open={drawer}
264
+ onClose={onDrawerClose}
265
+ destroyOnClose
266
+ getContainer="body"
267
+ width={600}
268
+ title={
269
+ <div className="node-wrap-drawer-title">
270
+ {isEditTitle ? (
271
+ <Input
272
+ ref={nodeTitleRef}
273
+ autoFocus
274
+ defaultValue={form.nodeName}
275
+ onBlur={onSaveTitle}
276
+ onPressEnter={onSaveTitle}
277
+ />
278
+ ) : (
279
+ <div className="drawer-title">
280
+ {form.nodeName || "条件设置"}
281
+ <EditOutlined className="node-wrap-drawer__title-edit" onClick={onEditTitle} />
282
+ </div>
283
+ )}
284
+ </div>
285
+ }
286
+ footer={
287
+ <>
288
+ <Button type="primary" onClick={onDrawerSave}>
289
+ 保存
290
+ </Button>
291
+ <Button onClick={onDrawerClose}>取消</Button>
292
+ </>
293
+ }
294
+ >
295
+ <div className="top-tips">满足以下条件时进入当前分支</div>
296
+ {form?.conditionList?.map((conditionGroup, conditionGroupIdx) => {
297
+ return (
298
+ <div key={conditionGroupIdx}>
299
+ {conditionGroupIdx != 0 ? <div className="or-branch-link-tip">或满足</div> : null}
300
+ <div className="condition-group-editor">
301
+ <div className="header">
302
+ <span>条件组 {conditionGroupIdx + 1}</span>
303
+ <div
304
+ onClick={() => {
305
+ deleteConditionGroup(conditionGroupIdx);
306
+ }}
307
+ >
308
+ <DeleteOutlined className="branch-delete-icon" />
309
+ </div>
310
+ </div>
311
+
312
+ <div className="main-content">
313
+ {/* <!-- 单个条件 --> */}
314
+ <div className="condition-content-box cell-box">
315
+ <div>描述</div>
316
+ <div>条件字段</div>
317
+ <div>运算符</div>
318
+ <div>值</div>
319
+ </div>
320
+ {conditionGroup?.map((condition, idx) => {
321
+ return (
322
+ <div className="condition-content" key={idx}>
323
+ <div className="condition-relation">
324
+ <span>{idx == 0 ? "当" : "且"}</span>
325
+ <div onClick={() => deleteConditionList(conditionGroup, idx)}>
326
+ <DeleteOutlined className="branch-delete-icon" />
327
+ </div>
328
+ </div>
329
+ <div className="condition-content">
330
+ <div className="condition-content-box">
331
+ <Input
332
+ value={condition.label}
333
+ onChange={(e) => {
334
+ condition.label = e.target.value;
335
+ // 更新数据
336
+ setForm((f) => ({ ...f }));
337
+ }}
338
+ placeholder="描述"
339
+ />
340
+ <Input
341
+ value={condition.field}
342
+ onChange={(e) => {
343
+ condition.field = e.target.value;
344
+ // 更新数据
345
+ setForm((f) => ({ ...f }));
346
+ }}
347
+ placeholder="条件字段"
348
+ />
349
+ <Select
350
+ value={condition.operator}
351
+ onChange={(val) => {
352
+ condition.operator = val;
353
+ }}
354
+ placeholder="请选择"
355
+ options={operatorOptions}
356
+ ></Select>
357
+ <Input
358
+ value={condition.value}
359
+ onChange={(e) => {
360
+ condition.value = e.target.value;
361
+ // 更新数据
362
+ setForm((f) => ({ ...f }));
363
+ }}
364
+ placeholder="值"
365
+ />
366
+ </div>
367
+ </div>
368
+ </div>
369
+ );
370
+ })}
371
+ </div>
372
+ <div className="sub-content">
373
+ <Button type="primary" onClick={() => onConditionAdd(conditionGroup)}>
374
+ 添加条件
375
+ </Button>
376
+ </div>
377
+ </div>
378
+ </div>
379
+ );
380
+ })}
381
+ <Button onClick={onConditionGroupAdd}>添加条件组</Button>
382
+ </Drawer>
383
+ </div>
384
+ );
385
+ };
386
+
387
+ export default Branch;
@@ -0,0 +1,10 @@
1
+ .promoter-wrap {
2
+ .start-node {
3
+ .title {
4
+ background-color: #576a95;
5
+ }
6
+ }
7
+ }
8
+
9
+ .promoter-drawer {
10
+ }