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 { translateOptions } from '@/utils/common';
import { routeKeyRecordOptions } from '@/constants/business'; import { routeKeyRecordOptions } from '@/constants/business';
defineOptions({
name: 'RouterKey'
});
const routeKeyRef = ref<Api.Common.RouteKey>(); const routeKeyRef = ref<Api.Common.RouteKey>();
const emit = defineEmits<Emits>(); 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 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> = { export const DelayLevel: Record<number, string> = {
1: '10s', 1: '10s',
@ -160,7 +182,7 @@ export const triggerTypeRecord: Record<Api.Job.TriggerType, App.I18n.I18nKey> =
// 只会在定时任务中使用 // 只会在定时任务中使用
99: 'page.jobTask.triggerTypeItem.workflow' 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> = { export const taskBatchStatusRecord: Record<Api.Common.TaskBatchStatus, App.I18n.I18nKey> = {
1: 'common.taskBatchStatus.items.waiting', 1: 'common.taskBatchStatus.items.waiting',
@ -170,7 +192,7 @@ export const taskBatchStatusRecord: Record<Api.Common.TaskBatchStatus, App.I18n.
5: 'common.taskBatchStatus.items.stop', 5: 'common.taskBatchStatus.items.stop',
6: 'common.taskBatchStatus.items.cancel' 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> = { export const operationReasonRecord: Record<Api.Common.OperationReason, App.I18n.I18nKey> = {
0: 'common.jobOperationReason.items.none', 0: 'common.jobOperationReason.items.none',
@ -189,4 +211,4 @@ export const operationReasonRecord: Record<Api.Common.OperationReason, App.I18n.
13: 'common.jobOperationReason.items.workflowNodeClosedSkipExecution', 13: 'common.jobOperationReason.items.workflowNodeClosedSkipExecution',
14: 'common.jobOperationReason.items.workflowDecisionFailed' 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' workflow: 'Workflow'
}, },
routeKey: { routeKey: {
routeLabel: '路由策略', routeLabel: 'Route key',
routeForm: '请输入路由策略', routeForm: 'Please enter route key',
items: { items: {
consistentHash: '一致性哈希', consistentHash: 'Consistent hash',
random: '随机', random: 'Random',
lru: 'LRU', 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: { taskBatchStatus: {
label: '执行状态', label: 'Task batch status',
form: '请选择执行状态', form: 'Please enter task batch status',
items: { items: {
waiting: '待处理', waiting: 'Waiting',
running: '运行中', running: 'Running',
success: '处理成功', success: 'Success',
fail: '处理失败', fail: 'Fail',
stop: '任务停止', stop: 'Stop',
cancel: '取消' cancel: 'Cancel'
} }
}, },
jobOperationReason: { jobOperationReason: {
label: '操作原因', label: 'Job operation reason',
form: '请选择执行状态', form: 'Please enter job operation reason',
items: { items: {
none: '', none: '',
taskExecutionTimeout: '任务执行超时', taskExecutionTimeout: 'Task execution timeout',
notClient: '无客户端节点', notClient: 'No client',
closed: '任务已关闭', closed: 'Job closed',
discard: '任务丢弃', discard: 'Job discard',
overlay: '任务被覆盖', overlay: 'Job overlapped',
notExecutionTask: '无可执行任务项', notExecutionTask: 'No execution task',
taskExecutionError: '任务执行期间发生非预期异常', taskExecutionError: 'Execution error',
mannerStop: '手动停止', mannerStop: 'Manual stop',
workflowConditionNodeExecutionError: '条件节点执行异常', workflowConditionNodeExecutionError: 'Condition node execution error',
jobTaskInterrupted: '任务中断', jobTaskInterrupted: 'Job interrupted',
workflowCallbackNodeExecutionError: '回调节点执行异常', workflowCallbackNodeExecutionError: 'Callback node execution error',
workflowNodeNoRequired: '无需处理', workflowNodeNoRequired: 'No process required',
workflowNodeClosedSkipExecution: '节点关闭跳过执行', workflowNodeClosedSkipExecution: 'Node closed, skip execution',
workflowDecisionFailed: '判定未通过' workflowDecisionFailed: 'Workflow decision failed'
} }
} }
}, },
@ -225,6 +259,7 @@ const local: App.I18n.Schema = {
retry: 'Retry task', retry: 'Retry task',
retry_task: 'Retry task', retry_task: 'Retry task',
retry_scene: 'Retry scene', retry_scene: 'Retry scene',
retry_log: 'Retry log',
workflow: 'Workflow', workflow: 'Workflow',
workflow_task: 'Workflow Task', workflow_task: 'Workflow Task',
workflow_batch: 'Workflow Batch', workflow_batch: 'Workflow Batch',
@ -803,7 +838,8 @@ const local: App.I18n.Schema = {
nextTriggerAt: 'Next trigger time', nextTriggerAt: 'Next trigger time',
jobStatus: 'State', jobStatus: 'State',
routeKey: 'Routing strategy', routeKey: 'Routing strategy',
executorType: 'Actuator type', executorType: 'Executor type',
executorInfo: 'Executor name',
triggerType: 'Trigger type', triggerType: 'Trigger type',
triggerInterval: 'Interval duration', triggerInterval: 'Interval duration',
blockStrategy: 'Blocking strategy', blockStrategy: 'Blocking strategy',
@ -823,10 +859,12 @@ const local: App.I18n.Schema = {
jobName: 'Please enter Mission name', jobName: 'Please enter Mission name',
executorTimeout: 'Please enter executor timeout', executorTimeout: 'Please enter executor timeout',
triggerInterval: 'Please enter interval duration', triggerInterval: 'Please enter interval duration',
triggerInterval_CRON: 'Please enter cron expression',
taskType: 'Please enter Task type', taskType: 'Please enter Task type',
parallelNum: 'Please enter Parallel number', parallelNum: 'Please enter Parallel number',
bucketIndex: 'Please enter Bucket', bucketIndex: 'Please enter Bucket',
executorType: 'Please enter Actuator type', executorType: 'Please enter executor type',
executorInfo: 'Please enter executor name',
routeKey: 'Please enter Routing strategy', routeKey: 'Please enter Routing strategy',
blockStrategy: 'Please enter Blocking strategy', blockStrategy: 'Please enter Blocking strategy',
argsType: 'Please enter Parameter Type', argsType: 'Please enter Parameter Type',

View File

@ -65,7 +65,7 @@ const local: App.I18n.Schema = {
}, },
routeKey: { routeKey: {
routeLabel: '路由策略', routeLabel: '路由策略',
routeForm: '请输入路由策略', routeForm: '请选择路由策略',
items: { items: {
consistentHash: '一致性哈希', consistentHash: '一致性哈希',
random: '随机', random: '随机',
@ -73,6 +73,40 @@ const local: App.I18n.Schema = {
round: '轮询' 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: { taskBatchStatus: {
label: '执行状态', label: '执行状态',
form: '请选择执行状态', form: '请选择执行状态',
@ -226,6 +260,7 @@ const local: App.I18n.Schema = {
retry: '重试任务', retry: '重试任务',
retry_task: '重试任务', retry_task: '重试任务',
retry_scene: '重试场景', retry_scene: '重试场景',
retry_log: '重试日志',
workflow: '工作流', workflow: '工作流',
workflow_task: '任务管理', workflow_task: '任务管理',
workflow_batch: '执行批次', workflow_batch: '执行批次',
@ -800,6 +835,7 @@ const local: App.I18n.Schema = {
jobStatus: '状态', jobStatus: '状态',
routeKey: '路由策略', routeKey: '路由策略',
executorType: '执行器类型', executorType: '执行器类型',
executorInfo: '执行器名称',
triggerType: '触发类型', triggerType: '触发类型',
triggerInterval: '间隔时长', triggerInterval: '间隔时长',
blockStrategy: '阻塞策略', blockStrategy: '阻塞策略',
@ -818,11 +854,13 @@ const local: App.I18n.Schema = {
triggerType: '请输入触发类型', triggerType: '请输入触发类型',
jobName: '请输入任务名称', jobName: '请输入任务名称',
executorTimeout: '请输入超时时间', executorTimeout: '请输入超时时间',
triggerInterval: '请输入间隔时长', triggerInterval: '请输入间隔时长(秒)',
triggerInterval_CRON: '请输入间隔时长',
taskType: '请输入任务类型', taskType: '请输入任务类型',
parallelNum: '请输入并行数', parallelNum: '请输入并行数',
bucketIndex: '请输入Bucket', bucketIndex: '请输入Bucket',
executorType: '请输入执行器类型', executorType: '请输入执行器类型',
executorInfo: '请输入执行器名称',
routeKey: '请输入路由策略', routeKey: '请输入路由策略',
blockStrategy: '请输入阻塞策略', blockStrategy: '请输入阻塞策略',
argsType: '请输入参数类型', argsType: '请输入参数类型',

View File

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

View File

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

View File

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

View File

@ -9,4 +9,4 @@ export * from './group';
export * from './retry-task'; export * from './retry-task';
export * from './retry'; export * from './retry';
export * from './workflow'; 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: 轮询 */ /** 1: 一致性Hash 2: 随机 3: LRU 4: 轮询 */
type RouteKey = 1 | 2 | 3 | 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、取消 */ /** 1、待处理 2、运行中 3、成功 4、失败 5、停止 6、取消 */
type TaskBatchStatus = 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 { namespace Job {
import EnableStatusNumber = Api.Common.EnableStatusNumber;
type CommonSearchParams = Pick<Common.PaginatingCommonParams, 'page' | 'size'>; type CommonSearchParams = Pick<Common.PaginatingCommonParams, 'page' | 'size'>;
/** Job */ /** Job */
@ -834,23 +845,25 @@ declare namespace Api {
/** 方法参数 */ /** 方法参数 */
argsStr: string; 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; executorTimeout: number;
/** 最大重试次数 */ /** 最大重试次数 */
@ -858,13 +871,13 @@ declare namespace Api {
/** 重试间隔 */ /** 重试间隔 */
retryInterval: number; retryInterval: number;
/** 任务类型 */ /** 任务类型 */
taskType: number; taskType: Common.TaskType;
/** 并行数 */ /** 并行数 */
parallelNum: number; parallelNum: number;
/** Bucket */ /** Bucket */
bucketIndex: number; bucketIndex?: number;
/** 描述 */ /** 描述 */
description: string; description?: string;
}>; }>;
/** JobTask search params */ /** JobTask search params */
@ -891,6 +904,11 @@ declare namespace Api {
CommonSearchParams CommonSearchParams
>; >;
type JobUpdateJobStatusRequestVO = {
id: string;
jobStatus: Common.EnableStatusNumber;
};
/** JobTask list */ /** JobTask list */
type JobList = Common.PaginatingQueryRecord<Job>; type JobList = Common.PaginatingQueryRecord<Job>;

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

@ -319,6 +319,40 @@ declare namespace App {
round: string; 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: { taskBatchStatus: {
label: string; label: string;
form: string; form: string;
@ -967,6 +1001,7 @@ declare namespace App {
jobStatus: string; jobStatus: string;
routeKey: string; routeKey: string;
executorType: string; executorType: string;
executorInfo: string;
triggerType: string; triggerType: string;
triggerInterval: string; triggerInterval: string;
blockStrategy: string; blockStrategy: string;
@ -986,10 +1021,12 @@ declare namespace App {
triggerType: string; triggerType: string;
executorTimeout: string; executorTimeout: string;
triggerInterval: string; triggerInterval: string;
triggerInterval_CRON: string;
taskType: string; taskType: string;
parallelNum: string; parallelNum: string;
bucketIndex: string; bucketIndex: string;
executorType: string; executorType: string;
executorInfo: string;
routeKey: string; routeKey: string;
blockStrategy: string; blockStrategy: string;
argsType: string; argsType: string;

View File

@ -1,16 +1,19 @@
<script setup lang="tsx"> <script setup lang="tsx">
import { NButton, NPopconfirm } from 'naive-ui'; import { ref } from 'vue';
import { fetchGetJobTaskPage } from '@/service/api'; import { NButton, NPopconfirm, NSwitch, NTag } from 'naive-ui';
import { fetchGetJobPage, fetchUpdateJobStatus } from '@/service/api';
import { $t } from '@/locales'; import { $t } from '@/locales';
import { useAppStore } from '@/store/modules/app'; import { useAppStore } from '@/store/modules/app';
import { useTable, useTableOperate } from '@/hooks/common/table'; import { useTable, useTableOperate } from '@/hooks/common/table';
import { blockStrategyRecord, taskTypeRecord, triggerTypeRecord } from '@/constants/business';
import JobTaskOperateDrawer from './modules/job-task-operate-drawer.vue'; import JobTaskOperateDrawer from './modules/job-task-operate-drawer.vue';
import JobTaskSearch from './modules/job-task-search.vue'; import JobTaskSearch from './modules/job-task-search.vue';
const appStore = useAppStore(); const appStore = useAppStore();
const statusSwithLoading = ref(false);
const { columns, columnChecks, data, getData, loading, mobilePagination, searchParams, resetSearchParams } = useTable({ const { columns, columnChecks, data, getData, loading, mobilePagination, searchParams, resetSearchParams } = useTable({
apiFn: fetchGetJobTaskPage, apiFn: fetchGetJobPage,
apiParams: { apiParams: {
page: 1, page: 1,
size: 10, size: 10,
@ -52,19 +55,56 @@ const { columns, columnChecks, data, getData, loading, mobilePagination, searchP
key: 'jobStatus', key: 'jobStatus',
title: $t('page.jobTask.jobStatus'), title: $t('page.jobTask.jobStatus'),
align: 'center', 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', key: 'taskType',
title: $t('page.jobTask.taskType'), title: $t('page.jobTask.taskType'),
align: 'center', 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', key: 'triggerType',
title: $t('page.jobTask.triggerType'), title: $t('page.jobTask.triggerType'),
align: 'center', 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', key: 'triggerInterval',
@ -76,7 +116,20 @@ const { columns, columnChecks, data, getData, loading, mobilePagination, searchP
key: 'blockStrategy', key: 'blockStrategy',
title: $t('page.jobTask.blockStrategy'), title: $t('page.jobTask.blockStrategy'),
align: 'center', 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', key: 'executorTimeout',
@ -145,6 +198,16 @@ function handleDelete(id: string) {
function edit(id: string) { function edit(id: string) {
handleEdit(id); 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> </script>
<template> <template>

View File

@ -1,11 +1,14 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed, reactive, watch } from 'vue'; import { computed, reactive, watch } from 'vue';
import CronInput from '@sa/cron-input';
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';
import { translateOptions } from '@/utils/common';
import { enableStatusNumberOptions } from '@/constants/business'; 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({ defineOptions({
name: 'JobTaskOperateDrawer' name: 'JobTaskOperateDrawer'
@ -43,6 +46,7 @@ const title = computed(() => {
type Model = Pick< type Model = Pick<
Api.Job.Job, Api.Job.Job,
| 'id'
| 'groupName' | 'groupName'
| 'jobName' | 'jobName'
| 'argsStr' | 'argsStr'
@ -50,6 +54,7 @@ type Model = Pick<
| 'jobStatus' | 'jobStatus'
| 'routeKey' | 'routeKey'
| 'executorType' | 'executorType'
| 'executorInfo'
| 'triggerType' | 'triggerType'
| 'triggerInterval' | 'triggerInterval'
| 'blockStrategy' | 'blockStrategy'
@ -68,12 +73,13 @@ function createDefaultModel(): Model {
groupName: '', groupName: '',
jobName: '', jobName: '',
argsStr: '', argsStr: '',
argsType: '', argsType: 1,
jobStatus: 0, jobStatus: 1,
routeKey: '', routeKey: 1,
executorType: '', executorType: 1,
triggerType: '', triggerType: 2,
triggerInterval: 1, executorInfo: '',
triggerInterval: '60',
blockStrategy: 1, blockStrategy: 1,
executorTimeout: 60, executorTimeout: 60,
maxRetryTimes: 3, maxRetryTimes: 3,
@ -88,12 +94,12 @@ type RuleKey = Extract<
keyof Model, keyof Model,
| 'groupName' | 'groupName'
| 'jobName' | 'jobName'
| 'argsStr'
| 'argsType' | 'argsType'
| 'jobStatus' | 'jobStatus'
| 'routeKey' | 'routeKey'
| 'executorType' | 'executorType'
| 'triggerType' | 'triggerType'
| 'executorInfo'
| 'triggerInterval' | 'triggerInterval'
| 'blockStrategy' | 'blockStrategy'
| 'executorTimeout' | 'executorTimeout'
@ -101,17 +107,16 @@ type RuleKey = Extract<
| 'retryInterval' | 'retryInterval'
| 'taskType' | 'taskType'
| 'parallelNum' | 'parallelNum'
| 'description'
>; >;
const rules: Record<RuleKey, App.Global.FormRule> = { const rules: Record<RuleKey, App.Global.FormRule> = {
groupName: defaultRequiredRule, groupName: defaultRequiredRule,
jobName: defaultRequiredRule, jobName: defaultRequiredRule,
argsStr: defaultRequiredRule,
argsType: defaultRequiredRule, argsType: defaultRequiredRule,
jobStatus: defaultRequiredRule, jobStatus: defaultRequiredRule,
routeKey: defaultRequiredRule, routeKey: defaultRequiredRule,
executorType: defaultRequiredRule, executorType: defaultRequiredRule,
executorInfo: defaultRequiredRule,
triggerType: defaultRequiredRule, triggerType: defaultRequiredRule,
triggerInterval: defaultRequiredRule, triggerInterval: defaultRequiredRule,
blockStrategy: defaultRequiredRule, blockStrategy: defaultRequiredRule,
@ -119,8 +124,7 @@ const rules: Record<RuleKey, App.Global.FormRule> = {
maxRetryTimes: defaultRequiredRule, maxRetryTimes: defaultRequiredRule,
retryInterval: defaultRequiredRule, retryInterval: defaultRequiredRule,
taskType: defaultRequiredRule, taskType: defaultRequiredRule,
parallelNum: defaultRequiredRule, parallelNum: defaultRequiredRule
description: defaultRequiredRule
}; };
function handleUpdateModelWhenEdit() { function handleUpdateModelWhenEdit() {
@ -140,17 +144,95 @@ function closeDrawer() {
async function handleSubmit() { async function handleSubmit() {
await validate(); await validate();
// request
// if (props.operateType === 'add') {
// const { ... } = model;
// fetchAddJobTask({ ... });
// }
// if (props.operateType === 'edit') { if (props.operateType === 'add') {
// const { ... } = model; const {
// fetchEditJobTask({ ... }); groupName,
// } jobName,
window.$message?.success($t('common.updateSuccess')); 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(); closeDrawer();
emit('submitted'); emit('submitted');
} }
@ -166,19 +248,106 @@ watch(visible, () => {
<template> <template>
<OperateDrawer v-model="visible" :title="title" @handle-submit="handleSubmit"> <OperateDrawer v-model="visible" :title="title" @handle-submit="handleSubmit">
<NForm ref="formRef" :model="model" :rules="rules"> <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"> <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>
<NFormItem :label="$t('page.jobTask.jobStatus')" path="jobStatus"> <NFormItem :label="$t('page.jobTask.jobStatus')" path="jobStatus">
<NSelect <NRadioGroup v-model:value="model.jobStatus" name="jobStatus">
v-model:value="model.jobStatus" <NSpace>
:placeholder="$t('page.jobTask.form.jobStatus')" <NRadio
:options="translateOptions(enableStatusNumberOptions)" 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>
<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> </NForm>
<template #footer> <template #footer>
<NSpace :size="16"> <NSpace :size="16">