feat: 工作流新增任务表单抽屉
This commit is contained in:
commit
9b79d41ecb
@ -40,7 +40,7 @@ defineExpose({
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<NPopover trigger="click" placement="bottom-start">
|
<NPopover class="cron-popover" trigger="click" placement="bottom-start">
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<NInput v-bind="attrs" v-model:value="cron" />
|
<NInput v-bind="attrs" v-model:value="cron" />
|
||||||
</template>
|
</template>
|
||||||
@ -49,10 +49,7 @@ defineExpose({
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
.n-popover {
|
.cron-popover {
|
||||||
padding: 0 !important;
|
padding: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.n-popover .n-popover-shared .n-popover-arrow-wrapper .n-popover-arrow {
|
|
||||||
}
|
|
||||||
</style>
|
</style>
|
||||||
|
@ -39,6 +39,14 @@ export function fetchAddWorkflow(data: Flow.NodeDataType) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function fetchUpdateWorkflow(data: Flow.NodeDataType) {
|
||||||
|
return request<null>({
|
||||||
|
url: `/workflow`,
|
||||||
|
method: 'put',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function fetchWorkflowInfo(id: string) {
|
export function fetchWorkflowInfo(id: string) {
|
||||||
return request<Flow.NodeDataType>({
|
return request<Flow.NodeDataType>({
|
||||||
url: `/workflow/${id}`,
|
url: `/workflow/${id}`,
|
||||||
|
60
packages/work-flow/src/common/editable-input.vue
Normal file
60
packages/work-flow/src/common/editable-input.vue
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import type { InputInst } from 'naive-ui';
|
||||||
|
import { nextTick, ref, watch } from 'vue';
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'EditableInput'
|
||||||
|
});
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
modelValue?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>();
|
||||||
|
|
||||||
|
interface Emits {
|
||||||
|
(e: 'update:modelValue', modelValue: string): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const emit = defineEmits<Emits>();
|
||||||
|
|
||||||
|
const inputRef = ref<InputInst>();
|
||||||
|
const value = ref();
|
||||||
|
const idEdit = ref<boolean>(false);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
val => {
|
||||||
|
value.value = val;
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
const edit = () => {
|
||||||
|
idEdit.value = true;
|
||||||
|
nextTick(() => {
|
||||||
|
inputRef.value?.focus();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const save = () => {
|
||||||
|
emit('update:modelValue', value.value!);
|
||||||
|
idEdit.value = false;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<NInput v-if="idEdit" ref="inputRef" v-model:value="value" type="text" @blur="save" />
|
||||||
|
<NEllipsis v-else>
|
||||||
|
<span class="flex items-center">
|
||||||
|
{{ value }}
|
||||||
|
<NButton text type="info" class="m-l-6px" @click="edit">
|
||||||
|
<template #icon>
|
||||||
|
<icon-ant-design:edit-outlined class="text-icon" />
|
||||||
|
</template>
|
||||||
|
</NButton>
|
||||||
|
</span>
|
||||||
|
</NEllipsis>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped lang="scss"></style>
|
@ -156,7 +156,7 @@ const getClass = (item: Flow.ConditionNodeType) => {
|
|||||||
<template v-if="item.callback?.webhook">
|
<template v-if="item.callback?.webhook">
|
||||||
<div class="flex justify-between">
|
<div class="flex justify-between">
|
||||||
<span class="content_label">Webhook:</span>
|
<span class="content_label">Webhook:</span>
|
||||||
<NEllipsis class="w-116px">{{ item.callback.webhook }}</NEllipsis>
|
<NEllipsis class="max-w-116px">{{ item.callback.webhook }}</NEllipsis>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="content_label">{{ $t('node.callback.conditionNodes.contentType') }}:</span>
|
<span class="content_label">{{ $t('node.callback.conditionNodes.contentType') }}:</span>
|
||||||
|
@ -88,18 +88,18 @@ const show = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div v-if="nodeData.groupName" class="content">
|
<div v-if="nodeData.groupName" class="content">
|
||||||
<div>
|
<div>
|
||||||
<span class="content_label">{{ $t('snail.groupName') }}:</span>
|
<span class="content_label">{{ $t('snail.groupName') }}: </span>
|
||||||
<NEllipsis class="w-135px">
|
<NEllipsis class="max-w-132px">
|
||||||
{{ nodeData.groupName }}
|
{{ nodeData.groupName }}
|
||||||
</NEllipsis>
|
</NEllipsis>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="content_label">{{ $t('snail.blockStrategy') }}:</span>
|
<span class="content_label">{{ $t('snail.blockStrategy') }}: </span>
|
||||||
{{ blockStrategyRecord[nodeData.blockStrategy!] }}
|
{{ $t(blockStrategyRecord[nodeData.blockStrategy!]) }}
|
||||||
</div>
|
</div>
|
||||||
<div>.........</div>
|
<div>.........</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="content">
|
<div v-else class="content min-h-85px">
|
||||||
<span class="placeholder">{{ $t('snail.form.workflowTip') }}</span>
|
<span class="placeholder">{{ $t('snail.form.workflowTip') }}</span>
|
||||||
</div>
|
</div>
|
||||||
<NTooltip v-if="store.type === 2" trigger="hover">
|
<NTooltip v-if="store.type === 2" trigger="hover">
|
||||||
|
@ -5,6 +5,7 @@ import { fetchNodeRetry, fetchNodeStop } from '../api';
|
|||||||
import { useFlowStore } from '../stores';
|
import { useFlowStore } from '../stores';
|
||||||
import { $t } from '../locales';
|
import { $t } from '../locales';
|
||||||
import { failStrategyRecord, taskBatchStatusEnum } from '../constants/business';
|
import { failStrategyRecord, taskBatchStatusEnum } from '../constants/business';
|
||||||
|
import TaskDrawer from '../drawer/task-drawer.vue';
|
||||||
import AddNode from './add-node.vue';
|
import AddNode from './add-node.vue';
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
@ -93,15 +94,15 @@ const index = ref<number>(0);
|
|||||||
const drawer = ref<boolean>(false);
|
const drawer = ref<boolean>(false);
|
||||||
const form = ref<Flow.ConditionNodeType>({});
|
const form = ref<Flow.ConditionNodeType>({});
|
||||||
|
|
||||||
// const save = (val: Flow.ConditionNodeType) => {
|
const save = (val: Flow.ConditionNodeType) => {
|
||||||
// const oldLevel = nodeConfig.value.conditionNodes![index.value].priorityLevel;
|
const oldLevel = nodeConfig.value.conditionNodes![index.value].priorityLevel;
|
||||||
// const newLevel = val.priorityLevel;
|
const newLevel = val.priorityLevel;
|
||||||
// nodeConfig.value.conditionNodes![index.value] = val;
|
nodeConfig.value.conditionNodes![index.value] = val;
|
||||||
// if (oldLevel !== newLevel) {
|
if (oldLevel !== newLevel) {
|
||||||
// arrTransfer(index.value, newLevel! - oldLevel!);
|
arrTransfer(index.value, newLevel! - oldLevel!);
|
||||||
// }
|
}
|
||||||
// emit('update:modelValue', nodeConfig.value);
|
emit('update:modelValue', nodeConfig.value);
|
||||||
// };
|
};
|
||||||
|
|
||||||
const show = (currentIndex: number) => {
|
const show = (currentIndex: number) => {
|
||||||
if (!props.disabled) {
|
if (!props.disabled) {
|
||||||
@ -214,16 +215,18 @@ const isStop = (taskBatchStatus: number) => {
|
|||||||
<span class="priority-title">{{ $t('node.priority') }}{{ item.priorityLevel }}</span>
|
<span class="priority-title">{{ $t('node.priority') }}{{ item.priorityLevel }}</span>
|
||||||
<icon-ant-design:close-outlined v-if="!disabled" class="close" @click.stop="delTerm(i)" />
|
<icon-ant-design:close-outlined v-if="!disabled" class="close" @click.stop="delTerm(i)" />
|
||||||
</div>
|
</div>
|
||||||
<div class="content min-h-81px">
|
<div class="content min-h-72px">
|
||||||
<div v-if="!item.jobTask?.jobId" class="placeholder">{{ $t('snail.form.taskTip') }}</div>
|
<div v-if="!item.jobTask?.jobId" class="placeholder">{{ $t('snail.form.taskTip') }}</div>
|
||||||
<template v-if="item.jobTask?.jobId">
|
<template v-if="item.jobTask?.jobId">
|
||||||
<div>
|
<div>
|
||||||
<span class="content_label">{{ $t('snail.taskName') }}:</span>
|
<span class="content_label">{{ $t('snail.taskName') }}: </span>
|
||||||
<NEllipsis class="w-126px">{{ `${item.jobTask?.jobName}(${item.jobTask?.jobId})` }}</NEllipsis>
|
<NEllipsis class="max-w-123px">
|
||||||
|
{{ `${item.jobTask?.jobName}(${item.jobTask?.jobId})` }}
|
||||||
|
</NEllipsis>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="content_label">{{ $t('snail.failStrategy') }} :</span>
|
<span class="content_label">{{ $t('snail.failStrategy') }}: </span>
|
||||||
{{ failStrategyRecord[item.failStrategy!] }}
|
{{ $t(failStrategyRecord[item.failStrategy!]) }}
|
||||||
</div>
|
</div>
|
||||||
<div>.........</div>
|
<div>.........</div>
|
||||||
</template>
|
</template>
|
||||||
@ -266,16 +269,15 @@ const isStop = (taskBatchStatus: number) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<AddNode v-if="nodeConfig.conditionNodes!.length > 1" v-model="nodeConfig.childNode!" :disabled="disabled" />
|
<AddNode v-if="nodeConfig.conditionNodes!.length > 1" v-model="nodeConfig.childNode!" :disabled="disabled" />
|
||||||
<!--
|
|
||||||
<TaskDrawer
|
<TaskDrawer
|
||||||
v-if="store.type === 0 && drawer"
|
v-if="store.type === 0"
|
||||||
v-model:open="drawer"
|
v-model:open="drawer"
|
||||||
v-model="form"
|
v-model="form"
|
||||||
v-model:len="nodeConfig.conditionNodes!.length"
|
v-model:len="nodeConfig.conditionNodes!.length"
|
||||||
@save="save"
|
@save="save"
|
||||||
/>
|
/>
|
||||||
<DetailCard v-if="store.type !== 0 && cardDrawer" :id="detailId" v-model:open="cardDrawer" :ids="detailIds" />
|
<!-- <DetailCard v-if="store.type !== 0 && cardDrawer" :id="detailId" v-model:open="cardDrawer" :ids="detailIds" /> -->
|
||||||
-->
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -44,8 +44,8 @@ export const triggerTypeRecord: Record<Flow.TriggerType, string> = {
|
|||||||
export const triggerTypeOptions = transformRecordToOption(triggerTypeRecord);
|
export const triggerTypeOptions = transformRecordToOption(triggerTypeRecord);
|
||||||
|
|
||||||
export const workFlowNodeStatusRecord: Record<Flow.WorkFlowNodeStatus, string> = {
|
export const workFlowNodeStatusRecord: Record<Flow.WorkFlowNodeStatus, string> = {
|
||||||
0: '关闭',
|
0: 'snail.enum.workFlowNodeStatus.close',
|
||||||
1: '开启'
|
1: 'snail.enum.workFlowNodeStatus.open'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const workFlowNodeStatusOptions = transformRecordToOption(workFlowNodeStatusRecord);
|
export const workFlowNodeStatusOptions = transformRecordToOption(workFlowNodeStatusRecord);
|
||||||
|
@ -7,9 +7,10 @@ import { $t } from '../locales';
|
|||||||
import { fetchGroupNameList } from '../api';
|
import { fetchGroupNameList } from '../api';
|
||||||
import { isNotNull } from '../utils/common';
|
import { isNotNull } from '../utils/common';
|
||||||
import { useFlowStore } from '../stores';
|
import { useFlowStore } from '../stores';
|
||||||
|
import EditableInput from '../common/editable-input.vue';
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'StartDetail'
|
name: 'StartDrawer'
|
||||||
});
|
});
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -49,6 +50,9 @@ watch(
|
|||||||
() => props.modelValue,
|
() => props.modelValue,
|
||||||
val => {
|
val => {
|
||||||
form.value = val;
|
form.value = val;
|
||||||
|
if (val.triggerType === 2) {
|
||||||
|
form.value.triggerInterval = Number(val.triggerInterval);
|
||||||
|
}
|
||||||
if (val.workflowName) {
|
if (val.workflowName) {
|
||||||
title = val.workflowName;
|
title = val.workflowName;
|
||||||
} else if (val.groupName) {
|
} else if (val.groupName) {
|
||||||
@ -92,7 +96,7 @@ const typeChange = (value: number) => {
|
|||||||
if (value === 1) {
|
if (value === 1) {
|
||||||
form.value.triggerInterval = '* * * * * ?';
|
form.value.triggerInterval = '* * * * * ?';
|
||||||
} else if (value === 2) {
|
} else if (value === 2) {
|
||||||
form.value.triggerInterval = '60';
|
form.value.triggerInterval = 60;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -116,10 +120,10 @@ const rules: Record<RuleKey, FormItemRule> = {
|
|||||||
<template>
|
<template>
|
||||||
<NDrawer v-model:show="drawer" display-directive="if" :width="610" @after-leave="close">
|
<NDrawer v-model:show="drawer" display-directive="if" :width="610" @after-leave="close">
|
||||||
<NDrawerContent :title="title">
|
<NDrawerContent :title="title">
|
||||||
|
<template #header>
|
||||||
|
<EditableInput v-model="form.workflowName" class="max-w-570px min-w-570px" />
|
||||||
|
</template>
|
||||||
<NForm ref="formRef" :model="form" :rules="rules" label-align="left" label-width="100px">
|
<NForm ref="formRef" :model="form" :rules="rules" label-align="left" label-width="100px">
|
||||||
<NFormItem path="workflowName" label="工作流名称">
|
|
||||||
<NInput v-model:value="form.workflowName" placeholder="请输入工作流名称" />
|
|
||||||
</NFormItem>
|
|
||||||
<NFormItem path="groupName" label="组名称">
|
<NFormItem path="groupName" label="组名称">
|
||||||
<NSelect
|
<NSelect
|
||||||
v-model:value="form.groupName"
|
v-model:value="form.groupName"
|
||||||
@ -177,8 +181,8 @@ const rules: Record<RuleKey, FormItemRule> = {
|
|||||||
<NRadioGroup v-model:value="form.blockStrategy">
|
<NRadioGroup v-model:value="form.blockStrategy">
|
||||||
<NSpace>
|
<NSpace>
|
||||||
<NRadio
|
<NRadio
|
||||||
v-for="options in blockStrategyOptions"
|
v-for="(options, index) in blockStrategyOptions"
|
||||||
:key="options.value"
|
:key="index"
|
||||||
:label="$t(options.label)"
|
:label="$t(options.label)"
|
||||||
:value="options.value"
|
:value="options.value"
|
||||||
/>
|
/>
|
||||||
@ -191,8 +195,8 @@ const rules: Record<RuleKey, FormItemRule> = {
|
|||||||
<NRadioGroup v-model:value="form.workflowStatus">
|
<NRadioGroup v-model:value="form.workflowStatus">
|
||||||
<NSpace>
|
<NSpace>
|
||||||
<NRadio
|
<NRadio
|
||||||
v-for="options in workFlowNodeStatusOptions"
|
v-for="(options, index) in workFlowNodeStatusOptions"
|
||||||
:key="options.value"
|
:key="index"
|
||||||
:label="$t(options.label)"
|
:label="$t(options.label)"
|
||||||
:value="options.value"
|
:value="options.value"
|
||||||
/>
|
/>
|
||||||
|
164
packages/work-flow/src/drawer/task-drawer.vue
Normal file
164
packages/work-flow/src/drawer/task-drawer.vue
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, watch } from 'vue';
|
||||||
|
import { type FormInst, useMessage } from 'naive-ui';
|
||||||
|
import { useFlowStore } from '../stores';
|
||||||
|
import { $t } from '../locales';
|
||||||
|
import { failStrategyOptions, workFlowNodeStatusOptions } from '../constants/business';
|
||||||
|
import EditableInput from '../common/editable-input.vue';
|
||||||
|
|
||||||
|
defineOptions({
|
||||||
|
name: 'TaskDrawer'
|
||||||
|
});
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
modelValue?: Flow.ConditionNodeType;
|
||||||
|
open?: boolean;
|
||||||
|
len?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
|
open: false,
|
||||||
|
len: 0,
|
||||||
|
modelValue: () => ({})
|
||||||
|
});
|
||||||
|
|
||||||
|
interface Emits {
|
||||||
|
(e: 'update:open', open: boolean): void;
|
||||||
|
(e: 'save', form: Flow.ConditionNodeType): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const emit = defineEmits<Emits>();
|
||||||
|
|
||||||
|
const store = useFlowStore();
|
||||||
|
const message = useMessage();
|
||||||
|
const drawer = ref<boolean>(false);
|
||||||
|
const form = ref<Flow.ConditionNodeType>({});
|
||||||
|
const jobList = ref<{ id: string; jobName: string }[]>([]);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => store.jobList,
|
||||||
|
val => {
|
||||||
|
jobList.value = val;
|
||||||
|
},
|
||||||
|
{ immediate: true, deep: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.open,
|
||||||
|
val => {
|
||||||
|
drawer.value = val;
|
||||||
|
},
|
||||||
|
{ immediate: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => props.modelValue,
|
||||||
|
val => {
|
||||||
|
form.value = val;
|
||||||
|
},
|
||||||
|
{ immediate: true, deep: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
const formRef = ref<FormInst>();
|
||||||
|
|
||||||
|
const close = () => {
|
||||||
|
emit('update:open', false);
|
||||||
|
drawer.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
const save = () => {
|
||||||
|
formRef.value?.validate(errors => {
|
||||||
|
if (!errors) {
|
||||||
|
close();
|
||||||
|
emit('save', form.value);
|
||||||
|
} else {
|
||||||
|
message.warning('请检查表单信息');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
failStrategy: [{ required: true, message: '请选择失败策略' }],
|
||||||
|
workflowNodeStatus: [{ required: true, message: '请选择工作流状态' }],
|
||||||
|
jobTask: {
|
||||||
|
jobId: [{ required: true, message: '请选择任务' }]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const jobTaskChange = (_: string, option: { label: string; value: number }) => {
|
||||||
|
form.value.jobTask!.jobName = option.label;
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<NDrawer v-model:show="drawer" display-directive="if" :width="500" @after-leave="close">
|
||||||
|
<NDrawerContent>
|
||||||
|
<template #header>
|
||||||
|
<div class="w-460px flex-center">
|
||||||
|
<EditableInput v-model="form.nodeName" class="mr-16px max-w-320px min-w-320px" />
|
||||||
|
|
||||||
|
<NSelect
|
||||||
|
v-model:value="form.priorityLevel"
|
||||||
|
class="max-w-110px"
|
||||||
|
:options="
|
||||||
|
Array(len)
|
||||||
|
.fill(0)
|
||||||
|
.map((_, index) => {
|
||||||
|
return {
|
||||||
|
label: '优先级 ' + (index + 1),
|
||||||
|
value: index + 1
|
||||||
|
};
|
||||||
|
})
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<NForm ref="formRef" :model="form" :rules="rules" label-align="left" label-width="100px">
|
||||||
|
<NFormItem path="jobTask.jobId" label="所属任务" placeholder="请选择任务">
|
||||||
|
<NSelect
|
||||||
|
v-model:value="form.jobTask!.jobId"
|
||||||
|
:options="
|
||||||
|
jobList.map(job => {
|
||||||
|
return {
|
||||||
|
label: job.jobName,
|
||||||
|
value: job.id
|
||||||
|
};
|
||||||
|
})
|
||||||
|
"
|
||||||
|
@update:value="jobTaskChange"
|
||||||
|
/>
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem path="failStrategy" label="失败策略">
|
||||||
|
<NRadioGroup v-model:value="form.failStrategy">
|
||||||
|
<NSpace>
|
||||||
|
<NRadio
|
||||||
|
v-for="(options, index) in failStrategyOptions"
|
||||||
|
:key="index"
|
||||||
|
:label="$t(options.label)"
|
||||||
|
:value="options.value"
|
||||||
|
/>
|
||||||
|
</NSpace>
|
||||||
|
</NRadioGroup>
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem path="workflowNodeStatus" label="节点状态">
|
||||||
|
<NRadioGroup v-model:value="form.workflowNodeStatus">
|
||||||
|
<NSpace>
|
||||||
|
<NRadio
|
||||||
|
v-for="(options, index) in workFlowNodeStatusOptions"
|
||||||
|
:key="index"
|
||||||
|
:label="$t(options.label)"
|
||||||
|
:value="options.value"
|
||||||
|
/>
|
||||||
|
</NSpace>
|
||||||
|
</NRadioGroup>
|
||||||
|
</NFormItem>
|
||||||
|
</NForm>
|
||||||
|
|
||||||
|
<template #footer>
|
||||||
|
<NButton type="primary" @click="save">保存</NButton>
|
||||||
|
<NButton class="ml-12px" @click="close">取消</NButton>
|
||||||
|
</template>
|
||||||
|
</NDrawerContent>
|
||||||
|
</NDrawer>
|
||||||
|
</template>
|
@ -33,6 +33,14 @@ const local: FlowI18n.Schema = {
|
|||||||
cancel: 'Cancel',
|
cancel: 'Cancel',
|
||||||
decisionFailed: 'Decision Failed',
|
decisionFailed: 'Decision Failed',
|
||||||
skip: 'Skip'
|
skip: 'Skip'
|
||||||
|
},
|
||||||
|
workFlowNodeStatus: {
|
||||||
|
open: 'Open',
|
||||||
|
close: 'Close'
|
||||||
|
},
|
||||||
|
triggerType: {
|
||||||
|
time: 'Fixed Time',
|
||||||
|
cron: 'CRON Expressions'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -33,6 +33,14 @@ const local: FlowI18n.Schema = {
|
|||||||
cancel: '取消',
|
cancel: '取消',
|
||||||
decisionFailed: '判定未通过',
|
decisionFailed: '判定未通过',
|
||||||
skip: '跳过'
|
skip: '跳过'
|
||||||
|
},
|
||||||
|
workFlowNodeStatus: {
|
||||||
|
open: '开启',
|
||||||
|
close: '关闭'
|
||||||
|
},
|
||||||
|
triggerType: {
|
||||||
|
time: '固定时间',
|
||||||
|
cron: 'CRON 表达式'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -595,7 +595,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.end-node .end-node-text {
|
.end-node .end-node-text {
|
||||||
color: #ccc;
|
color: #d6d6d6;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auto-judge .sort-left:hover,
|
.auto-judge .sort-left:hover,
|
||||||
@ -608,4 +608,8 @@
|
|||||||
.add-branch {
|
.add-branch {
|
||||||
background-color: #3e5a2d;
|
background-color: #3e5a2d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
color: #d6d6d6;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
8
packages/work-flow/src/typings/i18n.d.ts
vendored
8
packages/work-flow/src/typings/i18n.d.ts
vendored
@ -37,6 +37,14 @@ declare namespace FlowI18n {
|
|||||||
decisionFailed: string;
|
decisionFailed: string;
|
||||||
skip: string;
|
skip: string;
|
||||||
};
|
};
|
||||||
|
workFlowNodeStatus: {
|
||||||
|
open: string;
|
||||||
|
close: string;
|
||||||
|
};
|
||||||
|
triggerType: {
|
||||||
|
time: string;
|
||||||
|
cron: string;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
node: {
|
node: {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { BACKEND_ERROR_CODE, createFlatRequest } from '@sa/axios';
|
import { BACKEND_ERROR_CODE, createFlatRequest } from '@sa/axios';
|
||||||
import { localStg } from './storage';
|
import { localStg } from './storage';
|
||||||
|
|
||||||
const baseURL = '/proxy-default';
|
const baseURL = '/snail-job';
|
||||||
|
|
||||||
export const request = createFlatRequest<Service.Response>(
|
export const request = createFlatRequest<Service.Response>(
|
||||||
{
|
{
|
||||||
|
@ -66,7 +66,7 @@ export function getServiceBaseURL(env: Env.ImportMeta, isProxy: boolean) {
|
|||||||
*/
|
*/
|
||||||
function createProxyPattern(key?: App.Service.OtherBaseURLKey) {
|
function createProxyPattern(key?: App.Service.OtherBaseURLKey) {
|
||||||
if (!key) {
|
if (!key) {
|
||||||
return '/proxy-default';
|
return '/snail-job';
|
||||||
}
|
}
|
||||||
|
|
||||||
return `/proxy-${key}`;
|
return `/proxy-${key}`;
|
||||||
|
@ -9,6 +9,8 @@ defineOptions({
|
|||||||
name: 'PwdLogin'
|
name: 'PwdLogin'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const devMode = import.meta.env.DEV;
|
||||||
|
|
||||||
const authStore = useAuthStore();
|
const authStore = useAuthStore();
|
||||||
const { formRef, validate } = useNaiveForm();
|
const { formRef, validate } = useNaiveForm();
|
||||||
const { defaultRequiredRule } = useFormRules();
|
const { defaultRequiredRule } = useFormRules();
|
||||||
@ -19,8 +21,8 @@ interface FormModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const model: FormModel = reactive({
|
const model: FormModel = reactive({
|
||||||
userName: 'admin',
|
userName: devMode ? 'admin' : '',
|
||||||
password: 'admin'
|
password: devMode ? 'admin' : ''
|
||||||
});
|
});
|
||||||
|
|
||||||
type RuleKey = Extract<keyof FormModel, 'userName' | 'password'>;
|
type RuleKey = Extract<keyof FormModel, 'userName' | 'password'>;
|
||||||
|
@ -52,7 +52,7 @@ const model: Model = reactive(createDefaultModel());
|
|||||||
function createDefaultModel(): Model {
|
function createDefaultModel(): Model {
|
||||||
return {
|
return {
|
||||||
groupName: '',
|
groupName: '',
|
||||||
token: generateToken(32),
|
token: import.meta.env.VITE_APP_DEFAULT_TOKEN || '',
|
||||||
groupStatus: 1,
|
groupStatus: 1,
|
||||||
description: '',
|
description: '',
|
||||||
idGeneratorMode: 2,
|
idGeneratorMode: 2,
|
||||||
|
@ -351,11 +351,7 @@ watch(visible, () => {
|
|||||||
<NGrid cols="2 s:1 m:2" responsive="screen" x-gap="20">
|
<NGrid cols="2 s:1 m:2" responsive="screen" x-gap="20">
|
||||||
<NGi>
|
<NGi>
|
||||||
<NFormItem :label="$t('page.jobTask.triggerType')" path="triggerType">
|
<NFormItem :label="$t('page.jobTask.triggerType')" path="triggerType">
|
||||||
<TriggerType
|
<TriggerType v-model:value="model.triggerType" :placeholder="$t('page.jobTask.form.triggerType')" />
|
||||||
v-model:value="model.triggerType"
|
|
||||||
:placeholder="$t('page.jobTask.form.triggerType')"
|
|
||||||
@update:value="model.triggerInterval = ''"
|
|
||||||
/>
|
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
</NGi>
|
</NGi>
|
||||||
<NGi>
|
<NGi>
|
||||||
|
@ -28,13 +28,8 @@ const { columns, columnChecks, data, getData, loading, mobilePagination, searchP
|
|||||||
taskBatchStatus: null
|
taskBatchStatus: null
|
||||||
},
|
},
|
||||||
columns: () => [
|
columns: () => [
|
||||||
// {
|
|
||||||
// type: 'selection',
|
|
||||||
// align: 'center',
|
|
||||||
// width: 48
|
|
||||||
// },
|
|
||||||
{
|
{
|
||||||
key: 'index',
|
key: 'id',
|
||||||
title: $t('common.index'),
|
title: $t('common.index'),
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: 120
|
width: 120
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import { onMounted, ref } from 'vue';
|
import { onMounted, ref } from 'vue';
|
||||||
import Workflow, { flowFetch, flowStores } from '@sa/workflow';
|
import Workflow, { flowFetch, flowStores } from '@sa/workflow';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
|
import { $t } from '@/locales';
|
||||||
|
|
||||||
const store = flowStores.useFlowStore();
|
const store = flowStores.useFlowStore();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -16,6 +17,7 @@ onMounted(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const node = ref<Flow.NodeDataType>({
|
const node = ref<Flow.NodeDataType>({
|
||||||
|
workflowName: `Workflow ${new Date().getTime()}`,
|
||||||
workflowStatus: 1,
|
workflowStatus: 1,
|
||||||
blockStrategy: 1,
|
blockStrategy: 1,
|
||||||
description: undefined,
|
description: undefined,
|
||||||
@ -25,7 +27,7 @@ const node = ref<Flow.NodeDataType>({
|
|||||||
const save = async () => {
|
const save = async () => {
|
||||||
const { error } = await flowFetch.fetchAddWorkflow(node.value);
|
const { error } = await flowFetch.fetchAddWorkflow(node.value);
|
||||||
if (!error) {
|
if (!error) {
|
||||||
window.$message?.success('工作流新增成功');
|
window.$message?.info($t('common.addSuccess'));
|
||||||
router.push('/workflow/task');
|
router.push('/workflow/task');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,17 +1,52 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import WorkFlowIframe from '../modules/workflow-iframe.vue';
|
import { onMounted, ref } from 'vue';
|
||||||
|
import Workflow, { flowFetch, flowStores } from '@sa/workflow';
|
||||||
|
import { useRoute, useRouter } from 'vue-router';
|
||||||
|
import { $t } from '@/locales';
|
||||||
|
|
||||||
defineOptions({
|
const store = flowStores.useFlowStore();
|
||||||
name: 'WorkFlowEdit'
|
const route = useRoute();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const spinning = ref(false);
|
||||||
|
const disabled = ref(false);
|
||||||
|
|
||||||
|
const id: string = String(route.query.id);
|
||||||
|
|
||||||
|
const node = ref<Flow.NodeDataType>({});
|
||||||
|
|
||||||
|
const getDetail = async () => {
|
||||||
|
spinning.value = true;
|
||||||
|
const { data, error } = await flowFetch.fetchWorkflowInfo(id);
|
||||||
|
if (!error) {
|
||||||
|
node.value = data;
|
||||||
|
}
|
||||||
|
spinning.value = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
store.clear();
|
||||||
|
store.setType(0);
|
||||||
|
store.setId(id);
|
||||||
|
getDetail();
|
||||||
|
disabled.value = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const update = async () => {
|
||||||
|
const { error } = await flowFetch.fetchUpdateWorkflow(node.value);
|
||||||
|
if (!error) {
|
||||||
|
window.$message?.info($t('common.updateSuccess'));
|
||||||
|
router.push({ path: '/workflow/task' });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const cancel = () => {
|
||||||
|
router.push('/workflow/task');
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="iframe"><WorkFlowIframe value="D7Rzd7Oe" /></div>
|
<Workflow v-model="node" :spinning="spinning" :disabled="disabled" @save="update" @cancel="cancel" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped></style>
|
||||||
.iframe {
|
|
||||||
padding: 0 !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
@ -81,7 +81,7 @@ onActivated(() => {
|
|||||||
<iframe
|
<iframe
|
||||||
ref="iframeRef"
|
ref="iframeRef"
|
||||||
class="size-full"
|
class="size-full"
|
||||||
:src="`${mode === 'prod' ? baseUrl : ''}/lib/index.html?id=${id}&mode=${mode}&x1c2Hdd6=${value}`"
|
:src="`${mode === 'prod' ? baseUrl + '/' : '/'}lib/index.html?id=${id}&mode=${mode}&x1c2Hdd6=${value}`"
|
||||||
/>
|
/>
|
||||||
</NSpin>
|
</NSpin>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<script setup lang="tsx">
|
<script setup lang="tsx">
|
||||||
import { NButton, NButtonGroup, NPopconfirm, NPopover, NTag } from 'naive-ui';
|
import { NButton, NDropdown, NPopconfirm, NTag } from 'naive-ui';
|
||||||
import { useRouter } from 'vue-router';
|
import { useRouter } from 'vue-router';
|
||||||
import {
|
import {
|
||||||
fetchDelWorkflow,
|
fetchDelWorkflow,
|
||||||
@ -38,7 +38,7 @@ const { columns, columnChecks, data, getData, loading, mobilePagination, searchP
|
|||||||
// width: 48
|
// width: 48
|
||||||
// },
|
// },
|
||||||
{
|
{
|
||||||
key: 'index',
|
key: 'id',
|
||||||
title: $t('common.index'),
|
title: $t('common.index'),
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: 120
|
width: 120
|
||||||
@ -129,17 +129,50 @@ const { columns, columnChecks, data, getData, loading, mobilePagination, searchP
|
|||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
width: 200,
|
width: 200,
|
||||||
render: row => {
|
render: row => {
|
||||||
|
const options = [
|
||||||
|
{
|
||||||
|
label: $t('common.execute'),
|
||||||
|
key: 'execute',
|
||||||
|
click: () => execute(row.id!)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'divider',
|
||||||
|
key: 'd1'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: $t('common.copy'),
|
||||||
|
key: 'copy',
|
||||||
|
click: () => copy(row.id!)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'divider',
|
||||||
|
key: 'd2'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: $t('common.batchList'),
|
||||||
|
key: 'batchList',
|
||||||
|
click: () => batch(row.id!)
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
function onSelect(key: string) {
|
||||||
|
options.filter(o => o.key === key)[0].click!();
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div class="flex-center gap-8px">
|
<div class="flex-center gap-8px">
|
||||||
<NButton type="warning" ghost size="small" onClick={() => edit(row.id!)}>
|
<NButton text type="warning" ghost size="small" onClick={() => edit(row.id!)}>
|
||||||
{$t('common.edit')}
|
{$t('common.edit')}
|
||||||
</NButton>
|
</NButton>
|
||||||
|
|
||||||
|
<n-divider vertical />
|
||||||
|
|
||||||
{hasAuth('R_ADMIN') ? (
|
{hasAuth('R_ADMIN') ? (
|
||||||
<NPopconfirm onPositiveClick={() => handleDelete(row.id!)}>
|
<NPopconfirm onPositiveClick={() => handleDelete(row.id!)}>
|
||||||
{{
|
{{
|
||||||
default: () => $t('common.confirmDelete'),
|
default: () => $t('common.confirmDelete'),
|
||||||
trigger: () => (
|
trigger: () => (
|
||||||
<NButton type="error" ghost size="small">
|
<NButton text type="error" ghost size="small">
|
||||||
{$t('common.delete')}
|
{$t('common.delete')}
|
||||||
</NButton>
|
</NButton>
|
||||||
)
|
)
|
||||||
@ -149,30 +182,17 @@ const { columns, columnChecks, data, getData, loading, mobilePagination, searchP
|
|||||||
''
|
''
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<NPopover trigger="click" placement="bottom" raw show-arrow={false} class="b-rd-6px bg-#fff dark:bg-#000">
|
<n-divider vertical />
|
||||||
|
|
||||||
|
<NDropdown trigger="click" show-arrow={false} options={options} size="small" on-select={onSelect}>
|
||||||
{{
|
{{
|
||||||
trigger: () => (
|
default: () => (
|
||||||
<NButton type="primary" ghost size="small">
|
<NButton text type="primary" ghost size="small">
|
||||||
更多
|
更多
|
||||||
</NButton>
|
</NButton>
|
||||||
),
|
|
||||||
default: () => (
|
|
||||||
<div>
|
|
||||||
<NButtonGroup vertical>
|
|
||||||
<NButton type="primary" ghost size="small" onClick={() => execute(row.id!)}>
|
|
||||||
{$t('common.execute')}
|
|
||||||
</NButton>
|
|
||||||
<NButton type="primary" ghost size="small" onClick={() => copy(row.id!)}>
|
|
||||||
{$t('common.copy')}
|
|
||||||
</NButton>
|
|
||||||
<NButton type="success" ghost size="small" onClick={() => batch(row.id!)}>
|
|
||||||
{$t('common.batchList')}
|
|
||||||
</NButton>
|
|
||||||
</NButtonGroup>
|
|
||||||
</div>
|
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
</NPopover>
|
</NDropdown>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -188,8 +208,6 @@ const {
|
|||||||
|
|
||||||
async function handleBatchDelete() {
|
async function handleBatchDelete() {
|
||||||
// request
|
// request
|
||||||
console.log(checkedRowKeys.value);
|
|
||||||
|
|
||||||
onBatchDeleted();
|
onBatchDeleted();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,7 +225,7 @@ function edit(id: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleAdd() {
|
function handleAdd() {
|
||||||
router.push({ path: '/workflow/form/edit' });
|
router.push({ path: '/workflow/form/add' });
|
||||||
}
|
}
|
||||||
|
|
||||||
function detail(id: string) {
|
function detail(id: string) {
|
||||||
|
Loading…
Reference in New Issue
Block a user