mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-07-12 16:01:35 +08:00
feat: 增强工作流侧边栏,支持移动端显示和组件点击事件处理
This commit is contained in:
@@ -10,7 +10,7 @@ import WorkflowSidebar from '@/layouts/components/WorkflowSidebar.vue'
|
||||
import DropzoneBackground from '@/layouts/components/DropzoneBackground.vue'
|
||||
import ImportCodeDialog from '@/components/dialog/ImportCodeDialog.vue'
|
||||
|
||||
const { onConnect, addEdges, nodes, edges } = useVueFlow()
|
||||
const { onConnect, addEdges, nodes, edges, addNodes, screenToFlowCoordinate } = useVueFlow()
|
||||
|
||||
const { onDragOver, onDrop, onDragLeave, isDragOver } = useDragAndDrop()
|
||||
|
||||
@@ -98,6 +98,43 @@ const $toast = useToast()
|
||||
// 导入代码对话框
|
||||
const importCodeDialog = ref(false)
|
||||
|
||||
// 为移动端生成节点ID
|
||||
function getId() {
|
||||
return 'act_' + Math.random().toString(36).substr(2, 9)
|
||||
}
|
||||
|
||||
// 处理移动端组件点击事件
|
||||
function handleComponentClick(action: any) {
|
||||
// 计算当前视图中心点
|
||||
const centerX = window.innerWidth / 2
|
||||
const centerY = window.innerHeight / 3
|
||||
|
||||
// 转换为画布坐标
|
||||
const position = screenToFlowCoordinate({
|
||||
x: centerX,
|
||||
y: centerY,
|
||||
})
|
||||
|
||||
// 生成一个新节点ID
|
||||
const nodeId = getId()
|
||||
|
||||
// 创建新节点
|
||||
const newNode = {
|
||||
id: nodeId,
|
||||
type: action.type,
|
||||
name: action.name,
|
||||
description: action.desc || '',
|
||||
position,
|
||||
data: {},
|
||||
}
|
||||
|
||||
// 添加节点到画布
|
||||
addNodes(newNode)
|
||||
|
||||
// 显示提示
|
||||
$toast.success('已添加组件到画布')
|
||||
}
|
||||
|
||||
// 调用API 编辑任务
|
||||
async function updateWorkflow() {
|
||||
// 更新节点和流程
|
||||
@@ -157,32 +194,34 @@ const isMacOS = computed(() => {
|
||||
|
||||
<template>
|
||||
<VDialog scrollable fullscreen :scrim="false" transition="dialog-bottom-transition">
|
||||
<VCard>
|
||||
<VCard class="workflow-dialog">
|
||||
<!-- Toolbar -->
|
||||
<div>
|
||||
<VToolbar color="primary">
|
||||
<VToolbarItems>
|
||||
<VBtn icon @click="emit('close')" class="ms-3">
|
||||
<VIcon size="large" color="white" icon="mdi-close" />
|
||||
</VBtn>
|
||||
</VToolbarItems>
|
||||
<VToolbarTitle> 编辑流程 - {{ workflow?.name }} </VToolbarTitle>
|
||||
<VToolbarItems>
|
||||
<VBtn icon @click="importCodeDialog = true">
|
||||
<VIcon size="large" color="white" icon="mdi-import" />
|
||||
</VBtn>
|
||||
<VBtn icon @click="shareWorkflow">
|
||||
<VIcon size="large" color="white" icon="mdi-share" />
|
||||
</VBtn>
|
||||
<VBtn icon @click="updateWorkflow" class="mx-5">
|
||||
<VIcon size="large" color="white" icon="mdi-content-save" />
|
||||
</VBtn>
|
||||
</VToolbarItems>
|
||||
</VToolbar>
|
||||
</div>
|
||||
<VDivider />
|
||||
<VCardText class="px-0 py-0">
|
||||
<div class="dnd-flow" @drop="onDrop">
|
||||
<VToolbar color="primary">
|
||||
<VToolbarItems>
|
||||
<VBtn icon @click="emit('close')" class="ms-3">
|
||||
<VIcon size="large" color="white" icon="mdi-close" />
|
||||
</VBtn>
|
||||
</VToolbarItems>
|
||||
<VToolbarTitle class="text-truncate"> 编辑流程 - {{ workflow?.name }} </VToolbarTitle>
|
||||
<VSpacer></VSpacer>
|
||||
<VToolbarItems>
|
||||
<VBtn icon variant="text" @click="importCodeDialog = true" class="ms-2">
|
||||
<VIcon size="24" color="white" icon="mdi-import" />
|
||||
<VTooltip activator="parent" location="bottom">导入流程代码</VTooltip>
|
||||
</VBtn>
|
||||
<VBtn icon variant="text" @click="shareWorkflow" class="ms-2">
|
||||
<VIcon size="24" color="white" icon="mdi-share" />
|
||||
<VTooltip activator="parent" location="bottom">分享流程代码</VTooltip>
|
||||
</VBtn>
|
||||
<VBtn icon variant="text" @click="updateWorkflow" class="ms-2 me-3">
|
||||
<VIcon size="24" color="white" icon="mdi-content-save" />
|
||||
<VTooltip activator="parent" location="bottom">保存流程</VTooltip>
|
||||
</VBtn>
|
||||
</VToolbarItems>
|
||||
</VToolbar>
|
||||
|
||||
<VCardText class="workflow-content pa-0">
|
||||
<div class="workflow-canvas" @drop="onDrop">
|
||||
<VueFlow
|
||||
:nodes="nodes"
|
||||
:edges="edges"
|
||||
@@ -204,10 +243,11 @@ const isMacOS = computed(() => {
|
||||
>
|
||||
</DropzoneBackground>
|
||||
</VueFlow>
|
||||
<WorkflowSidebar />
|
||||
<WorkflowSidebar @component-click="handleComponentClick" />
|
||||
</div>
|
||||
</VCardText>
|
||||
</VCard>
|
||||
|
||||
<ImportCodeDialog
|
||||
v-if="importCodeDialog"
|
||||
v-model="importCodeDialog"
|
||||
@@ -218,88 +258,43 @@ const isMacOS = computed(() => {
|
||||
/>
|
||||
</VDialog>
|
||||
</template>
|
||||
<style>
|
||||
|
||||
<style lang="scss">
|
||||
@import '@vue-flow/core/dist/style.css';
|
||||
@import '@vue-flow/core/dist/theme-default.css';
|
||||
@import '@vue-flow/controls/dist/style.css';
|
||||
@import '@vue-flow/minimap/dist/style.css';
|
||||
@import '@vue-flow/node-resizer/dist/style.css';
|
||||
|
||||
.vue-flow__minimap {
|
||||
transform: scale(75%);
|
||||
transform-origin: bottom right;
|
||||
}
|
||||
|
||||
.dnd-flow {
|
||||
.workflow-dialog {
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
flex-direction: column;
|
||||
block-size: 100%;
|
||||
}
|
||||
|
||||
.dnd-flow aside {
|
||||
background: #10b981bf;
|
||||
border-inline-end: 1px solid #eee;
|
||||
box-shadow: 0 5px 10px 0 rgba(0, 0, 0, 30%);
|
||||
box-shadow: 0 5px 10px #0000004d;
|
||||
color: #fff;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
padding-block: 15px;
|
||||
padding-inline: 10px;
|
||||
.workflow-content {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.dnd-flow aside .nodes > * {
|
||||
box-shadow: 5px 5px 10px 2px rgba(0, 0, 0, 25%);
|
||||
box-shadow: 5px 5px 10px 2px #00000040;
|
||||
cursor: grab;
|
||||
font-weight: 500;
|
||||
margin-block-end: 10px;
|
||||
}
|
||||
|
||||
.dnd-flow aside .description {
|
||||
margin-block-end: 10px;
|
||||
}
|
||||
|
||||
.dnd-flow .vue-flow-wrapper {
|
||||
flex-grow: 1;
|
||||
block-size: 100%;
|
||||
}
|
||||
|
||||
@media screen and (width >= 640px) {
|
||||
.dnd-flow {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
.dnd-flow aside {
|
||||
max-inline-size: 25%;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (width <= 639px) {
|
||||
.dnd-flow aside .nodes {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.dropzone-background {
|
||||
.workflow-canvas {
|
||||
position: relative;
|
||||
block-size: 100%;
|
||||
inline-size: 100%;
|
||||
}
|
||||
|
||||
.dropzone-background .overlay {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
block-size: 100%;
|
||||
inline-size: 100%;
|
||||
inset-block-start: 0;
|
||||
inset-inline-start: 0;
|
||||
pointer-events: none;
|
||||
.vue-flow__minimap {
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||
border-radius: 8px;
|
||||
background-color: rgba(var(--v-theme-surface), 0.8);
|
||||
box-shadow: 0 4px 15px rgba(var(--v-shadow-key-umbra-color), 0.1);
|
||||
inset-block-end: 20px;
|
||||
inset-inline-end: 20px;
|
||||
transform: scale(75%);
|
||||
transform-origin: bottom right;
|
||||
}
|
||||
|
||||
.vue-flow__handle {
|
||||
@@ -320,4 +315,39 @@ const isMacOS = computed(() => {
|
||||
.vue-flow__handle-right {
|
||||
background-color: rgb(var(--v-theme-error));
|
||||
}
|
||||
|
||||
// 自定义节点样式
|
||||
.vue-flow__node {
|
||||
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||
border-radius: 12px;
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 8px 16px rgba(var(--v-shadow-key-umbra-color), 0.15) !important;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
&.selected {
|
||||
box-shadow: 0 0 0 1px rgb(var(--v-theme-primary)) !important;
|
||||
}
|
||||
}
|
||||
|
||||
// 自定义动作连线样式
|
||||
.vue-flow__edge.animation {
|
||||
.vue-flow__edge-path {
|
||||
stroke: rgb(var(--v-theme-primary));
|
||||
}
|
||||
|
||||
&.selected {
|
||||
.vue-flow__edge-path {
|
||||
stroke: rgb(var(--v-theme-primary));
|
||||
stroke-width: 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (width <= 600px) {
|
||||
.vue-flow__minimap {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user