gtsoft-snail-job-server/frontend/src/views/job/form/JobForm.vue
byteblogs168 05d024bf11 feat: 2.6.0
1. 定时任务支持重试次数为0
2024-01-29 22:04:53 +08:00

545 lines
18 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div>
<page-header-wrapper content="定时任务配置" @back="() => $router.go(-1)" style="margin: -24px -1px 0">
<div></div>
</page-header-wrapper>
<a-card :body-style="{padding: '24px 32px'}" :bordered="false" :loading="loading">
<a-form @submit="handleSubmit" :form="form" class="form-row" layout="vertical" style="width: 40%;margin: auto;">
<a-row class="form-row" :gutter="16">
<a-col :lg="24" :md="24" :sm="24">
<a-form-item>
<a-input
hidden
v-decorator="['id']" />
</a-form-item>
<a-form-item label="任务名称" >
<a-input
placeholder="请输入任务名称"
:maxLength="64"
v-decorator="[
'jobName',
{rules: [{ required: true, message: '请输入任务名称', whitespace: true},{required: true, max: 64, message: '最多支持64个字符'}]}
]" />
</a-form-item>
</a-col>
</a-row>
<a-row class="form-row" :gutter="16">
<a-col :lg="18" :md="18" :sm="24">
<a-form-item label="组">
<a-select
placeholder="请选择组"
v-decorator="['groupName', { rules: [{ required: true, message: '请选择组' }] }]"
>
<a-select-option v-for="item in groupNameList" :value="item" :key="item">{{ item }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :lg="6" :md="12" :sm="24">
<a-form-item label="状态">
<a-select
placeholder="请选择状态"
v-decorator="[
'jobStatus',
{
initialValue: '1',
rules: [{ required: true, message: '请选择状态'}]
}
]" >
<a-select-option :value="index" v-for="(item, index) in jobStatusEnum" :key="index">{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
<a-row class="form-row" :gutter="16">
<a-col :lg="12" :md="12" :sm="24">
<a-form-item label="路由策略">
<a-select
placeholder="请选择路由策略"
v-decorator="[
'routeKey',
{
initialValue: '4',
rules: [{ required: true, message: '请选择路由策略'}]
}
]" >
<a-select-option :value="index" v-for="(item, index) in routeKey" :key="index">{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :lg="12" :md="12" :sm="24">
<a-form-item label="阻塞策略">
<a-select
placeholder="请选择阻塞策略"
v-decorator="[
'blockStrategy',
{
initialValue: '1',
rules: [{ required: true, message: '请选择阻塞策略'}]
}
]" >
<a-select-option :value="index" v-for="(item, index) in blockStrategy" :key="index">{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
</a-row>
<a-row class="form-row" :gutter="16">
<a-col :lg="8" :md="12" :sm="12">
<a-form-item label="触发类型">
<a-select
placeholder="请选择触发类型"
@change="handleChange"
v-decorator="[
'triggerType',
{
initialValue: '2',
rules: [{ required: true, message: '请选择触发类型'}]
}
]" >
<a-select-option :value="index" v-for="(item, index) in triggerType" :key="index">{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :lg="16" :md="12" :sm="12">
<a-form-item label="间隔时长">
<a-input-number
v-if="triggerTypeValue === '2'"
style="width: -webkit-fill-available"
placeholder="请输入间隔时长(秒)"
:min="1"
v-decorator="[
'triggerInterval',
{initialValue: '60',
rules: [ { required: true, message: '请输入间隔时长'}]}
]" />
<a-input
v-if="triggerTypeValue === '1'"
@click="handlerCron"
placeholder="请输入间隔时长"
v-decorator="[
'triggerInterval',
{rules: [{ required: true, message: '请输入间隔时长', whitespace: true}]}
]" />
<a-input
v-if="triggerTypeValue === '3'"
disabled
placeholder=""
v-decorator="[
'triggerInterval'
]" />
</a-form-item>
</a-col>
</a-row>
<a-row class="form-row" :gutter="16">
<a-col :lg="8" :md="6" :sm="12">
<a-form-item label="执行器类型">
<a-select
placeholder="请选择执行器类型"
v-decorator="[
'executorType',
{
initialValue: '1',
rules: [{ required: true, message: '请选择执行器类型'}]
}
]" >
<a-select-option :value="index" v-for="(item, index) in executorType" :key="index">{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :lg="16" :md="24" :sm="24">
<a-form-item label="执行器名称">
<a-input
placeholder="请输入执行器名称"
type="textarea"
:rows="1"
v-decorator="[
'executorInfo',
{rules: [{ required: true, message: '请输入执行器名称', whitespace: true}]}
]" />
</a-form-item>
</a-col>
</a-row>
<a-row class="form-row" :gutter="16">
<a-col :lg="8" :md="12" :sm="24">
<a-form-item label="任务类型">
<a-select
placeholder="请选择任务类型"
@change="handleTaskTypeChange"
v-decorator="[
'taskType',
{
initialValue: taskTypeValue,
rules: [{ required: true, message: '请选择任务类型'}]
}
]" >
<a-select-option :value="index" v-for="(item, index) in taskType" :key="index">{{ item.name }}</a-select-option>
</a-select>
</a-form-item>
</a-col>
<a-col :lg="16" :md="24" :sm="24">
<a-form-item label="方法参数">
<a-input
placeholder="请输入方法参数"
type="textarea"
:rows="1"
@click="handleBlur"
v-decorator="[
'argsStr',
{rules: [{ required: this.taskTypeValue === '3', message: '请输入方法参数', whitespace: true}]}
]" />
</a-form-item>
</a-col>
</a-row>
<a-row class="form-row" :gutter="16">
<a-col :lg="6" :md="12" :sm="24">
<a-form-item label="超时时间(秒)">
<a-input-number
id="inputNumber"
:min="1"
:max="36000"
v-decorator="[
'executorTimeout',
{
initialValue: '60',
rules: [{ required: true, message: '请输入超时时间'}]
}
]" />
</a-form-item>
</a-col>
<a-col :lg="6" :md="12" :sm="24">
<a-form-item label="最大重试次数">
<a-input-number
:min="0"
v-decorator="[
'maxRetryTimes',
{
initialValue: '3',
rules: [{ required: true, message: '请输入最大重试次数'}]
}
]" />
</a-form-item>
</a-col>
<a-col :lg="6" :md="12" :sm="24">
<a-form-item label="重试间隔(秒)">
<a-input-number
:min="1"
v-decorator="[
'retryInterval',
{
initialValue: '1',
rules: [{ required: true, message: '请输入重试间隔'
}]
}
]" />
</a-form-item>
</a-col>
<a-col :lg="6" :md="12" :sm="24">
<a-form-item label="并行数">
<a-input-number
:min="1"
v-decorator="[
'parallelNum',
{
initialValue: '1',
rules: [{ required: true, message: '请输入并行数'}]
}
]" />
</a-form-item>
</a-col>
</a-row>
<a-row class="form-row" :gutter="16">
</a-row>
<a-row class="form-row" :gutter="16">
<a-col :lg="24" :md="24" :sm="24">
<a-form-item label="描述">
<a-input
placeholder="请输入描述"
type="textarea"
v-decorator="[
'description',
{rules: [{required: false, max: 256, message: '最多支持256个字符'}]}
]" />
</a-form-item>
</a-col>
</a-row>
<a-form-item
:wrapperCol="{ span: 24 }"
style="text-align: center"
>
<a-button htmlType="submit" type="primary">提交</a-button>
<a-button style="margin-left: 8px" @click="reset">重置</a-button>
</a-form-item>
</a-form>
</a-card>
<a-modal :visible="visible" title="分片参数" @ok="submitForm()" @cancel="handlerCancel" width="500px">
<a-form-model ref="dynamicValidateForm" :model="dynamicValidateForm" style="margin-left: 15%" layout="vertical" >
<a-form-model-item
v-for="(domain, index) in dynamicValidateForm.domains"
:key="domain.key"
:label="'分片' + (index)"
:prop="'domains.' + index + '.value'"
:rules="{
required: true,
message: '分区参数不能为空',
trigger: 'blur',
}"
>
<a-input
v-model="domain.value"
placeholder="请输入分区的参数"
style="width: 80%; margin-right: 8px"
/>
<a-icon
v-if="dynamicValidateForm.domains.length > 1"
class="dynamic-delete-button"
type="minus-circle-o"
:disabled="dynamicValidateForm.domains.length === 1"
@click="removeDomain(domain)"
/>
</a-form-model-item>
<a-form-model-item v-bind="formItemLayoutWithOutLabel">
<a-button type="dashed" style="width: 60%" @click="add">
<a-icon type="plus" /> 添加分片
</a-button>
</a-form-model-item>
<a-form-model-item
:wrapper-col="{
xs: { span: 24, offset: 0 },
sm: { span: 16, offset: 8 },
lg: { span: 7 }
}">
</a-form-model-item>
</a-form-model>
</a-modal>
<cron-modal ref="cronModalRef" @getCron="getCron"/>
</div>
</template>
<script>
import { getAllGroupNameList } from '@/api/manage'
import { getJobDetail, saveJob, updateJob } from '@/api/jobApi'
import pick from 'lodash.pick'
import CronModal from '@/views/job/form/CronModal'
import AFormModel from 'ant-design-vue/es/form-model/Form'
import AFormModelItem from 'ant-design-vue/es/form-model/FormItem'
const enums = require('@/utils/jobEnum')
export default {
name: 'JobFrom',
components: {
CronModal,
AFormModel,
AFormModelItem
},
props: {},
data () {
return {
form: this.$form.createForm(this),
formItemLayout: {
labelCol: {
xs: { span: 24 },
sm: { span: 4 }
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 20 }
}
},
formItemLayoutWithOutLabel: {
wrapperCol: {
xs: { span: 24, offset: 0 },
sm: { span: 20, offset: 4 }
}
},
formType: 'create',
groupNameList: [],
jobStatusEnum: enums.jobStatusEnum,
taskType: enums.taskType,
triggerType: enums.triggerType,
blockStrategy: enums.blockStrategy,
executorType: enums.executorType,
routeKey: enums.routeKey,
loading: false,
visible: false,
count: 0,
triggerTypeValue: '2',
taskTypeValue: '1',
argsStrValue: [],
dynamicValidateForm: {
domains: []
}
}
},
beforeCreate () {
// this.dynamicForm = this.$form.createForm(this, { name: 'dynamic_form_item' })
// this.dynamicForm.getFieldDecorator('keys', { initialValue: [], preserve: true })
},
mounted () {
getAllGroupNameList().then((res) => {
this.groupNameList = res.data
})
this.$nextTick(() => {
const id = this.$route.query.id
if (id) {
this.loading = true
getJobDetail(id).then(res => {
this.loadEditInfo(res.data)
this.loading = false
})
}
})
},
methods: {
handleChange (value) {
this.triggerTypeValue = value
this.form.setFieldsValue({
triggerInterval: null
})
},
handleTaskTypeChange (value) {
this.taskTypeValue = value
},
handlerCron () {
const triggerType = this.form.getFieldValue('triggerType')
if (triggerType === '1') {
let triggerInterval = this.form.getFieldValue('triggerInterval')
if (triggerInterval === null || triggerInterval === '') {
triggerInterval = '* * * * * ?'
}
this.$refs.cronModalRef.isShow(triggerInterval)
}
},
removeDomain (item) {
const index = this.dynamicValidateForm.domains.indexOf(item)
if (index !== -1) {
this.dynamicValidateForm.domains.splice(index, 1)
}
},
add () {
this.dynamicValidateForm.domains.push({
value: '',
key: Date.now()
})
},
handleBlur () {
const taskType = this.form.getFieldValue('taskType')
if (taskType === '3') {
this.visible = !this.visible
}
},
getCron (cron) {
this.form.setFieldsValue({
triggerInterval: cron
})
},
submitForm () {
const { form } = this
this.$refs['dynamicValidateForm'].validate(valid => {
if (valid) {
this.argsStrValue = this.dynamicValidateForm.domains.map((item, index) => item.value)
form.setFieldsValue({
argsStr: this.dynamicValidateForm.domains.map((item, index) => `分区:${index}=>${item.value}`).join('; ')
})
this.visible = !this.visible
} else {
console.log('error submit!!')
return false
}
})
},
handleOk (e) {
const { form } = this
e.preventDefault()
this.dynamicForm.validateFields((err, values) => {
if (!err) {
this.argsStrValue = values['sharding']
console.log(this.argsStrValue)
form.setFieldsValue({
argsStr: this.argsStrValue.filter(item => item).map((item, index) => `分区:${index}=>${item}`).join('; ')
})
this.visible = false
}
})
},
handlerCancel () {
this.visible = false
},
handleSubmit (e) {
e.preventDefault()
this.form.validateFields((err, values) => {
if (!err) {
if (this.taskTypeValue === '3') {
values['argsStr'] = JSON.stringify(this.argsStrValue)
}
if (this.triggerTypeValue === '3') {
values['triggerInterval'] = '0'
}
if (this.formType === 'create') {
saveJob(values).then(res => {
this.$message.success('任务新增完成')
this.form.resetFields()
this.$router.go(-1)
})
} else {
updateJob(values).then(res => {
this.$message.success('任务更新完成')
this.form.resetFields()
this.$router.go(-1)
})
}
}
})
},
loadEditInfo (data) {
this.formType = 'edit'
const { form } = this
// ajax
new Promise((resolve) => {
setTimeout(resolve, 100)
}).then(() => {
const formData = pick(data, [
'id', 'jobName', 'groupName', 'jobStatus', 'executorInfo', 'argsStr', 'executorTimeout', 'description',
'maxRetryTimes', 'parallelNum', 'retryInterval', 'triggerType', 'blockStrategy', 'executorType', 'taskType', 'triggerInterval'])
formData.jobStatus = formData.jobStatus.toString()
formData.taskType = formData.taskType.toString()
formData.executorType = formData.executorType.toString()
formData.blockStrategy = formData.blockStrategy.toString()
formData.triggerType = formData.triggerType.toString()
this.triggerTypeValue = formData.triggerType
this.taskTypeValue = formData.taskType
if (this.triggerTypeValue === '3') {
formData.triggerInterval = null
}
if (this.taskTypeValue === '3') {
this.argsStrValue = JSON.parse(formData.argsStr)
formData.argsStr = this.argsStrValue.map((item, index) => `分区:${index}=>${item}`).join(';')
this.argsStrValue.forEach((item, index) => {
this.dynamicValidateForm.domains.push({
value: item,
key: Date.now() + index
})
})
}
form.setFieldsValue(formData)
})
},
reset () {
this.form.resetFields()
this.dynamicForm.resetFields()
}
}
}
</script>