lw-cdp-ui 1.1.18 → 1.1.20

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.
@@ -1,6 +1,7 @@
1
1
  <template>
2
2
  <div class="node-panel">
3
- <el-collapse accordion>
3
+ <el-collapse v-model="activeNames"
4
+ accordion>
4
5
  <el-collapse-item v-for="item in nodeList"
5
6
  :title="item.title"
6
7
  :name="item.title">
@@ -21,6 +22,7 @@
21
22
  </div>
22
23
  </template>
23
24
  <script>
25
+
24
26
  /**
25
27
  * 节点面板
26
28
  */
@@ -30,6 +32,14 @@ export default {
30
32
  lf: Object,
31
33
  nodeList: Array,
32
34
  },
35
+ data() {
36
+ return {
37
+ activeNames: ''
38
+ }
39
+ },
40
+ mounted(){
41
+ this.activeNames = this.nodeList[0].title;
42
+ },
33
43
  methods: {
34
44
  dragNode(item) {
35
45
  this.$props.lf.dnd.startDrag({
@@ -0,0 +1,78 @@
1
+ export default [
2
+ {
3
+ title: '基础流程',
4
+ list: [
5
+ {
6
+ name: '开始',
7
+ icon: 'icon-next',
8
+ type: 'start',
9
+ themeColor: '#39bcc5'
10
+ },
11
+ {
12
+ name: '结束',
13
+ icon: 'icon-cease',
14
+ type: 'end',
15
+ themeColor: '#f53f3f'
16
+ }
17
+ ]
18
+ },
19
+ {
20
+ title: 'ET2L节点',
21
+ list: [
22
+ {
23
+ name: 'SOURCE',
24
+ icon: 'icon-table',
25
+ type: 'source',
26
+ themeColor: '#00B050'
27
+ },
28
+ {
29
+ name: 'MAPPER',
30
+ icon: 'icon-change-type',
31
+ type: 'mapper',
32
+ themeColor: '#56C4C3'
33
+ },
34
+ {
35
+ name: 'JOINER',
36
+ icon: 'icon-app-cdp',
37
+ type: 'joiner',
38
+ themeColor: '#7030A0'
39
+ },
40
+ {
41
+ name: 'TARGET',
42
+ icon: 'icon-table',
43
+ type: 'target',
44
+ themeColor: '#0070C0'
45
+ },
46
+ {
47
+ name: 'FILTER',
48
+ icon: 'icon-ma-filter',
49
+ type: 'filter',
50
+ themeColor: '#C7161E'
51
+ },
52
+ {
53
+ name: 'COLAP',
54
+ icon: 'icon-ma-branch',
55
+ type: 'collap',
56
+ themeColor: '#013E75'
57
+ },
58
+ {
59
+ name: 'EXPAND',
60
+ icon: 'icon-chaji',
61
+ type: 'expand',
62
+ themeColor: '#156858'
63
+ },
64
+ // {
65
+ // name: 'KEY_BY',
66
+ // icon: 'icon-flow-l',
67
+ // type: 'key_by',
68
+ // themeColor: '#FFC000'
69
+ // },
70
+ {
71
+ name: 'REDUCE',
72
+ icon: 'icon-reload',
73
+ type: 'reduce',
74
+ themeColor: '#EF5612'
75
+ }
76
+ ]
77
+ }
78
+ ]
@@ -3,21 +3,26 @@
3
3
  <!-- 画布 -->
4
4
  <div ref="container"
5
5
  class="logic-flow-body"></div>
6
+
6
7
  <!-- 工具栏 -->
7
8
  <lfControl class="logic-flow-control"
8
9
  v-if="logicFlow"
9
10
  :lf="logicFlow" />
10
- <!-- 节点 -->
11
- <lfNodePanel class="logic-flow-node"
12
- v-if="logicFlow"
13
- :lf="logicFlow"
14
- :nodeList="nodeList" />
15
11
 
16
- <!-- 属性编辑 -->
17
- <nodeEdit :lf="logicFlow"
18
- :drawerShow="drawerShow"
19
- :nodeData="clickNode"
20
- @onClose="nodeEditClose"/>
12
+ <template v-if="!isView">
13
+ <!-- 节点 -->
14
+ <lfNodePanel class="logic-flow-node"
15
+ v-if="logicFlow"
16
+ :lf="logicFlow"
17
+ :nodeList="nodeList" />
18
+
19
+ <!-- 属性编辑 -->
20
+ <nodeEdit v-if="drawerShow"
21
+ :lf="logicFlow"
22
+ :drawerShow="drawerShow"
23
+ :nodeData="clickNode"
24
+ @onClose="nodeEditClose" />
25
+ </template>
21
26
 
22
27
  </div>
23
28
 
@@ -36,10 +41,14 @@ import lfNodePanel from './components/lfNodePanel.vue'
36
41
  // 自定义节点
37
42
  import basisStart from './nodes/basisStart'
38
43
  import basisEnd from './nodes/basisEnd'
44
+ import et2lTable from './nodes/et2lTable'
39
45
  import nodeCustom from './nodes/custom'
40
46
 
41
47
  // 节点编辑
42
48
  import nodeEdit from './nodeEdit/index.vue'
49
+
50
+ // 参数配置
51
+ import configNodesList from './config/nodesList'
43
52
  export default {
44
53
  components: {
45
54
  lfControl,
@@ -80,6 +89,13 @@ export default {
80
89
  type: Boolean,
81
90
  default: true
82
91
  },
92
+ /**
93
+ * 是否仅查看
94
+ */
95
+ isView: {
96
+ type: Boolean,
97
+ default: false
98
+ },
83
99
  /**
84
100
  * apiNodes - 接口返回的节点数组,用于与内容节点合并。
85
101
  * @type {Array<Object>}
@@ -157,8 +173,6 @@ export default {
157
173
  thickness: 0.5
158
174
  }
159
175
  },
160
- edgeTextDraggable: true,
161
- hoverOutline: false,
162
176
  }
163
177
  }
164
178
  }
@@ -185,25 +199,7 @@ export default {
185
199
  computed: {
186
200
  nodeList() {
187
201
  // 基础节点
188
- let baseList = [
189
- {
190
- title: '基础流程',
191
- list: [
192
- {
193
- name: '开始',
194
- icon: 'icon-next',
195
- type: 'start',
196
- themeColor: "#39bcc5"
197
- },
198
- {
199
- name: '结束',
200
- icon: 'icon-flow-stop',
201
- type: 'end',
202
- themeColor: "#000000"
203
- }
204
- ]
205
- }
206
- ]
202
+ let baseList = configNodesList
207
203
 
208
204
  let list = {}
209
205
  this.apiNodes.forEach(item => {
@@ -237,6 +233,11 @@ export default {
237
233
  container: this.$refs.container,
238
234
  // 注册组件
239
235
  plugins: [Menu, MiniMap],
236
+ // 不可编辑
237
+ isSilentMode: this.isView,
238
+ hoverOutline: !this.isView,
239
+ nodeSelectedOutline: !this.isView,
240
+ edgeSelectedOutline: !this.isView,
240
241
  ...this.options
241
242
  })
242
243
  this.initMenu()
@@ -309,6 +310,18 @@ export default {
309
310
  _this.logicFlow.changeEdgeType(edge.id, "polyline")
310
311
  },
311
312
  },
313
+ {
314
+ text: '开启动画',
315
+ callback(edge) {
316
+ _this.logicFlow.openEdgeAnimation(edge.id)
317
+ },
318
+ },
319
+ {
320
+ text: '关闭动画',
321
+ callback(edge) {
322
+ _this.logicFlow.closeEdgeAnimation(edge.id)
323
+ },
324
+ },
312
325
  ], // 全局右键菜单
313
326
  graphMenu: [
314
327
  // {
@@ -349,6 +362,16 @@ export default {
349
362
  case 'end':
350
363
  await basisEnd(this.logicFlow);
351
364
  break;
365
+ case 'source':
366
+ case 'mapper':
367
+ case 'joiner':
368
+ case 'target':
369
+ case 'filter':
370
+ case 'collap':
371
+ case 'expand':
372
+ case 'reduce':
373
+ await et2lTable(this.logicFlow, node);
374
+ break;
352
375
  default:
353
376
  await nodeCustom(this.logicFlow, node);
354
377
  break;
@@ -378,6 +401,14 @@ export default {
378
401
  // 同步最后数据
379
402
  this.$emit('update:modelValue', undos[undos.length - 1])
380
403
  })
404
+
405
+ // 错误提示
406
+ this.logicFlow.on('connection:not-allowed', (data) => {
407
+ this.$message({
408
+ type: 'error',
409
+ message: data.msg
410
+ })
411
+ })
381
412
  },
382
413
  // 关闭属性抽屉
383
414
  nodeEditClose() {
@@ -469,6 +500,23 @@ export default {
469
500
  align-items: center;
470
501
  justify-content: center;
471
502
  }
503
+ // et2l节点样式
504
+ :deep(.lw-flow-node-et2l) {
505
+ width: 100%;
506
+ height: 100%;
507
+ color: #ffffff;
508
+ line-height: 20px;
509
+ font-size: 12px;
510
+ display: flex;
511
+ justify-content: left;
512
+ align-items: center;
513
+ gap: 10px;
514
+ padding: 0 0 0 10px;
515
+ position: relative;
516
+ i {
517
+ font-size: 20px;
518
+ }
519
+ }
472
520
  // 自定义节点样式
473
521
  :deep(.lw-flow-node-custom) {
474
522
  width: 100%;
@@ -2,7 +2,6 @@
2
2
  <lw-form ref="dataFormRef"
3
3
  :config="config"
4
4
  v-model="dataForm">
5
-
6
5
  <!-- 定时器 表单部分 -->
7
6
  <template #dateCron>
8
7
  <lwCronSelect v-model="dataForm.cron" />
@@ -39,13 +38,20 @@ export default {
39
38
  watch: {
40
39
  modelValue: {
41
40
  handler(val) {
42
- this.dataForm = val
41
+ if (val) {
42
+ this.dataForm = val
43
+ }
44
+
43
45
  },
46
+ immediate: true,
44
47
  deep: true
45
48
  },
46
49
  dataForm: {
47
- handler(val) {
48
- this.$emit('update:modelValue', val)
50
+ handler(val, old) {
51
+ if (Object.keys(old).length > 0) {
52
+ this.$emit('update:modelValue', val)
53
+ }
54
+
49
55
  },
50
56
  deep: true
51
57
  }
@@ -8,7 +8,7 @@
8
8
  accordion>
9
9
  <el-collapse-item title="基础信息"
10
10
  name="basicInfo">
11
- <basicSettings v-model="dataForm.properties.data"
11
+ <basicSettings ref="basicSettingsRef" v-model="dataForm.properties.data"
12
12
  :type="nodeData.type"
13
13
  :lf="lf" />
14
14
  </el-collapse-item>
@@ -74,7 +74,8 @@ export default {
74
74
  }
75
75
  },
76
76
  methods: {
77
- onSubmit() {
77
+ async onSubmit() {
78
+ await this.$refs.basicSettingsRef.$refs.dataFormRef.validate();
78
79
  const { id } = this.dataForm
79
80
  this.lf.setProperties(id, {
80
81
  ...this.dataForm.properties
@@ -38,6 +38,15 @@ export default function registerStart(lf) {
38
38
  this.height = 40
39
39
  this.text.editable = false
40
40
  }
41
+ getConnectedSourceRules() {
42
+ const rules = super.getConnectedSourceRules()
43
+ const notAsTarget = {
44
+ message: '终止节点不能作为连线的起点',
45
+ validate: () => false
46
+ }
47
+ rules.push(notAsTarget)
48
+ return rules
49
+ }
41
50
  }
42
51
  return {
43
52
  view: HtmlNodeView,
@@ -38,6 +38,15 @@ export default function registerStart(lf) {
38
38
  this.height = 40
39
39
  this.text.editable = false
40
40
  }
41
+ getConnectedTargetRules() {
42
+ const rules = super.getConnectedTargetRules()
43
+ const notAsTarget = {
44
+ message: '起始节点不能作为连线的终点',
45
+ validate: () => false
46
+ }
47
+ rules.push(notAsTarget)
48
+ return rules
49
+ }
41
50
  }
42
51
  return {
43
52
  view: HtmlNodeView,
@@ -0,0 +1,132 @@
1
+ /**
2
+ * @description ET2L节点节点初始化
3
+ */
4
+ import dayjs from 'dayjs'
5
+ import nodeDatas from '../nodesData/index.js'
6
+ export default function registerEt2l(lf, node) {
7
+ // 是否显示
8
+ function hideHandle(item, data) {
9
+ if (Object.keys(data).length == 0) return false
10
+ if (typeof item.hideHandle === 'string') {
11
+ const exp = eval(item.hideHandle.replace(/\$/g, 'data'))
12
+ return exp
13
+ } else if (typeof item.hideHandle === 'boolean') {
14
+ return item.hideHandle
15
+ }
16
+ return false
17
+ }
18
+ /**
19
+ * 解析模板字符串,将其中的占位符替换为对应的数据值。
20
+ * 占位符格式为 ${key},其中 key 可以是嵌套的对象属性。
21
+ * 如果数据中存在对应的值,则替换占位符;否则保留原占位符。
22
+ * @param {string} template - 待解析的模板字符串
23
+ * @param {object} data - 包含替换数据的对象
24
+ * @returns {string} 解析后的字符串
25
+ */
26
+ function parseTemplateString(data) {
27
+ let html = ''
28
+ nodeDatas[node.type].nodeHtml.forEach((item) => {
29
+ let value = item.value?.split('.').reduce((acc, part) => acc && acc[part], data)
30
+ // 日期
31
+ if (item?.component == 'date') {
32
+ if (Array.isArray(value)) {
33
+ value = `${dayjs(value[0]).format(item['value-format'] || 'YYYY-MM-DD HH:mm:ss')}到${dayjs(value[1]).format(item['value-format'] || 'YYYY-MM-DD HH:mm:ss')}`
34
+ } else {
35
+ value = dayjs(value).format(item['value-format'] || 'YYYY-MM-DD HH:mm:ss')
36
+ }
37
+ }
38
+ // 转换
39
+ if (item?.items) {
40
+ let x = item.items.find((x) => {
41
+ return x.value == value
42
+ })
43
+ value = x?.label
44
+ }
45
+ if (item.hideHandle) {
46
+ if (!hideHandle(item, data)) {
47
+ html += `<span>${item.label}: ${value || '--'}</span>`
48
+ }
49
+ } else {
50
+ html += `<span>${item.label}: ${value || '--'}</span>`
51
+ }
52
+ })
53
+ return html
54
+ }
55
+
56
+ lf.register(node.type, ({ HtmlNode, HtmlNodeModel, h }) => {
57
+ class HtmlNodeView extends HtmlNode {
58
+ setHtml(rootEl) {
59
+ const { properties, text } = this.props.model
60
+ const el = document.createElement('div')
61
+ el.className = 'lw-flow-node-et2l'
62
+ // 设置样式
63
+ el.style.backgroundColor = properties?.style?.backgroundColor || node.themeColor || ''
64
+ el.style.borderStyle = properties?.style?.borderStyle || ''
65
+ el.style.borderColor = properties?.style?.borderColor || node.themeColor || ''
66
+ el.style.borderWidth = `${properties?.style?.borderWidth || 2}px`
67
+ el.style.color = properties?.style?.fontColor || '' // 使用 color 替代 font-color
68
+ el.style.fontSize = `${properties?.style?.fontSize || 12}px` // 默认字体大小为 12px
69
+ el.style.fontFamily = properties?.style?.fontFamily || 'Microsoft YaHei' // 添加默认字体
70
+ el.style.lineHeight = properties?.style?.lineHeight || '1'
71
+ el.style.fontWeight = properties?.style?.fontWeight || ''
72
+ el.style.justifyContent = properties?.style?.textAlign || ''
73
+ el.style.textDecoration = properties?.style?.textDecoration || ''
74
+ el.style.fontStyle = properties?.style?.fontStyle || ''
75
+ const html = `<i class="iconfont ${node.icon}"></i> ${properties?.data?.name || node.name}`
76
+
77
+ // 暂无显示需求
78
+ // if (properties?.data.mode) {
79
+ // html += `<div class="details-body">
80
+ // <i class="iconfont icon-ziliao"></i>
81
+ // <div class="p-list">11111111111111${parseTemplateString({ ...properties.data })}</div>
82
+ // </div>`
83
+ // }
84
+
85
+ el.innerHTML = html
86
+ rootEl.innerHTML = ''
87
+ rootEl.appendChild(el)
88
+ window.stop = (ev) => {
89
+ ev.stopPropagation()
90
+ }
91
+ window.setData = () => {
92
+ const { graphModel, model } = this.props
93
+ graphModel.eventCenter.emit('custom:button-click', model)
94
+ }
95
+ }
96
+ }
97
+ class HtmlNodeModelAttributes extends HtmlNodeModel {
98
+ setAttributes() {
99
+ this.width = 120
100
+ this.height = 40
101
+ this.text.editable = false
102
+ }
103
+ initNodeData(data) {
104
+ super.initNodeData(data)
105
+
106
+ // const circleOnlyAsTarget = {
107
+ // message: '目标节点只允许一个上级连接',
108
+ // validate: (sourceNode, targetNode, sourceAnchor, targetAnchor) => {
109
+ // let { edges } = targetNode.graphModel
110
+ // let { id } = targetNode
111
+ // let number = [...edges].filter((item) => {
112
+ // let { targetNodeId } = { ...item }
113
+ // return targetNodeId == id
114
+ // })
115
+ // console.log(number)
116
+ // return number.length < 1
117
+ // }
118
+ // }
119
+ // this.targetRules.push(circleOnlyAsTarget)
120
+
121
+ // 目标节点校验
122
+ nodeDatas[node.type]?.targetRules?.forEach((item) => {
123
+ this.targetRules.push(item)
124
+ })
125
+ }
126
+ }
127
+ return {
128
+ view: HtmlNodeView,
129
+ model: HtmlNodeModelAttributes
130
+ }
131
+ })
132
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * ET2L节点 COLAP 配置数据
3
+ */
4
+
5
+ export default {
6
+ // 暂无显示需求
7
+ nodeHtml: [],
8
+ // 节点校验
9
+ targetRules: [
10
+ {
11
+ message: '目标节点只允许一个上级连接',
12
+ validate: (sourceNode, targetNode, sourceAnchor, targetAnchor) => {
13
+ let { edges } = targetNode.graphModel
14
+ let { id } = targetNode
15
+ let number = [...edges].filter((item) => {
16
+ let { targetNodeId } = { ...item }
17
+ return targetNodeId == id
18
+ })
19
+ return number.length < 1
20
+ }
21
+ }
22
+ ],
23
+ // 表单内容
24
+ formConfig: {
25
+ labelWidth: '70px',
26
+ labelPosition: 'top',
27
+ formItems: [
28
+ {
29
+ label: '节点名称',
30
+ name: 'name',
31
+ value: '',
32
+ component: 'input',
33
+ options: {
34
+ placeholder: '请输入节点名称'
35
+ },
36
+ span: 24,
37
+ rules: [{ required: true, message: '不能为空', trigger: 'blur' }]
38
+ },
39
+ {
40
+ label: '来源名称',
41
+ name: 'from',
42
+ value: '',
43
+ component: 'input',
44
+ options: {
45
+ placeholder: '请输入数据表名'
46
+ },
47
+ span: 24,
48
+ rules: [{ required: true, message: '不能为空', trigger: 'blur' }]
49
+ },
50
+ {
51
+ label: '折叠字段',
52
+ name: 'with',
53
+ value: '',
54
+ component: 'input',
55
+ options: {
56
+ placeholder: '请输入折叠字段名称'
57
+ },
58
+ span: 24,
59
+ rules: [{ required: true, message: '不能为空', trigger: 'blur' }]
60
+ },
61
+ {
62
+ label: '折叠排序方式',
63
+ name: 'sort',
64
+ value: '',
65
+ component: 'input',
66
+ options: {
67
+ placeholder: '请输入 例如:batchId, updateTime DESC'
68
+ },
69
+ span: 24
70
+ },
71
+ {
72
+ label: '描述信息',
73
+ name: 'desp',
74
+ value: '',
75
+ component: 'input',
76
+ options: {
77
+ type: 'textarea',
78
+ placeholder: '请输入'
79
+ },
80
+ span: 24
81
+ }
82
+ ]
83
+ }
84
+ }
@@ -0,0 +1,84 @@
1
+ /**
2
+ * ET2L节点 EXPAND 配置数据
3
+ */
4
+
5
+ export default {
6
+ // 暂无显示需求
7
+ nodeHtml: [],
8
+ // 节点校验
9
+ targetRules: [
10
+ {
11
+ message: '目标节点只允许一个上级连接',
12
+ validate: (sourceNode, targetNode, sourceAnchor, targetAnchor) => {
13
+ let { edges } = targetNode.graphModel
14
+ let { id } = targetNode
15
+ let number = [...edges].filter((item) => {
16
+ let { targetNodeId } = { ...item }
17
+ return targetNodeId == id
18
+ })
19
+ return number.length < 1
20
+ }
21
+ }
22
+ ],
23
+ // 表单内容
24
+ formConfig: {
25
+ labelWidth: '70px',
26
+ labelPosition: 'top',
27
+ formItems: [
28
+ {
29
+ label: '节点名称',
30
+ name: 'name',
31
+ value: '',
32
+ component: 'input',
33
+ options: {
34
+ placeholder: '请输入节点名称'
35
+ },
36
+ span: 24,
37
+ rules: [{ required: true, message: '不能为空', trigger: 'blur' }]
38
+ },
39
+ {
40
+ label: '来源名称',
41
+ name: 'from',
42
+ value: '',
43
+ component: 'input',
44
+ options: {
45
+ placeholder: '请输入数据表名'
46
+ },
47
+ span: 24,
48
+ rules: [{ required: true, message: '不能为空', trigger: 'blur' }]
49
+ },
50
+ {
51
+ label: '折叠字段',
52
+ name: 'with',
53
+ value: '',
54
+ component: 'input',
55
+ options: {
56
+ placeholder: '请输入折叠字段名称'
57
+ },
58
+ span: 24,
59
+ rules: [{ required: true, message: '不能为空', trigger: 'blur' }]
60
+ },
61
+ {
62
+ label: '折叠排序方式',
63
+ name: 'sort',
64
+ value: '',
65
+ component: 'input',
66
+ options: {
67
+ placeholder: '请输入 例如:batchId, updateTime DESC'
68
+ },
69
+ span: 24
70
+ },
71
+ {
72
+ label: '描述信息',
73
+ name: 'desp',
74
+ value: '',
75
+ component: 'input',
76
+ options: {
77
+ type: 'textarea',
78
+ placeholder: '请输入'
79
+ },
80
+ span: 24
81
+ }
82
+ ]
83
+ }
84
+ }