@epxing/business 5.3.0-beta.2 → 5.3.0-beta.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.
Files changed (98) hide show
  1. package/API.md +8 -4
  2. package/README.md +44 -44
  3. package/dist/src/base/AiSkillEditor.js +1 -1
  4. package/dist/src/base/AiSkillEditor.vue.js +2 -0
  5. package/dist/src/base/AppConfigFormItem.js +1 -3
  6. package/dist/src/base/AppConfigFormItem.vue.js +210 -85
  7. package/dist/src/base/CommonFieldList.js +1 -1
  8. package/dist/src/base/CommonFieldList.vue.js +2 -1
  9. package/dist/src/base/ConfigModuleIndex.js +38 -1
  10. package/dist/src/base/ManageAppNav.js +1 -1
  11. package/dist/src/base/ManageMenu.js +1 -1
  12. package/dist/src/base/RoleBindTrace.js +253 -0
  13. package/dist/src/base/RoleGroupManage.js +1037 -0
  14. package/dist/src/base/ServiceMenu.js +7 -6
  15. package/dist/src/components/AiList.js +1278 -3
  16. package/dist/src/components/EntityCheckboxFind.vue.js +14 -10
  17. package/dist/src/components/EntityRightFormItem.js +1 -5
  18. package/dist/src/components/EntityRightFormItem.vue.js +3 -1
  19. package/dist/src/components/EntitySystemEr.js +492 -0
  20. package/dist/src/components/HallNav.vue.js +7 -36
  21. package/dist/src/components/IconFontLibrary.js +22 -1
  22. package/dist/src/components/IconFontList.js +21 -1
  23. package/dist/src/components/PrintFormList.js +2 -1
  24. package/dist/src/components/PrintFormList.vue.js +3 -1
  25. package/dist/src/components/WikiWorkbench.js +153 -129
  26. package/dist/src/components/authorization/AuthorizationInterface.js +3 -1
  27. package/dist/src/components/custom-bpmn/PropertiesView.js +1991 -1942
  28. package/dist/src/components/icon-gallery/IconGallery.js +193 -0
  29. package/dist/src/components/icon-gallery/mixin.js +150 -0
  30. package/dist/src/components/wiki-workbench/WikiIntake.js +86 -93
  31. package/dist/src/components/wiki-workbench/WikiIntake.vue.js +153 -73
  32. package/dist/src/index.js +26 -20
  33. package/dist/src/public-components.js +16 -14
  34. package/dist/src/route-components.js +5 -5
  35. package/dist/src/system.component.index.js +1 -1
  36. package/dist/src/system.component.js +8 -3
  37. package/dist/src/system.component.lazy.js +1 -1
  38. package/dist/src/views/Add.js +1 -1
  39. package/dist/src/views/Add.vue.js +8 -3
  40. package/dist/src/views/AiToolManager.js +792 -317
  41. package/dist/src/views/App.js +3 -45
  42. package/dist/src/views/AppRoleSelect.js +3 -230
  43. package/dist/src/views/Error.js +3 -207
  44. package/dist/src/views/ExcelDesign.js +326 -316
  45. package/dist/src/views/JvmMemoryMonitor.js +463 -0
  46. package/dist/src/views/Module.js +3 -170
  47. package/dist/src/views/WikiBinding.js +88 -25
  48. package/dist/style.css +2867 -1487
  49. package/package.json +12 -6
  50. package/src/base/AiSkillEditor.vue +2 -0
  51. package/src/base/AppConfigFormItem.vue +211 -145
  52. package/src/base/CommonFieldList.vue +9 -6
  53. package/src/base/ConfigModuleIndex.vue +37 -1
  54. package/src/base/ManageAppNav.vue +1188 -1188
  55. package/src/base/ManageMenu.vue +933 -933
  56. package/src/base/RoleBindTrace.vue +364 -0
  57. package/src/base/RoleGroupManage.vue +1160 -0
  58. package/src/base/ServiceMenu.vue +6 -5
  59. package/src/components/AiList.vue +439 -113
  60. package/src/components/EntityCheckboxFind.vue +12 -8
  61. package/src/components/EntityRightFormItem.vue +9 -10
  62. package/src/components/EntitySystemEr.vue +517 -0
  63. package/src/components/HallNav.vue +6 -33
  64. package/src/components/IconFontLibrary.vue +27 -60
  65. package/src/components/IconFontList.vue +13 -64
  66. package/src/components/PrintFormList.vue +33 -27
  67. package/src/components/WikiWorkbench.vue +90 -60
  68. package/src/components/authorization/AuthorizationInterface.vue +2 -0
  69. package/src/components/custom-bpmn/CustomPalette.js +1 -1
  70. package/src/components/custom-bpmn/CustomRenderer.js +1 -1
  71. package/src/components/custom-bpmn/PropertiesView.vue +35 -4
  72. package/src/components/custom-bpmn/index.js +1 -1
  73. package/src/components/icon-gallery/IconGallery.vue +130 -0
  74. package/src/components/icon-gallery/mixin.jsx +109 -0
  75. package/src/components/wiki-workbench/WikiIntake.vue +178 -104
  76. package/src/index.js +24 -20
  77. package/src/public-components.js +1 -0
  78. package/src/route-components.js +4 -4
  79. package/src/system.component.index.js +1 -1
  80. package/src/views/Add.vue +8 -5
  81. package/src/views/AiToolManager.vue +326 -4
  82. package/src/views/App.vue +4 -53
  83. package/src/views/AppRoleSelect.vue +4 -334
  84. package/src/views/Error.vue +4 -63
  85. package/src/views/ExcelDesign.vue +24 -7
  86. package/src/views/JvmMemoryMonitor.vue +284 -0
  87. package/src/views/Module.vue +4 -210
  88. package/src/views/WikiBinding.vue +42 -0
  89. package/types/app.d.ts +1 -0
  90. package/types/dept-find.d.ts +1 -1
  91. package/types/index.d.ts +15 -14
  92. package/types/popup.d.ts +2 -2
  93. package/types/route-components.d.ts +1 -1
  94. package/types/user-find.d.ts +1 -1
  95. package/dist/assets/role_select-DTqRlFNz.webp +0 -0
  96. package/dist/src/components/AiList.vue.js +0 -93
  97. package/dist/src/components/IconFontLibrary.vue.js +0 -67
  98. package/dist/src/components/IconFontList.vue.js +0 -79
@@ -38,15 +38,19 @@ export default {
38
38
  }
39
39
  },
40
40
  watch: {
41
- checked (v) {
42
- const result = v.map(item => ({ id: item }))
43
- if (result.length === 0) {
44
- this.change({})
45
- } else {
46
- if (this.multiple) {
47
- this.change(result, v)
41
+ checked: {
42
+ // 兼容选中数组的原地变更,确保角色选择结果同步回表单。
43
+ deep: true,
44
+ handler (v) {
45
+ const result = v.map(item => ({ id: item }))
46
+ if (result.length === 0) {
47
+ this.change({})
48
48
  } else {
49
- this.change(result[0], v[0])
49
+ if (this.multiple) {
50
+ this.change(result, v)
51
+ } else {
52
+ this.change(result[0], v[0])
53
+ }
50
54
  }
51
55
  }
52
56
  },
@@ -248,7 +248,7 @@ export default {
248
248
  renderForm () {
249
249
  if (this.fieldsConfigs.length > 0) {
250
250
  return (
251
- <div>
251
+ <div class="epx-entity-right-form-item">
252
252
  <epx-table-form class="form-content" ref="form" metaId={this.$metaId} fieldsConfigs={this.fieldsConfigs} v-model={this.data}
253
253
  column={this.column} labelAlign={this.$configs.labelAlign}
254
254
  v-slots= {{
@@ -338,7 +338,9 @@ export default {
338
338
  }
339
339
  }
340
340
  </script>
341
- <style scoped lang="scss">
341
+ <style lang="scss">
342
+ // 继承的 JSX 渲染节点不带本组件的 scope 标记,以专用根类隔离样式。
343
+ .epx-entity-right-form-item {
342
344
  .container {
343
345
  background: var(--epx-bg-card);
344
346
  &.fold {
@@ -436,7 +438,7 @@ export default {
436
438
  display: flex;
437
439
  justify-content: center;
438
440
 
439
- :deep(.el-button) {
441
+ .el-button {
440
442
  padding: 12px 42px;
441
443
  margin: 0 12px;
442
444
  }
@@ -453,14 +455,12 @@ export default {
453
455
  margin-right: 16px;
454
456
  }
455
457
 
456
- :deep(.el-input) {
458
+ .el-input {
457
459
  width: 160px;
458
460
  margin-right: 10px;
459
461
  }
460
462
 
461
463
  }
462
- </style>
463
- <style lang="scss" scoped>
464
464
  .apis-checkbox__group {
465
465
  .checkbox{
466
466
  display: inline-block;
@@ -486,8 +486,6 @@ export default {
486
486
  max-height: 500px;
487
487
  overflow: auto;
488
488
  }
489
- </style>
490
- <style lang="scss" scoped>
491
489
  .interface {
492
490
  background: var(--epx-bg-card);
493
491
  }
@@ -568,7 +566,7 @@ export default {
568
566
  margin-left: 12px;
569
567
  }
570
568
 
571
- :deep(.el-input) {
569
+ .el-input {
572
570
  width: 220px;
573
571
  }
574
572
 
@@ -609,10 +607,11 @@ export default {
609
607
  .api-type__content {
610
608
  padding: 10px 20px;
611
609
 
612
- :deep(.el-checkbox) {
610
+ .el-checkbox {
613
611
  padding: 10px 0;
614
612
  color: var(--epx-text);
615
613
  }
616
614
 
615
+ }
617
616
  }
618
617
  </style>
@@ -0,0 +1,517 @@
1
+ <template>
2
+ <el-tabs v-model="activeTab" class="er-tabs" @tab-remove="removeTab">
3
+ <el-tab-pane name="panorama" label="对象全景图" :closable="false">
4
+ <div class="epx-entity-system-er">
5
+ <div class="er-header">
6
+ <div class="er-tools">
7
+ <el-input
8
+ v-model="keyword"
9
+ size="default"
10
+ clearable
11
+ placeholder="搜索对象名称 / 编号"
12
+ class="er-search"
13
+ @keyup.enter="locateNode"
14
+ @clear="clearHighlight"
15
+ >
16
+ <template #append><el-button icon="el-icon-search" @click="locateNode"></el-button></template>
17
+ </el-input>
18
+ <el-checkbox-group v-model="relationTypes" class="er-filter" @change="renderGraph">
19
+ <el-checkbox label="1">一对多</el-checkbox>
20
+ <el-checkbox label="2">单条</el-checkbox>
21
+ </el-checkbox-group>
22
+ <el-button size="default" @click="resetView">重置视图</el-button>
23
+ <el-button size="default" type="primary" @click="exportEr">导出</el-button>
24
+ </div>
25
+ <div class="er-legend">
26
+ <span class="er-count">对象 {{ nodes.length }} 个 · 关系 {{ edges.length }} 条</span>
27
+ <div class="legend-item">
28
+ <span class="legend-icon">
29
+ <i class="el-icon-caret-left"></i>
30
+ </span>
31
+ <span>单条</span>
32
+ </div>
33
+ <div class="legend-item">
34
+ <span class="legend-icon legend-icon--sub">
35
+ <i class="el-icon-caret-left"></i>
36
+ </span>
37
+ <span>一对多</span>
38
+ </div>
39
+ <div class="legend-item">
40
+ <span class="legend-node legend-node--external"></span>
41
+ <span>外部对象</span>
42
+ </div>
43
+ </div>
44
+ </div>
45
+ <div ref="er" v-loading="loading" class="er-container"></div>
46
+ </div>
47
+ </el-tab-pane>
48
+ <el-tab-pane
49
+ v-for="tab in relationTabs"
50
+ :key="tab.metaId"
51
+ :name="tab.metaId"
52
+ :label="tab.label"
53
+ closable
54
+ lazy
55
+ >
56
+ <relation-diagram :current-query="{ id: tab.metaId }" class="er-tab-diagram"></relation-diagram>
57
+ </el-tab-pane>
58
+ </el-tabs>
59
+ </template>
60
+ <script>
61
+ import component from '@epxing/core/src/mixins/component'
62
+ import { Graph } from '@antv/x6'
63
+ import { Export } from '@antv/x6-plugin-export'
64
+ import Er from './entity-relation-diagram/Er.vue'
65
+
66
+ // 内嵌单对象关系图:扩展 currentQuery prop,让 Er 内部的 $query.id 取到各标签自己的对象
67
+ const RelationDiagram = {
68
+ extends: Er,
69
+ props: ['currentQuery']
70
+ }
71
+ // 关系类型:一对多
72
+ const RELATION_ONE_MOST = '1'
73
+
74
+ // 对象级节点:上行对象名称、下行对象编号,外部对象灰显
75
+ Graph.registerNode(
76
+ 'er-system-node',
77
+ {
78
+ inherit: 'rect',
79
+ width: 180,
80
+ height: 56,
81
+ markup: [
82
+ {
83
+ tagName: 'rect',
84
+ selector: 'body'
85
+ },
86
+ {
87
+ tagName: 'text',
88
+ selector: 'name'
89
+ },
90
+ {
91
+ tagName: 'text',
92
+ selector: 'code'
93
+ }
94
+ ],
95
+ attrs: {
96
+ body: {
97
+ width: 180,
98
+ height: 56,
99
+ rx: 6,
100
+ ry: 6,
101
+ fill: '#1461E4',
102
+ stroke: '#76A8FF',
103
+ strokeWidth: 1,
104
+ cursor: 'pointer'
105
+ },
106
+ name: {
107
+ fontSize: 14,
108
+ fill: '#fff',
109
+ ref: 'body',
110
+ refX: '50%',
111
+ refY: 20,
112
+ textAnchor: 'middle',
113
+ textVerticalAnchor: 'middle',
114
+ textWrap: {
115
+ width: 160,
116
+ ellipsis: true
117
+ }
118
+ },
119
+ code: {
120
+ fontSize: 11,
121
+ fill: 'rgba(255, 255, 255, 0.75)',
122
+ ref: 'body',
123
+ refX: '50%',
124
+ refY: 40,
125
+ textAnchor: 'middle',
126
+ textVerticalAnchor: 'middle',
127
+ textWrap: {
128
+ width: 160,
129
+ ellipsis: true
130
+ }
131
+ }
132
+ }
133
+ },
134
+ true
135
+ )
136
+ export default {
137
+ name: 'epx-entity-system-er',
138
+ mixins: [component],
139
+ components: { RelationDiagram },
140
+ data () {
141
+ return {
142
+ relation: {},
143
+ keyword: '',
144
+ // 关系类型过滤:勾选后仅显示对应类型的关系,全不勾选显示全部
145
+ relationTypes: [],
146
+ loading: false,
147
+ // 当前标签;panorama 为固定全景图,其余为页内打开的对象关系图
148
+ activeTab: 'panorama',
149
+ relationTabs: []
150
+ }
151
+ },
152
+ computed: {
153
+ nodes () {
154
+ return this.relation.NODES || []
155
+ },
156
+ edges () {
157
+ return this.relation.EDGES || []
158
+ }
159
+ },
160
+ methods: {
161
+ getMetaRelation () {
162
+ this.loading = true
163
+ this.$http.get({
164
+ action: 'metaSystemER',
165
+ entityId: 'FM_ENTITY'
166
+ })
167
+ .then(data => {
168
+ this.loading = false
169
+ this.relation = data || {}
170
+ this.renderGraph()
171
+ })
172
+ .catch(() => {
173
+ this.loading = false
174
+ })
175
+ },
176
+ getVisibleEdges () {
177
+ if (this.relationTypes.length === 0 || this.relationTypes.length === 2) {
178
+ return this.edges
179
+ }
180
+ const types = this.relationTypes
181
+ return this.edges.filter(edge => (edge.SORTS || []).some(sort => types.includes(sort)))
182
+ },
183
+ // 轻量力导布局:环形初始布点,库仑斥力 + 弹簧引力 + 向心力迭代收敛,结果确定性可复现
184
+ forceLayout (nodes, edges) {
185
+ const pos = {}
186
+ const count = nodes.length
187
+ if (count === 0) return pos
188
+ const radius = Math.max(300, count * 8)
189
+ nodes.forEach((node, i) => {
190
+ const angle = (2 * Math.PI * i) / count
191
+ pos[node.META_ID] = {
192
+ x: radius * Math.cos(angle),
193
+ y: radius * Math.sin(angle),
194
+ vx: 0,
195
+ vy: 0
196
+ }
197
+ })
198
+ const ids = nodes.map(node => node.META_ID)
199
+ const pairs = edges.map(edge => [edge.SOURCE, edge.TARGET])
200
+ const REPULSION = 60000
201
+ const SPRING_LEN = 240
202
+ const SPRING = 0.03
203
+ const CENTER_PULL = 0.03
204
+ const MAX_STEP = 30
205
+ const ITERATIONS = 200
206
+ for (let iter = 0; iter < ITERATIONS; iter++) {
207
+ for (let i = 0; i < ids.length; i++) {
208
+ for (let j = i + 1; j < ids.length; j++) {
209
+ const a = pos[ids[i]]
210
+ const b = pos[ids[j]]
211
+ let dx = a.x - b.x
212
+ let dy = a.y - b.y
213
+ let dist2 = dx * dx + dy * dy
214
+ if (dist2 < 1) {
215
+ // 重合时按索引错开,避免除零
216
+ dx = (i % 7) - 3.5
217
+ dy = (j % 7) - 3.5
218
+ dist2 = dx * dx + dy * dy
219
+ }
220
+ const dist = Math.sqrt(dist2)
221
+ const force = REPULSION / dist2
222
+ const fx = (dx / dist) * force
223
+ const fy = (dy / dist) * force
224
+ a.vx += fx
225
+ a.vy += fy
226
+ b.vx -= fx
227
+ b.vy -= fy
228
+ }
229
+ }
230
+ pairs.forEach(pair => {
231
+ if (pair[0] === pair[1]) return
232
+ const a = pos[pair[0]]
233
+ const b = pos[pair[1]]
234
+ if (!a || !b) return
235
+ const dx = a.x - b.x
236
+ const dy = a.y - b.y
237
+ const dist = Math.sqrt(dx * dx + dy * dy) || 1
238
+ const force = SPRING * (dist - SPRING_LEN)
239
+ const fx = (dx / dist) * force
240
+ const fy = (dy / dist) * force
241
+ a.vx -= fx
242
+ a.vy -= fy
243
+ b.vx += fx
244
+ b.vy += fy
245
+ })
246
+ ids.forEach(id => {
247
+ const p = pos[id]
248
+ p.vx += -p.x * CENTER_PULL
249
+ p.vy += -p.y * CENTER_PULL
250
+ let stepX = p.vx * 0.5
251
+ let stepY = p.vy * 0.5
252
+ const step = Math.sqrt(stepX * stepX + stepY * stepY)
253
+ if (step > MAX_STEP) {
254
+ stepX = (stepX / step) * MAX_STEP
255
+ stepY = (stepY / step) * MAX_STEP
256
+ }
257
+ p.x += stepX
258
+ p.y += stepY
259
+ p.vx = 0
260
+ p.vy = 0
261
+ })
262
+ }
263
+ return pos
264
+ },
265
+ renderGraph () {
266
+ if (this.graph) this.graph.dispose()
267
+ const graph = new Graph({
268
+ container: this.$refs.er,
269
+ background: {
270
+ color: '#fff'
271
+ },
272
+ panning: true,
273
+ mousewheel: {
274
+ enabled: true
275
+ }
276
+ })
277
+ graph.use(new Export())
278
+ this.graph = graph
279
+ const edges = this.getVisibleEdges()
280
+ const pos = this.forceLayout(this.nodes, edges)
281
+ this.nodes.forEach(node => {
282
+ const p = pos[node.META_ID]
283
+ const external = node.EXTERNAL === '1'
284
+ graph.addNode({
285
+ id: node.META_ID,
286
+ shape: 'er-system-node',
287
+ x: p.x - 90,
288
+ y: p.y - 28,
289
+ data: node,
290
+ attrs: {
291
+ body: external
292
+ ? { fill: '#95A2B3', stroke: '#B8C0CC', cursor: 'default' }
293
+ : { fill: '#1461E4', stroke: '#76A8FF', cursor: 'pointer' },
294
+ name: { text: node.META_NAME },
295
+ code: { text: node.META_CODE }
296
+ },
297
+ zIndex: 2
298
+ })
299
+ })
300
+ edges.forEach(edge => {
301
+ // 自关联补一个顶点形成可见环路
302
+ const selfLoop = edge.SOURCE === edge.TARGET
303
+ graph.addEdge({
304
+ source: edge.SOURCE,
305
+ target: edge.TARGET,
306
+ vertices: selfLoop ? [{ x: pos[edge.SOURCE].x, y: pos[edge.SOURCE].y - 100 }] : undefined,
307
+ attrs: {
308
+ line: {
309
+ stroke: '#5795FF',
310
+ strokeWidth: 1.5,
311
+ strokeDasharray: (edge.SORTS || []).includes(RELATION_ONE_MOST) ? '5, 5' : '0'
312
+ }
313
+ },
314
+ labels: edge.COUNT > 1
315
+ ? [{
316
+ attrs: {
317
+ text: { text: '×' + edge.COUNT, fill: '#5A6473', fontSize: 11 },
318
+ rect: { fill: '#E8F2FF', stroke: '#91B9FF', rx: 3, strokeWidth: 1 }
319
+ }
320
+ }]
321
+ : undefined,
322
+ connector: {
323
+ name: 'smooth'
324
+ },
325
+ zIndex: 1
326
+ })
327
+ })
328
+ graph.on('node:click', ({ node }) => {
329
+ const data = node.getData()
330
+ if (!data || data.EXTERNAL === '1') return
331
+ this.openRelationTab(data)
332
+ })
333
+ graph.centerContent()
334
+ graph.zoomToFit({ padding: 40, maxScale: 1.5, minScale: 0.05 })
335
+ },
336
+ locateNode () {
337
+ if (!this.graph) return
338
+ const keyword = (this.keyword || '').trim().toLowerCase()
339
+ if (!keyword) {
340
+ this.clearHighlight()
341
+ return
342
+ }
343
+ const matched = []
344
+ this.nodes.forEach(node => {
345
+ if (
346
+ (node.META_NAME || '').toLowerCase().includes(keyword) ||
347
+ (node.META_CODE || '').toLowerCase().includes(keyword)
348
+ ) {
349
+ matched.push(node)
350
+ }
351
+ })
352
+ this.clearHighlight()
353
+ if (matched.length === 0) {
354
+ this.$message.info('未找到匹配的对象')
355
+ return
356
+ }
357
+ matched.forEach(node => {
358
+ const cell = this.graph.getCellById(node.META_ID)
359
+ if (cell) {
360
+ cell.attr('body/stroke', '#F59A23')
361
+ cell.attr('body/strokeWidth', 2.5)
362
+ }
363
+ })
364
+ this.highlighted = matched.map(node => node.META_ID)
365
+ const first = this.graph.getCellById(matched[0].META_ID)
366
+ if (first) this.graph.centerCell(first)
367
+ },
368
+ clearHighlight () {
369
+ if (!this.graph || !this.highlighted) return
370
+ this.highlighted.forEach(id => {
371
+ const cell = this.graph.getCellById(id)
372
+ if (!cell) return
373
+ const external = cell.getData().EXTERNAL === '1'
374
+ cell.attr('body/stroke', external ? '#B8C0CC' : '#76A8FF')
375
+ cell.attr('body/strokeWidth', 1)
376
+ })
377
+ this.highlighted = []
378
+ },
379
+ resetView () {
380
+ if (!this.graph) return
381
+ this.graph.centerContent()
382
+ this.graph.zoomToFit({ padding: 40, maxScale: 1.5, minScale: 0.05 })
383
+ },
384
+ exportEr () {
385
+ this.graph.exportPNG('对象全景图', {
386
+ padding: 20
387
+ })
388
+ },
389
+ // 页内新开对象关系图标签;同对象已打开则只聚焦
390
+ openRelationTab (node) {
391
+ if (this.relationTabs.some(tab => tab.metaId === node.META_ID)) {
392
+ this.activeTab = node.META_ID
393
+ return
394
+ }
395
+ this.relationTabs.push({
396
+ metaId: node.META_ID,
397
+ label: node.META_NAME || node.META_CODE
398
+ })
399
+ this.activeTab = node.META_ID
400
+ },
401
+ removeTab (name) {
402
+ if (name === 'panorama') return
403
+ const index = this.relationTabs.findIndex(tab => tab.metaId === name)
404
+ if (index === -1) return
405
+ this.relationTabs.splice(index, 1)
406
+ if (this.activeTab === name) {
407
+ const next = this.relationTabs[index] || this.relationTabs[index - 1]
408
+ this.activeTab = next ? next.metaId : 'panorama'
409
+ }
410
+ }
411
+ },
412
+ mounted () {
413
+ this.getMetaRelation()
414
+ },
415
+ beforeUnmount () {
416
+ if (this.graph) this.graph.dispose()
417
+ }
418
+ }
419
+ </script>
420
+ <style lang="scss" scoped>
421
+ .er-tabs {
422
+ height: 100%;
423
+ display: flex;
424
+ flex-direction: column;
425
+ :deep(.el-tabs__content) {
426
+ flex: 1;
427
+ overflow: hidden;
428
+ }
429
+ :deep(.el-tab-pane) {
430
+ height: 100%;
431
+ }
432
+ }
433
+ .er-tab-diagram {
434
+ height: 100%;
435
+ }
436
+ .epx-entity-system-er {
437
+ height: 100%;
438
+ min-height: 300px;
439
+ display: flex;
440
+ flex-direction: column;
441
+ }
442
+ .er-container {
443
+ flex: 1;
444
+ }
445
+ .er-header {
446
+ display: flex;
447
+ align-items: center;
448
+ justify-content: space-between;
449
+ margin-bottom: 10px;
450
+ }
451
+ .er-tools {
452
+ display: flex;
453
+ align-items: center;
454
+ }
455
+ .er-search {
456
+ width: 240px;
457
+ margin-right: 16px;
458
+ }
459
+ .er-filter {
460
+ margin-right: 16px;
461
+ }
462
+ .er-legend {
463
+ display: flex;
464
+ align-items: center;
465
+ height: 40px;
466
+ padding: 0 20px;
467
+ background: var(--epx-bg-card, #ffffff);
468
+ border-radius: 4px;
469
+ }
470
+ .er-count {
471
+ font-size: 13px;
472
+ color: var(--epx-text, #5a6473);
473
+ margin-right: 20px;
474
+ }
475
+ .legend-item {
476
+ display: flex;
477
+ align-items: center;
478
+ margin-right: 20px;
479
+ font-size: 13px;
480
+ color: var(--epx-text, #5a6473);
481
+ }
482
+ .legend-icon {
483
+ position: relative;
484
+ top: 2px;
485
+ height: 20px;
486
+ width: 40px;
487
+ margin-right: 8px;
488
+ i {
489
+ position: absolute;
490
+ left: 0;
491
+ color: var(--epx-text-secondary, #5795ff);
492
+ font-size: 20px;
493
+ }
494
+ &::after {
495
+ content: '';
496
+ position: absolute;
497
+ width: 30px;
498
+ height: 0;
499
+ border: 1px solid var(--epx-border, #5795ff);
500
+ left: 10px;
501
+ top: 50%;
502
+ margin-top: -1px;
503
+ }
504
+ }
505
+ .legend-icon--sub {
506
+ &::after {
507
+ border-style: dashed;
508
+ }
509
+ }
510
+ .legend-node {
511
+ width: 18px;
512
+ height: 12px;
513
+ border-radius: 3px;
514
+ margin-right: 8px;
515
+ background: var(--epx-bg, #95a2b3);
516
+ }
517
+ </style>
@@ -49,45 +49,18 @@ export default {
49
49
  dropdown: () => (<el-dropdown-menu >
50
50
  { this.manageRight.clientAdmin === 'true' && <el-dropdown-item command="frame" onClick={this.openFrameManage.bind(this)}>{this.$t('Platform Management Center')}</el-dropdown-item> }
51
51
  { this.manageRight.roleManage === 'true' && <el-dropdown-item command="role" onClick={this.openService.bind(this, 'role')}>{this.$t('navigation.role_assignment_management')}</el-dropdown-item> }
52
- {
53
- (this.appConfig.IS_SET_TOOLBAR ? this.toolbar.includes('skip') : this.clientConfig.THEME_FLAG !== '0') && (
54
- <el-popover
55
- popper-class="epx-app-nav__skin-popover"
56
- placement="left-start"
57
- trigger="hover"
58
- width="auto"
59
- v-slots={{
60
- // reference 必须是「根节点为真实元素」的东西:EP 的 ElOnlyChild 会用
61
- // withDirectives(cloneVNode(node), [[forwardRef]]) 挂指令来拿 reference 的真实
62
- // DOM,而 Vue 的运行时指令只能落在元素上。el-dropdown-item 的根节点是
63
- // ElRovingFocusItem 组件 ⇒ 指令挂不上,Vue 只发一条 "Runtime directive used on
64
- // component with non-element root node" 的 warning 就静默失效 ⇒ tooltip 拿不到
65
- // reference ⇒ hover 完全没反应。
66
- // 用原生 li + EP 的 item 类名:根是元素、在 ul.el-dropdown-menu 里也合法、样式不变。
67
- // 原来的 command 属性没人消费(所在 el-dropdown 无 onCommand),去掉无影响。
68
- reference: () => (<li class="el-dropdown-menu__item">{this.$t('skin')}</li>)
69
- }}>
70
- <ul class="epx-app-nav__theme">
71
- {
72
- this.themeList.map(theme => (
73
- <li class={{ 'is-active': theme.key === this.selectTheme }} style={!theme.icon && theme.color ? { background: theme.color } : {}} key={theme.key} onClick={this.changeTheme.bind(this, theme)}>
74
- {theme.icon && <img src={theme.icon} alt="" />}
75
- {!theme.icon && <span class="epx-app-nav__theme-custom-label">{theme.name}</span>}
76
- {theme.key === this.selectTheme && <i class="epx-app-nav__theme-select el-icon-success"></i>}
77
- </li>
78
- ))
79
- }
80
- </ul>
81
- </el-popover>
82
- )
83
- }
52
+ {!this.$isMobile && this.terminal !== 'mobile' && (
53
+ <el-dropdown-item command="interface-settings" onClick={() => { this.showInterfaceSettings = true }}>
54
+ 界面设置
55
+ </el-dropdown-item>
56
+ )}
84
57
  {
85
58
  this.languageFlag && (
86
59
  <el-popover
87
60
  placement="left-start"
88
61
  trigger="hover"
89
62
  v-slots={{
90
- // 同上:reference 的根必须是元素,详见「换肤」那处注释
63
+ // reference 使用原生元素,供 ElOnlyChild 正确获取 DOM。
91
64
  reference: () => (<li class="el-dropdown-menu__item">{this.$t('language')}</li>)
92
65
  }}>
93
66
  <ul class="epx-app-nav__language-list">