feat(sj_1.2.0-beta1): 新增支持 http 内置执行器
This commit is contained in:
parent
6ab0a21d10
commit
532b370838
@ -1,5 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, reactive, ref, watch } from 'vue';
|
import { computed, reactive, ref, watch } from 'vue';
|
||||||
|
import type { FormInst } from 'naive-ui';
|
||||||
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
|
||||||
import OperateDrawer from '@/components/common/operate-drawer.vue';
|
import OperateDrawer from '@/components/common/operate-drawer.vue';
|
||||||
import { $t } from '@/locales';
|
import { $t } from '@/locales';
|
||||||
@ -10,7 +11,7 @@ import ExecutorType from '@/components/common/executor-type.vue';
|
|||||||
import TaskType from '@/components/common/task-type.vue';
|
import TaskType from '@/components/common/task-type.vue';
|
||||||
import CodeMirror from '@/components/common/code-mirror.vue';
|
import CodeMirror from '@/components/common/code-mirror.vue';
|
||||||
import JobTriggerInterval from '@/components/common/job-trigger-interval.vue';
|
import JobTriggerInterval from '@/components/common/job-trigger-interval.vue';
|
||||||
import { translateOptions } from '@/utils/common';
|
import { isNotNull, translateOptions } from '@/utils/common';
|
||||||
|
|
||||||
defineOptions({
|
defineOptions({
|
||||||
name: 'JobTaskOperateDrawer'
|
name: 'JobTaskOperateDrawer'
|
||||||
@ -31,6 +32,7 @@ interface Emits {
|
|||||||
|
|
||||||
const emit = defineEmits<Emits>();
|
const emit = defineEmits<Emits>();
|
||||||
|
|
||||||
|
const executorCustomType = ref<0 | 1>(0);
|
||||||
const visible = defineModel<boolean>('visible', {
|
const visible = defineModel<boolean>('visible', {
|
||||||
default: false
|
default: false
|
||||||
});
|
});
|
||||||
@ -40,6 +42,7 @@ const dynamicForm = reactive({
|
|||||||
});
|
});
|
||||||
const shardNum = ref(0);
|
const shardNum = ref(0);
|
||||||
|
|
||||||
|
const customformRef = ref<FormInst | null>(null);
|
||||||
const { formRef, validate, restoreValidation } = useNaiveForm();
|
const { formRef, validate, restoreValidation } = useNaiveForm();
|
||||||
const { defaultRequiredRule } = useFormRules();
|
const { defaultRequiredRule } = useFormRules();
|
||||||
|
|
||||||
@ -77,7 +80,8 @@ const model: Model = reactive(createDefaultModel());
|
|||||||
|
|
||||||
function createDefaultModel(): Model {
|
function createDefaultModel(): Model {
|
||||||
return {
|
return {
|
||||||
groupName: '',
|
// @ts-expect-error groupName is required
|
||||||
|
groupName: undefined,
|
||||||
jobName: '',
|
jobName: '',
|
||||||
argsStr: '',
|
argsStr: '',
|
||||||
argsType: 1,
|
argsType: 1,
|
||||||
@ -85,7 +89,8 @@ function createDefaultModel(): Model {
|
|||||||
routeKey: 4,
|
routeKey: 4,
|
||||||
executorType: 1,
|
executorType: 1,
|
||||||
triggerType: 2,
|
triggerType: 2,
|
||||||
executorInfo: '',
|
// @ts-expect-error groupName is required
|
||||||
|
executorInfo: undefined,
|
||||||
triggerInterval: '60',
|
triggerInterval: '60',
|
||||||
blockStrategy: 1,
|
blockStrategy: 1,
|
||||||
executorTimeout: 60,
|
executorTimeout: 60,
|
||||||
@ -134,9 +139,74 @@ const rules: Record<RuleKey, App.Global.FormRule> = {
|
|||||||
parallelNum: defaultRequiredRule
|
parallelNum: defaultRequiredRule
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type HttpParams = {
|
||||||
|
method: string;
|
||||||
|
url: string;
|
||||||
|
mediaType: string;
|
||||||
|
body?: string;
|
||||||
|
headers: {
|
||||||
|
[key in string]: string;
|
||||||
|
};
|
||||||
|
timeout: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
const httpHeaders = ref<{ key: string; value: string }[]>([]);
|
||||||
|
|
||||||
|
const httpParams = reactive<HttpParams>(createDefaultHttpParams());
|
||||||
|
|
||||||
|
function createDefaultHttpParams() {
|
||||||
|
return {
|
||||||
|
method: 'POST',
|
||||||
|
url: '',
|
||||||
|
headers: {},
|
||||||
|
mediaType: 'application/json',
|
||||||
|
timeout: 60
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const executorCustomOptions = [
|
||||||
|
{
|
||||||
|
label: 'Http 执行器',
|
||||||
|
value: 'snailJobHttpExecutor'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'CMD 执行器',
|
||||||
|
value: 'snailJobCMDJobExecutor'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'PowerShell 执行器',
|
||||||
|
value: 'snailJobPowerShellJobExecutor'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Shell 执行器',
|
||||||
|
value: 'snailJobShellJobExecutor'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
const httpMethodOptions = [
|
||||||
|
{
|
||||||
|
label: 'GET',
|
||||||
|
value: 'get'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'POST',
|
||||||
|
value: 'post'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'PUT',
|
||||||
|
value: 'put'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'DELETE',
|
||||||
|
value: 'delete'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
function handleUpdateModelWhenEdit() {
|
function handleUpdateModelWhenEdit() {
|
||||||
if (props.operateType === 'add') {
|
if (props.operateType === 'add') {
|
||||||
Object.assign(model, createDefaultModel());
|
Object.assign(model, createDefaultModel());
|
||||||
|
executorCustomType.value = 0;
|
||||||
|
Object.assign(httpParams, createDefaultHttpParams());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,6 +225,18 @@ function handleUpdateModelWhenEdit() {
|
|||||||
shardNum.value = argsJson.shardNum;
|
shardNum.value = argsJson.shardNum;
|
||||||
model.argsStr = argsJson.argsStr;
|
model.argsStr = argsJson.argsStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (executorCustomOptions.map(item => item.value).includes(model.executorInfo)) {
|
||||||
|
executorCustomType.value = 1;
|
||||||
|
if (model.executorInfo === 'snailJobHttpExecutor') {
|
||||||
|
Object.assign(httpParams, JSON.parse(model.argsStr));
|
||||||
|
if (httpParams.headers) {
|
||||||
|
httpHeaders.value = Object.keys(httpParams.headers).map((item: string) => {
|
||||||
|
return { key: item, value: httpParams.headers![item] };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,13 +246,11 @@ function closeDrawer() {
|
|||||||
|
|
||||||
async function handleSubmit() {
|
async function handleSubmit() {
|
||||||
await validate();
|
await validate();
|
||||||
|
|
||||||
if (props.operateType === 'add') {
|
|
||||||
const {
|
const {
|
||||||
|
id,
|
||||||
groupName,
|
groupName,
|
||||||
jobName,
|
jobName,
|
||||||
argsType,
|
argsType,
|
||||||
argsStr,
|
|
||||||
jobStatus,
|
jobStatus,
|
||||||
routeKey,
|
routeKey,
|
||||||
executorType,
|
executorType,
|
||||||
@ -185,10 +265,24 @@ async function handleSubmit() {
|
|||||||
parallelNum,
|
parallelNum,
|
||||||
description
|
description
|
||||||
} = model;
|
} = model;
|
||||||
|
|
||||||
|
let argsStr = taskType === 5 ? JSON.stringify({ shardNum: shardNum.value, argsStr: model.argsStr }) : model.argsStr;
|
||||||
|
|
||||||
|
if (executorCustomType.value === 1) {
|
||||||
|
await customformRef.value?.validate();
|
||||||
|
if (model.executorInfo === 'snailJobHttpExecutor') {
|
||||||
|
httpHeaders.value.forEach(item => {
|
||||||
|
httpParams.headers[item.key] = item.value;
|
||||||
|
});
|
||||||
|
argsStr = JSON.stringify(httpParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.operateType === 'add') {
|
||||||
const { error } = await fetchAddJob({
|
const { error } = await fetchAddJob({
|
||||||
groupName,
|
groupName,
|
||||||
jobName,
|
jobName,
|
||||||
argsStr: taskType === 5 ? JSON.stringify({ shardNum: shardNum.value, argsStr }) : argsStr,
|
argsStr,
|
||||||
argsType,
|
argsType,
|
||||||
jobStatus,
|
jobStatus,
|
||||||
routeKey,
|
routeKey,
|
||||||
@ -209,31 +303,11 @@ async function handleSubmit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (props.operateType === 'edit') {
|
if (props.operateType === 'edit') {
|
||||||
const {
|
|
||||||
id,
|
|
||||||
groupName,
|
|
||||||
jobName,
|
|
||||||
argsStr,
|
|
||||||
argsType,
|
|
||||||
jobStatus,
|
|
||||||
routeKey,
|
|
||||||
executorType,
|
|
||||||
executorInfo,
|
|
||||||
triggerType,
|
|
||||||
triggerInterval,
|
|
||||||
blockStrategy,
|
|
||||||
executorTimeout,
|
|
||||||
maxRetryTimes,
|
|
||||||
retryInterval,
|
|
||||||
taskType,
|
|
||||||
parallelNum,
|
|
||||||
description
|
|
||||||
} = model;
|
|
||||||
const { error } = await fetchEditJob({
|
const { error } = await fetchEditJob({
|
||||||
id,
|
id,
|
||||||
groupName,
|
groupName,
|
||||||
jobName,
|
jobName,
|
||||||
argsStr: taskType === 5 ? JSON.stringify({ shardNum: shardNum.value, argsStr }) : argsStr,
|
argsStr,
|
||||||
argsType,
|
argsType,
|
||||||
jobStatus,
|
jobStatus,
|
||||||
routeKey,
|
routeKey,
|
||||||
@ -277,6 +351,7 @@ watch(visible, () => {
|
|||||||
if (visible.value) {
|
if (visible.value) {
|
||||||
handleUpdateModelWhenEdit();
|
handleUpdateModelWhenEdit();
|
||||||
restoreValidation();
|
restoreValidation();
|
||||||
|
customformRef.value?.restoreValidation();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -311,6 +386,14 @@ const blockStrategyOptions = computed(() => {
|
|||||||
}
|
}
|
||||||
return translateOptions(blockStrategyRecordOptions);
|
return translateOptions(blockStrategyRecordOptions);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function handleChangeExecutorCustomType() {
|
||||||
|
if (executorCustomType.value === 0) {
|
||||||
|
model.executorInfo = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
model.executorInfo = 'snailJobHttpExecutor';
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@ -339,14 +422,30 @@ const blockStrategyOptions = computed(() => {
|
|||||||
</NSpace>
|
</NSpace>
|
||||||
</NRadioGroup>
|
</NRadioGroup>
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
|
<NFormItem :label="$t('page.jobTask.taskType')" path="taskType">
|
||||||
|
<TaskType v-model:value="model.taskType" :placeholder="$t('page.jobTask.form.taskType')" />
|
||||||
|
</NFormItem>
|
||||||
<NFormItem :label="$t('page.jobTask.executorType')" path="executorType">
|
<NFormItem :label="$t('page.jobTask.executorType')" path="executorType">
|
||||||
<ExecutorType v-model:value="model.executorType" />
|
<ExecutorType v-model:value="model.executorType" />
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
<NFormItem :label="$t('page.jobTask.executorInfo')" path="executorInfo">
|
<NFormItem :label="$t('page.jobTask.executorInfo')" path="executorInfo">
|
||||||
<NInput v-model:value="model.executorInfo" :placeholder="$t('page.jobTask.form.executorInfo')" />
|
<div class="w-full w-full flex-col items-start gap-12px pt-5px">
|
||||||
</NFormItem>
|
<NRadioGroup v-model:value="executorCustomType" @change="handleChangeExecutorCustomType">
|
||||||
<NFormItem :label="$t('page.jobTask.taskType')" path="taskType">
|
<NRadio :value="0">自定义执行器</NRadio>
|
||||||
<TaskType v-model:value="model.taskType" :placeholder="$t('page.jobTask.form.taskType')" />
|
<NRadio :value="1">内置执行器</NRadio>
|
||||||
|
</NRadioGroup>
|
||||||
|
<NInput
|
||||||
|
v-if="executorCustomType === 0"
|
||||||
|
v-model:value="model.executorInfo"
|
||||||
|
:placeholder="$t('page.jobTask.form.executorInfo')"
|
||||||
|
/>
|
||||||
|
<NSelect
|
||||||
|
v-else
|
||||||
|
v-model:value="model.executorInfo"
|
||||||
|
:options="executorCustomOptions"
|
||||||
|
placeholder="请选择内置执行器"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
<NFormItem v-if="model.taskType === 5" :label="$t('page.jobTask.shardNum')">
|
<NFormItem v-if="model.taskType === 5" :label="$t('page.jobTask.shardNum')">
|
||||||
<NInputNumber v-model:value="shardNum" :min="1" :placeholder="$t('page.jobTask.form.shardNum')" />
|
<NInputNumber v-model:value="shardNum" :min="1" :placeholder="$t('page.jobTask.form.shardNum')" />
|
||||||
@ -354,8 +453,10 @@ const blockStrategyOptions = computed(() => {
|
|||||||
<NFormItem
|
<NFormItem
|
||||||
:label="$t('page.jobTask.argsStr')"
|
:label="$t('page.jobTask.argsStr')"
|
||||||
path="argsStr"
|
path="argsStr"
|
||||||
|
:show-feedback="executorCustomType === 0"
|
||||||
:rule="model.taskType === 3 ? defaultRequiredRule : undefined"
|
:rule="model.taskType === 3 ? defaultRequiredRule : undefined"
|
||||||
>
|
>
|
||||||
|
<template v-if="executorCustomType === 0">
|
||||||
<NCard v-if="model.taskType === 3" class="flex-col">
|
<NCard v-if="model.taskType === 3" class="flex-col">
|
||||||
<NFormItem
|
<NFormItem
|
||||||
v-for="(item, index) in dynamicForm.args"
|
v-for="(item, index) in dynamicForm.args"
|
||||||
@ -381,6 +482,66 @@ const blockStrategyOptions = computed(() => {
|
|||||||
<NButton block dashed attr-type="button" @click="addItem"><icon-ic-round-plus class="text-icon" /></NButton>
|
<NButton block dashed attr-type="button" @click="addItem"><icon-ic-round-plus class="text-icon" /></NButton>
|
||||||
</NCard>
|
</NCard>
|
||||||
<CodeMirror v-else v-model="model.argsStr" lang="json" :placeholder="$t('page.jobTask.form.argsStr')" />
|
<CodeMirror v-else v-model="model.argsStr" lang="json" :placeholder="$t('page.jobTask.form.argsStr')" />
|
||||||
|
</template>
|
||||||
|
<template v-else-if="model.executorInfo === 'snailJobHttpExecutor'">
|
||||||
|
<NForm ref="customformRef" class="w-full" :model="httpParams">
|
||||||
|
<NFormItem :show-label="false" :rule="defaultRequiredRule" path="url">
|
||||||
|
<NInputGroup>
|
||||||
|
<NSelect v-model:value="httpParams.method" class="http-method" :options="httpMethodOptions" />
|
||||||
|
<NInput v-model:value="httpParams.url" placeholder="请输入请求地址" class="w-full" />
|
||||||
|
</NInputGroup>
|
||||||
|
</NFormItem>
|
||||||
|
<NFormItem label="Media Type">
|
||||||
|
<NInput v-model:value="httpParams.mediaType" placeholder="请输入 Media Type" />
|
||||||
|
</NFormItem>
|
||||||
|
<div class="n-form-item-label">Header 参数</div>
|
||||||
|
<NDynamicInput
|
||||||
|
v-model:value="httpHeaders"
|
||||||
|
:class="httpHeaders.length ? undefined : 'mb-24px'"
|
||||||
|
item-style="margin-bottom: 0;"
|
||||||
|
:on-create="() => ({ key: '', value: '' })"
|
||||||
|
#="{ index }"
|
||||||
|
>
|
||||||
|
<div class="flex">
|
||||||
|
<NFormItem
|
||||||
|
ignore-path-change
|
||||||
|
:show-label="false"
|
||||||
|
:path="`headers[${index}].key`"
|
||||||
|
:rule="{
|
||||||
|
required: true,
|
||||||
|
message: `请输入键`,
|
||||||
|
trigger: ['input', 'blur'],
|
||||||
|
validator() {
|
||||||
|
return isNotNull(httpHeaders[index].key);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<NInput v-model:value="httpHeaders[index].key" placeholder="Key" @keydown.enter.prevent />
|
||||||
|
</NFormItem>
|
||||||
|
<div class="mx-8px h-34px text-center line-height-34px">=</div>
|
||||||
|
<NFormItem
|
||||||
|
ignore-path-change
|
||||||
|
:show-label="false"
|
||||||
|
:path="`headers[${index}].value`"
|
||||||
|
:rule="{
|
||||||
|
required: true,
|
||||||
|
message: `请输入值`,
|
||||||
|
trigger: ['input', 'blur'],
|
||||||
|
validator() {
|
||||||
|
return isNotNull(httpHeaders[index].value);
|
||||||
|
}
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<NInput v-model:value="httpHeaders[index].value" placeholder="Value" @keydown.enter.prevent />
|
||||||
|
</NFormItem>
|
||||||
|
</div>
|
||||||
|
</NDynamicInput>
|
||||||
|
<NFormItem label="Body 参数">
|
||||||
|
<CodeMirror v-model="httpParams.body" lang="json" placeholder="请输入Body 参数" />
|
||||||
|
</NFormItem>
|
||||||
|
</NForm>
|
||||||
|
</template>
|
||||||
|
<template v-else></template>
|
||||||
</NFormItem>
|
</NFormItem>
|
||||||
<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>
|
||||||
@ -477,4 +638,8 @@ const blockStrategyOptions = computed(() => {
|
|||||||
</OperateDrawer>
|
</OperateDrawer>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style scoped></style>
|
<style scoped>
|
||||||
|
.http-method {
|
||||||
|
width: 130px !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
Loading…
Reference in New Issue
Block a user