mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-05-24 17:59:40 +08:00
新增工作流触发类型和事件类型支持
This commit is contained in:
@@ -164,6 +164,10 @@ export interface WorkflowShare {
|
||||
description?: string
|
||||
// 定时器
|
||||
timer?: string
|
||||
// 触发类型:timer-定时触发 event-事件触发 manual-手动触发
|
||||
trigger_type?: string
|
||||
// 事件类型(当trigger_type为event时使用)
|
||||
event_type?: string
|
||||
// 动作列表
|
||||
actions?: any[]
|
||||
// 动作流
|
||||
@@ -1328,6 +1332,10 @@ export interface Workflow {
|
||||
description?: string
|
||||
// 定时器
|
||||
timer?: string
|
||||
// 触发类型:timer-定时触发 event-事件触发 manual-手动触发
|
||||
trigger_type?: string
|
||||
// 事件类型(当trigger_type为event时使用)
|
||||
event_type?: string
|
||||
// 状态
|
||||
state?: string
|
||||
// 当前执行动作
|
||||
|
||||
@@ -168,7 +168,7 @@ const resolveStatusVariant = (status: string | undefined) => {
|
||||
if (status === 'S') return { color: 'success', text: t('workflow.task.status.success') }
|
||||
else if (status === 'R') return { color: 'primary', text: t('workflow.task.status.running') }
|
||||
else if (status === 'F') return { color: 'error', text: t('workflow.task.status.failed') }
|
||||
else if (status === 'P') return { color: 'secondary', text: t('workflow.task.status.paused') }
|
||||
else if (status === 'P') return { color: 'warning', text: t('workflow.task.status.paused') }
|
||||
else return { color: 'info', text: t('workflow.task.status.waiting') }
|
||||
}
|
||||
|
||||
@@ -272,15 +272,28 @@ const resolveProgress = (item: Workflow) => {
|
||||
</VCardItem>
|
||||
<VDivider />
|
||||
<VCardText class="pa-3">
|
||||
<div class="d-flex flex-column gap-y-2">
|
||||
<div class="d-flex flex-column gap-y-3">
|
||||
<div class="d-flex flex-wrap gap-x-3">
|
||||
<div class="flex-1">
|
||||
<div class="mb-1">{{ t('workflow.task.info.timer') }}</div>
|
||||
<h5 class="text-lg">{{ workflow?.timer }}</h5>
|
||||
<div class="mb-1">{{ t('workflow.task.info.trigger') }}</div>
|
||||
<h5>
|
||||
<span v-if="workflow?.trigger_type === 'timer' || !workflow?.trigger_type">
|
||||
<VIcon icon="mdi-clock-outline" size="small" class="me-1" />
|
||||
{{ workflow?.timer }}
|
||||
</span>
|
||||
<span v-else-if="workflow?.trigger_type === 'event'">
|
||||
<VIcon icon="mdi-calendar-check" size="small" class="me-1" />
|
||||
{{ workflow?.event_type }}
|
||||
</span>
|
||||
<span v-else-if="workflow?.trigger_type === 'manual'">
|
||||
<VIcon icon="mdi-hand-pointing-up" size="small" class="me-1" />
|
||||
{{ t('workflow.task.info.manualTrigger') }}
|
||||
</span>
|
||||
</h5>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="mb-1">{{ t('workflow.task.info.status') }}</div>
|
||||
<h5 class="text-lg" :class="`text-${resolveStatusVariant(workflow?.state).color}`">
|
||||
<h5 :class="`text-${resolveStatusVariant(workflow?.state).color}`">
|
||||
{{ resolveStatusVariant(workflow?.state).text }}
|
||||
</h5>
|
||||
</div>
|
||||
@@ -289,14 +302,14 @@ const resolveProgress = (item: Workflow) => {
|
||||
<div class="flex-1">
|
||||
<div class="mb-1">{{ t('workflow.task.info.actionCount') }}</div>
|
||||
<div>
|
||||
<VAvatar size="28" color="primary" variant="tonal">
|
||||
<span class="text-sm">{{ workflow?.actions?.length }}</span>
|
||||
<VAvatar size="24" color="primary" variant="tonal">
|
||||
<span class="text-xs">{{ workflow?.actions?.length }}</span>
|
||||
</VAvatar>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
<div class="mb-1">{{ t('workflow.task.info.runCount') }}</div>
|
||||
<h5 class="text-lg">{{ workflow?.run_count }}</h5>
|
||||
<h5>{{ workflow?.run_count }}</h5>
|
||||
</div>
|
||||
</div>
|
||||
<div class="d-flex flex-wrap gap-x-3">
|
||||
|
||||
@@ -190,10 +190,23 @@ async function doDelete() {
|
||||
<span class="text-body-1"> {{ props.workflow?.share_user }}</span>
|
||||
</VListItemTitle>
|
||||
</VListItem>
|
||||
<VListItem class="ps-0" v-if="props.workflow?.timer">
|
||||
<VListItem class="ps-0" v-if="props.workflow?.trigger_type || props.workflow?.timer">
|
||||
<VListItemTitle class="text-center text-md-left">
|
||||
<span class="font-weight-medium">{{ t('workflow.timer') }}:</span>
|
||||
<span class="text-body-1"> {{ props.workflow?.timer }}</span>
|
||||
<span class="font-weight-medium">{{ t('workflow.trigger') }}:</span>
|
||||
<span class="text-body-1">
|
||||
<span v-if="props.workflow?.trigger_type === 'timer' || !props.workflow?.trigger_type">
|
||||
<VIcon icon="mdi-clock-outline" size="small" class="me-1" />
|
||||
{{ props.workflow?.timer }}
|
||||
</span>
|
||||
<span v-else-if="props.workflow?.trigger_type === 'event'">
|
||||
<VIcon icon="mdi-calendar-check" size="small" class="me-1" />
|
||||
{{ props.workflow?.event_type }}
|
||||
</span>
|
||||
<span v-else-if="props.workflow?.trigger_type === 'manual'">
|
||||
<VIcon icon="mdi-hand-pointing-up" size="small" class="me-1" />
|
||||
{{ t('workflow.manualTrigger') }}
|
||||
</span>
|
||||
</span>
|
||||
</VListItemTitle>
|
||||
</VListItem>
|
||||
<VListItem class="ps-0" v-if="parsedWorkflow?.actions">
|
||||
|
||||
@@ -33,20 +33,95 @@ const workflowForm = ref<Workflow>(
|
||||
name: undefined,
|
||||
timer: undefined,
|
||||
description: undefined,
|
||||
trigger_type: 'timer',
|
||||
event_type: undefined,
|
||||
state: 'P',
|
||||
run_count: 0,
|
||||
},
|
||||
)
|
||||
|
||||
// 监听props变化,处理存量数据
|
||||
watch(
|
||||
() => props.workflow,
|
||||
newWorkflow => {
|
||||
if (newWorkflow) {
|
||||
// 如果trigger_type为空,默认为timer
|
||||
if (!newWorkflow.trigger_type) {
|
||||
newWorkflow.trigger_type = 'timer'
|
||||
}
|
||||
workflowForm.value = { ...newWorkflow }
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
)
|
||||
|
||||
// 事件类型列表
|
||||
const eventTypes = ref<Array<{ title: string; value: string }>>([])
|
||||
|
||||
// 触发类型选项
|
||||
const triggerTypeOptions = computed(() => [
|
||||
{
|
||||
title: t('dialog.workflowAddEdit.triggerTypeTimer'),
|
||||
value: 'timer',
|
||||
prependIcon: 'mdi-clock-outline',
|
||||
},
|
||||
{
|
||||
title: t('dialog.workflowAddEdit.triggerTypeEvent'),
|
||||
value: 'event',
|
||||
prependIcon: 'mdi-calendar-check',
|
||||
},
|
||||
{
|
||||
title: t('dialog.workflowAddEdit.triggerTypeManual'),
|
||||
value: 'manual',
|
||||
prependIcon: 'mdi-hand-pointing-up',
|
||||
},
|
||||
])
|
||||
|
||||
// 加载事件类型列表
|
||||
async function loadEventTypes() {
|
||||
try {
|
||||
eventTypes.value = await api.get('workflow/event_types')
|
||||
} catch (error) {
|
||||
console.error('Failed to load event types:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 监听触发类型变化
|
||||
watch(
|
||||
() => workflowForm.value.trigger_type,
|
||||
newType => {
|
||||
if (newType !== 'event') {
|
||||
workflowForm.value.event_type = undefined
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
// 提示框
|
||||
const $toast = useToast()
|
||||
|
||||
// 调用API 新增任务
|
||||
async function addWorkflow() {
|
||||
if (!workflowForm.value.name || !workflowForm.value.timer) {
|
||||
if (!workflowForm.value.name) {
|
||||
$toast.error(t('dialog.workflowAddEdit.nameRequired'))
|
||||
return
|
||||
}
|
||||
|
||||
if (!workflowForm.value.trigger_type) {
|
||||
$toast.error(t('dialog.workflowAddEdit.triggerRequired'))
|
||||
return
|
||||
}
|
||||
|
||||
// 根据触发类型验证必填字段
|
||||
if (workflowForm.value.trigger_type === 'timer' && !workflowForm.value.timer) {
|
||||
$toast.error(t('dialog.workflowAddEdit.timerRequired'))
|
||||
return
|
||||
}
|
||||
|
||||
if (workflowForm.value.trigger_type === 'event' && !workflowForm.value.event_type) {
|
||||
$toast.error(t('dialog.workflowAddEdit.eventTypeRequired'))
|
||||
return
|
||||
}
|
||||
|
||||
startNProgress()
|
||||
try {
|
||||
const result: { [key: string]: string } = await api.post('workflow/', workflowForm.value)
|
||||
@@ -64,10 +139,27 @@ async function addWorkflow() {
|
||||
|
||||
// 调用API 编辑任务
|
||||
async function editWorkflow() {
|
||||
if (!workflowForm.value.name || !workflowForm.value.timer) {
|
||||
if (!workflowForm.value.name) {
|
||||
$toast.error(t('dialog.workflowAddEdit.nameRequired'))
|
||||
return
|
||||
}
|
||||
|
||||
if (!workflowForm.value.trigger_type) {
|
||||
$toast.error(t('dialog.workflowAddEdit.triggerRequired'))
|
||||
return
|
||||
}
|
||||
|
||||
// 根据触发类型验证必填字段
|
||||
if (workflowForm.value.trigger_type === 'timer' && !workflowForm.value.timer) {
|
||||
$toast.error(t('dialog.workflowAddEdit.timerRequired'))
|
||||
return
|
||||
}
|
||||
|
||||
if (workflowForm.value.trigger_type === 'event' && !workflowForm.value.event_type) {
|
||||
$toast.error(t('dialog.workflowAddEdit.eventTypeRequired'))
|
||||
return
|
||||
}
|
||||
|
||||
startNProgress()
|
||||
try {
|
||||
const result: { [key: string]: string } = await api.put(`workflow/${workflowForm.value.id}`, workflowForm.value)
|
||||
@@ -82,6 +174,11 @@ async function editWorkflow() {
|
||||
}
|
||||
doneNProgress()
|
||||
}
|
||||
|
||||
// 组件挂载时加载事件类型
|
||||
onMounted(() => {
|
||||
loadEventTypes()
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -109,6 +206,25 @@ async function editWorkflow() {
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12">
|
||||
<VSelect
|
||||
v-model="workflowForm.trigger_type"
|
||||
:label="t('dialog.workflowAddEdit.triggerType')"
|
||||
:items="triggerTypeOptions"
|
||||
item-title="title"
|
||||
item-value="value"
|
||||
:rules="[requiredValidator]"
|
||||
prepend-inner-icon="mdi-run"
|
||||
>
|
||||
<template #item="{ item, props: itemProps }">
|
||||
<VListItem v-bind="itemProps">
|
||||
<template #prepend>
|
||||
<VIcon :icon="item.raw.prependIcon" />
|
||||
</template>
|
||||
</VListItem>
|
||||
</template>
|
||||
</VSelect>
|
||||
</VCol>
|
||||
<VCol v-if="workflowForm.trigger_type === 'timer'" cols="12">
|
||||
<VCronField
|
||||
v-model="workflowForm.timer"
|
||||
:label="t('dialog.workflowAddEdit.schedule')"
|
||||
@@ -119,6 +235,19 @@ async function editWorkflow() {
|
||||
prepend-inner-icon="mdi-clock-outline"
|
||||
/>
|
||||
</VCol>
|
||||
<VCol v-if="workflowForm.trigger_type === 'event'" cols="12">
|
||||
<VSelect
|
||||
v-model="workflowForm.event_type"
|
||||
:label="t('dialog.workflowAddEdit.eventType')"
|
||||
:items="eventTypes"
|
||||
item-title="title"
|
||||
item-value="value"
|
||||
:rules="[requiredValidator]"
|
||||
persistent-hint
|
||||
:hint="t('dialog.workflowAddEdit.eventTypePlaceholder')"
|
||||
prepend-inner-icon="mdi-calendar-check"
|
||||
/>
|
||||
</VCol>
|
||||
<VCol cols="12">
|
||||
<VTextarea
|
||||
v-model="workflowForm.description"
|
||||
|
||||
@@ -523,12 +523,14 @@ export default {
|
||||
waiting: 'Waiting',
|
||||
},
|
||||
info: {
|
||||
trigger: 'Trigger',
|
||||
timer: 'Timer',
|
||||
status: 'Status',
|
||||
actionCount: 'Action Count',
|
||||
runCount: 'Run Count',
|
||||
progress: 'Progress',
|
||||
error: 'Error Message',
|
||||
manualTrigger: 'Manual',
|
||||
},
|
||||
},
|
||||
scanFile: {
|
||||
@@ -675,7 +677,9 @@ export default {
|
||||
searchShares: 'Search Workflow Shares',
|
||||
noShareData: 'No shared workflows',
|
||||
sharer: 'Sharer',
|
||||
trigger: 'Trigger',
|
||||
timer: 'Timer',
|
||||
manualTrigger: 'Manual Trigger',
|
||||
actionCount: 'Action Count',
|
||||
normalFork: 'Fork Workflow',
|
||||
cancelShare: 'Cancel Share',
|
||||
@@ -1867,10 +1871,19 @@ export default {
|
||||
desc: 'Description',
|
||||
descPlaceholder: 'Workflow description',
|
||||
enabled: 'Enabled',
|
||||
triggerType: 'Trigger Type',
|
||||
triggerTypeTimer: 'Timer Trigger',
|
||||
triggerTypeEvent: 'Event Trigger',
|
||||
triggerTypeManual: 'Manual Trigger',
|
||||
schedule: 'Schedule',
|
||||
cronExpr: 'Cron Expression',
|
||||
cronExprDesc: 'Cron expression for workflow scheduling',
|
||||
eventType: 'Event Type',
|
||||
eventTypePlaceholder: 'Please select event type',
|
||||
nameRequired: 'Please fill in complete information!',
|
||||
triggerRequired: 'Please select trigger type!',
|
||||
timerRequired: 'Please fill in timer expression!',
|
||||
eventTypeRequired: 'Please select event type!',
|
||||
addSuccess: 'Task created successfully, please edit the workflow!',
|
||||
addFailed: 'Failed to create task: {message}',
|
||||
editSuccess: 'Task modified successfully!',
|
||||
|
||||
@@ -520,12 +520,14 @@ export default {
|
||||
waiting: '等待',
|
||||
},
|
||||
info: {
|
||||
trigger: '触发方式',
|
||||
timer: '定时',
|
||||
status: '状态',
|
||||
actionCount: '动作数',
|
||||
runCount: '已执行次数',
|
||||
progress: '进度',
|
||||
error: '错误信息',
|
||||
manualTrigger: '手动',
|
||||
},
|
||||
},
|
||||
scanFile: {
|
||||
@@ -672,7 +674,9 @@ export default {
|
||||
searchShares: '搜索工作流分享',
|
||||
noShareData: '暂无分享的工作流',
|
||||
sharer: '分享人',
|
||||
trigger: '触发方式',
|
||||
timer: '定时器',
|
||||
manualTrigger: '手动触发',
|
||||
actionCount: '动作数量',
|
||||
normalFork: '复用工作流',
|
||||
cancelShare: '取消分享',
|
||||
@@ -1842,10 +1846,19 @@ export default {
|
||||
desc: '描述',
|
||||
descPlaceholder: '工作流描述',
|
||||
enabled: '启用',
|
||||
triggerType: '触发类型',
|
||||
triggerTypeTimer: '定时触发',
|
||||
triggerTypeEvent: '事件触发',
|
||||
triggerTypeManual: '手动触发',
|
||||
schedule: '定时执行',
|
||||
cronExpr: 'Cron表达式',
|
||||
cronExprDesc: '工作流定时执行的cron表达式',
|
||||
eventType: '事件类型',
|
||||
eventTypePlaceholder: '请选择事件类型',
|
||||
nameRequired: '请填写完整信息!',
|
||||
triggerRequired: '请选择触发类型!',
|
||||
timerRequired: '请填写定时表达式!',
|
||||
eventTypeRequired: '请选择事件类型!',
|
||||
addSuccess: '创建任务成功,请编辑流程!',
|
||||
addFailed: '创建任务失败:{message}',
|
||||
editSuccess: '修改任务成功!',
|
||||
|
||||
@@ -518,12 +518,14 @@ export default {
|
||||
waiting: '等待中',
|
||||
},
|
||||
info: {
|
||||
trigger: '觸發方式',
|
||||
timer: '定時器',
|
||||
status: '狀態',
|
||||
actionCount: '動作數量',
|
||||
runCount: '執行次數',
|
||||
progress: '進度',
|
||||
error: '錯誤訊息',
|
||||
manualTrigger: '手動',
|
||||
},
|
||||
},
|
||||
scanFile: {
|
||||
@@ -670,7 +672,9 @@ export default {
|
||||
searchShares: '搜索工作流分享',
|
||||
noShareData: '暫無分享的工作流',
|
||||
sharer: '分享人',
|
||||
trigger: '觸發方式',
|
||||
timer: '定時器',
|
||||
manualTrigger: '手動觸發',
|
||||
actionCount: '動作數量',
|
||||
normalFork: '復用工作流',
|
||||
cancelShare: '取消分享',
|
||||
@@ -1841,10 +1845,19 @@ export default {
|
||||
desc: '描述',
|
||||
descPlaceholder: '工作流描述',
|
||||
enabled: '啟用',
|
||||
triggerType: '觸發類型',
|
||||
triggerTypeTimer: '定時觸發',
|
||||
triggerTypeEvent: '事件觸發',
|
||||
triggerTypeManual: '手動觸發',
|
||||
schedule: '定時執行',
|
||||
cronExpr: 'Cron表達式',
|
||||
cronExprDesc: '工作流定時執行的cron表達式',
|
||||
eventType: '事件類型',
|
||||
eventTypePlaceholder: '請選擇事件類型',
|
||||
nameRequired: '請填寫完整資訊!',
|
||||
triggerRequired: '請選擇觸發類型!',
|
||||
timerRequired: '請填寫定時表達式!',
|
||||
eventTypeRequired: '請選擇事件類型!',
|
||||
addSuccess: '建立任務成功,請編輯流程!',
|
||||
addFailed: '建立任務失敗:{message}',
|
||||
editSuccess: '修改任務成功!',
|
||||
|
||||
Reference in New Issue
Block a user