diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..d70a5c3b4 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "MaxKB", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/ui/package.json b/ui/package.json index 4bc39ccc8..b70010026 100644 --- a/ui/package.json +++ b/ui/package.json @@ -14,6 +14,7 @@ }, "dependencies": { "@ctrl/tinycolor": "^4.1.0", + "@logicflow/core": "^1.2.27", "@vueuse/core": "^10.9.0", "axios": "^0.28.0", "cropperjs": "^1.6.2", diff --git a/ui/src/components/work-flow/common/app-node/index.ts b/ui/src/components/work-flow/common/app-node/index.ts new file mode 100644 index 000000000..8e2ae4af2 --- /dev/null +++ b/ui/src/components/work-flow/common/app-node/index.ts @@ -0,0 +1,165 @@ +import Components from '@/components' +import ElementPlus from 'element-plus' +import { HtmlNode, HtmlNodeModel } from '@logicflow/core' +import { createApp, h } from 'vue' +import directives from '@/directives' + +class AppNode extends HtmlNode { + isMounted + r + app + + constructor(props: any, VueNode: any) { + super(props) + this.isMounted = false + + this.r = h(VueNode, { + properties: props.model.properties, + nodeModel: props.model + }) + + this.app = createApp({ + render: () => this.r + }) + this.app.use(ElementPlus) + this.app.use(Components) + this.app.use(directives) + } + + setHtml(rootEl: HTMLElement) { + if (!this.isMounted) { + this.isMounted = true + const node = document.createElement('div') + rootEl.appendChild(node) + this.app.mount(node) + } else { + if (this.r && this.r.component) { + this.r.component.props.properties = this.props.model.getProperties() + } + } + } +} + +class AppNodeModel extends HtmlNodeModel { + /** + * 给model自定义添加字段方法 + */ + addField(item: any) { + this.properties.fields.unshift(item) + this.setAttributes() + // 为了保持节点顶部位置不变,在节点变化后,对节点进行一个位移,位移距离为添加高度的一半。 + this.move(0, 24 / 2) + // 更新节点连接边的path + this.incoming.edges.forEach((egde: any) => { + // 调用自定义的更新方案 + egde.updatePathByAnchor() + }) + this.outgoing.edges.forEach((edge: any) => { + // 调用自定义的更新方案 + edge.updatePathByAnchor() + }) + } + getOutlineStyle() { + const style = super.getOutlineStyle() + style.stroke = 'none' + if (style.hover) { + style.hover.stroke = 'none' + } + return style + } + // 如果不用修改锚地形状,可以重写颜色相关样式 + getAnchorStyle(anchorInfo: any) { + const style = super.getAnchorStyle(anchorInfo) + if (anchorInfo.type === 'left') { + style.fill = 'red' + style.hover.fill = 'transparent' + style.hover.stroke = 'transpanrent' + style.className = 'lf-hide-default' + } else { + style.fill = 'green' + } + return style + } + setHeight(height: number, inputContainerHeight: number, outputContainerHeight: number) { + this.height = height + inputContainerHeight + outputContainerHeight + 100 + this.baseHeight = height + this.inputContainerHeight = inputContainerHeight + this.outputContainerHeight = outputContainerHeight + + this.outgoing.edges.forEach((edge: any) => { + // 调用自定义的更新方案 + edge.updatePathByAnchor() + }) + this.incoming.edges.forEach((edge: any) => { + // 调用自定义的更新方案 + edge.updatePathByAnchor() + }) + } + setAttributes() { + this.width = 500 + + const circleOnlyAsTarget = { + message: '只允许从右边的锚点连出', + validate: (sourceNode: any, targetNode: any, sourceAnchor: any) => { + return sourceAnchor.type === 'right' + } + } + this.sourceRules.push(circleOnlyAsTarget) + this.targetRules.push({ + message: '只允许连接左边的锚点', + validate: (sourceNode: any, targetNode: any, sourceAnchor: any, targetAnchor: any) => { + return targetAnchor.type === 'left' + } + }) + } + getDefaultAnchor() { + const { + id, + x, + y, + width, + height, + properties: { input, output } + } = this + + if (this.baseHeight === undefined) { + this.baseHeight = 0 + } + if (this.inputContainerHeight === undefined) { + this.inputContainerHeight = 0 + } + if (this.height === undefined) { + this.height = 200 + } + if (this.outputContainerHeight === undefined) { + this.outputContainerHeight = 0 + } + + const anchors: any = [] + if (input) { + input.forEach((feild: any, index: any) => { + anchors.push({ + x: x - width / 2 + 10, + y: y - height / 2 + this.baseHeight + 35 + index * 24, + id: `${id}_${feild.key}_left`, + edgeAddable: false, + type: 'left' + }) + }) + } + if (output) { + output.forEach((feild: any, index: any) => { + anchors.push({ + x: x + width / 2 - 10, + y: y - height / 2 + this.baseHeight + this.inputContainerHeight + 30 + index * 24, + id: `${id}_${feild.key}_right`, + type: 'right' + }) + }) + } + + return anchors + } +} + +export { AppNodeModel, AppNode } diff --git a/ui/src/components/work-flow/common/edge/index.ts b/ui/src/components/work-flow/common/edge/index.ts new file mode 100644 index 000000000..df9c55089 --- /dev/null +++ b/ui/src/components/work-flow/common/edge/index.ts @@ -0,0 +1,62 @@ +import { BezierEdge, BezierEdgeModel } from '@logicflow/core' + +class CustomEdge2 extends BezierEdge {} + +class CustomEdgeModel2 extends BezierEdgeModel { + getEdgeStyle() { + const style = super.getEdgeStyle() + + // svg属性 + style.strokeWidth = 1 + style.stroke = '#ababac' + return style + } + /** + * 重写此方法,使保存数据是能带上锚点数据。 + */ + getData() { + const data: any = super.getData() + if (data) { + data.sourceAnchorId = this.sourceAnchorId + data.targetAnchorId = this.targetAnchorId + } + return data + } + /** + * 给边自定义方案,使其支持基于锚点的位置更新边的路径 + */ + updatePathByAnchor() { + // TODO + const sourceNodeModel = this.graphModel.getNodeModelById(this.sourceNodeId) + const sourceAnchor = sourceNodeModel + .getDefaultAnchor() + .find((anchor: any) => anchor.id === this.sourceAnchorId) + + const targetNodeModel = this.graphModel.getNodeModelById(this.targetNodeId) + const targetAnchor = targetNodeModel + .getDefaultAnchor() + .find((anchor: any) => anchor.id === this.targetAnchorId) + if (sourceAnchor && targetAnchor) { + const startPoint = { + x: sourceAnchor.x, + y: sourceAnchor.y + } + this.updateStartPoint(startPoint) + const endPoint = { + x: targetAnchor.x, + y: targetAnchor.y + } + this.updateEndPoint(endPoint) + } + + // 这里需要将原有的pointsList设置为空,才能触发bezier的自动计算control点。 + this.pointsList = [] + this.initPoints() + } +} + +export default { + type: 'app-edge', + view: CustomEdge2, + model: CustomEdgeModel2 +} diff --git a/ui/src/components/work-flow/common/menu/data.ts b/ui/src/components/work-flow/common/menu/data.ts new file mode 100644 index 000000000..bf19a69d9 --- /dev/null +++ b/ui/src/components/work-flow/common/menu/data.ts @@ -0,0 +1,24 @@ +const shapeList = [ + { + type: 'ai-chat-node', + text: '', + label: 'AI对话', + icon: 'data:image/png;base64,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', + properties: { + height: 200, + stepName: 'AI对话', + input: [ + { + key: '输入' + } + ], + output: [ + { + key: '输出' + } + ] + } + } +] + +export { shapeList } diff --git a/ui/src/components/work-flow/common/menu/index.ts b/ui/src/components/work-flow/common/menu/index.ts new file mode 100644 index 000000000..a9076d115 --- /dev/null +++ b/ui/src/components/work-flow/common/menu/index.ts @@ -0,0 +1,115 @@ +import LogicFlow from '@logicflow/core' +import { shapeList } from './data' +type ShapeItem = { + type?: string + text?: string + icon?: string + label?: string + className?: string + disabled?: boolean + properties?: Record + callback?: (lf: LogicFlow, container: HTMLElement) => void +} + +class AppMenu { + lf: LogicFlow + shapeList: ShapeItem[] + panelEl?: HTMLDivElement + static pluginName = 'AppMenu' + domContainer?: HTMLElement + constructor({ lf }: { lf: LogicFlow }) { + this.lf = lf + this.lf.setPatternItems = (shapeList: Array) => { + this.setPatternItems(shapeList) + } + this.shapeList = shapeList + this.panelEl = undefined + this.domContainer = undefined + } + render(lf: LogicFlow, domContainer: HTMLElement) { + this.destroy() + if (!this.shapeList || this.shapeList.length === 0) { + // 首次render后失败后,后续调用setPatternItems支持渲染 + this.domContainer = domContainer + return + } + this.panelEl = document.createElement('div') + this.panelEl.className = 'lf-dndpanel' + this.shapeList.forEach((shapeItem) => { + this.panelEl?.appendChild(this.createDndItem(shapeItem)) + }) + domContainer.appendChild(this.panelEl) + this.domContainer = domContainer + } + destroy() { + if (this.domContainer && this.panelEl && this.domContainer.contains(this.panelEl)) { + this.domContainer.removeChild(this.panelEl) + } + } + setPatternItems(shapeList: Array) { + this.shapeList = shapeList + // 支持渲染后重新设置拖拽面板 + if (this.domContainer) { + this.render(this.lf, this.domContainer) + } + } + private createDndItem(shapeItem: ShapeItem): HTMLElement { + const el = document.createElement('div') + el.className = shapeItem.className ? `lf-dnd-item ${shapeItem.className}` : 'lf-dnd-item' + const shape = document.createElement('div') + shape.className = 'lf-dnd-shape' + + if (shapeItem.icon) { + shape.style.backgroundImage = `url(${shapeItem.icon})` + } + el.appendChild(shape) + if (shapeItem.label) { + const text = document.createElement('div') + text.innerText = shapeItem.label + text.className = 'lf-dnd-text' + el.appendChild(text) + } + if (shapeItem.disabled) { + el.classList.add('disabled') + // 保留callback的执行,可用于界面提示当前shapeItem的禁用状态 + el.onmousedown = () => { + if (shapeItem.callback && this.domContainer) { + shapeItem.callback(this.lf, this.domContainer) + } + } + return el + } + el.onmousedown = () => { + if (shapeItem.type) { + this.lf.dnd.startDrag({ + type: shapeItem.type, + properties: shapeItem.properties + }) + } + if (shapeItem.callback && this.domContainer) { + shapeItem.callback(this.lf, this.domContainer) + } + } + el.ondblclick = (e) => { + this.lf.graphModel.eventCenter.emit('dnd:panel-dbclick', { + e, + data: shapeItem + }) + } + el.onclick = (e) => { + this.lf.graphModel.eventCenter.emit('dnd:panel-click', { + e, + data: shapeItem + }) + } + el.oncontextmenu = (e) => { + this.lf.graphModel.eventCenter.emit('dnd:panel-contextmenu', { + e, + data: shapeItem + }) + } + return el + } +} + +export { AppMenu } diff --git a/ui/src/components/work-flow/common/node-container/index.vue b/ui/src/components/work-flow/common/node-container/index.vue new file mode 100644 index 000000000..102ef4c60 --- /dev/null +++ b/ui/src/components/work-flow/common/node-container/index.vue @@ -0,0 +1,170 @@ + + + diff --git a/ui/src/components/work-flow/index.vue b/ui/src/components/work-flow/index.vue new file mode 100644 index 000000000..a1082f564 --- /dev/null +++ b/ui/src/components/work-flow/index.vue @@ -0,0 +1,153 @@ + + + diff --git a/ui/src/components/work-flow/nodes/ai-chat-node/index.ts b/ui/src/components/work-flow/nodes/ai-chat-node/index.ts new file mode 100644 index 000000000..04581c63e --- /dev/null +++ b/ui/src/components/work-flow/nodes/ai-chat-node/index.ts @@ -0,0 +1,12 @@ +import ChatNodeVue from '@/flow/nodes/ai-chat-node/index.vue' +import { AppNode, AppNodeModel } from '@/flow/common/app-node/index' +class ChatNode extends AppNode { + constructor(props: any) { + super(props, ChatNodeVue) + } +} +export default { + type: 'ai-chat-node', + model: AppNodeModel, + view: ChatNode +} diff --git a/ui/src/components/work-flow/nodes/ai-chat-node/index.vue b/ui/src/components/work-flow/nodes/ai-chat-node/index.vue new file mode 100644 index 000000000..2698b3093 --- /dev/null +++ b/ui/src/components/work-flow/nodes/ai-chat-node/index.vue @@ -0,0 +1,72 @@ + + + diff --git a/ui/src/components/work-flow/nodes/search-dataset-node/index.ts b/ui/src/components/work-flow/nodes/search-dataset-node/index.ts new file mode 100644 index 000000000..4a8539034 --- /dev/null +++ b/ui/src/components/work-flow/nodes/search-dataset-node/index.ts @@ -0,0 +1,12 @@ +import SearchDatasetVue from './index.vue' +import { AppNode, AppNodeModel } from '@/flow/common/app-node/index' +class SearchDatasetNode extends AppNode { + constructor(props: any) { + super(props, SearchDatasetVue) + } +} +export default { + type: 'search-dataset-node', + model: AppNodeModel, + view: SearchDatasetNode +} diff --git a/ui/src/components/work-flow/nodes/search-dataset-node/index.vue b/ui/src/components/work-flow/nodes/search-dataset-node/index.vue new file mode 100644 index 000000000..786cfe539 --- /dev/null +++ b/ui/src/components/work-flow/nodes/search-dataset-node/index.vue @@ -0,0 +1,51 @@ + + +