This commit is contained in:
lzp
2026-03-04 15:06:22 +08:00
parent 9817e5e0db
commit cee42d8b78
28 changed files with 340 additions and 84 deletions

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

Before

Width:  |  Height:  |  Size: 481 B

After

Width:  |  Height:  |  Size: 481 B

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -1,29 +1,48 @@
<template>
<div class="header-tools">
<span class="icon" @click="emit('mouse')"><svg-icon name="c-mouse" size="16" /></span>
<span class="icon" @click="emit('hand')"><svg-icon name="c-hand" size="18" /></span>
<span class="icon" @click="emit('t')"><svg-icon name="c-t" size="18" /></span>
<span class="line"></span>
<span class="icon" @click="emit('undo')"><svg-icon name="c-undo" size="18" /></span>
<span class="icon" @click="emit('redo')"><svg-icon name="c-redo" size="18" /></span>
<template v-for="(v, i) in tools" :key="i">
<span class="line" v-if="v.type === 'line'"></span>
<span
v-else
class="icon"
@click="onClickTool(v.name)"
:class="{ active: v.name === tool }"
>
<svg-icon :name="v.icon" :size="v.iconSize" />
</span>
</template>
<button class="export" @click="emit('export')">
<span class="icon"><svg-icon name="export" size="11" /></span>
<span class="text">Export</span>
</button>
<button class="import" @click="emit('import')">
<span class="icon"><svg-icon name="import" size="11" /></span>
<span class="text">Import</span>
</button>
</div>
</template>
<script setup lang="ts">
import { ref, watch } from 'vue'
import { ref, inject, computed } from 'vue'
import { TOOLS } from '../manager/ToolManager'
const props = defineProps({
zoom: { default: 1, type: Number },
step: { default: 0.1, type: Number }
})
const emit = defineEmits(['mouse', 'hand', 't', 'undo', 'redo', 'export', 'import'])
const emit = defineEmits(['export', 'import'])
const stateManager = inject('stateManager') as any
const toolManager = inject('toolManager') as any
const tool = computed(() => stateManager.tool.value)
const tools = ref([
{ name: TOOLS.SELECT, icon: 'c-select', iconSize: 16 },
{ name: TOOLS.MOVE, icon: 'c-move', iconSize: 18 },
{ name: TOOLS.TEXT, icon: 'c-text', iconSize: 18 },
{ type: 'line' },
{ name: TOOLS.UNDO, icon: 'c-undo', iconSize: 18 },
{ name: TOOLS.REDO, icon: 'c-redo', iconSize: 18 }
])
const onClickTool = (tool: any) => {
toolManager.setTool(tool)
}
</script>
<style lang="less" scoped>
@@ -60,6 +79,7 @@
height: 3rem;
--svg-icon-color: #000;
border-radius: 0.4rem;
&.active,
&:hover {
background-color: #dfdfdf;
}

View File

@@ -1,7 +1,7 @@
<template>
<div class="node" :class="{ center: posCenter }">
<div class="node" :class="{ center: posCenter, mask: mask }">
<Handle
v-for="handle in handles[type]"
v-for="handle in handles[type] || []"
:key="handle.id"
:type="handle.type"
:id="handle.id"
@@ -14,6 +14,7 @@
<div class="add" @mousedown.stop v-if="isAdd" @click="onAdd">
<svg-icon name="add" size="14" size-unit="px" />
</div>
<div class="mask" v-show="mask"></div>
</div>
</template>
<script lang="ts" setup>
@@ -27,7 +28,8 @@
{ id: 'Left', type: 'target', position: Position.Left },
{ id: 'Right', type: 'source', position: Position.Right }
],
[NODE_TYPE.OUTPUT]: [{ id: 'Left', type: 'target', position: Position.Left }]
[NODE_TYPE.OUTPUT]: [{ id: 'Left', type: 'target', position: Position.Left }],
[NODE_TYPE.ALONE]: []
})
const props = defineProps({
type: {
@@ -41,6 +43,10 @@
stateManager: {
type: Object,
required: true
},
mask: {
type: Boolean,
default: false
}
})
const nodes = computed(() => props.stateManager.nodes.value)
@@ -68,6 +74,10 @@
.node {
position: relative;
--top: 50px;
&.mask *,
&.mask {
pointer-events: none;
}
.vue-flow__handle {
width: 12px;
height: 12px;
@@ -101,5 +111,13 @@
&.center {
--top: 50%;
}
> .mask {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 100;
}
}
</style>

View File

@@ -59,11 +59,11 @@
<script setup lang="ts">
import { reactive, onMounted } from 'vue'
import myTextarea from '../tools/my-textarea.vue'
import uploadFile from '../tools/upload-file.vue'
import myInput from '../tools/my-input.vue'
import offsetTool from '../tools/offset-tool.vue'
import slider from '../tools/slider.vue'
import myTextarea from '../../tools/my-textarea.vue'
import uploadFile from '../../tools/upload-file.vue'
import myInput from '../../tools/my-input.vue'
import offsetTool from '../../tools/offset-tool.vue'
import slider from '../../tools/slider.vue'
const data = reactive({
prompt: '',

View File

@@ -12,7 +12,7 @@
<script setup lang="ts">
import { ref, inject, computed } from 'vue'
import { NODE_DATATYPE, NODE_DATATIER } from '../../tools/index.d'
import { NODE_DATATYPE, NODE_DATATIER } from '../../../tools/index.d'
const nodeManager = inject('nodeManager') as any
const stateManager = inject('stateManager') as any
const props = defineProps({
@@ -56,7 +56,13 @@
if (!id) return
stateManager.deleteNode(id)
const superiorID = props.node.data.superiorID
nodeManager.createCardNode({ data: { type: v.type, superiorID } })
nodeManager.createCardNode({
data: {
tier: v.tier,
type: v.type,
superiorID
}
})
}
defineExpose({})

View File

@@ -23,7 +23,7 @@
</template>
<script setup lang="ts">
import { NODE_DATATYPE, NODE_DATATIER } from '../../tools/index.d'
import { NODE_DATATYPE, NODE_DATATIER } from '../../../tools/index.d'
import { computed, ref, useAttrs, onMounted, inject } from 'vue'
import CardsSelect from './cards-select.vue'
import ToRealStyle from './to-real-style.vue'
@@ -122,7 +122,7 @@
})
} else {
subordNode.data.data.url =
'https://s3-alpha-sig.figma.com/img/ea2f/590e/9638f62a2fc91e31f33db0022db1642c?Expires=1773014400&Key-Pair-Id=APKAQ4GOSFWCW27IBOMQ&Signature=M0B8oJJOk~dGG0aZAqOIocAp7T0LFdJ9FYmCrEZVTCRzYxM6SJRNtYMTX-rTO3Z~s14QINh~o-S41XiZnBv-0zcKjuWot~VVaNHfd0~1LesfNe2KwvCinT~72btFut1pheLnKE-wWCX5ewtonxU77bnw386YPMTqv7DBZzksf2udsJA7NmOYD6~TUG3Q2dWSt~zPH~lkaidscPqpCnCbqzljCEi4RiHY4U3A45l5XypcX2umqn1UaYUFCTqV9471J4qdB6Dg2pcKocdp-7-3s1De6Q~2SmBOrSgDQ~KEADCB2lhKfhxgWmy0lwMvhTd4l90ygVZDWZRABgjHNrGUvg__'
'https://s3-alpha-sig.figma.com/img/8ce2/f1a4/12b93da90e5f17109e7430f14837fd14?Expires=1773619200&Key-Pair-Id=APKAQ4GOSFWCW27IBOMQ&Signature=kmLsTFtXJqfvuxj6husWlDkRDMOIRDjzUUjb7zh79GkBKihUHc0f59k5OAImHTPdaiEREUCCpn~8sQ-si5lenuauJpApCmAU~NsxjfQhuh9m5O~GiHenr2fKu0DIJ75-oCE3859fyxoSFXQgZ9PRmeb98kikMR6uRX9nI5TPUHgKO8ZgkhDBTW~iyaDT~1ybnoK7elPa6T2VzfO-bpIyY-MZ71VRq3RxwmZRxduqHEb3Dh-jjrHyh2SoQsHmUjSJOf-uYilfvpGUResZAjAq8ZVLEjvhzKC2bmCNZIp3RmhYO8ctU7pd5t91J6Xaa6jBLtGfMxbqIm652EC79K0RoA__'
}
}
onMounted(() => {

View File

@@ -23,7 +23,7 @@
<script setup lang="ts">
import { computed, ref, reactive, onMounted } from 'vue'
import myTextarea from '../tools/my-textarea.vue'
import myTextarea from '../../tools/my-textarea.vue'
const styleList = ref([
{ label: 'Colorful', value: 'Colorful' },
{ label: 'Minimalist', value: 'Minimalist' },

View File

@@ -10,8 +10,8 @@
<script setup lang="ts">
import { reactive, onMounted } from 'vue'
import myTextarea from '../tools/my-textarea.vue'
import uploadFile from '../tools/upload-file.vue'
import myTextarea from '../../tools/my-textarea.vue'
import uploadFile from '../../tools/upload-file.vue'
const data = reactive({
prompt: '',
file: null

View File

@@ -10,7 +10,7 @@
<script setup lang="ts">
import { reactive, onMounted } from 'vue'
import uploadFile from '../tools/upload-file.vue'
import uploadFile from '../../tools/upload-file.vue'
const data = reactive({
file: null
})

View File

@@ -10,8 +10,8 @@
<script setup lang="ts">
import { reactive, onMounted } from 'vue'
import myTextarea from '../tools/my-textarea.vue'
import uploadFile from '../tools/upload-file.vue'
import myTextarea from '../../tools/my-textarea.vue'
import uploadFile from '../../tools/upload-file.vue'
const data = reactive({
prompt: '',
file: null

View File

@@ -22,9 +22,9 @@
<script setup lang="ts">
import { computed, ref, reactive, onMounted } from 'vue'
import myTextarea from '../tools/my-textarea.vue'
import mySelect from '../tools/my-select.vue'
import pixelRatioSelection from '../tools/pixel-ratio-selection.vue'
import myTextarea from '../../tools/my-textarea.vue'
import mySelect from '../../tools/my-select.vue'
import pixelRatioSelection from '../../tools/pixel-ratio-selection.vue'
const shortcutList = ref([
{
label: 'Change the...',

View File

@@ -27,9 +27,9 @@
<script setup lang="ts">
import { reactive, ref } from 'vue'
import myTextarea from '../tools/my-textarea.vue'
import uploadFile from '../tools/upload-file.vue'
import pixelRatioSelection from '../tools/pixel-ratio-selection.vue'
import myTextarea from '../../tools/my-textarea.vue'
import uploadFile from '../../tools/upload-file.vue'
import pixelRatioSelection from '../../tools/pixel-ratio-selection.vue'
const aspectRatioList = ref(['720p', '1080p', '1440p', '2160p', '1k', '2k'])
const timeList = ref(['5s', '10s', '15s', '20s', '30s', '60s'])
const data = reactive({
@@ -78,9 +78,9 @@
}
}
}
.el-popper{
.el-select-dropdown{
li{
.el-popper {
.el-select-dropdown {
li {
padding-left: 8px;
height: 30px;
line-height: 30px;

View File

@@ -44,7 +44,7 @@
default: () => ({})
}
})
const nodeManager = inject('nodeManager') as any
const emit = defineEmits(['delete-node', 'copy-node'])
const attrs = useAttrs()
const showHeader = ref(!!attrs.node?.data?.isHeader)
const showMenu = ref(false)
@@ -58,10 +58,10 @@
}
)
const menus = ref([
{ label: 'Copy', tip: 'Ctrl+C', on: () => {} },
{ label: 'Copy', tip: 'Ctrl+C', on: () => emit('copy-node') },
{ label: 'Paste', tip: 'Ctrl+V', on: () => {} },
{ label: 'Duplicate', tip: 'Ctrl+D', on: () => {} },
{ label: 'Delete', tip: 'Del', on: () => nodeManager.deleteNode(attrs.node.id) },
{ label: 'Delete', tip: 'Del', on: () => emit('delete-node') },
{ isDivide: true },
{ label: 'Bring to font', tip: 'Del', on: () => {} },
{ label: 'Send to back', tip: 'Del', on: () => {} },

View File

@@ -0,0 +1,74 @@
<template>
<!-- 结果图片 -->
<div
class="text"
:class="{ edit }"
@click="onClick"
@mousedown="onMouseDown"
@dblclick="onDoubleClick"
>
<div
tabindex="0"
class="input"
ref="inputRef"
contenteditable="true"
@input="onInput"
@blur="onBlur"
@paste.prevent
>
双击编辑文本
</div>
</div>
</template>
<script setup lang="ts">
import { reactive, ref, nextTick, useAttrs, inject, watch } from 'vue'
const props = defineProps({
data: {
type: Object,
default: () => ({})
}
})
const emit = defineEmits(['delete-node', 'copy-node'])
const data = reactive({
text: props.data?.text || '双击编辑文本'
})
const edit = ref(false)
const time = ref(null)
const inputRef = ref<any>()
const onInput = () => {
const text = inputRef.value.innerText
data.text = text
}
const onBlur = () => {
edit.value = false
}
const onClick = () => {
if (edit.value) return
time.value = setTimeout(() => {
edit.value = false
}, 500)
edit.value = true
}
const onDoubleClick = () => {
clearTimeout(time.value)
}
const onMouseDown = (e: MouseEvent) => {
if (edit.value) e.stopPropagation()
}
defineExpose({ data })
</script>
<style lang="less" scoped>
.text {
&.edit {
> .input {
cursor: text;
}
}
> .input {
outline: none;
min-width: 1px;
}
}
</style>

View File

@@ -6,18 +6,32 @@
:edges="edges"
:min-zoom="0.1"
:max-zoom="10"
:nodes-draggable="true"
:nodes-draggable="nodesDraggable"
:pan-on-drag="panOnDrag"
@nodes-initialized="layoutGraph('LR')"
@node-drag-stop="(e) => eventManager.handleNodeDragStop(e)"
@viewport-change="(e) => eventManager.handleViewportChange(e)"
@pane-click="(e) => eventManager.handleClick(e)"
:class="{ 'custom-cursor': !!stateManager.cursor.value }"
:style="{ '--custom-cursor': stateManager.cursor.value }"
>
<template v-for="v in nodeTypes" :key="v" #[`node-${v}`]="nodeProps">
<node :type="v" :stateManager="stateManager" :node="nodeProps">
<template v-for="v in nodeTypes" :key="v" #[`node-${v}`]="node">
<node
:type="v"
:stateManager="stateManager"
:node="node"
:mask="
stateManager.tool.value === TOOLS.MOVE ||
stateManager.tool.value === TOOLS.TEXT
"
>
<component
:is="components[nodeProps.data.component]"
:node="nodeProps"
:data="nodeProps.data.data"
v-bind="nodeProps.data"
:is="components[node.data.component]"
:node="node"
:data="node.data.data"
v-bind="node.data"
@delete-node="deleteNode(node.id)"
@copy-node="copyNode(node.id)"
/>
</node>
</template>
@@ -44,11 +58,13 @@
import zoom from '../components/zoom.vue'
// 节点
import node from './components/node.vue'
import resultImage from './components/result/result-image.vue'
import card from './components/cards/index.vue'
import resultImage from './components/nodes/result-image.vue'
import card from './components/nodes/cards/index.vue'
import text from './components/nodes/text.vue'
const components = {
[NODE_COMPONENT.RESULT_IMAGE]: resultImage,
[NODE_COMPONENT.CARD]: card
[NODE_COMPONENT.CARD]: card,
[NODE_COMPONENT.TEXT]: text
}
// 管理器
@@ -56,6 +72,7 @@
import { EventManager } from './manager/EventManager'
import { FlowManager } from './manager/FlowManager'
import { NodeManager } from './manager/NodeManager'
import { ToolManager, TOOLS } from './manager/ToolManager'
const props = defineProps({
config: {
@@ -65,29 +82,36 @@
})
const vueFlow = ref<any>()
const nodeTypes = ref([NODE_TYPE.INPUT, NODE_TYPE.SECONDARY, NODE_TYPE.OUTPUT])
const nodeTypes = ref([NODE_TYPE.INPUT, NODE_TYPE.SECONDARY, NODE_TYPE.OUTPUT, NODE_TYPE.ALONE])
// 状态管理器
const stateManager = new StateManager({ vueFlow })
const nodes = computed(() => stateManager.nodes_.value)
const edges = computed(() => stateManager.edges.value)
provide('stateManager', stateManager)
// 事件管理器
const eventManager = new EventManager({ stateManager, vueFlow })
stateManager.setManager({ eventManager })
provide('eventManager', eventManager)
// 流程管理器
const flowManager = new FlowManager({ stateManager, vueFlow })
stateManager.setManager({ flowManager })
provide('flowManager', flowManager)
// 节点管理器
const nodeManager = new NodeManager({ stateManager, vueFlow })
stateManager.setManager({
eventManager,
flowManager,
nodeManager
})
stateManager.setManager({ nodeManager })
provide('nodeManager', nodeManager)
provide('stateManager', stateManager)
provide('eventManager', eventManager)
provide('flowManager', flowManager)
provide('nodeManager', nodeManager)
provide('nodeManager', nodeManager)
// 工具管理器
const toolManager = new ToolManager({ stateManager, vueFlow })
stateManager.setManager({ toolManager })
provide('toolManager', toolManager)
const nodes = computed(() => stateManager.nodes_.value)
const edges = computed(() => stateManager.edges.value)
const nodesDraggable = computed(() => stateManager.nodesDraggable.value)
const panOnDrag = computed(() => stateManager.panOnDrag.value)
const { fitView } = useVueFlow()
const { layout } = useLayout()
@@ -107,6 +131,15 @@
}, 0)
}
/** 删除节点 */
const deleteNode = (id) => {
nodeManager.deleteNode(id)
}
/** 复制节点 */
const copyNode = (id) => {
console.log('复制:', id)
}
// 导出流程
const exportFlow = () => {
// flowManager.exportFlow()
@@ -156,6 +189,9 @@
> .vue-flow {
width: 100%;
height: 100%;
&.custom-cursor {
cursor: var(--custom-cursor, pointer);
}
}
}
</style>

View File

@@ -1,3 +1,4 @@
import { TOOLS } from "./ToolManager"
export class EventManager {
stateManager: any
vueFlow: any
@@ -7,10 +8,12 @@ export class EventManager {
this.vueFlow = options.vueFlow
this.zoom = this.stateManager.zoom
}
/** 处理视口变化 */
handleViewportChange(e: any) {
const { zoom } = e
this.zoom.value = zoom
}
/** 处理节点拖动停止 */
handleNodeDragStop(e: any) {
const { node } = e
const { id, position } = node
@@ -21,4 +24,17 @@ export class EventManager {
}
})
}
/** 处理点击 */
handleClick(event: any) {
const tool = this.stateManager.tool.value
if (tool === TOOLS.TEXT) {
const { x, y, zoom } = this.vueFlow.value.viewport
const position = {
x: (event.offsetX - x) / zoom,
y: (event.offsetY - y) / zoom
}
this.stateManager.nodeManager.createTextNode({ position })
this.stateManager.toolManager.setTool(TOOLS.SELECT)
}
}
}

View File

@@ -1,5 +1,5 @@
import { createId } from '../../tools/tools'
import { NODE_DATATYPE, NODE_COMPONENT } from '../tools/index.d'
import { NODE_DATATYPE, NODE_COMPONENT, NODE_DATATIER } from '../tools/index.d'
interface NodeOptions {
id?: string
position?: { x: number, y: number }
@@ -34,11 +34,12 @@ export class NodeManager {
const positionX = options.positionX || 0
const positionY = options.positionY || 0
const position = options.position ||
!snode ? { x: positionX, y: positionY } :
{
x: snode.position.x + snode.dimensions.width + 50 + positionX,
y: snode.position.y + positionY
}
(!snode ?
{ x: positionX, y: positionY } :
{
x: snode.position.x + snode.dimensions.width + 50 + positionX,
y: snode.position.y + positionY
})
const data = options?.data || {}
data['component'] = options.component
const options_ = {
@@ -55,7 +56,7 @@ export class NodeManager {
...(options ? options : {}),
component: NODE_COMPONENT.RESULT_IMAGE,
data: {
tier: 0,
tier: NODE_DATATIER.RESULT_IMAGE,
type: NODE_DATATYPE.RESULT_IMAGE,
isHeader: true,
...(options?.data || {}),
@@ -70,7 +71,7 @@ export class NodeManager {
component: NODE_COMPONENT.CARD,
positionY: 50,
data: {
tier: 1,
tier: NODE_DATATIER.CARDS_SELECT,
type: NODE_DATATYPE.CARDS_SELECT,
...(options?.data || {}),
},
@@ -82,6 +83,20 @@ export class NodeManager {
const options_ = {
...(options ? options : {}),
component: NODE_COMPONENT.CARD,
data: {
...(options?.data || {}),
}
}
return this.createNode(options_)
}
/** 创建文本节点 */
createTextNode(options?: NodeOptions) {
const options_ = {
...(options ? options : {}),
component: NODE_COMPONENT.TEXT,
data: {
...(options?.data || {}),
}
}
return this.createNode(options_)
}

View File

@@ -14,19 +14,30 @@ export class StateManager {
nodes_: any
edges: any
zoom: any
// 管理器
tool: any
cursor: any
nodesDraggable: any
panOnDrag: any
// 管理器
eventManager: any
flowManager: any
nodeManager: any
toolManager: any
// 设置管理器
setManager(options) {
options.eventManager && (this.eventManager = options.eventManager)
options.flowManager && (this.flowManager = options.flowManager)
options.nodeManager && (this.nodeManager = options.nodeManager)
options.toolManager && (this.toolManager = options.toolManager)
}
constructor(options) {
this.vueFlow = options.vueFlow
this.zoom = ref(1)
this.tool = ref("")
this.cursor = ref("")
this.nodesDraggable = ref(false)
this.panOnDrag = ref(false)
this.nodes = ref<NodesItem[]>([]);
this.nodes_ = computed(() => {
return this.nodes.value.map((node, index) => {
@@ -41,14 +52,14 @@ export class StateManager {
const superiorID = node.data.superiorID;
const isSuperior = this.nodes.value.some((v) => v.id === superiorID)
const isSubord = this.nodes.value.some((v) => v.data.superiorID === node.id)
if (!superiorID) {// 没有上级ID
if (!isSuperior && isSubord) {// 没有上级 有下级
obj.type = NODE_TYPE.INPUT;
} else if (isSuperior && isSubord) {// 有上级ID并找到下级
} else if (isSuperior && isSubord) {// 有上级下级
obj.type = NODE_TYPE.SECONDARY;
} else if (isSuperior && !isSubord) {// 有上级ID但未找到下级
} else if (isSuperior && !isSubord) {// 有上级 没有下级
obj.type = NODE_TYPE.OUTPUT;
} else {// 其他情况-有上级ID未找到上
obj.type = NODE_TYPE.INPUT;
} else {// 其他情况-有上级 没有下
obj.type = NODE_TYPE.ALONE;
}
return obj
})
@@ -105,4 +116,15 @@ export class StateManager {
getLastNode() {
return this.nodes.value[this.nodes.value.length - 1]
}
/** 设置工具 */
setTool(tool: string) {
this.tool.value = tool
}
/** 设置光标 */
setCursor(v: string) { this.cursor.value = v }
/** 设置节点是否可拖动 */
setNodesDraggable(v: boolean) { this.nodesDraggable.value = v }
/** 设置是否可以平移画布 */
setPanOnDrag(v: boolean) { this.panOnDrag.value = v }
}

View File

@@ -0,0 +1,47 @@
export const TOOLS = {
SELECT: "SELECT",
MOVE: "MOVE",
TEXT: "TEXT",
UNDO: "UNDO",
REDO: "REDO",
}
export const tools = [
/** 选择工具 */
{
name: TOOLS.SELECT,
nodesDraggable: true,
panOnDrag: false,
},
/** 移动工具 */
{
name: TOOLS.MOVE,
nodesDraggable: false,
panOnDrag: true,
},
/** 文本工具 */
{
name: TOOLS.TEXT,
cursor: "text",
nodesDraggable: false,
panOnDrag: false,
},
]
export class ToolManager {
stateManager: any
vueFlow: any
constructor(options) {
this.stateManager = options.stateManager;
this.vueFlow = options.vueFlow
this.setTool(TOOLS.SELECT)
}
setTool(value: string) {
const tool = tools.find((t) => t.name === value)
if (!tool) return console.warn(`工具${tool}不存在`)
this.stateManager.tool.value = tool.name
this.stateManager.setNodesDraggable(!!tool.nodesDraggable)
this.stateManager.setPanOnDrag(!!tool.panOnDrag)
this.stateManager.setCursor(tool.cursor || "")
}
}

View File

@@ -4,6 +4,7 @@
export const NODE_COMPONENT = {
RESULT_IMAGE: 'result-image',
CARD: 'card',
TEXT: 'text',
}
/**
@@ -13,6 +14,7 @@ export const NODE_TYPE = {
INPUT: 'InputNode',
SECONDARY: 'SecondaryNode',
OUTPUT: 'OutputNode',
ALONE: 'AloneNode',
}
/**

View File

@@ -64,7 +64,7 @@ export default {
rename: 'Rename',
delete: 'Delete',
setting: 'Setting',
logout: 'Logout',
logout: 'Log out',
general: 'General',
profile: 'Profile',
learnMore: 'Learn More',

View File

@@ -46,12 +46,12 @@
<style lang="less" scoped>
.logout-btn {
cursor: pointer;
height: 3.7rem;
width: 9.6rem;
height: 3rem;
width: 7.7rem;
border-radius: 3.7rem;
border: none;
background-color: #ff7a51;
color: #fff;
font-size: 1.4rem;
font-size: 1.2rem;
}
</style>

View File

@@ -22,12 +22,12 @@
<style lang="less" scoped>
button {
width: 10rem;
height: 3.73rem;
width: 7.7rem;
height: 3rem;
background-color: transparent;
border: 0.01rem solid #b5b5b5;
color: #000;
font-size: 1.4rem;
font-size: 1.2rem;
border-radius: 3rem;
}
</style>

View File

@@ -11,7 +11,7 @@
<div class="setting-header">
<div class="title">{{ $t('Home.setting') }}</div>
<span class="close" @click="close">
<svg-icon name="close" size="10" color="#000" />
<svg-icon name="close" size="12" color="#000" />
</span>
</div>
</template>