feat(sj_1.0.0): 定时任务-添加/编辑

This commit is contained in:
dhb52 2024-04-25 02:01:38 +08:00
parent 05674c4939
commit 777dbeae34
18 changed files with 659 additions and 118 deletions

View File

@ -0,0 +1,33 @@
<script setup lang="ts">
import { ref } from 'vue';
import { $t } from '@/locales';
import { translateOptions } from '@/utils/common';
import { blockStrategyRecordOptions } from '@/constants/business';
defineOptions({
name: 'BlockStrategy'
});
const valueRef = ref<Api.Common.BlockStrategy>();
const emit = defineEmits<Emits>();
interface Emits {
(e: 'update:value', value: Api.Common.BlockStrategy): void;
}
const handleUpdate = (value: Api.Common.BlockStrategy) => {
emit('update:value', value);
};
</script>
<template>
<NSelect
v-model:value="valueRef"
:placeholder="$t('common.blockStrategy.form')"
:options="translateOptions(blockStrategyRecordOptions)"
clearable
@update:value="handleUpdate"
/>
</template>
<style scoped></style>

View File

@ -0,0 +1,33 @@
<script setup lang="ts">
import { ref } from 'vue';
import { $t } from '@/locales';
import { translateOptions } from '@/utils/common';
import { executorTypeRecordOptions } from '@/constants/business';
defineOptions({
name: 'TriggerStrategy'
});
const valueRef = ref<Api.Common.TriggerType>();
const emit = defineEmits<Emits>();
interface Emits {
(e: 'update:value', value: Api.Common.TriggerType): void;
}
const handleUpdate = (value: Api.Common.TriggerType) => {
emit('update:value', value);
};
</script>
<template>
<NSelect
v-model:value="valueRef"
:placeholder="$t('common.executorType.form')"
:options="translateOptions(executorTypeRecordOptions)"
clearable
@update:value="handleUpdate"
/>
</template>
<style scoped></style>

View File

@ -4,6 +4,10 @@ import { $t } from '@/locales';
import { translateOptions } from '@/utils/common';
import { routeKeyRecordOptions } from '@/constants/business';
defineOptions({
name: 'RouterKey'
});
const routeKeyRef = ref<Api.Common.RouteKey>();
const emit = defineEmits<Emits>();

View File

@ -0,0 +1,33 @@
<script setup lang="ts">
import { ref } from 'vue';
import { $t } from '@/locales';
import { translateOptions } from '@/utils/common';
import { taskTypeRecordRecordOptions } from '@/constants/business';
defineOptions({
name: 'TaskType'
});
const valueRef = ref<Api.Common.BlockStrategy>();
const emit = defineEmits<Emits>();
interface Emits {
(e: 'update:value', value: Api.Common.BlockStrategy): void;
}
const handleUpdate = (value: Api.Common.BlockStrategy) => {
emit('update:value', value);
};
</script>
<template>
<NSelect
v-model:value="valueRef"
:placeholder="$t('common.routeKey.routeForm')"
:options="translateOptions(taskTypeRecordRecordOptions)"
clearable
@update:value="handleUpdate"
/>
</template>
<style scoped></style>

View File

@ -0,0 +1,33 @@
<script setup lang="ts">
import { ref } from 'vue';
import { $t } from '@/locales';
import { translateOptions } from '@/utils/common';
import { triggerTypeOptions } from '@/constants/business';
defineOptions({
name: 'TriggerType'
});
const valueRef = ref<Api.Common.TriggerType>();
const emit = defineEmits<Emits>();
interface Emits {
(e: 'update:value', value: Api.Common.TriggerType): void;
}
const handleUpdate = (value: Api.Common.TriggerType) => {
emit('update:value', value);
};
</script>
<template>
<NSelect
v-model:value="valueRef"
:placeholder="$t('common.triggerType.form')"
:options="translateOptions(triggerTypeOptions)"
clearable
@update:value="handleUpdate"
/>
</template>
<style scoped></style>

View File

@ -124,6 +124,28 @@ export const routeKeyRecord: Record<Api.Common.RouteKey, App.I18n.I18nKey> = {
};
export const routeKeyRecordOptions = transformRecordToNumberOption(routeKeyRecord, true);
/** 阻塞策略 */
export const blockStrategyRecord: Record<Api.Common.BlockStrategy, App.I18n.I18nKey> = {
1: 'common.blockStrategy.items.discard',
2: 'common.blockStrategy.items.overwrite',
3: 'common.blockStrategy.items.parallel'
};
export const blockStrategyRecordOptions = transformRecordToNumberOption(blockStrategyRecord);
/** 执行器类型 */
export const executorTypeRecord: Record<Api.Common.ExecutorType, App.I18n.I18nKey> = {
1: 'common.executorType.items.java'
};
export const executorTypeRecordOptions = transformRecordToNumberOption(executorTypeRecord);
/** 任务类型 */
export const taskTypeRecord: Record<Api.Common.TaskType, App.I18n.I18nKey> = {
1: 'common.taskType.items.cluster',
2: 'common.taskType.items.broadcast',
3: 'common.taskType.items.slice'
};
export const taskTypeRecordRecordOptions = transformRecordToNumberOption(taskTypeRecord);
/** 延迟等级 */
export const DelayLevel: Record<number, string> = {
1: '10s',
@ -160,7 +182,7 @@ export const triggerTypeRecord: Record<Api.Job.TriggerType, App.I18n.I18nKey> =
// 只会在定时任务中使用
99: 'page.jobTask.triggerTypeItem.workflow'
};
export const triggerTypeOptions = transformRecordToNumberOption(triggerTypeRecord, true);
export const triggerTypeOptions = transformRecordToNumberOption(triggerTypeRecord);
export const taskBatchStatusRecord: Record<Api.Common.TaskBatchStatus, App.I18n.I18nKey> = {
1: 'common.taskBatchStatus.items.waiting',
@ -170,7 +192,7 @@ export const taskBatchStatusRecord: Record<Api.Common.TaskBatchStatus, App.I18n.
5: 'common.taskBatchStatus.items.stop',
6: 'common.taskBatchStatus.items.cancel'
};
export const taskBatchStatusRecordOptions = transformRecordToNumberOption(taskBatchStatusRecord, true);
export const taskBatchStatusRecordOptions = transformRecordToNumberOption(taskBatchStatusRecord);
export const operationReasonRecord: Record<Api.Common.OperationReason, App.I18n.I18nKey> = {
0: 'common.jobOperationReason.items.none',
@ -189,4 +211,4 @@ export const operationReasonRecord: Record<Api.Common.OperationReason, App.I18n.
13: 'common.jobOperationReason.items.workflowNodeClosedSkipExecution',
14: 'common.jobOperationReason.items.workflowDecisionFailed'
};
export const operationReasonOptions = transformRecordToNumberOption(operationReasonRecord, true);
export const operationReasonOptions = transformRecordToNumberOption(operationReasonRecord);

View File

@ -64,46 +64,80 @@ const local: App.I18n.Schema = {
workflow: 'Workflow'
},
routeKey: {
routeLabel: '路由策略',
routeForm: '请输入路由策略',
routeLabel: 'Route key',
routeForm: 'Please enter route key',
items: {
consistentHash: '一致性哈希',
random: '随机',
consistentHash: 'Consistent hash',
random: 'Random',
lru: 'LRU',
round: '轮询'
round: 'Round robin'
}
},
blockStrategy: {
label: 'Block strategy',
form: 'Please enter block strategy',
items: {
discard: 'Discard',
overwrite: 'Overwrite',
parallel: 'Parallel'
}
},
executorType: {
label: 'Executor type',
form: 'Please enter executor type',
items: {
java: 'Java'
}
},
taskType: {
label: 'Task type',
form: 'Please enter task type',
items: {
cluster: 'Cluster',
broadcast: 'Broadcast',
slice: 'Slice'
}
},
triggerType: {
label: 'Trigger type',
form: 'Please enter trigger type',
items: {
cron: 'CRON',
fixed: 'Fixed time',
workflow: 'Workflow'
}
},
taskBatchStatus: {
label: '执行状态',
form: '请选择执行状态',
label: 'Task batch status',
form: 'Please enter task batch status',
items: {
waiting: '待处理',
running: '运行中',
success: '处理成功',
fail: '处理失败',
stop: '任务停止',
cancel: '取消'
waiting: 'Waiting',
running: 'Running',
success: 'Success',
fail: 'Fail',
stop: 'Stop',
cancel: 'Cancel'
}
},
jobOperationReason: {
label: '操作原因',
form: '请选择执行状态',
label: 'Job operation reason',
form: 'Please enter job operation reason',
items: {
none: '',
taskExecutionTimeout: '任务执行超时',
notClient: '无客户端节点',
closed: '任务已关闭',
discard: '任务丢弃',
overlay: '任务被覆盖',
notExecutionTask: '无可执行任务项',
taskExecutionError: '任务执行期间发生非预期异常',
mannerStop: '手动停止',
workflowConditionNodeExecutionError: '条件节点执行异常',
jobTaskInterrupted: '任务中断',
workflowCallbackNodeExecutionError: '回调节点执行异常',
workflowNodeNoRequired: '无需处理',
workflowNodeClosedSkipExecution: '节点关闭跳过执行',
workflowDecisionFailed: '判定未通过'
taskExecutionTimeout: 'Task execution timeout',
notClient: 'No client',
closed: 'Job closed',
discard: 'Job discard',
overlay: 'Job overlapped',
notExecutionTask: 'No execution task',
taskExecutionError: 'Execution error',
mannerStop: 'Manual stop',
workflowConditionNodeExecutionError: 'Condition node execution error',
jobTaskInterrupted: 'Job interrupted',
workflowCallbackNodeExecutionError: 'Callback node execution error',
workflowNodeNoRequired: 'No process required',
workflowNodeClosedSkipExecution: 'Node closed, skip execution',
workflowDecisionFailed: 'Workflow decision failed'
}
}
},
@ -225,6 +259,7 @@ const local: App.I18n.Schema = {
retry: 'Retry task',
retry_task: 'Retry task',
retry_scene: 'Retry scene',
retry_log: 'Retry log',
workflow: 'Workflow',
workflow_task: 'Workflow Task',
workflow_batch: 'Workflow Batch',
@ -803,7 +838,8 @@ const local: App.I18n.Schema = {
nextTriggerAt: 'Next trigger time',
jobStatus: 'State',
routeKey: 'Routing strategy',
executorType: 'Actuator type',
executorType: 'Executor type',
executorInfo: 'Executor name',
triggerType: 'Trigger type',
triggerInterval: 'Interval duration',
blockStrategy: 'Blocking strategy',
@ -823,10 +859,12 @@ const local: App.I18n.Schema = {
jobName: 'Please enter Mission name',
executorTimeout: 'Please enter executor timeout',
triggerInterval: 'Please enter interval duration',
triggerInterval_CRON: 'Please enter cron expression',
taskType: 'Please enter Task type',
parallelNum: 'Please enter Parallel number',
bucketIndex: 'Please enter Bucket',
executorType: 'Please enter Actuator type',
executorType: 'Please enter executor type',
executorInfo: 'Please enter executor name',
routeKey: 'Please enter Routing strategy',
blockStrategy: 'Please enter Blocking strategy',
argsType: 'Please enter Parameter Type',

View File

@ -65,7 +65,7 @@ const local: App.I18n.Schema = {
},
routeKey: {
routeLabel: '路由策略',
routeForm: '请输入路由策略',
routeForm: '请选择路由策略',
items: {
consistentHash: '一致性哈希',
random: '随机',
@ -73,6 +73,40 @@ const local: App.I18n.Schema = {
round: '轮询'
}
},
blockStrategy: {
label: '阻塞策略',
form: '请选择阻塞策略',
items: {
discard: '丢弃',
overwrite: '覆盖',
parallel: '并行'
}
},
executorType: {
label: '执行器类型',
form: '请选择执行器类型',
items: {
java: 'Java'
}
},
taskType: {
label: '任务类型',
form: '请选择任务类型',
items: {
cluster: '集群',
broadcast: '广播',
slice: '切片'
}
},
triggerType: {
label: '触发类型',
form: '请选择触发类型',
items: {
cron: 'CRON表达式',
fixed: '固定时间',
workflow: '工作流'
}
},
taskBatchStatus: {
label: '执行状态',
form: '请选择执行状态',
@ -226,6 +260,7 @@ const local: App.I18n.Schema = {
retry: '重试任务',
retry_task: '重试任务',
retry_scene: '重试场景',
retry_log: '重试日志',
workflow: '工作流',
workflow_task: '任务管理',
workflow_batch: '执行批次',
@ -800,6 +835,7 @@ const local: App.I18n.Schema = {
jobStatus: '状态',
routeKey: '路由策略',
executorType: '执行器类型',
executorInfo: '执行器名称',
triggerType: '触发类型',
triggerInterval: '间隔时长',
blockStrategy: '阻塞策略',
@ -818,11 +854,13 @@ const local: App.I18n.Schema = {
triggerType: '请输入触发类型',
jobName: '请输入任务名称',
executorTimeout: '请输入超时时间',
triggerInterval: '请输入间隔时长',
triggerInterval: '请输入间隔时长(秒)',
triggerInterval_CRON: '请输入间隔时长',
taskType: '请输入任务类型',
parallelNum: '请输入并行数',
bucketIndex: '请输入Bucket',
executorType: '请输入执行器类型',
executorInfo: '请输入执行器名称',
routeKey: '请输入路由策略',
blockStrategy: '请输入阻塞策略',
argsType: '请输入参数类型',

View File

@ -41,6 +41,7 @@ export const views: Record<LastLevelRouteKey, RouteComponent | (() => Promise<Ro
notify_recipient: () => import("@/views/notify/recipient/index.vue"),
notify_scene: () => import("@/views/notify/scene/index.vue"),
pods: () => import("@/views/pods/index.vue"),
retry_log: () => import("@/views/retry/log/index.vue"),
retry_scene: () => import("@/views/retry/scene/index.vue"),
retry_task: () => import("@/views/retry/task/index.vue"),
"user-center": () => import("@/views/user-center/index.vue"),

View File

@ -420,6 +420,15 @@ export const generatedRoutes: GeneratedRoute[] = [
icon: 'carbon:retry-failed'
},
children: [
{
name: 'retry_log',
path: '/retry/log',
component: 'view.retry_log',
meta: {
title: 'retry_log',
i18nKey: 'route.retry_log'
}
},
{
name: 'retry_scene',
path: '/retry/scene',

View File

@ -183,6 +183,7 @@ const routeMap: RouteMap = {
"notify_scene": "/notify/scene",
"pods": "/pods",
"retry": "/retry",
"retry_log": "/retry/log",
"retry_scene": "/retry/scene",
"retry_task": "/retry/task",
"user-center": "/user-center",

View File

@ -9,4 +9,4 @@ export * from './group';
export * from './retry-task';
export * from './retry';
export * from './workflow';
export * from './job-task';
export * from './job';

View File

@ -1,28 +0,0 @@
import { request } from '../request';
/** get JobTask page */
export function fetchGetJobTaskPage(params?: Api.Job.JobSearchParams) {
return request<Api.Job.JobList>({
url: '/job/page/list',
method: 'get',
params
});
}
/** add JobTask */
export function fetchAddJobTask(params?: Api.Job.Job) {
return request<boolean>({
url: '/job/page/list',
method: 'post',
params
});
}
/** edit JobTask */
export function fetchEditJobTask(params?: Api.Job.Job) {
return request<boolean>({
url: '/job/page/list',
method: 'put',
params
});
}

37
src/service/api/job.ts Normal file
View File

@ -0,0 +1,37 @@
import { request } from '../request';
/** get Job page */
export function fetchGetJobPage(params?: Api.Job.JobSearchParams) {
return request<Api.Job.JobList>({
url: '/job/page/list',
method: 'get',
params
});
}
/** add Job */
export function fetchAddJob(data: Api.Job.Job) {
return request<boolean>({
url: '/job',
method: 'post',
data
});
}
/** edit Job */
export function fetchEditJob(data: Api.Job.Job) {
return request<boolean>({
url: '/job',
method: 'put',
data
});
}
/** edit Job */
export function fetchUpdateJobStatus(data: Api.Job.JobUpdateJobStatusRequestVO) {
return request<boolean>({
url: '/job/status',
method: 'put',
data
});
}

48
src/typings/api.d.ts vendored
View File

@ -73,6 +73,18 @@ declare namespace Api {
/** 1: 一致性Hash 2: 随机 3: LRU 4: 轮询 */
type RouteKey = 1 | 2 | 3 | 4;
/** 阻塞策略 1:丢弃 2:覆盖 3:并行 */
type BlockStrategy = 1 | 2 | 3;
/** 执行器类型 1:Java */
type ExecutorType = 1;
/** 触发类型 2:固定时间 3:CRON 表达式 99:工作流 */
type TriggerType = 2 | 3 | 99;
/** 任务类型 1:集群 2:广播 3:切片 */
type TaskType = 1 | 2 | 3;
/** 1、待处理 2、运行中 3、成功 4、失败 5、停止 6、取消 */
type TaskBatchStatus = 1 | 2 | 3 | 4 | 5 | 6;
@ -817,12 +829,11 @@ declare namespace Api {
}
/**
* namespace JobTask
* namespace Job
*
* backend api module: "jobTask"
* backend api module: "job"
*/
namespace Job {
import EnableStatusNumber = Api.Common.EnableStatusNumber;
type CommonSearchParams = Pick<Common.PaginatingCommonParams, 'page' | 'size'>;
/** Job */
@ -834,23 +845,25 @@ declare namespace Api {
/** 方法参数 */
argsStr: string;
/** 参数类型 */
argsType: string;
argsType: number;
/** 扩展字段 */
extAttrs: string;
extAttrs?: string;
/** 下次触发时间 */
nextTriggerAt: string;
nextTriggerAt?: string;
/** 状态 */
jobStatus: EnableStatusNumber;
jobStatus: Common.EnableStatusNumber;
/** 路由策略 */
routeKey: string;
routeKey: Common.RouteKey;
/** 执行器类型 */
executorType: string;
executorType: Common.ExecutorType;
/** 执行器名称 */
executorInfo: string;
/** 触发类型 */
triggerType: string;
triggerType: Common.TriggerType;
/** 间隔时长 */
triggerInterval: number;
triggerInterval: string;
/** 阻塞策略 */
blockStrategy: number;
blockStrategy: Common.BlockStrategy;
/** 超时时间 */
executorTimeout: number;
/** 最大重试次数 */
@ -858,13 +871,13 @@ declare namespace Api {
/** 重试间隔 */
retryInterval: number;
/** 任务类型 */
taskType: number;
taskType: Common.TaskType;
/** 并行数 */
parallelNum: number;
/** Bucket */
bucketIndex: number;
bucketIndex?: number;
/** 描述 */
description: string;
description?: string;
}>;
/** JobTask search params */
@ -891,6 +904,11 @@ declare namespace Api {
CommonSearchParams
>;
type JobUpdateJobStatusRequestVO = {
id: string;
jobStatus: Common.EnableStatusNumber;
};
/** JobTask list */
type JobList = Common.PaginatingQueryRecord<Job>;

37
src/typings/app.d.ts vendored
View File

@ -319,6 +319,40 @@ declare namespace App {
round: string;
};
};
blockStrategy: {
label: string;
form: string;
items: {
discard: string;
overwrite: string;
parallel: string;
};
};
executorType: {
label: string;
form: string;
items: {
java: string;
};
};
taskType: {
label: string;
form: string;
items: {
cluster: string;
broadcast: string;
slice: string;
};
};
triggerType: {
label: string;
form: string;
items: {
cron: string;
fixed: string;
workflow: string;
};
};
taskBatchStatus: {
label: string;
form: string;
@ -967,6 +1001,7 @@ declare namespace App {
jobStatus: string;
routeKey: string;
executorType: string;
executorInfo: string;
triggerType: string;
triggerInterval: string;
blockStrategy: string;
@ -986,10 +1021,12 @@ declare namespace App {
triggerType: string;
executorTimeout: string;
triggerInterval: string;
triggerInterval_CRON: string;
taskType: string;
parallelNum: string;
bucketIndex: string;
executorType: string;
executorInfo: string;
routeKey: string;
blockStrategy: string;
argsType: string;

View File

@ -1,16 +1,19 @@
<script setup lang="tsx">
import { NButton, NPopconfirm } from 'naive-ui';
import { fetchGetJobTaskPage } from '@/service/api';
import { ref } from 'vue';
import { NButton, NPopconfirm, NSwitch, NTag } from 'naive-ui';
import { fetchGetJobPage, fetchUpdateJobStatus } from '@/service/api';
import { $t } from '@/locales';
import { useAppStore } from '@/store/modules/app';
import { useTable, useTableOperate } from '@/hooks/common/table';
import { blockStrategyRecord, taskTypeRecord, triggerTypeRecord } from '@/constants/business';
import JobTaskOperateDrawer from './modules/job-task-operate-drawer.vue';
import JobTaskSearch from './modules/job-task-search.vue';
const appStore = useAppStore();
const statusSwithLoading = ref(false);
const { columns, columnChecks, data, getData, loading, mobilePagination, searchParams, resetSearchParams } = useTable({
apiFn: fetchGetJobTaskPage,
apiFn: fetchGetJobPage,
apiParams: {
page: 1,
size: 10,
@ -52,19 +55,56 @@ const { columns, columnChecks, data, getData, loading, mobilePagination, searchP
key: 'jobStatus',
title: $t('page.jobTask.jobStatus'),
align: 'center',
minWidth: 120
minWidth: 120,
render: row => {
return (
<NSwitch
v-model:value={row.jobStatus}
v-model:loading={statusSwithLoading.value}
checkedValue={1}
uncheckedValue={0}
onUpdateValue={() => handleUpdateValue(row)}
></NSwitch>
);
}
},
{
key: 'taskType',
title: $t('page.jobTask.taskType'),
align: 'center',
minWidth: 120
minWidth: 120,
render: row => {
if (row.taskType === null) {
return null;
}
const tagMap: Record<Api.Common.TaskType, NaiveUI.ThemeColor> = {
1: 'info',
2: 'success',
3: 'error'
};
const label = $t(taskTypeRecord[row.taskType!]);
return <NTag type={tagMap[row.taskType!]}>{label}</NTag>;
}
},
{
key: 'triggerType',
title: $t('page.jobTask.triggerType'),
align: 'center',
minWidth: 120
minWidth: 120,
render: row => {
if (row.triggerType === null) {
return null;
}
const tagMap: Record<Api.Job.TriggerType, NaiveUI.ThemeColor> = {
2: 'info',
3: 'success',
99: 'error'
};
const label = $t(triggerTypeRecord[row.triggerType!]);
return <NTag type={tagMap[row.triggerType!]}>{label}</NTag>;
}
},
{
key: 'triggerInterval',
@ -76,7 +116,20 @@ const { columns, columnChecks, data, getData, loading, mobilePagination, searchP
key: 'blockStrategy',
title: $t('page.jobTask.blockStrategy'),
align: 'center',
minWidth: 120
minWidth: 120,
render: row => {
if (row.blockStrategy === null) {
return null;
}
const tagMap: Record<Api.Common.BlockStrategy, NaiveUI.ThemeColor> = {
1: 'info',
2: 'success',
3: 'error'
};
const label = $t(blockStrategyRecord[row.blockStrategy!]);
return <NTag type={tagMap[row.blockStrategy!]}>{label}</NTag>;
}
},
{
key: 'executorTimeout',
@ -145,6 +198,16 @@ function handleDelete(id: string) {
function edit(id: string) {
handleEdit(id);
}
async function handleUpdateValue(job: Api.Job.Job) {
statusSwithLoading.value = true;
try {
await fetchUpdateJobStatus({ id: job.id!, jobStatus: job.jobStatus });
} finally {
await getData();
statusSwithLoading.value = false;
}
}
</script>
<template>

View File

@ -1,11 +1,14 @@
<script setup lang="ts">
import { computed, reactive, watch } from 'vue';
import CronInput from '@sa/cron-input';
import { useFormRules, useNaiveForm } from '@/hooks/common/form';
import OperateDrawer from '@/components/common/operate-drawer.vue';
import { $t } from '@/locales';
import { translateOptions } from '@/utils/common';
import { enableStatusNumberOptions } from '@/constants/business';
// import { fetchAddJobTask, fetchEditJobTask } from '@/service/api';
import { fetchAddJob, fetchEditJob } from '@/service/api';
import RouteKey from '@/components/common/route-key.vue';
import ExecutorType from '@/components/common/executor-type.vue';
import TaskType from '@/components/common/task-type.vue';
defineOptions({
name: 'JobTaskOperateDrawer'
@ -43,6 +46,7 @@ const title = computed(() => {
type Model = Pick<
Api.Job.Job,
| 'id'
| 'groupName'
| 'jobName'
| 'argsStr'
@ -50,6 +54,7 @@ type Model = Pick<
| 'jobStatus'
| 'routeKey'
| 'executorType'
| 'executorInfo'
| 'triggerType'
| 'triggerInterval'
| 'blockStrategy'
@ -68,12 +73,13 @@ function createDefaultModel(): Model {
groupName: '',
jobName: '',
argsStr: '',
argsType: '',
jobStatus: 0,
routeKey: '',
executorType: '',
triggerType: '',
triggerInterval: 1,
argsType: 1,
jobStatus: 1,
routeKey: 1,
executorType: 1,
triggerType: 2,
executorInfo: '',
triggerInterval: '60',
blockStrategy: 1,
executorTimeout: 60,
maxRetryTimes: 3,
@ -88,12 +94,12 @@ type RuleKey = Extract<
keyof Model,
| 'groupName'
| 'jobName'
| 'argsStr'
| 'argsType'
| 'jobStatus'
| 'routeKey'
| 'executorType'
| 'triggerType'
| 'executorInfo'
| 'triggerInterval'
| 'blockStrategy'
| 'executorTimeout'
@ -101,17 +107,16 @@ type RuleKey = Extract<
| 'retryInterval'
| 'taskType'
| 'parallelNum'
| 'description'
>;
const rules: Record<RuleKey, App.Global.FormRule> = {
groupName: defaultRequiredRule,
jobName: defaultRequiredRule,
argsStr: defaultRequiredRule,
argsType: defaultRequiredRule,
jobStatus: defaultRequiredRule,
routeKey: defaultRequiredRule,
executorType: defaultRequiredRule,
executorInfo: defaultRequiredRule,
triggerType: defaultRequiredRule,
triggerInterval: defaultRequiredRule,
blockStrategy: defaultRequiredRule,
@ -119,8 +124,7 @@ const rules: Record<RuleKey, App.Global.FormRule> = {
maxRetryTimes: defaultRequiredRule,
retryInterval: defaultRequiredRule,
taskType: defaultRequiredRule,
parallelNum: defaultRequiredRule,
description: defaultRequiredRule
parallelNum: defaultRequiredRule
};
function handleUpdateModelWhenEdit() {
@ -140,17 +144,95 @@ function closeDrawer() {
async function handleSubmit() {
await validate();
// request
// if (props.operateType === 'add') {
// const { ... } = model;
// fetchAddJobTask({ ... });
// }
// if (props.operateType === 'edit') {
// const { ... } = model;
// fetchEditJobTask({ ... });
// }
window.$message?.success($t('common.updateSuccess'));
if (props.operateType === 'add') {
const {
groupName,
jobName,
argsStr,
argsType,
jobStatus,
routeKey,
executorType,
executorInfo,
triggerType,
triggerInterval,
blockStrategy,
executorTimeout,
maxRetryTimes,
retryInterval,
taskType,
parallelNum,
description
} = model;
const { error } = await fetchAddJob({
groupName,
jobName,
argsStr,
argsType,
jobStatus,
routeKey,
executorType,
executorInfo,
triggerType,
triggerInterval,
blockStrategy,
executorTimeout,
maxRetryTimes,
retryInterval,
taskType,
parallelNum,
description
});
if (error) return;
window.$message?.success($t('common.addSuccess'));
}
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({
id,
groupName,
jobName,
argsStr,
argsType,
jobStatus,
routeKey,
executorType,
executorInfo,
triggerType,
triggerInterval,
blockStrategy,
executorTimeout,
maxRetryTimes,
retryInterval,
taskType,
parallelNum,
description
});
if (error) return;
window.$message?.success($t('common.updateSuccess'));
}
closeDrawer();
emit('submitted');
}
@ -166,19 +248,106 @@ watch(visible, () => {
<template>
<OperateDrawer v-model="visible" :title="title" @handle-submit="handleSubmit">
<NForm ref="formRef" :model="model" :rules="rules">
<NFormItem :label="$t('page.jobTask.groupName')" path="groupName">
<NInput v-model:value="model.groupName" :placeholder="$t('page.jobTask.form.groupName')" />
</NFormItem>
<NFormItem :label="$t('page.jobTask.jobName')" path="jobName">
<NInput v-model:value="model.jobName" :placeholder="$t('page.jobTask.form.jobName')" />
<NInput
v-model:value="model.jobName"
:maxlength="64"
show-count
:placeholder="$t('page.jobTask.form.jobName')"
/>
</NFormItem>
<NFormItem :label="$t('page.jobTask.groupName')" path="groupName">
<SelectGroup v-model:value="model.groupName" />
</NFormItem>
<NFormItem :label="$t('page.jobTask.jobStatus')" path="jobStatus">
<NSelect
v-model:value="model.jobStatus"
:placeholder="$t('page.jobTask.form.jobStatus')"
:options="translateOptions(enableStatusNumberOptions)"
<NRadioGroup v-model:value="model.jobStatus" name="jobStatus">
<NSpace>
<NRadio
v-for="item in enableStatusNumberOptions"
:key="item.value"
:value="item.value"
:label="$t(item.label)"
/>
</NSpace>
</NRadioGroup>
</NFormItem>
<NFormItem :label="$t('page.jobTask.routeKey')" path="routeKey">
<RouteKey v-model:value="model.routeKey" />
</NFormItem>
<NFormItem :label="$t('page.jobTask.blockStrategy')" path="blockStrategy">
<BlockStrategy v-model:value="model.blockStrategy" />
</NFormItem>
<NFormItem :label="$t('page.jobTask.executorType')" path="executorType">
<ExecutorType v-model:value="model.executorType" />
</NFormItem>
<NFormItem :label="$t('page.jobTask.executorInfo')" path="executorInfo">
<NInput v-model:value="model.executorInfo" :placeholder="$t('page.jobTask.form.executorInfo')" />
</NFormItem>
<NFormItem :label="$t('page.jobTask.argsStr')" path="argsStr">
<NInput v-model:value="model.argsStr" :placeholder="$t('page.jobTask.form.argsStr')" />
</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.triggerType')" path="triggerType">
<TriggerType
v-model:value="model.triggerType"
:placeholder="$t('page.jobTask.form.triggerType')"
@update:value="model.triggerInterval = ''"
/>
</NFormItem>
<NFormItem :label="$t('page.jobTask.triggerInterval')" path="triggerInterval">
<NInput
v-if="model.triggerType === 2"
v-model:value="model.triggerInterval"
:placeholder="$t('page.jobTask.form.triggerInterval')"
/>
<CronInput
v-else-if="model.triggerType === 3"
v-model:value="model.triggerInterval"
:placeholder="$t('page.jobTask.form.triggerInterval_CRON')"
/>
<NInput v-else-if="model.triggerType === 99" v-model:value="model.triggerInterval" disabled />
</NFormItem>
<NFormItem :label="$t('page.jobTask.executorTimeout')" path="executorTimeout">
<NInputNumber
v-model:value="model.executorTimeout"
:min="1"
:max="60"
:placeholder="$t('page.jobTask.form.executorTimeout')"
clearable
/>
</NFormItem>
<NFormItem :label="$t('page.jobTask.maxRetryTimes')" path="maxRetryTimes">
<NInputNumber
v-model:value="model.maxRetryTimes"
:min="1"
:max="60"
:placeholder="$t('page.jobTask.form.maxRetryTimes')"
clearable
/>
</NFormItem>
<NFormItem :label="$t('page.jobTask.retryInterval')" path="retryInterval">
<NInputNumber
v-model:value="model.retryInterval"
:min="1"
:max="60"
:placeholder="$t('page.jobTask.form.retryInterval')"
clearable
/>
</NFormItem>
<NFormItem :label="$t('page.jobTask.parallelNum')" path="parallelNum">
<NInputNumber
v-model:value="model.parallelNum"
:min="1"
:max="60"
:placeholder="$t('page.jobTask.form.parallelNum')"
clearable
/>
</NFormItem>
<NFormItem :label="$t('page.jobTask.description')" path="description">
<NInput v-model:value="model.description" type="textarea" :placeholder="$t('page.jobTask.form.description')" />
</NFormItem>
</NForm>
<template #footer>
<NSpace :size="16">