mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-05 23:56:42 +08:00
更新工作流分享功能
This commit is contained in:
+1
-1
@@ -147,7 +147,7 @@ export interface SubscribeShare {
|
|||||||
// 工作流分享
|
// 工作流分享
|
||||||
export interface WorkflowShare {
|
export interface WorkflowShare {
|
||||||
// 分享ID
|
// 分享ID
|
||||||
id?: number
|
id?: string
|
||||||
// 工作流ID
|
// 工作流ID
|
||||||
workflow_id?: string
|
workflow_id?: string
|
||||||
// 分享标题
|
// 分享标题
|
||||||
|
|||||||
@@ -1,26 +1,16 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { formatDateDifference } from '@/@core/utils/formatters'
|
import { formatDateDifference } from '@/@core/utils/formatters'
|
||||||
import type { WorkflowShare } from '@/api/types'
|
import type { WorkflowShare } from '@/api/types'
|
||||||
import WorkflowEditDialog from '../dialog/WorkflowAddEditDialog.vue'
|
|
||||||
import ForkWorkflowDialog from '../dialog/ForkWorkflowDialog.vue'
|
import ForkWorkflowDialog from '../dialog/ForkWorkflowDialog.vue'
|
||||||
import { useGlobalSettingsStore } from '@/stores'
|
|
||||||
|
|
||||||
// 输入参数
|
// 输入参数
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
media: Object as PropType<WorkflowShare>,
|
workflow: Object as PropType<WorkflowShare>,
|
||||||
})
|
})
|
||||||
|
|
||||||
// 定义删除事件
|
// 定义删除事件
|
||||||
const emit = defineEmits(['delete'])
|
const emit = defineEmits(['delete'])
|
||||||
|
|
||||||
// 从 provide 中获取全局设置
|
|
||||||
// 全局设置
|
|
||||||
const globalSettingsStore = useGlobalSettingsStore()
|
|
||||||
const globalSettings = globalSettingsStore.globalSettings
|
|
||||||
|
|
||||||
// 工作流编辑弹窗
|
|
||||||
const workflowEditDialog = ref(false)
|
|
||||||
|
|
||||||
// 复用工作流弹窗
|
// 复用工作流弹窗
|
||||||
const forkWorkflowDialog = ref(false)
|
const forkWorkflowDialog = ref(false)
|
||||||
|
|
||||||
@@ -28,7 +18,46 @@ const forkWorkflowDialog = ref(false)
|
|||||||
const workflowId = ref<string>()
|
const workflowId = ref<string>()
|
||||||
|
|
||||||
// 分享时间
|
// 分享时间
|
||||||
const dateText = ref(props.media && props.media?.date ? formatDateDifference(props.media.date) : '')
|
const dateText = ref(props.workflow && props.workflow?.date ? formatDateDifference(props.workflow.date) : '')
|
||||||
|
|
||||||
|
// 随机渐变背景
|
||||||
|
const gradientStyle = ref('')
|
||||||
|
|
||||||
|
// 生成随机渐变背景
|
||||||
|
function generateRandomGradient() {
|
||||||
|
const gradients = [
|
||||||
|
'linear-gradient(135deg, #4a5568 0%, #2d3748 100%)',
|
||||||
|
'linear-gradient(135deg, #553c9a 0%, #b794f4 100%)',
|
||||||
|
'linear-gradient(135deg, #2c5aa0 0%, #1a365d 100%)',
|
||||||
|
'linear-gradient(135deg, #2f855a 0%, #22543d 100%)',
|
||||||
|
'linear-gradient(135deg, #c53030 0%, #742a2a 100%)',
|
||||||
|
'linear-gradient(135deg, #d69e2e 0%, #975a16 100%)',
|
||||||
|
'linear-gradient(135deg, #805ad5 0%, #553c9a 100%)',
|
||||||
|
'linear-gradient(135deg, #3182ce 0%, #2c5282 100%)',
|
||||||
|
'linear-gradient(135deg, #38a169 0%, #276749 100%)',
|
||||||
|
'linear-gradient(135deg, #e53e3e 0%, #c53030 100%)',
|
||||||
|
'linear-gradient(135deg, #dd6b20 0%, #c05621 100%)',
|
||||||
|
'linear-gradient(135deg, #6b46c1 0%, #553c9a 100%)',
|
||||||
|
'linear-gradient(135deg, #2b6cb0 0%, #2c5282 100%)',
|
||||||
|
'linear-gradient(135deg, #38a169 0%, #2f855a 100%)',
|
||||||
|
'linear-gradient(135deg, #d53f8c 0%, #97266d 100%)',
|
||||||
|
]
|
||||||
|
|
||||||
|
// 基于工作流ID生成固定的随机数,确保同一工作流总是显示相同的渐变
|
||||||
|
const seed = String(props.workflow?.id || Math.random())
|
||||||
|
const hash = seed.split('').reduce((a, b) => {
|
||||||
|
a = (a << 5) - a + b.charCodeAt(0)
|
||||||
|
return a & a
|
||||||
|
}, 0)
|
||||||
|
|
||||||
|
const index = Math.abs(hash) % gradients.length
|
||||||
|
return gradients[index]
|
||||||
|
}
|
||||||
|
|
||||||
|
// 初始化渐变背景
|
||||||
|
onMounted(() => {
|
||||||
|
gradientStyle.value = generateRandomGradient()
|
||||||
|
})
|
||||||
|
|
||||||
// 复用工作流
|
// 复用工作流
|
||||||
function showForkWorkflow() {
|
function showForkWorkflow() {
|
||||||
@@ -39,7 +68,6 @@ function showForkWorkflow() {
|
|||||||
function finishForkWorkflow(wid: string) {
|
function finishForkWorkflow(wid: string) {
|
||||||
workflowId.value = wid
|
workflowId.value = wid
|
||||||
forkWorkflowDialog.value = false
|
forkWorkflowDialog.value = false
|
||||||
workflowEditDialog.value = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 删除工作流分享时处理
|
// 删除工作流分享时处理
|
||||||
@@ -62,37 +90,38 @@ function doDelete() {
|
|||||||
>
|
>
|
||||||
<VCard
|
<VCard
|
||||||
v-bind="hover.props"
|
v-bind="hover.props"
|
||||||
:key="props.media?.id"
|
:key="props.workflow?.id"
|
||||||
class="flex flex-col h-full"
|
class="flex flex-col h-full"
|
||||||
rounded="0"
|
rounded="0"
|
||||||
min-height="150"
|
min-height="150"
|
||||||
|
:style="{ background: gradientStyle }"
|
||||||
@click="showForkWorkflow"
|
@click="showForkWorkflow"
|
||||||
>
|
>
|
||||||
<div class="h-full flex flex-col">
|
<div class="h-full flex flex-col">
|
||||||
<VCardText class="flex items-center pa-3 pb-1 grow">
|
<VCardText class="flex items-center pa-3 pb-1 grow">
|
||||||
<div class="flex flex-col justify-center">
|
<div class="flex flex-col justify-center">
|
||||||
<div class="mr-2 min-w-0 text-lg font-bold line-clamp-2 overflow-hidden text-ellipsis ...">
|
<VCardTitle class="text-lg text-bold text-white line-clamp-2 overflow-hidden text-ellipsis ...">
|
||||||
{{ props.media?.share_title }}
|
{{ props.workflow?.share_title }}
|
||||||
</div>
|
</VCardTitle>
|
||||||
<div class="text-sm font-medium text-gray-600 sm:pt-1 line-clamp-3 overflow-hidden text-ellipsis ...">
|
<VCardSubtitle class="line-clamp-3 overflow-hidden text-white text-ellipsis ...">
|
||||||
{{ props.media?.share_comment }}
|
{{ props.workflow?.share_comment }}
|
||||||
</div>
|
</VCardSubtitle>
|
||||||
</div>
|
</div>
|
||||||
</VCardText>
|
</VCardText>
|
||||||
<VCardText class="flex justify-space-between align-center flex-wrap py-2">
|
<VCardText class="flex justify-space-between align-center flex-wrap py-2">
|
||||||
<div class="flex align-center">
|
<div class="flex align-center">
|
||||||
<IconBtn v-bind="props" icon="mdi-account" class="me-1" />
|
<IconBtn v-bind="props" icon="mdi-account" class="me-1 text-white" />
|
||||||
<div class="text-subtitle-2 me-4">
|
<div class="text-subtitle-2 me-4 text-white text-opacity-90">
|
||||||
{{ props.media?.share_user }}
|
{{ props.workflow?.share_user }}
|
||||||
</div>
|
</div>
|
||||||
<IconBtn v-if="props.media?.count" icon="mdi-fire" class="me-1" />
|
<IconBtn v-if="props.workflow?.count" icon="mdi-fire" class="me-1 text-white" />
|
||||||
<span v-if="props.media?.count" class="text-subtitle-2 me-4">
|
<span v-if="props.workflow?.count" class="text-subtitle-2 me-4 text-white text-opacity-90">
|
||||||
{{ props.media?.count.toLocaleString() }}
|
{{ props.workflow?.count.toLocaleString() }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</VCardText>
|
</VCardText>
|
||||||
<VCardText class="absolute right-0 bottom-0 d-flex align-center p-2 text-gray-500">
|
<VCardText class="absolute right-0 bottom-0 d-flex align-center p-2 text-white text-sm text-opacity-75">
|
||||||
<VIcon icon="mdi-calendar" class="me-1" />
|
<VIcon icon="mdi-calendar" size="small" class="me-1" />
|
||||||
{{ dateText }}
|
{{ dateText }}
|
||||||
</VCardText>
|
</VCardText>
|
||||||
</div>
|
</div>
|
||||||
@@ -100,22 +129,14 @@ function doDelete() {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</VHover>
|
</VHover>
|
||||||
<!-- 工作流编辑弹窗 -->
|
|
||||||
<WorkflowEditDialog
|
|
||||||
v-if="workflowEditDialog"
|
|
||||||
v-model="workflowEditDialog"
|
|
||||||
:workflow="workflowId ? { id: workflowId } : undefined"
|
|
||||||
@close="workflowEditDialog = false"
|
|
||||||
@save="workflowEditDialog = false"
|
|
||||||
@remove="workflowEditDialog = false"
|
|
||||||
/>
|
|
||||||
<!-- 复用工作流弹窗 -->
|
<!-- 复用工作流弹窗 -->
|
||||||
<ForkWorkflowDialog
|
<ForkWorkflowDialog
|
||||||
v-if="forkWorkflowDialog"
|
v-if="forkWorkflowDialog"
|
||||||
:media="props.media"
|
v-model="forkWorkflowDialog"
|
||||||
|
:workflow="props.workflow"
|
||||||
@close="forkWorkflowDialog = false"
|
@close="forkWorkflowDialog = false"
|
||||||
@fork="finishForkWorkflow"
|
@fork="finishForkWorkflow"
|
||||||
@delete="doDelete"
|
@delete="doDelete"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -334,10 +334,6 @@ const resolveProgress = (item: Workflow) => {
|
|||||||
:workflow="workflow"
|
:workflow="workflow"
|
||||||
/>
|
/>
|
||||||
<!-- 分享对话框 -->
|
<!-- 分享对话框 -->
|
||||||
<WorkflowShareDialog
|
<WorkflowShareDialog v-if="shareDialog" v-model="shareDialog" :workflow="workflow" @close="shareDialog = false" />
|
||||||
v-if="shareDialog"
|
|
||||||
:workflow="workflow"
|
|
||||||
@close="shareDialog = false"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -5,13 +5,14 @@ import { WorkflowShare } from '@/api/types'
|
|||||||
import { useToast } from 'vue-toastification'
|
import { useToast } from 'vue-toastification'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useGlobalSettingsStore } from '@/stores'
|
import { useGlobalSettingsStore } from '@/stores'
|
||||||
|
import { VueFlow, useVueFlow } from '@vue-flow/core'
|
||||||
|
|
||||||
// 国际化
|
// 国际化
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
// 输入参数
|
// 输入参数
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
media: Object as PropType<WorkflowShare>,
|
workflow: Object as PropType<WorkflowShare>,
|
||||||
})
|
})
|
||||||
|
|
||||||
// 定义事件
|
// 定义事件
|
||||||
@@ -31,14 +32,67 @@ const processing = ref(false)
|
|||||||
// 删除中
|
// 删除中
|
||||||
const deleting = ref(false)
|
const deleting = ref(false)
|
||||||
|
|
||||||
// 是否折叠
|
// 流程图相关
|
||||||
const isExpanded = ref(false)
|
const { nodes, edges } = useVueFlow()
|
||||||
|
|
||||||
// 折叠展开
|
// 自定义节点类型
|
||||||
function toggleExpand() {
|
const nodeTypes: Record<string, any> = ref({})
|
||||||
isExpanded.value = !isExpanded.value
|
|
||||||
|
// 自动扫描目录下所有的 .vue 文件
|
||||||
|
const components = import.meta.glob('../workflow/*Action.vue')
|
||||||
|
|
||||||
|
// 动态加载某个组件
|
||||||
|
const loadComponent = async (componentName: string) => {
|
||||||
|
const component = components[`../workflow/${componentName}.vue`]
|
||||||
|
if (component) {
|
||||||
|
return ((await component()) as any).default
|
||||||
|
}
|
||||||
|
throw new Error(t('dialog.workflowActions.componentNotFound', { component: componentName }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 将所有components中的组件加载到nodeTypes中
|
||||||
|
for (const path in components) {
|
||||||
|
const componentName = path.match(/\.\/workflow\/(.*).vue$/)?.[1]
|
||||||
|
if (!componentName) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
loadComponent(componentName).then(component => {
|
||||||
|
nodeTypes.value[componentName] = markRaw(component)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析工作流数据
|
||||||
|
const parsedWorkflow = computed(() => {
|
||||||
|
if (!props.workflow) return null
|
||||||
|
|
||||||
|
try {
|
||||||
|
const workflow = { ...props.workflow }
|
||||||
|
|
||||||
|
// 解析actions
|
||||||
|
if (typeof workflow.actions === 'string') {
|
||||||
|
workflow.actions = JSON.parse(workflow.actions)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 解析flows
|
||||||
|
if (typeof workflow.flows === 'string') {
|
||||||
|
workflow.flows = JSON.parse(workflow.flows)
|
||||||
|
}
|
||||||
|
|
||||||
|
return workflow
|
||||||
|
} catch (error) {
|
||||||
|
console.error('解析工作流数据失败:', error)
|
||||||
|
return props.workflow
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// 初始化流程图数据
|
||||||
|
onMounted(() => {
|
||||||
|
if (parsedWorkflow.value) {
|
||||||
|
nodes.value = parsedWorkflow.value.actions ?? []
|
||||||
|
edges.value = parsedWorkflow.value.flows ?? []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// 复用工作流
|
// 复用工作流
|
||||||
async function doFork() {
|
async function doFork() {
|
||||||
// 开始处理
|
// 开始处理
|
||||||
@@ -46,14 +100,14 @@ async function doFork() {
|
|||||||
try {
|
try {
|
||||||
processing.value = true
|
processing.value = true
|
||||||
// 请求API
|
// 请求API
|
||||||
const result: { [key: string]: any } = await api.post('workflow/fork', props.media)
|
const result: { [key: string]: any } = await api.post('workflow/fork', props.workflow)
|
||||||
// 工作流状态
|
// 工作流状态
|
||||||
if (result.success) {
|
if (result.success) {
|
||||||
$toast.success(t('workflow.addSuccess', { name: props.media?.share_title }))
|
$toast.success(t('workflow.addSuccess', { name: props.workflow?.share_title }))
|
||||||
// 完成
|
// 完成
|
||||||
emit('fork', result.data.id)
|
emit('fork', result.data.id)
|
||||||
} else {
|
} else {
|
||||||
$toast.error(t('workflow.addFailed', { name: props.media?.share_title, message: result.message }))
|
$toast.error(t('workflow.addFailed', { name: props.workflow?.share_title, message: result.message }))
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error)
|
console.error(error)
|
||||||
@@ -70,7 +124,7 @@ async function doDelete() {
|
|||||||
try {
|
try {
|
||||||
deleting.value = true
|
deleting.value = true
|
||||||
// 请求API
|
// 请求API
|
||||||
const result: { [key: string]: any } = await api.delete(`workflow/share/${props.media?.id}`, {
|
const result: { [key: string]: any } = await api.delete(`workflow/share/${props.workflow?.id}`, {
|
||||||
params: {
|
params: {
|
||||||
share_uid: globalSettings.USER_UNIQUE_ID,
|
share_uid: globalSettings.USER_UNIQUE_ID,
|
||||||
},
|
},
|
||||||
@@ -98,35 +152,55 @@ async function doDelete() {
|
|||||||
<VCardText>
|
<VCardText>
|
||||||
<VCol>
|
<VCol>
|
||||||
<div class="d-flex justify-space-between flex-wrap flex-md-nowrap flex-column flex-md-row">
|
<div class="d-flex justify-space-between flex-wrap flex-md-nowrap flex-column flex-md-row">
|
||||||
|
<div class="ma-auto">
|
||||||
|
<div class="workflow-preview">
|
||||||
|
<VueFlow
|
||||||
|
:nodes="nodes"
|
||||||
|
:edges="edges"
|
||||||
|
:nodeTypes="nodeTypes"
|
||||||
|
:default-edge-options="{ type: 'animation', animated: true }"
|
||||||
|
:delete-key-code="null"
|
||||||
|
:select-nodes-on-drag="false"
|
||||||
|
:nodes-draggable="false"
|
||||||
|
:nodes-connectable="false"
|
||||||
|
:fit-view="true"
|
||||||
|
:fit-view-options="{ padding: 0.1, minZoom: 0.2, maxZoom: 1 }"
|
||||||
|
:default-viewport="{ x: 0, y: 0, zoom: 0.2 }"
|
||||||
|
class="workflow-preview-flow"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 右侧内容 -->
|
||||||
<div class="flex-grow">
|
<div class="flex-grow">
|
||||||
<VCardItem>
|
<VCardItem>
|
||||||
<VCardTitle
|
<VCardTitle
|
||||||
class="text-center text-md-left break-words whitespace-break-spaces line-clamp-2 overflow-hidden text-ellipsis"
|
class="text-center text-md-left break-words whitespace-break-spaces line-clamp-2 overflow-hidden text-ellipsis"
|
||||||
>
|
>
|
||||||
{{ props.media?.share_title }}
|
{{ props.workflow?.share_title }}
|
||||||
</VCardTitle>
|
</VCardTitle>
|
||||||
<VCardSubtitle
|
<VCardSubtitle
|
||||||
class="text-center text-md-left break-words whitespace-break-spaces line-clamp-4 overflow-hidden text-ellipsis"
|
class="text-center text-md-left break-words whitespace-break-spaces line-clamp-4 overflow-hidden text-ellipsis"
|
||||||
>
|
>
|
||||||
{{ props.media?.share_comment }}
|
{{ props.workflow?.share_comment }}
|
||||||
</VCardSubtitle>
|
</VCardSubtitle>
|
||||||
<VList lines="one">
|
<VList lines="one">
|
||||||
<VListItem class="ps-0">
|
<VListItem class="ps-0">
|
||||||
<VListItemTitle class="text-center text-md-left">
|
<VListItemTitle class="text-center text-md-left">
|
||||||
<span class="font-weight-medium">{{ t('workflow.sharer') }}:</span>
|
<span class="font-weight-medium">{{ t('workflow.sharer') }}:</span>
|
||||||
<span class="text-body-1"> {{ media?.share_user }}</span>
|
<span class="text-body-1"> {{ props.workflow?.share_user }}</span>
|
||||||
</VListItemTitle>
|
</VListItemTitle>
|
||||||
</VListItem>
|
</VListItem>
|
||||||
<VListItem class="ps-0" v-if="media?.timer">
|
<VListItem class="ps-0" v-if="props.workflow?.timer">
|
||||||
<VListItemTitle class="text-center text-md-left">
|
<VListItemTitle class="text-center text-md-left">
|
||||||
<span class="font-weight-medium">{{ t('workflow.timer') }}:</span>
|
<span class="font-weight-medium">{{ t('workflow.timer') }}:</span>
|
||||||
<span class="text-body-1"> {{ media?.timer }}</span>
|
<span class="text-body-1"> {{ props.workflow?.timer }}</span>
|
||||||
</VListItemTitle>
|
</VListItemTitle>
|
||||||
</VListItem>
|
</VListItem>
|
||||||
<VListItem class="ps-0" v-if="media?.actions">
|
<VListItem class="ps-0" v-if="parsedWorkflow?.actions">
|
||||||
<VListItemTitle class="text-center text-md-left">
|
<VListItemTitle class="text-center text-md-left">
|
||||||
<span class="font-weight-medium">{{ t('workflow.actionCount') }}:</span>
|
<span class="font-weight-medium">{{ t('workflow.actionCount') }}:</span>
|
||||||
<span class="text-body-1"> {{ media?.actions?.length }}</span>
|
<span class="text-body-1"> {{ parsedWorkflow?.actions?.length }}</span>
|
||||||
</VListItemTitle>
|
</VListItemTitle>
|
||||||
</VListItem>
|
</VListItem>
|
||||||
</VList>
|
</VList>
|
||||||
@@ -144,7 +218,7 @@ async function doDelete() {
|
|||||||
</VBtn>
|
</VBtn>
|
||||||
<VBtn
|
<VBtn
|
||||||
v-if="
|
v-if="
|
||||||
(props.media?.share_uid && props.media?.share_uid === globalSettings.USER_UNIQUE_ID) ||
|
(props.workflow?.share_uid && props.workflow?.share_uid === globalSettings.USER_UNIQUE_ID) ||
|
||||||
globalSettings.WORKFLOW_SHARE_MANAGE
|
globalSettings.WORKFLOW_SHARE_MANAGE
|
||||||
"
|
"
|
||||||
color="error"
|
color="error"
|
||||||
@@ -157,9 +231,9 @@ async function doDelete() {
|
|||||||
{{ t('workflow.cancelShare') }}
|
{{ t('workflow.cancelShare') }}
|
||||||
</VBtn>
|
</VBtn>
|
||||||
</div>
|
</div>
|
||||||
<div class="text-xs mt-2" v-if="props.media?.count">
|
<div class="text-xs mt-2" v-if="props.workflow?.count">
|
||||||
<VIcon icon="mdi-fire" />{{
|
<VIcon icon="mdi-fire" />{{
|
||||||
t('workflow.usageCount', { count: props.media?.count?.toLocaleString() })
|
t('workflow.usageCount', { count: props.workflow?.count?.toLocaleString() })
|
||||||
}}
|
}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -170,4 +244,72 @@ async function doDelete() {
|
|||||||
</VCardText>
|
</VCardText>
|
||||||
</VCard>
|
</VCard>
|
||||||
</VDialog>
|
</VDialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '@vue-flow/core/dist/style.css';
|
||||||
|
@import '@vue-flow/core/dist/theme-default.css';
|
||||||
|
@import '@vue-flow/minimap/dist/style.css';
|
||||||
|
|
||||||
|
.workflow-preview {
|
||||||
|
position: relative;
|
||||||
|
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);
|
||||||
|
block-size: 320px;
|
||||||
|
inline-size: 240px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.workflow-preview-flow {
|
||||||
|
block-size: 100%;
|
||||||
|
inline-size: 100%;
|
||||||
|
|
||||||
|
.vue-flow__node {
|
||||||
|
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||||
|
border-radius: 8px;
|
||||||
|
font-size: 10px;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
box-shadow: none;
|
||||||
|
transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.selected {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-flow__edge-path,
|
||||||
|
.vue-flow__connection-path {
|
||||||
|
stroke-width: 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vue-flow__handle {
|
||||||
|
border-radius: 2px;
|
||||||
|
block-size: 12px;
|
||||||
|
inline-size: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 自定义动作连线样式
|
||||||
|
.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: 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (width <= 600px) {
|
||||||
|
.workflow-preview {
|
||||||
|
block-size: 240px;
|
||||||
|
inline-size: 320px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -25,17 +25,23 @@ const shareDoing = ref(false)
|
|||||||
|
|
||||||
// 工作流分享表单
|
// 工作流分享表单
|
||||||
const shareForm = ref<WorkflowShare>({
|
const shareForm = ref<WorkflowShare>({
|
||||||
workflow_id: props.workflow?.id ?? '',
|
id: props.workflow?.id ?? '',
|
||||||
share_title: props.workflow?.name ?? '',
|
share_title: props.workflow?.name ?? '',
|
||||||
|
share_comment: '',
|
||||||
|
share_user: '',
|
||||||
})
|
})
|
||||||
|
|
||||||
// 监听props变化
|
// 监听props变化
|
||||||
watch(() => props.workflow, (newWorkflow) => {
|
watch(
|
||||||
if (newWorkflow) {
|
() => props.workflow,
|
||||||
shareForm.value.workflow_id = newWorkflow.id ?? ''
|
newWorkflow => {
|
||||||
shareForm.value.share_title = newWorkflow.name ?? ''
|
if (newWorkflow) {
|
||||||
}
|
shareForm.value.id = newWorkflow.id ?? ''
|
||||||
}, { immediate: true })
|
shareForm.value.share_title = newWorkflow.name ?? ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ immediate: true },
|
||||||
|
)
|
||||||
|
|
||||||
// 分享工作流
|
// 分享工作流
|
||||||
async function doShare() {
|
async function doShare() {
|
||||||
@@ -119,4 +125,4 @@ const $toast = useToast()
|
|||||||
</VCardActions>
|
</VCardActions>
|
||||||
</VCard>
|
</VCard>
|
||||||
</VDialog>
|
</VDialog>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.grid-workflow-share-card {
|
.grid-workflow-share-card {
|
||||||
grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
.v-tabs:not(.v-tabs-pill).v-tabs--horizontal {
|
.v-tabs:not(.v-tabs-pill).v-tabs--horizontal {
|
||||||
|
|||||||
@@ -113,9 +113,13 @@ async function fetchData({ done }: { done: any }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 将数据从列表中移除
|
// 将数据从列表中移除
|
||||||
function removeData(id: number) {
|
function removeData(id: string) {
|
||||||
dataList.value = dataList.value.filter(item => item.id !== id)
|
dataList.value = dataList.value.filter(item => item.id !== id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onActivated(() => {
|
||||||
|
fetchData({ done: () => {} })
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -126,7 +130,7 @@ function removeData(id: number) {
|
|||||||
<template #empty />
|
<template #empty />
|
||||||
<div v-if="dataList.length > 0" class="grid gap-4 grid-workflow-share-card" tabindex="0">
|
<div v-if="dataList.length > 0" class="grid gap-4 grid-workflow-share-card" tabindex="0">
|
||||||
<div v-for="data in dataList" :key="data.id">
|
<div v-for="data in dataList" :key="data.id">
|
||||||
<WorkflowShareCard :media="data" @delete="removeData(data.id || 0)" />
|
<WorkflowShareCard :workflow="data" @delete="removeData(data.id || '')" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<NoDataFound
|
<NoDataFound
|
||||||
@@ -136,4 +140,4 @@ function removeData(id: number) {
|
|||||||
:error-description="keyword ? t('common.noContent') : t('workflow.noShareData')"
|
:error-description="keyword ? t('common.noContent') : t('workflow.noShareData')"
|
||||||
/>
|
/>
|
||||||
</VInfiniteScroll>
|
</VInfiniteScroll>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
Reference in New Issue
Block a user