feat: 新增工作流开始节点编辑抽屉
This commit is contained in:
parent
60d0c218d4
commit
5fcd6ed214
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@ -11,7 +11,7 @@
|
|||||||
"i18n-ally.enabledFrameworks": ["vue"],
|
"i18n-ally.enabledFrameworks": ["vue"],
|
||||||
"i18n-ally.editor.preferEditor": true,
|
"i18n-ally.editor.preferEditor": true,
|
||||||
"i18n-ally.keystyle": "nested",
|
"i18n-ally.keystyle": "nested",
|
||||||
"i18n-ally.localesPaths": ["src/locales/langs"],
|
"i18n-ally.localesPaths": ["src/locales/langs", "packages/work-flow/src/locales/langs"],
|
||||||
"prettier.enable": false,
|
"prettier.enable": false,
|
||||||
"typescript.tsdk": "node_modules/typescript/lib",
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
"unocss.root": ["./"]
|
"unocss.root": ["./"]
|
||||||
|
@ -30,3 +30,18 @@ export function fetchGroupNameList() {
|
|||||||
method: 'get'
|
method: 'get'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function fetchAddWorkflow(data: Flow.NodeDataType) {
|
||||||
|
return request<null>({
|
||||||
|
url: `/workflow`,
|
||||||
|
method: 'post',
|
||||||
|
data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fetchWorkflowInfo(id: string) {
|
||||||
|
return request<Flow.NodeDataType>({
|
||||||
|
url: `/workflow/${id}`,
|
||||||
|
method: 'get'
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -45,7 +45,7 @@ const addType = (type: number) => {
|
|||||||
nodeType: 2,
|
nodeType: 2,
|
||||||
conditionNodes: [
|
conditionNodes: [
|
||||||
{
|
{
|
||||||
nodeName: `${$t('node.condition.conditionNodes.nodeName')}1`,
|
nodeName: `${$t('node.condition.conditionNodes.nodeName')} 1`,
|
||||||
priorityLevel: 1,
|
priorityLevel: 1,
|
||||||
decision: {
|
decision: {
|
||||||
expressionType: 1,
|
expressionType: 1,
|
||||||
|
@ -40,7 +40,7 @@ watch(
|
|||||||
const addTerm = () => {
|
const addTerm = () => {
|
||||||
const len = nodeConfig.value.conditionNodes!.length;
|
const len = nodeConfig.value.conditionNodes!.length;
|
||||||
nodeConfig.value.conditionNodes!.splice(-1, 0, {
|
nodeConfig.value.conditionNodes!.splice(-1, 0, {
|
||||||
nodeName: `$t('node.condition.nodeName')${len}`,
|
nodeName: `${$t('node.condition.nodeName')} ${len}`,
|
||||||
priorityLevel: len,
|
priorityLevel: len,
|
||||||
decision: {
|
decision: {
|
||||||
expressionType: 1,
|
expressionType: 1,
|
||||||
@ -187,7 +187,7 @@ const getClass = (item: Flow.ConditionNodeType) => {
|
|||||||
<div class="branch-wrap">
|
<div class="branch-wrap">
|
||||||
<div class="branch-box-wrap">
|
<div class="branch-box-wrap">
|
||||||
<div class="branch-box">
|
<div class="branch-box">
|
||||||
<NButton v-if="!disabled" type="success" class="add-branch" @click="addTerm">
|
<NButton v-if="!disabled" strong type="success" class="add-branch" @click="addTerm">
|
||||||
{{ $t('node.condition.addBranch') }}
|
{{ $t('node.condition.addBranch') }}
|
||||||
</NButton>
|
</NButton>
|
||||||
<div v-for="(item, index) in nodeConfig.conditionNodes" :key="index" class="col-box">
|
<div v-for="(item, index) in nodeConfig.conditionNodes" :key="index" class="col-box">
|
||||||
|
@ -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="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>
|
||||||
|
@ -80,10 +80,10 @@ const show = () => {
|
|||||||
class="node-wrap-box node-error-success start-node"
|
class="node-wrap-box node-error-success start-node"
|
||||||
@click="show"
|
@click="show"
|
||||||
>
|
>
|
||||||
<div class="title bg-#ffffff">
|
<div class="title">
|
||||||
<span class="text" calss="color-#ff943e">
|
<span class="text text-#ff943e">
|
||||||
<NBadge dot :color="nodeData.workflowStatus === 1 ? '#52c41a' : '#ff000d'" />
|
<NBadge dot :color="nodeData.workflowStatus === 1 ? '#52c41a' : '#ff000d'" />
|
||||||
{{ nodeData.workflowName ? nodeData.workflowName : $t('snail.form.groupName') }}
|
{{ nodeData.workflowName ? nodeData.workflowName : $t('snail.form.groupName') }}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="nodeData.groupName" class="content">
|
<div v-if="nodeData.groupName" class="content">
|
||||||
|
@ -43,7 +43,7 @@ watch(
|
|||||||
const addTerm = () => {
|
const addTerm = () => {
|
||||||
const len = nodeConfig.value.conditionNodes!.length + 1;
|
const len = nodeConfig.value.conditionNodes!.length + 1;
|
||||||
nodeConfig.value.conditionNodes?.push({
|
nodeConfig.value.conditionNodes?.push({
|
||||||
nodeName: `${$t('node.task.name')}${len}`,
|
nodeName: `${$t('node.task.name')} ${len}`,
|
||||||
priorityLevel: len,
|
priorityLevel: len,
|
||||||
failStrategy: 1,
|
failStrategy: 1,
|
||||||
workflowNodeStatus: 1,
|
workflowNodeStatus: 1,
|
||||||
@ -179,7 +179,9 @@ const isStop = (taskBatchStatus: number) => {
|
|||||||
<template>
|
<template>
|
||||||
<div class="node-wrap">
|
<div class="node-wrap">
|
||||||
<div class="branch-box">
|
<div class="branch-box">
|
||||||
<NButton v-if="!disabled" class="add-branch" type="success" @click="addTerm">{{ $t('node.task.add') }}</NButton>
|
<NButton v-if="!disabled" class="add-branch" strong type="success" @click="addTerm">
|
||||||
|
{{ $t('node.task.add') }}
|
||||||
|
</NButton>
|
||||||
<div v-for="(item, i) in nodeConfig.conditionNodes" :key="i" class="col-box">
|
<div v-for="(item, i) in nodeConfig.conditionNodes" :key="i" class="col-box">
|
||||||
<div class="condition-node">
|
<div class="condition-node">
|
||||||
<div class="condition-node-box">
|
<div class="condition-node-box">
|
||||||
@ -207,7 +209,7 @@ const isStop = (taskBatchStatus: number) => {
|
|||||||
<div class="title">
|
<div class="title">
|
||||||
<span class="text color-#3296fa">
|
<span class="text color-#3296fa">
|
||||||
<NBadge processing dot :color="item.workflowNodeStatus === 1 ? '#52c41a' : '#ff4d4f'" />
|
<NBadge processing dot :color="item.workflowNodeStatus === 1 ? '#52c41a' : '#ff4d4f'" />
|
||||||
{{ item.nodeName }}
|
{{ item.nodeName }}
|
||||||
</span>
|
</span>
|
||||||
<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)" />
|
||||||
|
@ -3,6 +3,7 @@ import { ref, watch } from 'vue';
|
|||||||
import CronInput from '@sa/cron-input';
|
import CronInput from '@sa/cron-input';
|
||||||
import { type FormInst, type FormItemRule, useMessage } from 'naive-ui';
|
import { type FormInst, type FormItemRule, useMessage } from 'naive-ui';
|
||||||
import { blockStrategyOptions, triggerTypeOptions, workFlowNodeStatusOptions } from '../constants/business';
|
import { blockStrategyOptions, triggerTypeOptions, workFlowNodeStatusOptions } from '../constants/business';
|
||||||
|
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';
|
||||||
@ -132,9 +133,9 @@ const rules: Record<RuleKey, FormItemRule> = {
|
|||||||
};
|
};
|
||||||
})
|
})
|
||||||
"
|
"
|
||||||
></NSelect>
|
/>
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
<NGrid :cols="24">
|
<NGrid :cols="24" x-gap="20">
|
||||||
<NGi :span="8">
|
<NGi :span="8">
|
||||||
<NFormItem path="triggerType" label="触发类型">
|
<NFormItem path="triggerType" label="触发类型">
|
||||||
<NSelect
|
<NSelect
|
||||||
@ -152,13 +153,18 @@ const rules: Record<RuleKey, FormItemRule> = {
|
|||||||
v-model:value="form.triggerInterval"
|
v-model:value="form.triggerInterval"
|
||||||
placeholder="请输入Cron表达式"
|
placeholder="请输入Cron表达式"
|
||||||
/>
|
/>
|
||||||
<NInputNumber v-else v-model:value="form.triggerInterval as number" placeholder="请输入触发间隔">
|
<NInputNumber
|
||||||
|
v-else
|
||||||
|
v-model:value="form.triggerInterval as number"
|
||||||
|
class="w-full"
|
||||||
|
placeholder="请输入触发间隔"
|
||||||
|
>
|
||||||
<template #suffix>秒</template>
|
<template #suffix>秒</template>
|
||||||
</NInputNumber>
|
</NInputNumber>
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
</NGi>
|
</NGi>
|
||||||
</NGrid>
|
</NGrid>
|
||||||
<NGrid :cols="24">
|
<NGrid :cols="24" x-gap="20">
|
||||||
<NGi :span="8">
|
<NGi :span="8">
|
||||||
<NFormItem path="executorTimeout" label="执行超时时间">
|
<NFormItem path="executorTimeout" label="执行超时时间">
|
||||||
<NInputNumber v-model:value="form.executorTimeout" placeholder="请输入超时时间">
|
<NInputNumber v-model:value="form.executorTimeout" placeholder="请输入超时时间">
|
||||||
@ -168,12 +174,30 @@ const rules: Record<RuleKey, FormItemRule> = {
|
|||||||
</NGi>
|
</NGi>
|
||||||
<NGi :span="16">
|
<NGi :span="16">
|
||||||
<NFormItem path="blockStrategy" label="阻塞策略">
|
<NFormItem path="blockStrategy" label="阻塞策略">
|
||||||
<NRadioGroup v-model:value="form.blockStrategy" :option="blockStrategyOptions" />
|
<NRadioGroup v-model:value="form.blockStrategy">
|
||||||
|
<NSpace>
|
||||||
|
<NRadio
|
||||||
|
v-for="options in blockStrategyOptions"
|
||||||
|
:key="options.value"
|
||||||
|
:label="$t(options.label)"
|
||||||
|
:value="options.value"
|
||||||
|
/>
|
||||||
|
</NSpace>
|
||||||
|
</NRadioGroup>
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
</NGi>
|
</NGi>
|
||||||
</NGrid>
|
</NGrid>
|
||||||
<NFormItem path="workflowStatus" label="节点状态">
|
<NFormItem path="workflowStatus" label="节点状态">
|
||||||
<NRadioGroup v-model:value="form.workflowStatus" :option="workFlowNodeStatusOptions" />
|
<NRadioGroup v-model:value="form.workflowStatus">
|
||||||
|
<NSpace>
|
||||||
|
<NRadio
|
||||||
|
v-for="options in workFlowNodeStatusOptions"
|
||||||
|
:key="options.value"
|
||||||
|
:label="$t(options.label)"
|
||||||
|
:value="options.value"
|
||||||
|
/>
|
||||||
|
</NSpace>
|
||||||
|
</NRadioGroup>
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
<NFormItem path="description" label="描述">
|
<NFormItem path="description" label="描述">
|
||||||
<NInput
|
<NInput
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import Workflow from './workflow.vue';
|
import Workflow from './workflow.vue';
|
||||||
import * as flowLocales from './locales';
|
import * as flowLocales from './locales';
|
||||||
import * as flowStores from './stores';
|
import * as flowStores from './stores';
|
||||||
|
import * as flowFetch from './api';
|
||||||
|
|
||||||
export { flowLocales, flowStores };
|
export { flowLocales, flowStores, flowFetch };
|
||||||
export default Workflow;
|
export default Workflow;
|
||||||
|
@ -40,6 +40,14 @@ export const useFlowStore = defineStore('workflow', () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function clear() {
|
||||||
|
id.value = undefined;
|
||||||
|
type.value = undefined;
|
||||||
|
groupName.value = undefined;
|
||||||
|
jobList.value = [];
|
||||||
|
clearFLowStorage();
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id,
|
id,
|
||||||
type,
|
type,
|
||||||
@ -49,6 +57,7 @@ export const useFlowStore = defineStore('workflow', () => {
|
|||||||
setType,
|
setType,
|
||||||
setId,
|
setId,
|
||||||
clearFLowStorage,
|
clearFLowStorage,
|
||||||
getJobList
|
getJobList,
|
||||||
|
clear
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
@ -149,7 +149,7 @@
|
|||||||
left: 50%;
|
left: 50%;
|
||||||
transform: translateX(-50%);
|
transform: translateX(-50%);
|
||||||
transform-origin: center center;
|
transform-origin: center center;
|
||||||
z-index: 1;
|
z-index: 10;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
@ -171,13 +171,12 @@
|
|||||||
padding: 8px 15px !important;
|
padding: 8px 15px !important;
|
||||||
color: #67c23a;
|
color: #67c23a;
|
||||||
background-color: #f0f9eb;
|
background-color: #f0f9eb;
|
||||||
border: 1px solid #dcdfe6;
|
// border: 1px solid #b3e19d;
|
||||||
border-color: #b3e19d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.add-branch:hover {
|
.add-branch:hover {
|
||||||
color: #ffffff;
|
color: #ffffff;
|
||||||
border-color: #b3e19d;
|
// border-color: #b3e19d;
|
||||||
background-color: #67c23a;
|
background-color: #67c23a;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -282,7 +281,7 @@
|
|||||||
border-style: solid;
|
border-style: solid;
|
||||||
border-width: 8px 6px 4px;
|
border-width: 8px 6px 4px;
|
||||||
border-color: rgb(202, 202, 202) transparent transparent;
|
border-color: rgb(202, 202, 202) transparent transparent;
|
||||||
background: rgb(239, 239, 239);
|
background: rgb(255 255 255 / 0%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.auto-judge .title {
|
.auto-judge .title {
|
||||||
@ -590,22 +589,11 @@
|
|||||||
background: var(--el-bg-color);
|
background: var(--el-bg-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.top-left-cover-line,
|
|
||||||
.top-right-cover-line,
|
|
||||||
.bottom-left-cover-line,
|
|
||||||
.bottom-right-cover-line {
|
|
||||||
background-color: var(--el-bg-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.node-wrap-box::before,
|
.node-wrap-box::before,
|
||||||
.auto-judge::before {
|
.auto-judge::before {
|
||||||
background-color: var(--el-bg-color);
|
background-color: var(--el-bg-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
.branch-box .add-branch {
|
|
||||||
background: var(--el-bg-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.end-node .end-node-text {
|
.end-node .end-node-text {
|
||||||
color: #ccc;
|
color: #ccc;
|
||||||
}
|
}
|
||||||
@ -615,3 +603,9 @@
|
|||||||
background: var(--el-bg-color);
|
background: var(--el-bg-color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.dark {
|
||||||
|
.add-branch {
|
||||||
|
background-color: #3e5a2d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
2
packages/work-flow/src/typings/flow.d.ts
vendored
2
packages/work-flow/src/typings/flow.d.ts
vendored
@ -9,7 +9,7 @@ declare namespace Flow {
|
|||||||
type WorkFlowNodeStatus = 0 | 1;
|
type WorkFlowNodeStatus = 0 | 1;
|
||||||
|
|
||||||
/** 组 */
|
/** 组 */
|
||||||
type NodeDataType = {
|
export type NodeDataType = {
|
||||||
/** 流程ID */
|
/** 流程ID */
|
||||||
id?: string;
|
id?: string;
|
||||||
/** 工作流名称 */
|
/** 工作流名称 */
|
||||||
|
27
packages/work-flow/src/typings/global.d.ts
vendored
Normal file
27
packages/work-flow/src/typings/global.d.ts
vendored
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
interface Window {
|
||||||
|
/** NProgress instance */
|
||||||
|
NProgress?: import('nprogress').NProgress;
|
||||||
|
/** Loading bar instance */
|
||||||
|
$loadingBar?: import('naive-ui').LoadingBarProviderInst;
|
||||||
|
/** Dialog instance */
|
||||||
|
$dialog?: import('naive-ui').DialogProviderInst;
|
||||||
|
/** Message instance */
|
||||||
|
$message?: import('naive-ui').MessageProviderInst;
|
||||||
|
/** Notification instance */
|
||||||
|
$notification?: import('naive-ui').NotificationProviderInst;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ViewTransition {
|
||||||
|
ready: Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Document {
|
||||||
|
startViewTransition?: (callback: () => Promise<void> | void) => ViewTransition;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImportMeta {
|
||||||
|
readonly env: Env.ImportMeta;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Build time of the project */
|
||||||
|
declare const BUILD_TIME: string;
|
@ -1,5 +1,4 @@
|
|||||||
import { BACKEND_ERROR_CODE, createFlatRequest } from '@sa/axios';
|
import { BACKEND_ERROR_CODE, createFlatRequest } from '@sa/axios';
|
||||||
import { useMessage } from 'naive-ui';
|
|
||||||
import { localStg } from './storage';
|
import { localStg } from './storage';
|
||||||
|
|
||||||
const baseURL = '/proxy-default';
|
const baseURL = '/proxy-default';
|
||||||
@ -36,12 +35,12 @@ export const request = createFlatRequest<Service.Response>(
|
|||||||
onError(error) {
|
onError(error) {
|
||||||
// when the request is fail, you can show error message
|
// when the request is fail, you can show error message
|
||||||
|
|
||||||
let message = error.message;
|
let msg = error.message;
|
||||||
let backendErrorCode = '';
|
let backendErrorCode = '';
|
||||||
|
|
||||||
// get backend error message and code
|
// get backend error message and code
|
||||||
if (error.code === BACKEND_ERROR_CODE) {
|
if (error.code === BACKEND_ERROR_CODE) {
|
||||||
message = error.response?.data?.message || message;
|
msg = error.response?.data?.message || msg;
|
||||||
backendErrorCode = error.response?.data?.status.toString() || '';
|
backendErrorCode = error.response?.data?.status.toString() || '';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -57,7 +56,7 @@ export const request = createFlatRequest<Service.Response>(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
useMessage().error(message);
|
window.$message?.error(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -10,22 +10,35 @@ defineOptions({
|
|||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
modelValue?: Flow.NodeDataType;
|
modelValue?: Flow.NodeDataType;
|
||||||
|
spinning?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Props>(), {
|
const props = withDefaults(defineProps<Props>(), {
|
||||||
disabled: false,
|
disabled: false,
|
||||||
|
spinning: false,
|
||||||
modelValue: () => ({})
|
modelValue: () => ({})
|
||||||
});
|
});
|
||||||
|
|
||||||
interface Emits {
|
interface Emits {
|
||||||
(e: 'update:modelValue', modelValue: Flow.NodeDataType): void;
|
(e: 'update:modelValue', modelValue: Flow.NodeDataType): void;
|
||||||
|
(e: 'save'): void;
|
||||||
|
(e: 'cancel'): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const emit = defineEmits<Emits>();
|
const emit = defineEmits<Emits>();
|
||||||
|
|
||||||
|
const zoom = ref<number>(100);
|
||||||
const nodeData = ref<Flow.NodeDataType>({});
|
const nodeData = ref<Flow.NodeDataType>({});
|
||||||
|
|
||||||
|
const save = async () => {
|
||||||
|
emit('save');
|
||||||
|
};
|
||||||
|
|
||||||
|
const cancel = () => {
|
||||||
|
emit('cancel');
|
||||||
|
};
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.modelValue,
|
() => props.modelValue,
|
||||||
val => {
|
val => {
|
||||||
@ -40,10 +53,49 @@ watch(
|
|||||||
emit('update:modelValue', val);
|
emit('update:modelValue', val);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const onZoom = (n: number) => {
|
||||||
|
zoom.value += 10 * n;
|
||||||
|
|
||||||
|
if (zoom.value <= 10) {
|
||||||
|
zoom.value = 10;
|
||||||
|
} else if (zoom.value >= 300) {
|
||||||
|
zoom.value = 300;
|
||||||
|
}
|
||||||
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="workflow-design">
|
<div class="workflow">
|
||||||
|
<div class="workflow-affix">
|
||||||
|
<NAffix :trigger-top="0">
|
||||||
|
<div class="header">
|
||||||
|
<div>
|
||||||
|
<NTooltip title="缩小">
|
||||||
|
<template #trigger>
|
||||||
|
<NButton type="info" strong @click="onZoom(-1)">
|
||||||
|
<icon-ant-design:minus-outlined />
|
||||||
|
</NButton>
|
||||||
|
</template>
|
||||||
|
</NTooltip>
|
||||||
|
<span class="ml-8px mr-8px text-#333639 dark:text-#d6d6d6">{{ zoom }}%</span>
|
||||||
|
<NTooltip title="放大">
|
||||||
|
<template #trigger>
|
||||||
|
<NButton type="info" strong @click="onZoom(1)">
|
||||||
|
<icon-ant-design:plus-outlined />
|
||||||
|
</NButton>
|
||||||
|
</template>
|
||||||
|
</NTooltip>
|
||||||
|
</div>
|
||||||
|
<div v-if="!disabled" class="buttons">
|
||||||
|
<NButton type="info" siz="large" @click="save">保存</NButton>
|
||||||
|
<NButton siz="large" class="ml-16px" @click="cancel">取消</NButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</NAffix>
|
||||||
|
<div class="workflow-body">
|
||||||
|
<NSpin :show="spinning">
|
||||||
|
<div class="workflow-design" :style="`transform: scale(${zoom / 100})`">
|
||||||
<div class="box-scale">
|
<div class="box-scale">
|
||||||
<StartNode v-model="nodeData" :disabled="disabled" />
|
<StartNode v-model="nodeData" :disabled="disabled" />
|
||||||
<NodeWrap v-if="nodeData.nodeConfig" v-model="nodeData.nodeConfig" :disabled="disabled" />
|
<NodeWrap v-if="nodeData.nodeConfig" v-model="nodeData.nodeConfig" :disabled="disabled" />
|
||||||
@ -53,8 +105,50 @@ watch(
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</NSpin>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
@import './styles/index';
|
@import './styles/index';
|
||||||
|
|
||||||
|
.workflow {
|
||||||
|
padding: 0 !important;
|
||||||
|
height: calc(100% - 50px);
|
||||||
|
|
||||||
|
&-affix {
|
||||||
|
.header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
box-shadow: 0 1px 4px rgba(0, 21, 41, 0.08);
|
||||||
|
background-color: #fff;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 8px 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-body {
|
||||||
|
overflow: auto;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-design {
|
||||||
|
margin-top: 16px;
|
||||||
|
transform-origin: 0 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.dark {
|
||||||
|
.workflow {
|
||||||
|
&-affix {
|
||||||
|
.header {
|
||||||
|
box-shadow: 0 1px 4px rgba(255, 255, 255, 0.08);
|
||||||
|
background-color: #121212;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -299,6 +299,7 @@ const local: App.I18n.Schema = {
|
|||||||
workflow_form_batch: 'Workflow Batch Detail',
|
workflow_form_batch: 'Workflow Batch Detail',
|
||||||
workflow_form_detail: 'Workflow Detail',
|
workflow_form_detail: 'Workflow Detail',
|
||||||
workflow_form_edit: 'Edit Workflow',
|
workflow_form_edit: 'Edit Workflow',
|
||||||
|
workflow_form_add: 'Add Workflow',
|
||||||
job: 'Schedule Task Management',
|
job: 'Schedule Task Management',
|
||||||
job_task: 'Schedule Task List',
|
job_task: 'Schedule Task List',
|
||||||
job_batch: 'Schedule Task Batch List',
|
job_batch: 'Schedule Task Batch List',
|
||||||
|
@ -300,6 +300,7 @@ const local: App.I18n.Schema = {
|
|||||||
workflow_form_batch: '工作流批次详情',
|
workflow_form_batch: '工作流批次详情',
|
||||||
workflow_form_detail: '工作流详情',
|
workflow_form_detail: '工作流详情',
|
||||||
workflow_form_edit: '编辑工作流',
|
workflow_form_edit: '编辑工作流',
|
||||||
|
workflow_form_add: '新增工作流',
|
||||||
job: '定时任务',
|
job: '定时任务',
|
||||||
job_task: '任务管理',
|
job_task: '任务管理',
|
||||||
job_batch: '执行批次',
|
job_batch: '执行批次',
|
||||||
|
@ -50,6 +50,7 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
|
|||||||
"user-center": () => import("@/views/user-center/index.vue"),
|
"user-center": () => import("@/views/user-center/index.vue"),
|
||||||
user_manager: () => import("@/views/user/manager/index.vue"),
|
user_manager: () => import("@/views/user/manager/index.vue"),
|
||||||
workflow_batch: () => import("@/views/workflow/batch/index.vue"),
|
workflow_batch: () => import("@/views/workflow/batch/index.vue"),
|
||||||
|
workflow_form_add: () => import("@/views/workflow/form/add/index.vue"),
|
||||||
workflow_form_batch: () => import("@/views/workflow/form/batch/index.vue"),
|
workflow_form_batch: () => import("@/views/workflow/form/batch/index.vue"),
|
||||||
workflow_form_copy: () => import("@/views/workflow/form/copy/index.vue"),
|
workflow_form_copy: () => import("@/views/workflow/form/copy/index.vue"),
|
||||||
workflow_form_detail: () => import("@/views/workflow/form/detail/index.vue"),
|
workflow_form_detail: () => import("@/views/workflow/form/detail/index.vue"),
|
||||||
|
@ -556,6 +556,16 @@ export const generatedRoutes: GeneratedRoute[] = [
|
|||||||
i18nKey: 'route.workflow_form'
|
i18nKey: 'route.workflow_form'
|
||||||
},
|
},
|
||||||
children: [
|
children: [
|
||||||
|
{
|
||||||
|
name: 'workflow_form_add',
|
||||||
|
path: '/workflow/form/add',
|
||||||
|
component: 'view.workflow_form_add',
|
||||||
|
meta: {
|
||||||
|
hideInMenu: true,
|
||||||
|
title: 'workflow_form_add',
|
||||||
|
i18nKey: 'route.workflow_form_add'
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'workflow_form_batch',
|
name: 'workflow_form_batch',
|
||||||
path: '/workflow/form/batch',
|
path: '/workflow/form/batch',
|
||||||
|
@ -203,6 +203,7 @@ const routeMap: RouteMap = {
|
|||||||
"workflow": "/workflow",
|
"workflow": "/workflow",
|
||||||
"workflow_batch": "/workflow/batch",
|
"workflow_batch": "/workflow/batch",
|
||||||
"workflow_form": "/workflow/form",
|
"workflow_form": "/workflow/form",
|
||||||
|
"workflow_form_add": "/workflow/form/add",
|
||||||
"workflow_form_batch": "/workflow/form/batch",
|
"workflow_form_batch": "/workflow/form/batch",
|
||||||
"workflow_form_copy": "/workflow/form/copy",
|
"workflow_form_copy": "/workflow/form/copy",
|
||||||
"workflow_form_detail": "/workflow/form/detail",
|
"workflow_form_detail": "/workflow/form/detail",
|
||||||
|
23
src/typings/global.d.ts
vendored
23
src/typings/global.d.ts
vendored
@ -1,27 +1,4 @@
|
|||||||
interface Window {
|
interface Window {
|
||||||
/** NProgress instance */
|
|
||||||
NProgress?: import('nprogress').NProgress;
|
|
||||||
/** Loading bar instance */
|
|
||||||
$loadingBar?: import('naive-ui').LoadingBarProviderInst;
|
|
||||||
/** Dialog instance */
|
|
||||||
$dialog?: import('naive-ui').DialogProviderInst;
|
|
||||||
/** Message instance */
|
/** Message instance */
|
||||||
$message?: import('naive-ui').MessageProviderInst;
|
$message?: import('naive-ui').MessageProviderInst;
|
||||||
/** Notification instance */
|
|
||||||
$notification?: import('naive-ui').NotificationProviderInst;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ViewTransition {
|
|
||||||
ready: Promise<void>;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Document {
|
|
||||||
startViewTransition?: (callback: () => Promise<void> | void) => ViewTransition;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ImportMeta {
|
|
||||||
readonly env: Env.ImportMeta;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Build time of the project */
|
|
||||||
declare const BUILD_TIME: string;
|
|
||||||
|
42
src/views/workflow/form/add/index.vue
Normal file
42
src/views/workflow/form/add/index.vue
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { onMounted, ref } from 'vue';
|
||||||
|
import Workflow, { flowFetch, flowStores } from '@sa/workflow';
|
||||||
|
import { useRouter } from 'vue-router';
|
||||||
|
|
||||||
|
const store = flowStores.useFlowStore();
|
||||||
|
const router = useRouter();
|
||||||
|
|
||||||
|
const spinning = ref(false);
|
||||||
|
const disabled = ref(false);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
store.clear();
|
||||||
|
store.setType(0);
|
||||||
|
disabled.value = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
const node = ref<Flow.NodeDataType>({
|
||||||
|
workflowStatus: 1,
|
||||||
|
blockStrategy: 1,
|
||||||
|
description: undefined,
|
||||||
|
executorTimeout: 60
|
||||||
|
});
|
||||||
|
|
||||||
|
const save = async () => {
|
||||||
|
const { error } = await flowFetch.fetchAddWorkflow(node.value);
|
||||||
|
if (!error) {
|
||||||
|
window.$message?.success('工作流新增成功');
|
||||||
|
router.push('/workflow/task');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const cancel = () => {
|
||||||
|
router.push('/workflow/task');
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<Workflow v-model="node" :spinning="spinning" :disabled="disabled" @save="save" @cancel="cancel" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
Loading…
Reference in New Issue
Block a user