mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-07 00:36:41 +08:00
Add workflow sharing functionality (#371)
* Add workflow sharing feature with share, fork, and browse functionality Co-authored-by: jxxghp <jxxghp@163.com> * Refactor workflow page with dynamic tabs and internationalization support Co-authored-by: jxxghp <jxxghp@163.com> * Remove workflow share implementation documentation Co-authored-by: jxxghp <jxxghp@163.com> * Fix indentation and structure in Chinese locale files Co-authored-by: jxxghp <jxxghp@163.com> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com>
This commit is contained in:
co-authored by
jxxghp
Cursor Agent
parent
f2bc832aca
commit
35332544e4
@@ -144,6 +144,38 @@ export interface SubscribeShare {
|
|||||||
episode_group?: string
|
episode_group?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 工作流分享
|
||||||
|
export interface WorkflowShare {
|
||||||
|
// 分享ID
|
||||||
|
id?: number
|
||||||
|
// 工作流ID
|
||||||
|
workflow_id?: string
|
||||||
|
// 分享标题
|
||||||
|
share_title?: string
|
||||||
|
// 分享说明
|
||||||
|
share_comment?: string
|
||||||
|
// 分享人
|
||||||
|
share_user?: string
|
||||||
|
// 分享人唯一ID
|
||||||
|
share_uid?: string
|
||||||
|
// 工作流名称
|
||||||
|
name?: string
|
||||||
|
// 工作流描述
|
||||||
|
description?: string
|
||||||
|
// 定时器
|
||||||
|
timer?: string
|
||||||
|
// 动作列表
|
||||||
|
actions?: any[]
|
||||||
|
// 动作流
|
||||||
|
flows?: any[]
|
||||||
|
// 上下文
|
||||||
|
context?: string
|
||||||
|
// 时间
|
||||||
|
date?: string
|
||||||
|
// 复用次数
|
||||||
|
count?: number
|
||||||
|
}
|
||||||
|
|
||||||
// 历史记录
|
// 历史记录
|
||||||
export interface TransferHistory {
|
export interface TransferHistory {
|
||||||
// ID
|
// ID
|
||||||
|
|||||||
@@ -0,0 +1,121 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { formatDateDifference } from '@/@core/utils/formatters'
|
||||||
|
import type { WorkflowShare } from '@/api/types'
|
||||||
|
import WorkflowEditDialog from '../dialog/WorkflowAddEditDialog.vue'
|
||||||
|
import ForkWorkflowDialog from '../dialog/ForkWorkflowDialog.vue'
|
||||||
|
import { useGlobalSettingsStore } from '@/stores'
|
||||||
|
|
||||||
|
// 输入参数
|
||||||
|
const props = defineProps({
|
||||||
|
media: Object as PropType<WorkflowShare>,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 定义删除事件
|
||||||
|
const emit = defineEmits(['delete'])
|
||||||
|
|
||||||
|
// 从 provide 中获取全局设置
|
||||||
|
// 全局设置
|
||||||
|
const globalSettingsStore = useGlobalSettingsStore()
|
||||||
|
const globalSettings = globalSettingsStore.globalSettings
|
||||||
|
|
||||||
|
// 工作流编辑弹窗
|
||||||
|
const workflowEditDialog = ref(false)
|
||||||
|
|
||||||
|
// 复用工作流弹窗
|
||||||
|
const forkWorkflowDialog = ref(false)
|
||||||
|
|
||||||
|
// 工作流ID
|
||||||
|
const workflowId = ref<string>()
|
||||||
|
|
||||||
|
// 分享时间
|
||||||
|
const dateText = ref(props.media && props.media?.date ? formatDateDifference(props.media.date) : '')
|
||||||
|
|
||||||
|
// 复用工作流
|
||||||
|
function showForkWorkflow() {
|
||||||
|
forkWorkflowDialog.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 完成复用工作流
|
||||||
|
function finishForkWorkflow(wid: string) {
|
||||||
|
workflowId.value = wid
|
||||||
|
forkWorkflowDialog.value = false
|
||||||
|
workflowEditDialog.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除工作流分享时处理
|
||||||
|
function doDelete() {
|
||||||
|
forkWorkflowDialog.value = false
|
||||||
|
// 通知父组件刷新
|
||||||
|
emit('delete')
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="h-full">
|
||||||
|
<VHover>
|
||||||
|
<template #default="hover">
|
||||||
|
<div
|
||||||
|
class="w-full h-full rounded-lg overflow-hidden"
|
||||||
|
:class="{
|
||||||
|
'transition transform-cpu duration-300 -translate-y-1': hover.isHovering,
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<VCard
|
||||||
|
v-bind="hover.props"
|
||||||
|
:key="props.media?.id"
|
||||||
|
class="flex flex-col h-full"
|
||||||
|
rounded="0"
|
||||||
|
min-height="150"
|
||||||
|
@click="showForkWorkflow"
|
||||||
|
>
|
||||||
|
<div class="h-full flex flex-col">
|
||||||
|
<VCardText class="flex items-center pa-3 pb-1 grow">
|
||||||
|
<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 ...">
|
||||||
|
{{ props.media?.share_title }}
|
||||||
|
</div>
|
||||||
|
<div class="text-sm font-medium text-gray-600 sm:pt-1 line-clamp-3 overflow-hidden text-ellipsis ...">
|
||||||
|
{{ props.media?.share_comment }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
<VCardText class="flex justify-space-between align-center flex-wrap py-2">
|
||||||
|
<div class="flex align-center">
|
||||||
|
<IconBtn v-bind="props" icon="mdi-account" class="me-1" />
|
||||||
|
<div class="text-subtitle-2 me-4">
|
||||||
|
{{ props.media?.share_user }}
|
||||||
|
</div>
|
||||||
|
<IconBtn v-if="props.media?.count" icon="mdi-fire" class="me-1" />
|
||||||
|
<span v-if="props.media?.count" class="text-subtitle-2 me-4">
|
||||||
|
{{ props.media?.count.toLocaleString() }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</VCardText>
|
||||||
|
<VCardText class="absolute right-0 bottom-0 d-flex align-center p-2 text-gray-500">
|
||||||
|
<VIcon icon="mdi-calendar" class="me-1" />
|
||||||
|
{{ dateText }}
|
||||||
|
</VCardText>
|
||||||
|
</div>
|
||||||
|
</VCard>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</VHover>
|
||||||
|
<!-- 工作流编辑弹窗 -->
|
||||||
|
<WorkflowEditDialog
|
||||||
|
v-if="workflowEditDialog"
|
||||||
|
v-model="workflowEditDialog"
|
||||||
|
:workflow="workflowId ? { id: workflowId } : undefined"
|
||||||
|
@close="workflowEditDialog = false"
|
||||||
|
@save="workflowEditDialog = false"
|
||||||
|
@remove="workflowEditDialog = false"
|
||||||
|
/>
|
||||||
|
<!-- 复用工作流弹窗 -->
|
||||||
|
<ForkWorkflowDialog
|
||||||
|
v-if="forkWorkflowDialog"
|
||||||
|
:media="props.media"
|
||||||
|
@close="forkWorkflowDialog = false"
|
||||||
|
@fork="finishForkWorkflow"
|
||||||
|
@delete="doDelete"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
@@ -4,6 +4,7 @@ import { useToast } from 'vue-toastification'
|
|||||||
import { useConfirm } from '@/composables/useConfirm'
|
import { useConfirm } from '@/composables/useConfirm'
|
||||||
import WorkflowAddEditDialog from '@/components/dialog/WorkflowAddEditDialog.vue'
|
import WorkflowAddEditDialog from '@/components/dialog/WorkflowAddEditDialog.vue'
|
||||||
import WorkflowActionsDialog from '@/components/dialog/WorkflowActionsDialog.vue'
|
import WorkflowActionsDialog from '@/components/dialog/WorkflowActionsDialog.vue'
|
||||||
|
import WorkflowShareDialog from '@/components/dialog/WorkflowShareDialog.vue'
|
||||||
import api from '@/api'
|
import api from '@/api'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
@@ -32,6 +33,9 @@ const editDialog = ref(false)
|
|||||||
// 流程对话框
|
// 流程对话框
|
||||||
const flowDialog = ref(false)
|
const flowDialog = ref(false)
|
||||||
|
|
||||||
|
// 分享对话框
|
||||||
|
const shareDialog = ref(false)
|
||||||
|
|
||||||
// 加载中
|
// 加载中
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
|
|
||||||
@@ -45,10 +49,16 @@ function handleFlow(item: Workflow) {
|
|||||||
flowDialog.value = true
|
flowDialog.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 分享工作流
|
||||||
|
function handleShare(item: Workflow) {
|
||||||
|
shareDialog.value = true
|
||||||
|
}
|
||||||
|
|
||||||
// 编辑完成
|
// 编辑完成
|
||||||
function editDone() {
|
function editDone() {
|
||||||
editDialog.value = false
|
editDialog.value = false
|
||||||
flowDialog.value = false
|
flowDialog.value = false
|
||||||
|
shareDialog.value = false
|
||||||
emit('refresh')
|
emit('refresh')
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,6 +250,12 @@ const resolveProgress = (item: Workflow) => {
|
|||||||
</template>
|
</template>
|
||||||
<VListItemTitle>{{ t('workflow.task.reset') }}</VListItemTitle>
|
<VListItemTitle>{{ t('workflow.task.reset') }}</VListItemTitle>
|
||||||
</VListItem>
|
</VListItem>
|
||||||
|
<VListItem base-color="info" @click="handleShare(workflow)">
|
||||||
|
<template #prepend>
|
||||||
|
<VIcon icon="mdi-share" />
|
||||||
|
</template>
|
||||||
|
<VListItemTitle>{{ t('workflow.task.share') }}</VListItemTitle>
|
||||||
|
</VListItem>
|
||||||
<VListItem base-color="error" @click="handleDelete(workflow)">
|
<VListItem base-color="error" @click="handleDelete(workflow)">
|
||||||
<template #prepend>
|
<template #prepend>
|
||||||
<VIcon icon="mdi-delete" />
|
<VIcon icon="mdi-delete" />
|
||||||
@@ -317,5 +333,11 @@ const resolveProgress = (item: Workflow) => {
|
|||||||
@save="editDone"
|
@save="editDone"
|
||||||
:workflow="workflow"
|
:workflow="workflow"
|
||||||
/>
|
/>
|
||||||
|
<!-- 分享对话框 -->
|
||||||
|
<WorkflowShareDialog
|
||||||
|
v-if="shareDialog"
|
||||||
|
:workflow="workflow"
|
||||||
|
@close="shareDialog = false"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -0,0 +1,173 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import api from '@/api'
|
||||||
|
import { doneNProgress, startNProgress } from '@/api/nprogress'
|
||||||
|
import { WorkflowShare } from '@/api/types'
|
||||||
|
import { useToast } from 'vue-toastification'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { useGlobalSettingsStore } from '@/stores'
|
||||||
|
|
||||||
|
// 国际化
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
// 输入参数
|
||||||
|
const props = defineProps({
|
||||||
|
media: Object as PropType<WorkflowShare>,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 定义事件
|
||||||
|
const emit = defineEmits(['fork', 'delete', 'close'])
|
||||||
|
|
||||||
|
// 从 provide 中获取全局设置
|
||||||
|
// 全局设置
|
||||||
|
const globalSettingsStore = useGlobalSettingsStore()
|
||||||
|
const globalSettings = globalSettingsStore.globalSettings
|
||||||
|
|
||||||
|
// 提示框
|
||||||
|
const $toast = useToast()
|
||||||
|
|
||||||
|
// 处理中
|
||||||
|
const processing = ref(false)
|
||||||
|
|
||||||
|
// 删除中
|
||||||
|
const deleting = ref(false)
|
||||||
|
|
||||||
|
// 是否折叠
|
||||||
|
const isExpanded = ref(false)
|
||||||
|
|
||||||
|
// 折叠展开
|
||||||
|
function toggleExpand() {
|
||||||
|
isExpanded.value = !isExpanded.value
|
||||||
|
}
|
||||||
|
|
||||||
|
// 复用工作流
|
||||||
|
async function doFork() {
|
||||||
|
// 开始处理
|
||||||
|
startNProgress()
|
||||||
|
try {
|
||||||
|
processing.value = true
|
||||||
|
// 请求API
|
||||||
|
const result: { [key: string]: any } = await api.post('workflow/fork', props.media)
|
||||||
|
// 工作流状态
|
||||||
|
if (result.success) {
|
||||||
|
$toast.success(t('workflow.addSuccess', { name: props.media?.share_title }))
|
||||||
|
// 完成
|
||||||
|
emit('fork', result.data.id)
|
||||||
|
} else {
|
||||||
|
$toast.error(t('workflow.addFailed', { name: props.media?.share_title, message: result.message }))
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
} finally {
|
||||||
|
processing.value = false
|
||||||
|
doneNProgress()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除工作流分享
|
||||||
|
async function doDelete() {
|
||||||
|
// 开始处理
|
||||||
|
startNProgress()
|
||||||
|
try {
|
||||||
|
deleting.value = true
|
||||||
|
// 请求API
|
||||||
|
const result: { [key: string]: any } = await api.delete(`workflow/share/${props.media?.id}`, {
|
||||||
|
params: {
|
||||||
|
share_uid: globalSettings.USER_UNIQUE_ID,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
// 工作流状态
|
||||||
|
if (result.success) {
|
||||||
|
$toast.success(t('workflow.cancelSuccess'))
|
||||||
|
// 完成
|
||||||
|
emit('delete', result.data.id)
|
||||||
|
} else {
|
||||||
|
$toast.error(t('workflow.cancelFailed', { message: result.message }))
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
} finally {
|
||||||
|
deleting.value = false
|
||||||
|
doneNProgress()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<VDialog max-width="40rem" scrollable>
|
||||||
|
<VCard>
|
||||||
|
<VDialogCloseBtn @click="emit('close')" />
|
||||||
|
<VCardText>
|
||||||
|
<VCol>
|
||||||
|
<div class="d-flex justify-space-between flex-wrap flex-md-nowrap flex-column flex-md-row">
|
||||||
|
<div class="flex-grow">
|
||||||
|
<VCardItem>
|
||||||
|
<VCardTitle
|
||||||
|
class="text-center text-md-left break-words whitespace-break-spaces line-clamp-2 overflow-hidden text-ellipsis"
|
||||||
|
>
|
||||||
|
{{ props.media?.share_title }}
|
||||||
|
</VCardTitle>
|
||||||
|
<VCardSubtitle
|
||||||
|
class="text-center text-md-left break-words whitespace-break-spaces line-clamp-4 overflow-hidden text-ellipsis"
|
||||||
|
>
|
||||||
|
{{ props.media?.share_comment }}
|
||||||
|
</VCardSubtitle>
|
||||||
|
<VList lines="one">
|
||||||
|
<VListItem class="ps-0">
|
||||||
|
<VListItemTitle class="text-center text-md-left">
|
||||||
|
<span class="font-weight-medium">{{ t('workflow.sharer') }}:</span>
|
||||||
|
<span class="text-body-1"> {{ media?.share_user }}</span>
|
||||||
|
</VListItemTitle>
|
||||||
|
</VListItem>
|
||||||
|
<VListItem class="ps-0" v-if="media?.timer">
|
||||||
|
<VListItemTitle class="text-center text-md-left">
|
||||||
|
<span class="font-weight-medium">{{ t('workflow.timer') }}:</span>
|
||||||
|
<span class="text-body-1"> {{ media?.timer }}</span>
|
||||||
|
</VListItemTitle>
|
||||||
|
</VListItem>
|
||||||
|
<VListItem class="ps-0" v-if="media?.actions">
|
||||||
|
<VListItemTitle class="text-center text-md-left">
|
||||||
|
<span class="font-weight-medium">{{ t('workflow.actionCount') }}:</span>
|
||||||
|
<span class="text-body-1"> {{ media?.actions?.length }}</span>
|
||||||
|
</VListItemTitle>
|
||||||
|
</VListItem>
|
||||||
|
</VList>
|
||||||
|
<div class="text-center text-md-left">
|
||||||
|
<div>
|
||||||
|
<VBtn
|
||||||
|
color="primary"
|
||||||
|
:disabled="processing"
|
||||||
|
@click="doFork"
|
||||||
|
prepend-icon="mdi-heart"
|
||||||
|
:loading="processing"
|
||||||
|
class="mb-2 me-2"
|
||||||
|
>
|
||||||
|
{{ t('workflow.normalFork') }}
|
||||||
|
</VBtn>
|
||||||
|
<VBtn
|
||||||
|
v-if="
|
||||||
|
(props.media?.share_uid && props.media?.share_uid === globalSettings.USER_UNIQUE_ID) ||
|
||||||
|
globalSettings.WORKFLOW_SHARE_MANAGE
|
||||||
|
"
|
||||||
|
color="error"
|
||||||
|
:disabled="deleting"
|
||||||
|
@click="doDelete"
|
||||||
|
prepend-icon="mdi-delete"
|
||||||
|
:loading="deleting"
|
||||||
|
class="mb-2 me-2"
|
||||||
|
>
|
||||||
|
{{ t('workflow.cancelShare') }}
|
||||||
|
</VBtn>
|
||||||
|
</div>
|
||||||
|
<div class="text-xs mt-2" v-if="props.media?.count">
|
||||||
|
<VIcon icon="mdi-fire" />{{
|
||||||
|
t('workflow.usageCount', { count: props.media?.count?.toLocaleString() })
|
||||||
|
}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</VCardItem>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</VCol>
|
||||||
|
</VCardText>
|
||||||
|
</VCard>
|
||||||
|
</VDialog>
|
||||||
|
</template>
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { useToast } from 'vue-toastification'
|
||||||
|
import { requiredValidator } from '@/@validators'
|
||||||
|
import api from '@/api'
|
||||||
|
import type { Workflow, WorkflowShare } from '@/api/types'
|
||||||
|
import { useDisplay } from 'vuetify'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
// 多语言支持
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
// 显示器宽度
|
||||||
|
const display = useDisplay()
|
||||||
|
|
||||||
|
// 输入参数
|
||||||
|
const props = defineProps({
|
||||||
|
workflow: Object as PropType<Workflow>,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 定义触发的自定义事件
|
||||||
|
const emit = defineEmits(['close'])
|
||||||
|
|
||||||
|
// 分享处理状态
|
||||||
|
const shareDoing = ref(false)
|
||||||
|
|
||||||
|
// 工作流分享表单
|
||||||
|
const shareForm = ref<WorkflowShare>({
|
||||||
|
workflow_id: props.workflow?.id ?? '',
|
||||||
|
share_title: props.workflow?.name ?? '',
|
||||||
|
})
|
||||||
|
|
||||||
|
// 监听props变化
|
||||||
|
watch(() => props.workflow, (newWorkflow) => {
|
||||||
|
if (newWorkflow) {
|
||||||
|
shareForm.value.workflow_id = newWorkflow.id ?? ''
|
||||||
|
shareForm.value.share_title = newWorkflow.name ?? ''
|
||||||
|
}
|
||||||
|
}, { immediate: true })
|
||||||
|
|
||||||
|
// 分享工作流
|
||||||
|
async function doShare() {
|
||||||
|
if (!shareForm.value.share_title || !shareForm.value.share_comment || !shareForm.value.share_user) return
|
||||||
|
try {
|
||||||
|
shareDoing.value = true
|
||||||
|
const result: { [key: string]: any } = await api.post('workflow/share', shareForm.value)
|
||||||
|
shareDoing.value = false
|
||||||
|
// 提示
|
||||||
|
if (result.success) {
|
||||||
|
$toast.success(t('dialog.workflowShare.shareSuccess', { name: props.workflow?.name }))
|
||||||
|
// 通知父组件刷新
|
||||||
|
emit('close')
|
||||||
|
} else {
|
||||||
|
$toast.error(t('dialog.workflowShare.shareFailed', { name: props.workflow?.name, message: result.message }))
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 提示框
|
||||||
|
const $toast = useToast()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VDialog scrollable max-width="30rem" :fullscreen="!display.mdAndUp.value">
|
||||||
|
<VCard>
|
||||||
|
<VCardItem class="py-2">
|
||||||
|
<template #prepend>
|
||||||
|
<VIcon icon="mdi-share-outline" class="me-2" />
|
||||||
|
</template>
|
||||||
|
<VCardTitle>{{ t('dialog.workflowShare.shareWorkflow') }}</VCardTitle>
|
||||||
|
<VCardSubtitle>
|
||||||
|
{{ props.workflow?.name }}
|
||||||
|
</VCardSubtitle>
|
||||||
|
</VCardItem>
|
||||||
|
<VDivider />
|
||||||
|
<VCardText>
|
||||||
|
<VDialogCloseBtn @click="emit('close')" />
|
||||||
|
<VForm @submit.prevent="() => {}" class="pt-2">
|
||||||
|
<VRow>
|
||||||
|
<VCol cols="12">
|
||||||
|
<VTextField
|
||||||
|
v-model="shareForm.share_title"
|
||||||
|
readonly
|
||||||
|
:label="t('dialog.workflowShare.title')"
|
||||||
|
:rules="[requiredValidator]"
|
||||||
|
persistent-hint
|
||||||
|
prepend-inner-icon="mdi-format-title"
|
||||||
|
/>
|
||||||
|
</VCol>
|
||||||
|
<VCol cols="12">
|
||||||
|
<VTextarea
|
||||||
|
v-model="shareForm.share_comment"
|
||||||
|
:label="t('dialog.workflowShare.description')"
|
||||||
|
:rules="[requiredValidator]"
|
||||||
|
:hint="t('dialog.workflowShare.descriptionHint')"
|
||||||
|
persistent-hint
|
||||||
|
prepend-inner-icon="mdi-comment-text-outline"
|
||||||
|
/>
|
||||||
|
</VCol>
|
||||||
|
<VCol cols="12">
|
||||||
|
<VTextField
|
||||||
|
v-model="shareForm.share_user"
|
||||||
|
:label="t('dialog.workflowShare.shareUser')"
|
||||||
|
:rules="[requiredValidator]"
|
||||||
|
:hint="t('dialog.workflowShare.shareUserHint')"
|
||||||
|
persistent-hint
|
||||||
|
prepend-inner-icon="mdi-account-outline"
|
||||||
|
/>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</VForm>
|
||||||
|
</VCardText>
|
||||||
|
<VCardActions class="pt-3">
|
||||||
|
<VSpacer />
|
||||||
|
<VBtn :disabled="shareDoing" @click="doShare" prepend-icon="mdi-share" class="px-5" :loading="shareDoing">
|
||||||
|
{{ t('dialog.workflowShare.confirmShare') }}
|
||||||
|
</VBtn>
|
||||||
|
</VCardActions>
|
||||||
|
</VCard>
|
||||||
|
</VDialog>
|
||||||
|
</template>
|
||||||
@@ -329,6 +329,10 @@ export default {
|
|||||||
share: 'Subscription Shares',
|
share: 'Subscription Shares',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
workflowTabs: {
|
||||||
|
list: 'Workflow',
|
||||||
|
share: 'Workflow Share',
|
||||||
|
},
|
||||||
pluginTabs: {
|
pluginTabs: {
|
||||||
installed: 'My Plugins',
|
installed: 'My Plugins',
|
||||||
market: 'Plugin Market',
|
market: 'Plugin Market',
|
||||||
@@ -488,6 +492,7 @@ export default {
|
|||||||
dragComponentHint: 'Drag component to canvas',
|
dragComponentHint: 'Drag component to canvas',
|
||||||
task: {
|
task: {
|
||||||
edit: 'Edit Task',
|
edit: 'Edit Task',
|
||||||
|
share: 'Share',
|
||||||
continue: 'Continue',
|
continue: 'Continue',
|
||||||
restart: 'Restart',
|
restart: 'Restart',
|
||||||
run: 'Run Now',
|
run: 'Run Now',
|
||||||
@@ -655,6 +660,19 @@ export default {
|
|||||||
loadPluginSettingFailed: 'Failed to load plugin settings',
|
loadPluginSettingFailed: 'Failed to load plugin settings',
|
||||||
},
|
},
|
||||||
title: 'Workflow',
|
title: 'Workflow',
|
||||||
|
share: 'Workflow Share',
|
||||||
|
searchShares: 'Search Workflow Shares',
|
||||||
|
noShareData: 'No shared workflows',
|
||||||
|
sharer: 'Sharer',
|
||||||
|
timer: 'Timer',
|
||||||
|
actionCount: 'Action Count',
|
||||||
|
normalFork: 'Fork Workflow',
|
||||||
|
cancelShare: 'Cancel Share',
|
||||||
|
cancelSuccess: 'Share cancelled successfully',
|
||||||
|
cancelFailed: 'Failed to cancel share: {message}',
|
||||||
|
usageCount: 'Used {count} times',
|
||||||
|
addSuccess: 'Forked {name} successfully!',
|
||||||
|
addFailed: 'Failed to fork {name}: {message}',
|
||||||
noWorkflow: 'No Workflow',
|
noWorkflow: 'No Workflow',
|
||||||
noWorkflowDescription: 'Click the add button to create a workflow task.',
|
noWorkflowDescription: 'Click the add button to create a workflow task.',
|
||||||
},
|
},
|
||||||
@@ -1730,6 +1748,18 @@ export default {
|
|||||||
shareSuccess: '{name} shared successfully!',
|
shareSuccess: '{name} shared successfully!',
|
||||||
shareFailed: '{name} share failed: {message}!',
|
shareFailed: '{name} share failed: {message}!',
|
||||||
},
|
},
|
||||||
|
workflowShare: {
|
||||||
|
shareWorkflow: 'Share Workflow',
|
||||||
|
title: 'Title',
|
||||||
|
description: 'Description',
|
||||||
|
descriptionHint:
|
||||||
|
'Add a description about this workflow. Actions and flows will be included in the share by default',
|
||||||
|
shareUser: 'Share User',
|
||||||
|
shareUserHint: "Sharer's nickname",
|
||||||
|
confirmShare: 'Confirm Share',
|
||||||
|
shareSuccess: '{name} shared successfully!',
|
||||||
|
shareFailed: '{name} share failed: {message}!',
|
||||||
|
},
|
||||||
u115Auth: {
|
u115Auth: {
|
||||||
loginTitle: '115 Cloud Login',
|
loginTitle: '115 Cloud Login',
|
||||||
scanQrCode: 'Please scan with WeChat or 115 client',
|
scanQrCode: 'Please scan with WeChat or 115 client',
|
||||||
|
|||||||
@@ -328,6 +328,10 @@ export default {
|
|||||||
share: '订阅分享',
|
share: '订阅分享',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
workflowTabs: {
|
||||||
|
list: '工作流',
|
||||||
|
share: '工作流分享',
|
||||||
|
},
|
||||||
pluginTabs: {
|
pluginTabs: {
|
||||||
installed: '我的插件',
|
installed: '我的插件',
|
||||||
market: '插件市场',
|
market: '插件市场',
|
||||||
@@ -486,6 +490,7 @@ export default {
|
|||||||
dragComponentHint: '拖动组件到画布',
|
dragComponentHint: '拖动组件到画布',
|
||||||
task: {
|
task: {
|
||||||
edit: '编辑任务',
|
edit: '编辑任务',
|
||||||
|
share: '分享',
|
||||||
continue: '继续执行',
|
continue: '继续执行',
|
||||||
restart: '重新执行',
|
restart: '重新执行',
|
||||||
run: '立即执行',
|
run: '立即执行',
|
||||||
@@ -653,6 +658,19 @@ export default {
|
|||||||
loadPluginSettingFailed: '加载插件设置失败',
|
loadPluginSettingFailed: '加载插件设置失败',
|
||||||
},
|
},
|
||||||
title: '工作流',
|
title: '工作流',
|
||||||
|
share: '工作流分享',
|
||||||
|
searchShares: '搜索工作流分享',
|
||||||
|
noShareData: '暂无分享的工作流',
|
||||||
|
sharer: '分享人',
|
||||||
|
timer: '定时器',
|
||||||
|
actionCount: '动作数量',
|
||||||
|
normalFork: '复用工作流',
|
||||||
|
cancelShare: '取消分享',
|
||||||
|
cancelSuccess: '取消分享成功',
|
||||||
|
cancelFailed: '取消分享失败:{message}',
|
||||||
|
usageCount: '复用 {count} 次',
|
||||||
|
addSuccess: '复用 {name} 成功!',
|
||||||
|
addFailed: '复用 {name} 失败:{message}',
|
||||||
noWorkflow: '没有工作流',
|
noWorkflow: '没有工作流',
|
||||||
noWorkflowDescription: '点击添加按钮创建工作流任务。',
|
noWorkflowDescription: '点击添加按钮创建工作流任务。',
|
||||||
},
|
},
|
||||||
@@ -1709,6 +1727,17 @@ export default {
|
|||||||
shareSuccess: '{name} 分享成功!',
|
shareSuccess: '{name} 分享成功!',
|
||||||
shareFailed: '{name} 分享失败:{message}!',
|
shareFailed: '{name} 分享失败:{message}!',
|
||||||
},
|
},
|
||||||
|
workflowShare: {
|
||||||
|
shareWorkflow: '分享工作流',
|
||||||
|
title: '标题',
|
||||||
|
description: '说明',
|
||||||
|
descriptionHint: '填写关于该工作流的说明,工作流的动作和流程将会默认包含在分享中',
|
||||||
|
shareUser: '分享用户',
|
||||||
|
shareUserHint: '分享人的昵称',
|
||||||
|
confirmShare: '确认分享',
|
||||||
|
shareSuccess: '{name} 分享成功!',
|
||||||
|
shareFailed: '{name} 分享失败:{message}!',
|
||||||
|
},
|
||||||
u115Auth: {
|
u115Auth: {
|
||||||
loginTitle: '115网盘登录',
|
loginTitle: '115网盘登录',
|
||||||
scanQrCode: '请使用微信或115客户端扫码',
|
scanQrCode: '请使用微信或115客户端扫码',
|
||||||
|
|||||||
@@ -329,6 +329,10 @@ export default {
|
|||||||
share: '訂閱分享',
|
share: '訂閱分享',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
workflowTabs: {
|
||||||
|
list: '工作流',
|
||||||
|
share: '工作流分享',
|
||||||
|
},
|
||||||
pluginTabs: {
|
pluginTabs: {
|
||||||
installed: '我的插件',
|
installed: '我的插件',
|
||||||
market: '插件市場',
|
market: '插件市場',
|
||||||
@@ -484,6 +488,7 @@ export default {
|
|||||||
dragComponentHint: '拖曳組件到畫布',
|
dragComponentHint: '拖曳組件到畫布',
|
||||||
task: {
|
task: {
|
||||||
edit: '編輯任務',
|
edit: '編輯任務',
|
||||||
|
share: '分享',
|
||||||
continue: '繼續',
|
continue: '繼續',
|
||||||
restart: '重新開始',
|
restart: '重新開始',
|
||||||
run: '立即執行',
|
run: '立即執行',
|
||||||
@@ -651,6 +656,19 @@ export default {
|
|||||||
loadPluginSettingFailed: '加載插件設置失敗',
|
loadPluginSettingFailed: '加載插件設置失敗',
|
||||||
},
|
},
|
||||||
title: '工作流',
|
title: '工作流',
|
||||||
|
share: '工作流分享',
|
||||||
|
searchShares: '搜索工作流分享',
|
||||||
|
noShareData: '暫無分享的工作流',
|
||||||
|
sharer: '分享人',
|
||||||
|
timer: '定時器',
|
||||||
|
actionCount: '動作數量',
|
||||||
|
normalFork: '復用工作流',
|
||||||
|
cancelShare: '取消分享',
|
||||||
|
cancelSuccess: '取消分享成功',
|
||||||
|
cancelFailed: '取消分享失敗:{message}',
|
||||||
|
usageCount: '復用 {count} 次',
|
||||||
|
addSuccess: '復用 {name} 成功!',
|
||||||
|
addFailed: '復用 {name} 失敗:{message}',
|
||||||
noWorkflow: '沒有工作流',
|
noWorkflow: '沒有工作流',
|
||||||
noWorkflowDescription: '點擊添加按鈕創建工作流任務。',
|
noWorkflowDescription: '點擊添加按鈕創建工作流任務。',
|
||||||
},
|
},
|
||||||
@@ -1708,6 +1726,17 @@ export default {
|
|||||||
shareSuccess: '{name} 分享成功!',
|
shareSuccess: '{name} 分享成功!',
|
||||||
shareFailed: '{name} 分享失敗:{message}!',
|
shareFailed: '{name} 分享失敗:{message}!',
|
||||||
},
|
},
|
||||||
|
workflowShare: {
|
||||||
|
shareWorkflow: '分享工作流',
|
||||||
|
title: '標題',
|
||||||
|
description: '說明',
|
||||||
|
descriptionHint: '填寫關於該工作流的說明,工作流的動作和流程將會默認包含在分享中',
|
||||||
|
shareUser: '分享用戶',
|
||||||
|
shareUserHint: '分享人的暱稱',
|
||||||
|
confirmShare: '確認分享',
|
||||||
|
shareSuccess: '{name} 分享成功!',
|
||||||
|
shareFailed: '{name} 分享失敗:{message}!',
|
||||||
|
},
|
||||||
u115Auth: {
|
u115Auth: {
|
||||||
loginTitle: '115網盤登錄',
|
loginTitle: '115網盤登錄',
|
||||||
scanQrCode: '請使用微信或115客戶端掃碼',
|
scanQrCode: '請使用微信或115客戶端掃碼',
|
||||||
|
|||||||
+125
-1
@@ -1,9 +1,133 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import WorkflowListView from '@/views/workflow/WorkflowListView.vue'
|
import WorkflowListView from '@/views/workflow/WorkflowListView.vue'
|
||||||
|
import WorkflowShareView from '@/views/workflow/WorkflowShareView.vue'
|
||||||
|
import WorkflowAddEditDialog from '@/components/dialog/WorkflowAddEditDialog.vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { useDynamicHeaderTab } from '@/composables/useDynamicHeaderTab'
|
||||||
|
import { getWorkflowTabs } from '@/router/i18n-menu'
|
||||||
|
|
||||||
|
// 国际化
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
const activeTab = ref((route.query.tab as string) || '')
|
||||||
|
const shareViewKey = ref(0)
|
||||||
|
|
||||||
|
// 获取标签页
|
||||||
|
const workflowTabs = computed(() => {
|
||||||
|
return getWorkflowTabs()
|
||||||
|
})
|
||||||
|
|
||||||
|
// 新增工作流对话框
|
||||||
|
const addWorkflowDialog = ref(false)
|
||||||
|
|
||||||
|
// 工作流列表刷新key
|
||||||
|
const workflowListKey = ref(0)
|
||||||
|
|
||||||
|
// 分享搜索词
|
||||||
|
const shareKeyword = ref('')
|
||||||
|
|
||||||
|
// 搜索分享
|
||||||
|
const searchShares = () => {
|
||||||
|
shareViewKey.value++
|
||||||
|
}
|
||||||
|
|
||||||
|
// VMenu activator选择器
|
||||||
|
const searchActivator = computed(() => '[data-menu-activator="search-btn"]')
|
||||||
|
|
||||||
|
// 使用动态标签页
|
||||||
|
const { registerHeaderTab } = useDynamicHeaderTab()
|
||||||
|
|
||||||
|
// 注册动态标签页
|
||||||
|
registerHeaderTab({
|
||||||
|
items: workflowTabs.value,
|
||||||
|
modelValue: activeTab,
|
||||||
|
appendButtons: [
|
||||||
|
{
|
||||||
|
icon: 'mdi-movie-search-outline',
|
||||||
|
variant: 'text',
|
||||||
|
color: computed(() => (shareKeyword.value ? 'primary' : 'gray')),
|
||||||
|
class: 'settings-icon-button',
|
||||||
|
dataAttr: 'search-btn',
|
||||||
|
action: () => {
|
||||||
|
// 这里可以添加搜索弹窗逻辑
|
||||||
|
console.log('Search workflow shares')
|
||||||
|
},
|
||||||
|
show: computed(() => activeTab.value === 'share'),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'mdi-plus',
|
||||||
|
variant: 'text',
|
||||||
|
color: 'gray',
|
||||||
|
class: 'settings-icon-button',
|
||||||
|
action: () => {
|
||||||
|
addWorkflowDialog.value = true
|
||||||
|
},
|
||||||
|
show: computed(() => activeTab.value === 'list'),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
// 注册动态标签页
|
||||||
|
onMounted(() => {
|
||||||
|
// 设置初始activeTab值
|
||||||
|
if (!activeTab.value && workflowTabs.value.length > 0) {
|
||||||
|
activeTab.value = workflowTabs.value[0].tab
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<WorkflowListView />
|
<VWindow v-model="activeTab" class="disable-tab-transition content-window" :touch="false">
|
||||||
|
<VWindowItem value="list">
|
||||||
|
<transition name="fade-slide" appear>
|
||||||
|
<div>
|
||||||
|
<WorkflowListView />
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</VWindowItem>
|
||||||
|
<VWindowItem value="share">
|
||||||
|
<transition name="fade-slide" appear>
|
||||||
|
<div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<VRow>
|
||||||
|
<VCol cols="12" md="6">
|
||||||
|
<VTextField
|
||||||
|
v-model="shareKeyword"
|
||||||
|
:label="t('workflow.searchShares')"
|
||||||
|
prepend-inner-icon="mdi-magnify"
|
||||||
|
clearable
|
||||||
|
@keyup.enter="searchShares"
|
||||||
|
@click:clear="searchShares"
|
||||||
|
/>
|
||||||
|
</VCol>
|
||||||
|
<VCol cols="12" md="6" class="d-flex align-center">
|
||||||
|
<VBtn @click="searchShares" prepend-icon="mdi-magnify" class="me-2">
|
||||||
|
{{ t('workflow.searchShares') }}
|
||||||
|
</VBtn>
|
||||||
|
</VCol>
|
||||||
|
</VRow>
|
||||||
|
</div>
|
||||||
|
<WorkflowShareView :keyword="shareKeyword" :key="shareViewKey" />
|
||||||
|
</div>
|
||||||
|
</transition>
|
||||||
|
</VWindowItem>
|
||||||
|
</VWindow>
|
||||||
|
|
||||||
|
<!-- 新增工作流对话框 -->
|
||||||
|
<WorkflowAddEditDialog
|
||||||
|
v-if="addWorkflowDialog"
|
||||||
|
v-model="addWorkflowDialog"
|
||||||
|
@close="addWorkflowDialog = false"
|
||||||
|
@save="addWorkflowDialog = false"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.content-window {
|
||||||
|
margin-block-start: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -293,3 +293,21 @@ export function getDiscoverTabs() {
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取工作流标签页
|
||||||
|
export function getWorkflowTabs() {
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
title: t('workflowTabs.list'),
|
||||||
|
tab: 'list',
|
||||||
|
icon: 'mdi-format-list-bulleted',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: t('workflowTabs.share'),
|
||||||
|
tab: 'share',
|
||||||
|
icon: 'mdi-share',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|||||||
@@ -236,6 +236,10 @@ body {
|
|||||||
grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
|
grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.grid-workflow-share-card {
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
.v-tabs:not(.v-tabs-pill).v-tabs--horizontal {
|
.v-tabs:not(.v-tabs-pill).v-tabs--horizontal {
|
||||||
border-block-end: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
border-block-end: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { Workflow } from '@/api/types'
|
|||||||
import WorkflowAddEditDialog from '@/components/dialog/WorkflowAddEditDialog.vue'
|
import WorkflowAddEditDialog from '@/components/dialog/WorkflowAddEditDialog.vue'
|
||||||
import WorkflowTaskCard from '@/components/cards/WorkflowTaskCard.vue'
|
import WorkflowTaskCard from '@/components/cards/WorkflowTaskCard.vue'
|
||||||
import NoDataFound from '@/components/NoDataFound.vue'
|
import NoDataFound from '@/components/NoDataFound.vue'
|
||||||
import { useDynamicButton } from '@/composables/useDynamicButton'
|
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { usePWA } from '@/composables/usePWA'
|
import { usePWA } from '@/composables/usePWA'
|
||||||
|
|
||||||
@@ -49,14 +48,6 @@ onMounted(() => {
|
|||||||
onActivated(() => {
|
onActivated(() => {
|
||||||
fetchData()
|
fetchData()
|
||||||
})
|
})
|
||||||
|
|
||||||
// 使用动态按钮钩子 新增
|
|
||||||
useDynamicButton({
|
|
||||||
icon: 'mdi-plus',
|
|
||||||
onClick: () => {
|
|
||||||
addDialog.value = true
|
|
||||||
},
|
|
||||||
})
|
|
||||||
</script>
|
</script>
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
@@ -72,21 +63,4 @@ useDynamicButton({
|
|||||||
:error-description="t('workflow.noWorkflowDescription')"
|
:error-description="t('workflow.noWorkflowDescription')"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- 新增按钮 -->
|
|
||||||
<Teleport to="body" v-if="route.path === '/workflow'">
|
|
||||||
<VFab
|
|
||||||
v-if="isRefreshed && !appMode"
|
|
||||||
icon="mdi-plus"
|
|
||||||
location="bottom"
|
|
||||||
size="x-large"
|
|
||||||
fixed
|
|
||||||
app
|
|
||||||
appear
|
|
||||||
:class="{ 'mb-12': appMode }"
|
|
||||||
@click="addDialog = true"
|
|
||||||
/>
|
|
||||||
</Teleport>
|
|
||||||
<!-- 新增对话框 -->
|
|
||||||
<WorkflowAddEditDialog v-if="addDialog" v-model="addDialog" @close="addDialog = false" @save="addDone" />
|
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -0,0 +1,139 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import api from '@/api'
|
||||||
|
import type { WorkflowShare } from '@/api/types'
|
||||||
|
import NoDataFound from '@/components/NoDataFound.vue'
|
||||||
|
import WorkflowShareCard from '@/components/cards/WorkflowShareCard.vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
|
||||||
|
// 国际化
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
// 定义输入参数
|
||||||
|
const props = defineProps({
|
||||||
|
// 过滤关键字
|
||||||
|
keyword: String,
|
||||||
|
})
|
||||||
|
|
||||||
|
// 判断是否有滚动条
|
||||||
|
function hasScroll() {
|
||||||
|
return document.body.scrollHeight - (window.innerHeight || document.documentElement.clientHeight) > 2
|
||||||
|
}
|
||||||
|
|
||||||
|
// API
|
||||||
|
const apipath = 'workflow/shares'
|
||||||
|
|
||||||
|
// 当前页码
|
||||||
|
const page = ref(1)
|
||||||
|
|
||||||
|
// 搜索关键字
|
||||||
|
const keyword = ref(props.keyword)
|
||||||
|
|
||||||
|
// 是否加载中
|
||||||
|
const loading = ref(false)
|
||||||
|
|
||||||
|
// 是否加载完成
|
||||||
|
const isRefreshed = ref(false)
|
||||||
|
|
||||||
|
// 数据列表
|
||||||
|
const dataList = ref<WorkflowShare[]>([])
|
||||||
|
const currData = ref<WorkflowShare[]>([])
|
||||||
|
|
||||||
|
// 拼装参数
|
||||||
|
function getParams() {
|
||||||
|
let params = {
|
||||||
|
page: page.value,
|
||||||
|
count: 30,
|
||||||
|
name: keyword.value,
|
||||||
|
}
|
||||||
|
return params
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取列表数据
|
||||||
|
async function fetchData({ done }: { done: any }) {
|
||||||
|
try {
|
||||||
|
// 如果正在加载中,直接返回
|
||||||
|
if (loading.value) {
|
||||||
|
done('ok')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// 加载到满屏或者加载出错
|
||||||
|
if (!hasScroll()) {
|
||||||
|
// 加载多次
|
||||||
|
while (!hasScroll()) {
|
||||||
|
// 设置加载中
|
||||||
|
loading.value = true
|
||||||
|
// 请求API
|
||||||
|
currData.value = await api.get(apipath, {
|
||||||
|
params: getParams(),
|
||||||
|
})
|
||||||
|
// 取消加载中
|
||||||
|
loading.value = false
|
||||||
|
// 标计为已请求完成
|
||||||
|
isRefreshed.value = true
|
||||||
|
if (currData.value.length === 0) {
|
||||||
|
// 如果没有数据,跳出
|
||||||
|
done('empty')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// 合并数据
|
||||||
|
dataList.value = [...dataList.value, ...currData.value]
|
||||||
|
// 页码+1
|
||||||
|
page.value++
|
||||||
|
// 返回加载成功
|
||||||
|
done('ok')
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 设置加载中
|
||||||
|
loading.value = true
|
||||||
|
// 请求API
|
||||||
|
currData.value = await api.get(apipath, {
|
||||||
|
params: getParams(),
|
||||||
|
})
|
||||||
|
loading.value = false
|
||||||
|
// 标计为已请求完成
|
||||||
|
isRefreshed.value = true
|
||||||
|
if (currData.value.length === 0) {
|
||||||
|
// 如果没有数据,跳出
|
||||||
|
done('empty')
|
||||||
|
} else {
|
||||||
|
// 合并数据
|
||||||
|
dataList.value = [...dataList.value, ...currData.value]
|
||||||
|
// 页码+1
|
||||||
|
page.value++
|
||||||
|
// 返回加载成功
|
||||||
|
done('ok')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
|
// 返回加载失败
|
||||||
|
done('error')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 将数据从列表中移除
|
||||||
|
function removeData(id: number) {
|
||||||
|
dataList.value = dataList.value.filter(item => item.id !== id)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<VPageContentTitle v-if="keyword" :title="`${t('common.search')}:${keyword}`" />
|
||||||
|
<LoadingBanner v-if="!isRefreshed" class="mt-12" />
|
||||||
|
<VInfiniteScroll mode="intersect" side="end" :items="dataList" class="overflow-visible px-2" @load="fetchData">
|
||||||
|
<template #loading />
|
||||||
|
<template #empty />
|
||||||
|
<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">
|
||||||
|
<WorkflowShareCard :media="data" @delete="removeData(data.id || 0)" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<NoDataFound
|
||||||
|
v-if="dataList.length === 0 && isRefreshed"
|
||||||
|
error-code="404"
|
||||||
|
:error-title="t('common.noData')"
|
||||||
|
:error-description="keyword ? t('common.noContent') : t('workflow.noShareData')"
|
||||||
|
/>
|
||||||
|
</VInfiniteScroll>
|
||||||
|
</template>
|
||||||
@@ -1068,6 +1068,11 @@
|
|||||||
resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz"
|
resolved "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz"
|
||||||
integrity sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==
|
integrity sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==
|
||||||
|
|
||||||
|
"@img/sharp-libvips-linuxmusl-x64@1.0.4":
|
||||||
|
version "1.0.4"
|
||||||
|
resolved "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz"
|
||||||
|
integrity sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==
|
||||||
|
|
||||||
"@img/sharp-linux-x64@0.33.5":
|
"@img/sharp-linux-x64@0.33.5":
|
||||||
version "0.33.5"
|
version "0.33.5"
|
||||||
resolved "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz"
|
resolved "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz"
|
||||||
@@ -1075,6 +1080,13 @@
|
|||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
"@img/sharp-libvips-linux-x64" "1.0.4"
|
"@img/sharp-libvips-linux-x64" "1.0.4"
|
||||||
|
|
||||||
|
"@img/sharp-linuxmusl-x64@0.33.5":
|
||||||
|
version "0.33.5"
|
||||||
|
resolved "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz"
|
||||||
|
integrity sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==
|
||||||
|
optionalDependencies:
|
||||||
|
"@img/sharp-libvips-linuxmusl-x64" "1.0.4"
|
||||||
|
|
||||||
"@intlify/bundle-utils@^10.0.1":
|
"@intlify/bundle-utils@^10.0.1":
|
||||||
version "10.0.1"
|
version "10.0.1"
|
||||||
resolved "https://registry.npmjs.org/@intlify/bundle-utils/-/bundle-utils-10.0.1.tgz"
|
resolved "https://registry.npmjs.org/@intlify/bundle-utils/-/bundle-utils-10.0.1.tgz"
|
||||||
@@ -1292,6 +1304,11 @@
|
|||||||
resolved "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz"
|
resolved "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.1.tgz"
|
||||||
integrity sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==
|
integrity sha512-GcESn8NZySmfwlTsIur+49yDqSny2IhPeZfXunQi48DMugKeZ7uy1FX83pO0X22sHntJ4Ub+9k34XQCX+oHt2A==
|
||||||
|
|
||||||
|
"@parcel/watcher-linux-x64-musl@2.5.1":
|
||||||
|
version "2.5.1"
|
||||||
|
resolved "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.1.tgz"
|
||||||
|
integrity sha512-n0E2EQbatQ3bXhcH2D1XIAANAcTZkQICBPVaxMeaCVBtOpBZpWJuf7LwyWPSBDITb7In8mqQgJ7gH8CILCURXg==
|
||||||
|
|
||||||
"@parcel/watcher@^2.4.1":
|
"@parcel/watcher@^2.4.1":
|
||||||
version "2.5.1"
|
version "2.5.1"
|
||||||
resolved "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz"
|
resolved "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.1.tgz"
|
||||||
@@ -1385,6 +1402,11 @@
|
|||||||
resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.1.tgz"
|
resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.1.tgz"
|
||||||
integrity sha512-XiK5z70PEFEFqcNj3/zRSz/qX4bp4QIraTy9QjwJAb/Z8GM7kVUsD0Uk8maIPeTyPCP03ChdI+VVmJriKYbRHQ==
|
integrity sha512-XiK5z70PEFEFqcNj3/zRSz/qX4bp4QIraTy9QjwJAb/Z8GM7kVUsD0Uk8maIPeTyPCP03ChdI+VVmJriKYbRHQ==
|
||||||
|
|
||||||
|
"@rollup/rollup-linux-x64-musl@4.40.1":
|
||||||
|
version "4.40.1"
|
||||||
|
resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.1.tgz"
|
||||||
|
integrity sha512-2BRORitq5rQ4Da9blVovzNCMaUlyKrzMSvkVR0D4qPuOy/+pMCrh1d7o01RATwVy+6Fa1WBw+da7QPeLWU/1mQ==
|
||||||
|
|
||||||
"@rtsao/scc@^1.1.0":
|
"@rtsao/scc@^1.1.0":
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
resolved "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz"
|
resolved "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz"
|
||||||
@@ -1437,6 +1459,11 @@
|
|||||||
resolved "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.12.9.tgz"
|
resolved "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.12.9.tgz"
|
||||||
integrity sha512-SFUxyhWLZRNL8QmgGNqdi2Q43PNyFVkRZ2zIif30SOGFSxnxcf2JNeSeBgKIGVgaLSuk6xFVVCtJ3KIeaStgRg==
|
integrity sha512-SFUxyhWLZRNL8QmgGNqdi2Q43PNyFVkRZ2zIif30SOGFSxnxcf2JNeSeBgKIGVgaLSuk6xFVVCtJ3KIeaStgRg==
|
||||||
|
|
||||||
|
"@swc/core-linux-x64-musl@1.12.9":
|
||||||
|
version "1.12.9"
|
||||||
|
resolved "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.12.9.tgz"
|
||||||
|
integrity sha512-9FB0wM+6idCGTI20YsBNBg9xSWtkDBymnpaTCsZM3qDc0l4uOpJMqbfWhQvp17x7r/ulZfb2QY8RDvQmCL6AcQ==
|
||||||
|
|
||||||
"@swc/core@^1.10.16":
|
"@swc/core@^1.10.16":
|
||||||
version "1.12.9"
|
version "1.12.9"
|
||||||
resolved "https://registry.npmjs.org/@swc/core/-/core-1.12.9.tgz"
|
resolved "https://registry.npmjs.org/@swc/core/-/core-1.12.9.tgz"
|
||||||
@@ -1692,6 +1719,11 @@
|
|||||||
resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.7.2.tgz"
|
resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.7.2.tgz"
|
||||||
integrity sha512-dEidzJDubxxhUCBJ/SHSMJD/9q7JkyfBMT77Px1npl4xpg9t0POLvnWywSk66BgZS/b2Hy9Y1yFaoMTFJUe9yg==
|
integrity sha512-dEidzJDubxxhUCBJ/SHSMJD/9q7JkyfBMT77Px1npl4xpg9t0POLvnWywSk66BgZS/b2Hy9Y1yFaoMTFJUe9yg==
|
||||||
|
|
||||||
|
"@unrs/resolver-binding-linux-x64-musl@1.7.2":
|
||||||
|
version "1.7.2"
|
||||||
|
resolved "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.7.2.tgz"
|
||||||
|
integrity sha512-RvP+Ux3wDjmnZDT4XWFfNBRVG0fMsc+yVzNFUqOflnDfZ9OYujv6nkh+GOr+watwrW4wdp6ASfG/e7bkDradsw==
|
||||||
|
|
||||||
"@vitejs/plugin-vue-jsx@^4.1.1":
|
"@vitejs/plugin-vue-jsx@^4.1.1":
|
||||||
version "4.1.2"
|
version "4.1.2"
|
||||||
resolved "https://registry.npmjs.org/@vitejs/plugin-vue-jsx/-/plugin-vue-jsx-4.1.2.tgz"
|
resolved "https://registry.npmjs.org/@vitejs/plugin-vue-jsx/-/plugin-vue-jsx-4.1.2.tgz"
|
||||||
|
|||||||
Reference in New Issue
Block a user