diff --git a/packages/antv-x6-design/CHANGELOG.md b/packages/antv-x6-design/CHANGELOG.md index 950859c03d9dd210597236acd1eb7fbd23a3e838..4ed7f9d7e466e9d2c7b3a4d23d3a142a33d27465 100644 --- a/packages/antv-x6-design/CHANGELOG.md +++ b/packages/antv-x6-design/CHANGELOG.md @@ -7,6 +7,10 @@ ## [Unreleased] +### Added + +- 新增插件参数DESIGNMODE,若值为STYLE2,则选中连线没有背景框和label,并且识别主设计视图配置的关系视图打开方式 + ## [0.0.2] - 2024-06-07 ### Added diff --git a/packages/antv-x6-design/src/controller/x6-link-controller/x6-link-controller.ts b/packages/antv-x6-design/src/controller/x6-link-controller/x6-link-controller.ts index b0927882a5a9cbc71ff4cd9efbbac64bfa5d6843..025b8b05b98640da9e47837911d02eca3cccecb8 100644 --- a/packages/antv-x6-design/src/controller/x6-link-controller/x6-link-controller.ts +++ b/packages/antv-x6-design/src/controller/x6-link-controller/x6-link-controller.ts @@ -186,7 +186,7 @@ export class X6LinkController extends X6CellController { this.items.map(item => { const data = this.provider.createDataProvider(item); this.map.set(data.id, data); - return this.provider.createCell(data); + return this.provider.createCell(data, this.context.designmode); }), ); } @@ -209,7 +209,10 @@ export class X6LinkController extends X6CellController { this.map.set(dataProvider.id, dataProvider); // 删除原本连线,创建新连线并选中。因为连线的id是不可变的,所以需要先删除再创建 this.g.removeEdge(edge.id); - const cell = this.provider.createCell(dataProvider); + const cell = this.provider.createCell( + dataProvider, + this.context.designmode, + ); const newEdge = this.g.addEdge(cell); this.g.resetSelection([newEdge]); this.x6.evt.emit('onLinkCreated', undefined); diff --git a/packages/antv-x6-design/src/interface/provider/x6-cell.service.provider.ts b/packages/antv-x6-design/src/interface/provider/x6-cell.service.provider.ts index 1ce6872556d6677c2070494f5fb4811f419d1b6d..47197497e2a13dbf9b846a11996f2454a3260801 100644 --- a/packages/antv-x6-design/src/interface/provider/x6-cell.service.provider.ts +++ b/packages/antv-x6-design/src/interface/provider/x6-cell.service.provider.ts @@ -33,12 +33,12 @@ export interface X6CellServiceProvider { /** * 创建图形实例 * - * @author chitanda - * @date 2023-11-21 18:11:20 * @param {X6CellDataProvider} data + * @param {string} [designMode] * @return {*} {Cell.Metadata} + * @memberof X6CellServiceProvider */ - createCell(data: X6CellDataProvider): Cell.Metadata; + createCell(data: X6CellDataProvider, designMode?: string): Cell.Metadata; /** * 初始化 diff --git a/packages/antv-x6-design/src/interface/provider/x6-link.service.provider.ts b/packages/antv-x6-design/src/interface/provider/x6-link.service.provider.ts index 9b2c697a3cf4ce5fea950adb9f76832bba3c12a4..e73485a736806a0ff1c99ec9299f201e2c3ff73d 100644 --- a/packages/antv-x6-design/src/interface/provider/x6-link.service.provider.ts +++ b/packages/antv-x6-design/src/interface/provider/x6-link.service.provider.ts @@ -19,12 +19,15 @@ export interface X6LinkServiceProvider /** * 创建连线实例 * - * @author chitanda - * @date 2023-11-21 17:11:02 * @param {X6LinkDataProvider} data + * @param {string} [designMode] * @return {*} {Edge.Metadata} + * @memberof X6LinkServiceProvider */ - createCell(data: X6LinkDataProvider): Edge.Metadata; + createCell( + data: X6LinkDataProvider, + designMode?: string, + ): Edge.Metadata; /** * 自定义渲染label标签 diff --git a/packages/antv-x6-design/src/plugins/logic-design/cell.ts b/packages/antv-x6-design/src/plugins/logic-design/cell.ts index 6b9800ce254f860544107ccee865b790d3c082c8..db2c0b7a27b1c48c3f66ed42ceee81cab5c93a84 100644 --- a/packages/antv-x6-design/src/plugins/logic-design/cell.ts +++ b/packages/antv-x6-design/src/plugins/logic-design/cell.ts @@ -153,7 +153,10 @@ export abstract class CellProviderImpl data: IDataEntity, ): X6CellDataProvider; - abstract createCell(data: X6CellDataProvider): Cell.Metadata; + abstract createCell( + data: X6CellDataProvider, + shape?: string, + ): Cell.Metadata; /** * 获取当前节点对应的应用实体模型 diff --git a/packages/antv-x6-design/src/plugins/logic-design/custom-edge/index.ts b/packages/antv-x6-design/src/plugins/logic-design/custom-edge/index.ts index eafd08d56201a2dea689f96b0254e16d83d2d42b..1bda04b342456299fa03b22070b62f06eb0e423d 100644 --- a/packages/antv-x6-design/src/plugins/logic-design/custom-edge/index.ts +++ b/packages/antv-x6-design/src/plugins/logic-design/custom-edge/index.ts @@ -1,5 +1,6 @@ import { Graph } from '@antv/x6'; import { LogicLink } from './logic-link'; +import { LogicLink2 } from './logic-link2'; /** * 安装自定义连线 @@ -10,6 +11,7 @@ import { LogicLink } from './logic-link'; */ export function installCustomEdge(): void { Graph.registerEdge('logic-link', LogicLink, true); + Graph.registerEdge('logic-link2', LogicLink2, true); Graph.registerEdgeTool( 'logic-link-shift-button', { diff --git a/packages/antv-x6-design/src/plugins/logic-design/custom-edge/logic-link2.ts b/packages/antv-x6-design/src/plugins/logic-design/custom-edge/logic-link2.ts new file mode 100644 index 0000000000000000000000000000000000000000..6baf0c55a0e6b4ed2f5c563518f1e48a5c31daa9 --- /dev/null +++ b/packages/antv-x6-design/src/plugins/logic-design/custom-edge/logic-link2.ts @@ -0,0 +1,360 @@ +import { Shape, Edge, Graph } from '@antv/x6'; +import { IDataEntity } from '@ibiz-template/runtime'; +import { Namespace } from '@ibiz-template/core'; +import { createApp } from 'vue'; +import { X6LinkDataProvider } from '../../../interface'; +import { LogicDesignLabel } from '../components'; +import { + loopIcon, + shiftButton, + sourceArrowhead, + targetArrowhead, + vertices, +} from './tools'; + +/** + * 逻辑连线 + * - 设计模式(DESIGNMODE)为样式2(STYLE2)时的连线 + * @export + * @class LogicLink2 + * @extends {Shape.Edge} + */ +export class LogicLink2 extends Shape.Edge { + protected ns: Namespace = new Namespace('logic-link'); + + protected shiftButtonStatus: boolean = false; + + protected logicType: string = ''; + + protected g?: Graph; + + protected get isSelected(): boolean { + const g = this.model?.graph; + if (g) { + return g.isSelected(this); + } + return false; + } + + protected getShiftButtonClassName(): { + svg_shift_wrapper: string; + svg_shift1: string; + svg_shift2: string; + } { + const className: { + svg_shift_wrapper: string; + svg_shift1: string; + svg_shift2: string; + [key: string]: string; + } = { + svg_shift_wrapper: this.ns.b('svg_shift_wrapper'), + svg_shift1: this.ns.b('svg_shift1'), + svg_shift2: this.ns.b('svg_shift2'), + }; + const s = this.getSourceNode()?.position(); + const t = this.getTargetNode()?.position(); + if (s && t) { + if (s.x < t.x) { + if (s.y > t.y) { + Object.keys(className).forEach(key => { + className[key] += '_lb'; + }); + } else { + Object.keys(className).forEach(key => { + className[key] += '_lt'; + }); + } + } else if (s.y > t.y) { + Object.keys(className).forEach(key => { + className[key] += '_rb'; + }); + } else { + Object.keys(className).forEach(key => { + className[key] += '_rt'; + }); + } + } else { + Object.keys(className).forEach(key => { + className[key] += '_lb'; + }); + } + return className; + } + + protected onShiftButtonClick(): void { + this.shiftButtonStatus = !this.shiftButtonStatus; + this.removeTool('logic-link-shift-button'); + this.removeTool('vertices'); + this.addTools( + shiftButton( + this.shiftButtonStatus, + this.getShiftButtonClassName(), + this.onShiftButtonClick, + ), + ); + if (this.shiftButtonStatus) { + this.removeTool('source-arrowhead'); + this.removeTool('target-arrowhead'); + } + } + + protected getLogicDesignLabel( + dataProvider: X6LinkDataProvider, + ): { el: HTMLElement; width: number; height: number } { + const content = document.createElement('div'); + let isOpenLoopPostProcess = false; + let sourceNodeOutgoingEdgeLength = 0; + const sourceNode = this.getSourceNode(); + if (sourceNode) { + const sourceNodeDataProvider = sourceNode.getData(); + if (sourceNodeDataProvider) { + const sourceNodeData = sourceNodeDataProvider.data; + isOpenLoopPostProcess = sourceNodeData?.paralleloutput || false; + } + const g = sourceNode.model?.graph; + if (g) { + const outgoingEdges = g.getOutgoingEdges(sourceNode); + if (Array.isArray(outgoingEdges)) { + sourceNodeOutgoingEdgeLength = outgoingEdges.length; + } + } + } + const app = createApp(LogicDesignLabel, { + dataProvider, + isOpenLoopPostProcess, + sourceNodeOutgoingEdgeLength, + logicType: this.logicType, + }); + app.mount(content); + content.style.position = 'absolute'; + document.body.appendChild(content); + const width = content.offsetWidth; + const height = content.offsetHeight; + content.style.position = ''; + document.body.removeChild(content); + return { + el: content, + width, + height, + }; + } + + protected getLogicDesignLabelPosition(width: number): Edge.Label['position'] { + const labelVertices = this.getVertices(); + const vertex = labelVertices?.[0]; + const sourcePoint = this.getSourcePoint(); + const targetPoint = + vertex && vertex.x != null && vertex.y != null + ? vertex + : this.getTargetPoint(); + let angle = + Math.atan2(targetPoint.y - sourcePoint.y, targetPoint.x - sourcePoint.x) * + (180 / Math.PI); + let distance = 20; + if (angle < -90 || angle > 90) { + angle += 180; + distance += width; + } + return { + distance, + angle, + }; + } + + protected setLogicLinkLabel(): void { + const dataProvider = this.getData(); + if (!dataProvider) { + return; + } + const logicDesignLabel = this.getLogicDesignLabel(dataProvider); + const position = this.getLogicDesignLabelPosition(logicDesignLabel.width); + this.setLabelAt(0, { + position, + }); + this.setLabelAt(1, dataProvider.label); + } + + protected setLinkMode(): void { + const dataProvider = this.getData(); + if (!dataProvider) { + return; + } + const data = dataProvider.data; + if (data && typeof data === 'object') { + let color = '#999999'; + const linkType: number = data.defaultlink; + this.removeTool('logic-link-loop-icon'); + if (linkType === 1) { + color = '#52d456'; + } else if (linkType === 9) { + color = '#e43b3b'; + } else if (linkType === 10) { + this.addTools(loopIcon()); + } + if (this.isSelected) { + return; + } + this.setAttrs({ + line: { + stroke: color, + }, + }); + } + } + + constructor(metadata: Edge.Metadata = {}) { + super({ + markup: [ + { + tagName: 'path', + selector: 'wrap', + attrs: { + fill: 'none', + cursor: 'pointer', + stroke: 'transparent', + }, + }, + { + tagName: 'path', + selector: 'line', + attrs: { + fill: 'none', + cursor: 'pointer', + stroke: 'transparent', + }, + }, + ], + attrs: { + arrow: { + d: 'M 0 -6 8 0 0 6 z', + fill: '#1890ff', + stroke: '#1890ff', + }, + background: { + color: 'rgba(0, 255, 0, 0.3)', + }, + wrap: { + connection: true, + strokeWidth: 20, + strokeLinejoin: 'round', + }, + line: { + connection: true, + strokeLinejoin: 'round', + targetMarker: 'classic', + stroke: '#999999', + strokeWidth: 1, + }, + }, + connector: { + name: 'jumpover', + }, + router: { + name: 'normal', + args: { + startDirections: ['top', 'right', 'bottom', 'left'], + endDirections: ['top', 'right', 'bottom', 'left'], + }, + }, + label: metadata.label, + ...metadata, + }); + this.logicType = metadata.logicType || ''; + this.setLinkMode(); + this.onShiftButtonClick = this.onShiftButtonClick.bind(this); + this.on('update', (dataProvider: X6LinkDataProvider): void => { + this.replaceData(dataProvider, { silent: true }); + this.setLogicLinkLabel(); + this.setLinkMode(); + }); + this.on('added', () => { + this.g = this.model?.graph; + const sourceNode = this.getSourceNode(); + if (sourceNode) { + const g = sourceNode.model?.graph; + if (g) { + const outgoingEdges = g.getOutgoingEdges(sourceNode); + if (Array.isArray(outgoingEdges)) { + outgoingEdges.forEach(edge => { + if (edge.getData()) { + edge.trigger('update', edge.getData()); + } + }); + } + } + } + }); + this.on('selected', (): void => { + this.setAttrs({ + line: { + stroke: '#feb663', + strokeWidth: 2, + strokeDasharray: 5, + style: { + animation: 'logic-link-ant-line 30s infinite linear', + }, + }, + }); + this.shiftButtonStatus = false; + if (!this.hasTool('source-arrowhead')) { + this.addTools(sourceArrowhead()); + } + if (!this.hasTool('target-arrowhead')) { + this.addTools(targetArrowhead()); + } + }); + this.on('unselected', (): void => { + this.setAttrs({ + line: { + stroke: '#999999', + strokeWidth: 1, + strokeDasharray: 0, + style: { + animation: 'none', + }, + }, + }); + this.setLinkMode(); + this.shiftButtonStatus = false; + this.removeTool('source-arrowhead'); + this.removeTool('target-arrowhead'); + this.removeTool('vertices'); + }); + this.on('mouseenter', (): void => { + if (!this.hasTool('source-arrowhead') && !this.shiftButtonStatus) { + this.addTools(sourceArrowhead()); + } + if (!this.hasTool('target-arrowhead') && !this.shiftButtonStatus) { + this.addTools(targetArrowhead()); + } + if (!this.hasTool('vertices') && this.shiftButtonStatus) { + this.addTools(vertices()); + } + }); + this.on('mouseleave', (): void => { + this.removeTool('source-arrowhead'); + this.removeTool('target-arrowhead'); + this.removeTool('vertices'); + }); + this.on('removed', (args): void => { + const { options } = args; + if (options.g || this.g) { + const g = (options.g || this.g) as Graph; + const sourceNodeId = this.getSourceCellId(); + if (sourceNodeId) { + const sourceNode = g.getCellById(sourceNodeId); + if (sourceNode) { + const outgoingEdges = g.getOutgoingEdges(sourceNode); + if (Array.isArray(outgoingEdges)) { + outgoingEdges.forEach(edge => { + if (edge.getData()) { + edge.trigger('update', edge.getData()); + } + }); + } + } + } + } + }); + } +} diff --git a/packages/antv-x6-design/src/plugins/logic-design/link.ts b/packages/antv-x6-design/src/plugins/logic-design/link.ts index 9f2c501fa7b85a823e5be64ca32baa28d5f5f4b9..97d7bd78153abee9bc8c1090d22e2b6cb545d61e 100644 --- a/packages/antv-x6-design/src/plugins/logic-design/link.ts +++ b/packages/antv-x6-design/src/plugins/logic-design/link.ts @@ -144,9 +144,12 @@ export class LinkProviderImpl throw new Error('Method not implemented.'); } - createCell(data: X6LinkDataProvider): Edge.Metadata { + createCell( + data: X6LinkDataProvider, + designMode: string, + ): Edge.Metadata { return { - shape: 'logic-link', + shape: `logic-${designMode === 'STYLE2' ? 'link2' : 'link'}`, id: data.id, source: data.source, target: data.target, diff --git a/packages/antv-x6-design/src/plugins/work-flow-design/cell.ts b/packages/antv-x6-design/src/plugins/work-flow-design/cell.ts index f16b60981bf6e318091da7cd0a55068c9890202a..81543246943a333a1d148b8131645e6ec095c5c1 100644 --- a/packages/antv-x6-design/src/plugins/work-flow-design/cell.ts +++ b/packages/antv-x6-design/src/plugins/work-flow-design/cell.ts @@ -153,7 +153,10 @@ export abstract class CellProviderImpl data: IDataEntity, ): X6CellDataProvider; - abstract createCell(data: X6CellDataProvider): Cell.Metadata; + abstract createCell( + data: X6CellDataProvider, + designMode?: string, + ): Cell.Metadata; /** * 获取当前节点对应的应用实体模型 diff --git a/packages/antv-x6-design/src/views/x6-design-view/x6-design-view.controller.ts b/packages/antv-x6-design/src/views/x6-design-view/x6-design-view.controller.ts index 84d222b5e584c30a36211440134429133c16e307..08caa1785d7f99d4edb1a93d855b94e9e8b860fb 100644 --- a/packages/antv-x6-design/src/views/x6-design-view/x6-design-view.controller.ts +++ b/packages/antv-x6-design/src/views/x6-design-view/x6-design-view.controller.ts @@ -1,4 +1,4 @@ -import { ViewController } from '@ibiz-template/runtime'; +import { ViewController, getPFPlugin } from '@ibiz-template/runtime'; import { IAppDECustomView } from '@ibiz/model-core'; import { X6DesignViewEngine } from './x6-design-view.engine'; import { X6DesignViewState } from './interface/x6-design-view.state'; @@ -19,6 +19,27 @@ export class X6DesignViewController extends ViewController< */ readonly select = new SelectState(); + /** + * 生命周期-创建完成 + * + * @protected + * @return {*} {Promise} + * @memberof X6DesignViewController + */ + protected async onCreated(): Promise { + await super.onCreated(); + const { sysPFPluginId, appId } = this.model; + const plugin = getPFPlugin(sysPFPluginId!, appId); + if (plugin && plugin.pluginParams) { + const params = plugin.pluginParams; + Object.keys(params).forEach(key => { + if (params[key] && key !== 'appId') { + this.context[key.toLowerCase()] = params[key]; + } + }); + } + } + protected initEngines(): void { this.engines.push(new X6DesignViewEngine(this)); } diff --git a/packages/antv-x6-design/src/views/x6-design-view/x6-design-view.engine.ts b/packages/antv-x6-design/src/views/x6-design-view/x6-design-view.engine.ts index c07f74250e57364dad4170e4867dff3fec61461b..55f51d62752eac48288541b380461b946d8e2693 100644 --- a/packages/antv-x6-design/src/views/x6-design-view/x6-design-view.engine.ts +++ b/packages/antv-x6-design/src/views/x6-design-view/x6-design-view.engine.ts @@ -1,9 +1,11 @@ +/* eslint-disable no-unused-expressions */ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable no-restricted-syntax */ import { DEMainViewEngine, EditFormService, IDataEntity, + OpenAppViewCommand, SysUIActionTag, ViewController, ViewMode, @@ -287,7 +289,9 @@ export class X6DesignViewEngine extends DEMainViewEngine { protected onSelect(data: X6CellDataProvider | undefined | null): void { if (data) { - this.onActive(data); + this.view.context.designmode === 'STYLE2' + ? this.onActiveByStyle2(data) + : this.onActive(data); } } @@ -490,4 +494,62 @@ export class X6DesignViewEngine extends DEMainViewEngine { } } } + + /** + * 设置激活数据(样式2) + * + * @protected + * @param {X6CellDataProvider} data + * @return {*} {void} + * @memberof X6DesignViewEngine + */ + protected onActiveByStyle2(data: X6CellDataProvider): void { + const { forceRefresh } = data; + const refs = this.view.model.appViewRefs; + if (refs) { + const type = data.type ? data.type.toUpperCase() : null; + const ref = refs.find( + item => + item.name === + `EDITDATA:${data.data.srfdecodename.toUpperCase()}${ + type ? `:${type}` : '' + }`, + ); + if (ref) { + const context = this.view.context.clone(); + context[data.data.srfdecodename.toLowerCase()] = data.id; + if ( + ref.openMode && + ![ + 'INDEXVIEWTAB', + 'INDEXVIEWTAB_POPUP', + 'INDEXVIEWTAB_POPUPMODAL', + ].includes(ref.openMode) + ) { + ibiz.commands.execute( + OpenAppViewCommand.TAG, + ref.refAppViewId, + context, + {}, + { + openMode: ref.openMode, + }, + ); + return; + } + this.navPos.openView({ + key: forceRefresh ? createUUID() : data.id, + viewId: ref.refAppViewId, + context, + }); + } else { + throw new RuntimeModelError( + this.view.model, + data.type + ? `未匹配到对应[${data.type}]的属性编辑视图` + : '当前数据未指定类型,无法匹配到属性编辑视图', + ); + } + } + } }