|
@@ -0,0 +1,857 @@
|
|
|
|
+<template>
|
|
|
|
+ <div class="app-container">
|
|
|
|
+ <el-form :inline="true" size="small">
|
|
|
|
+ <el-form-item label="执行器" lable-width="auto">
|
|
|
|
+ <el-select v-model="tableQuery.jobGroup" placeholder="请选择" @change="groupChange" filterable>
|
|
|
|
+ <el-option
|
|
|
|
+ v-for="item in groupListData"
|
|
|
|
+ :key="item.id"
|
|
|
|
+ :label="item.title"
|
|
|
|
+ :value="item.id"
|
|
|
|
+ >
|
|
|
|
+ </el-option>
|
|
|
|
+ </el-select>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ <!-- 运行状态-->
|
|
|
|
+ <el-form-item label="" width="auto" class="triggerCondition">
|
|
|
|
+ <el-select v-model="tableQuery.triggerStatus" placeholder="请选择">
|
|
|
|
+ <el-option
|
|
|
|
+ v-for="(item) in triggerStatusEnum"
|
|
|
|
+ :key="item.val"
|
|
|
|
+ :label="item.title"
|
|
|
|
+ :value="item.val"
|
|
|
|
+ >
|
|
|
|
+ </el-option>
|
|
|
|
+ </el-select>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ <el-form-item label="">
|
|
|
|
+ <el-input v-model="tableQuery.jobDesc" placeholder="请输入任务描述" clearable></el-input>
|
|
|
|
+ </el-form-item>
|
|
|
|
+
|
|
|
|
+ <el-form-item label="">
|
|
|
|
+ <el-input v-model="tableQuery.executorHandler" placeholder="请输入JobHandler" clearable></el-input>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ <el-form-item label="">
|
|
|
|
+ <el-input v-model="tableQuery.author" placeholder="请输入负责人" clearable></el-input>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ <el-form-item class="searchBtn">
|
|
|
|
+ <el-button type="primary" @click="getJobList">查询</el-button>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ <el-button class="filter-item" style="margin-left: 10px;" @click="jobCreate" size="small"
|
|
|
|
+ v-hasPermi="['xxl:job:info:add']"
|
|
|
|
+ :type="pageBoolean.addColor" icon="el-icon-plus"
|
|
|
|
+ >{{ pageBoolean.addText }}
|
|
|
|
+ </el-button>
|
|
|
|
+ </el-form>
|
|
|
|
+ <el-table
|
|
|
|
+ ref="multipleTable"
|
|
|
|
+ :data="jobList"
|
|
|
|
+ v-loading="listLoading"
|
|
|
|
+ element-loading-text="数据加载中,请稍后"
|
|
|
|
+ border
|
|
|
|
+ fit
|
|
|
|
+ :highlight-current-row="false"
|
|
|
|
+ style="width: 100%"
|
|
|
|
+ >
|
|
|
|
+ <el-table-column label="任务ID" align="center" min-width="30" prop="id">
|
|
|
|
+ <template slot-scope="scope"> {{ scope.row.id }}</template>
|
|
|
|
+ </el-table-column>
|
|
|
|
+ <el-table-column align="center" prop="jobDesc" label="任务描述" min-width="100">
|
|
|
|
+ <template slot-scope="scope"> {{ scope.row.jobDesc }}</template>
|
|
|
|
+ </el-table-column>
|
|
|
|
+ <el-table-column align="center" prop="gulueType" label="调度类型" min-width="100">
|
|
|
|
+ <template slot-scope="scope"> {{ scope.row.glueType }}: {{ scope.row.executorHandler }}</template>
|
|
|
|
+ </el-table-column>
|
|
|
|
+ <el-table-column align="center" prop="schedule" label="运行模式" min-width="60">
|
|
|
|
+ <template slot-scope="scope">{{ scope.row.scheduleType }}: {{ scope.row.scheduleConf }}</template>
|
|
|
|
+ </el-table-column>
|
|
|
|
+ <el-table-column align="center" prop="author" label="负责人" min-width="50">
|
|
|
|
+ <template slot-scope="scope"> {{ scope.row.author }}</template>
|
|
|
|
+ </el-table-column>
|
|
|
|
+ <el-table-column align="center" prop="triggerStatus" label="状态" min-width="40"
|
|
|
|
+ :filters="[{ text: 'RUNNING', value: 1 }, { text: 'STOP', value: 0 }]"
|
|
|
|
+ :filter-method="filterTriggerStatus"
|
|
|
|
+ filter-placement="bottom-end"
|
|
|
|
+ >
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
+ <el-tag size="small"
|
|
|
|
+ :type="scope.row.triggerStatus === 0 ? 'info' : 'success'"
|
|
|
|
+ disable-transitions v-html="formatTriggerStatus(scope.row.triggerStatus)"
|
|
|
|
+ ></el-tag>
|
|
|
|
+ </template>
|
|
|
|
+ </el-table-column>
|
|
|
|
+ <el-table-column align="center" prop="name" label="操作" show-overflow-tooltip min-width="60">
|
|
|
|
+ <template slot-scope="scope">
|
|
|
|
+ <el-dropdown size="small" trigger="click" split-button type="primary"
|
|
|
|
+ @command="(command)=>{handleRowOp(command,scope.row)}"
|
|
|
|
+ >
|
|
|
|
+ 操作
|
|
|
|
+ <el-dropdown-menu slot="dropdown">
|
|
|
|
+ <el-dropdown-item command="beforeRunOnce" v-hasPermi="['xxl:job:info:trigger']">执行一次</el-dropdown-item>
|
|
|
|
+ <el-dropdown-item command="regNode">注册节点</el-dropdown-item>
|
|
|
|
+ <el-dropdown-item v-if="scope.row.scheduleType == 'CRON' || scope.row.scheduleType == 'FIX_RATE'"
|
|
|
|
+ command="nextTriggerTime"
|
|
|
|
+ >下次执行时间
|
|
|
|
+ </el-dropdown-item>
|
|
|
|
+ <hr>
|
|
|
|
+ <el-dropdown-item command="startOrStop" v-hasPermi="['xxl:job:info:start']" v-if="scope.row.triggerStatus === 0">
|
|
|
|
+ 启动
|
|
|
|
+ </el-dropdown-item>
|
|
|
|
+ <el-dropdown-item command="startOrStop" v-hasPermi="['xxl:job:info:stop']" v-if="scope.row.triggerStatus === 1">
|
|
|
|
+ 停止
|
|
|
|
+ </el-dropdown-item>
|
|
|
|
+ <el-dropdown-item command="editJob" v-hasPermi="['xxl:job:info:update']">编辑</el-dropdown-item>
|
|
|
|
+ <el-dropdown-item command="deleteJob" v-hasPermi="['xxl:job:info:remove']">删除</el-dropdown-item>
|
|
|
|
+ <el-dropdown-item command="copyJob">复制</el-dropdown-item>
|
|
|
|
+ </el-dropdown-menu>
|
|
|
|
+ </el-dropdown>
|
|
|
|
+ </template>
|
|
|
|
+ </el-table-column>
|
|
|
|
+ </el-table>
|
|
|
|
+
|
|
|
|
+ <el-row type="flex" justify="space-between" style="padding-top:20px;">
|
|
|
|
+ <el-col style="text-align:right;">
|
|
|
|
+ <el-pagination
|
|
|
|
+ background
|
|
|
|
+ @size-change="handleSizeChange"
|
|
|
|
+ @current-change="handleCurrentChange"
|
|
|
|
+ :current-page.sync="tableQuery.currentPage"
|
|
|
|
+ :page-sizes="[10, 20, 30, 50]"
|
|
|
|
+ :page-size="tableQuery.length"
|
|
|
|
+ layout="total, sizes, prev, pager, next, jumper"
|
|
|
|
+ :total="total"
|
|
|
|
+ >
|
|
|
|
+ </el-pagination>
|
|
|
|
+ </el-col>
|
|
|
|
+ </el-row>
|
|
|
|
+
|
|
|
|
+ <!-- dialog -->
|
|
|
|
+ <el-dialog width="60%" id="jobFormDialog" :title="formDialogType=='create' ? '新增任务' : '编辑任务'"
|
|
|
|
+ :visible.sync="dialogFormVisible" center
|
|
|
|
+ >
|
|
|
|
+ <el-form :model="jobForm" :rules="rules" ref="jobForm" label-width="100px" size="small">
|
|
|
|
+ <div>
|
|
|
|
+ <form-group group-name="基础配置"/>
|
|
|
|
+ </div>
|
|
|
|
+ <el-row>
|
|
|
|
+ <el-col :span="12">
|
|
|
|
+ <el-form-item label="执行器" prop="jobGroup">
|
|
|
|
+ <el-select v-model="jobForm.jobGroup" placeholder="请选择">
|
|
|
|
+ <el-option v-for="item in groupListData"
|
|
|
|
+ :key="item.id"
|
|
|
|
+ :label="item.title"
|
|
|
|
+ :value="item.id"
|
|
|
|
+ ></el-option>
|
|
|
|
+ </el-select>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ <el-form-item label="负责人" prop="author">
|
|
|
|
+ <el-input v-model="jobForm.author" placeholder="请输入负责人"></el-input>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ </el-col>
|
|
|
|
+ <el-col :span="12">
|
|
|
|
+ <el-form-item label="任务描述" prop="jobDesc">
|
|
|
|
+ <el-input v-model="jobForm.jobDesc" label="请输入任务描述"></el-input>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ <el-form-item label="报警邮件" prop="alarmEmail">
|
|
|
|
+ <el-input v-model="jobForm.alarmEmail" label="请输入任务描述"></el-input>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ </el-col>
|
|
|
|
+ </el-row>
|
|
|
|
+ <el-row>
|
|
|
|
+ <div>
|
|
|
|
+ <form-group group-name="调度配置"/>
|
|
|
|
+ </div>
|
|
|
|
+ <el-col :span="12">
|
|
|
|
+ <el-form-item label="调度类型" prop="glueType">
|
|
|
|
+ <el-select v-model="jobForm.scheduleType" placeholder="请选择">
|
|
|
|
+ <el-option v-for="item in scheduleTypeEnum"
|
|
|
|
+ :key="item.val"
|
|
|
|
+ :label="item.title"
|
|
|
|
+ :value="item.val"
|
|
|
|
+ ></el-option>
|
|
|
|
+ </el-select>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ </el-col>
|
|
|
|
+ <el-col :span="12" v-if="jobForm.scheduleType != 'NONE'">
|
|
|
|
+ <el-form-item label="cron表达式" prop="scheduleConf">
|
|
|
|
+ <el-input v-model="jobForm.scheduleConf" placeholder="请输入cron执行表达式">
|
|
|
|
+ <template slot="append">
|
|
|
|
+ <el-button type="primary" @click="handleShowCron">
|
|
|
|
+ 生成
|
|
|
|
+ <i class="el-icon-time el-icon--right"></i>
|
|
|
|
+ </el-button>
|
|
|
|
+ </template>
|
|
|
|
+ </el-input>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ </el-col>
|
|
|
|
+
|
|
|
|
+ </el-row>
|
|
|
|
+ <div>
|
|
|
|
+ <form-group group-name="任务配置"/>
|
|
|
|
+ </div>
|
|
|
|
+ <el-row>
|
|
|
|
+ <el-col :span="12">
|
|
|
|
+ <el-form-item label="运行模式" prop="glueType">
|
|
|
|
+ <el-select v-model="jobForm.glueType" placeholder="请选择" :disabled="formDialogType=='update'">
|
|
|
|
+ <el-option v-for="item in glueTypeEnum"
|
|
|
|
+ :key="item.val"
|
|
|
|
+ :label="item.title"
|
|
|
|
+ :value="item.val"
|
|
|
|
+ ></el-option>
|
|
|
|
+ </el-select>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ </el-col>
|
|
|
|
+ <el-col :span="12">
|
|
|
|
+ <el-form-item label="JobHandler" prop="executorHandler">
|
|
|
|
+ <el-input v-model="jobForm.executorHandler" label="executorHandler"
|
|
|
|
+ :disabled="jobForm.glueType != null && jobForm.glueType.search('GLUE') === 0"
|
|
|
|
+ ></el-input>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ </el-col>
|
|
|
|
+ </el-row>
|
|
|
|
+ <el-row>
|
|
|
|
+ <el-col>
|
|
|
|
+ <el-form-item label="任务参数" prop="executorParam">
|
|
|
|
+ <el-input type="textarea" :rows="2" placeholder="请输入任务参数" v-model="jobForm.executorParam">
|
|
|
|
+ </el-input>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ </el-col>
|
|
|
|
+ </el-row>
|
|
|
|
+ <div class="chart-wrapper">
|
|
|
|
+ <form-group group-name="高级配置"/>
|
|
|
|
+ </div>
|
|
|
|
+ <el-row>
|
|
|
|
+ <el-col :span="12">
|
|
|
|
+ <el-form-item label="路由策略" prop="misfireStrategy">
|
|
|
|
+ <el-select v-model="jobForm.executorRouteStrategy" placeholder="请选择">
|
|
|
|
+ <el-option v-for="item in routeStrategyEnum"
|
|
|
|
+ :key="item.val"
|
|
|
|
+ :label="item.title"
|
|
|
|
+ :value="item.val"
|
|
|
|
+ ></el-option>
|
|
|
|
+ </el-select>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ <el-form-item label="调度过期策略" prop="misfireStrategy">
|
|
|
|
+ <el-select v-model="jobForm.misfireStrategy" placeholder="请选择">
|
|
|
|
+ <el-option v-for="item in failStrategyEnum"
|
|
|
|
+ :key="item.val"
|
|
|
|
+ :label="item.title"
|
|
|
|
+ :value="item.val"
|
|
|
|
+ ></el-option>
|
|
|
|
+ </el-select>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ <el-form-item label="任务超时时间" prop="executorTimeout">
|
|
|
|
+ <el-input v-model.number="jobForm.executorTimeout" placeholder="请输入超时时间,单位秒,大于零时生效"></el-input>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ </el-col>
|
|
|
|
+ <el-col :span="12">
|
|
|
|
+ <el-form-item label="子任务ID" prop="childJobId">
|
|
|
|
+ <el-input v-model="jobForm.childJobId" placeholder="请输入子任务的ID,如果存在多个则逗号分隔"></el-input>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ <el-form-item label="阻塞处理策略" prop="executorBlockStrategy">
|
|
|
|
+ <el-select v-model="jobForm.executorBlockStrategy" placeholder="请选择">
|
|
|
|
+ <el-option v-for="item in blockStrategyEnum"
|
|
|
|
+ :key="item.val"
|
|
|
|
+ :label="item.title"
|
|
|
|
+ :value="item.val"
|
|
|
|
+ ></el-option>
|
|
|
|
+ </el-select>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ <el-form-item label="失败重试次数" prop="executorFailRetryCount">
|
|
|
|
+ <el-input v-model.number="jobForm.executorFailRetryCount" placeholder="重试次数,大于零时生效"></el-input>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ </el-col>
|
|
|
|
+ </el-row>
|
|
|
|
+ </el-form>
|
|
|
|
+ <div slot="footer" class="dialog-footer">
|
|
|
|
+ <el-button @click="dialogFormVisible = false" size="small">取 消</el-button>
|
|
|
|
+ <el-button v-if="formDialogType=='create'" type="primary" @click="executorAddForm" size="small">新 增</el-button>
|
|
|
|
+ <el-button v-else type="primary" @click="executorUpdateForm" size="small">更 新</el-button>
|
|
|
|
+ </div>
|
|
|
|
+ </el-dialog>
|
|
|
|
+
|
|
|
|
+ <el-dialog title="Cron表达式生成器" :visible.sync="openCron" append-to-body destroy-on-close class="scrollbar">
|
|
|
|
+ <crontab @hide="openCron=false" @fill="crontabFill" :expression="expression"></crontab>
|
|
|
|
+ </el-dialog>
|
|
|
|
+
|
|
|
|
+ <el-dialog width="50%" id="runOnceDialog" title="执行一次" :visible.sync="runOnceDialogVisible" center>
|
|
|
|
+ <el-form :model="runOnceForm" ref="runOnceForm" label-width="80px" size="small">
|
|
|
|
+ <el-row>
|
|
|
|
+ <el-col :span="22">
|
|
|
|
+ <el-form-item label="任务参数" prop="executorParam">
|
|
|
|
+ <el-input type="textarea" :rows="2" placeholder="请输入任务参数" v-model="runOnceForm.executorParam">
|
|
|
|
+ </el-input>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ </el-col>
|
|
|
|
+ </el-row>
|
|
|
|
+ <el-row>
|
|
|
|
+ <el-col :span="22">
|
|
|
|
+ <el-form-item label="机器地址" prop="addressList">
|
|
|
|
+ <el-input type="textarea" :rows="2" placeholder="请输入任务参数" v-model="runOnceForm.addressList">
|
|
|
|
+ </el-input>
|
|
|
|
+ </el-form-item>
|
|
|
|
+ </el-col>
|
|
|
|
+ </el-row>
|
|
|
|
+ </el-form>
|
|
|
|
+ <div slot="footer" class="dialog-footer">
|
|
|
|
+ <el-button type="primary" @click="runOnce">执 行</el-button>
|
|
|
|
+ <el-button @click="runOnceDialogVisible = false">取 消</el-button>
|
|
|
|
+ </div>
|
|
|
|
+ </el-dialog>
|
|
|
|
+ </div>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+<script>
|
|
|
|
+import { getGroupList, groupDetail } from '@/api/xxlJob/group'
|
|
|
|
+import FormGroup from './components/FormGroup'
|
|
|
|
+
|
|
|
|
+import {
|
|
|
|
+ create,
|
|
|
|
+ getJobPageList,
|
|
|
|
+ jobStart,
|
|
|
|
+ jobStop,
|
|
|
|
+ jobTrigger,
|
|
|
|
+ nextTriggerTime,
|
|
|
|
+ remove,
|
|
|
|
+ update
|
|
|
|
+} from '@/api/xxlJob/jobinfo'
|
|
|
|
+import Crontab from '@/components/Crontab'
|
|
|
|
+
|
|
|
|
+export default {
|
|
|
|
+ name: 'JobsList',
|
|
|
|
+ components: {
|
|
|
|
+ FormGroup, Crontab
|
|
|
|
+ },
|
|
|
|
+ watch: {},
|
|
|
|
+ data() {
|
|
|
|
+ return {
|
|
|
|
+ openCron: false,
|
|
|
|
+ expression: '',
|
|
|
|
+ formDialogType: '',
|
|
|
|
+ groupListData: [],
|
|
|
|
+ //禁用jobhandler,仅在
|
|
|
|
+ disableJobHandler: false,
|
|
|
|
+ //运行模式枚举
|
|
|
|
+ glueTypeEnum: [{ val: 'BEAN', title: 'BEAN' }],
|
|
|
|
+ //调度模式枚举
|
|
|
|
+ scheduleTypeEnum: [{ val: 'NONE', title: '无' }, { val: 'CRON', title: 'CRON' }, {
|
|
|
|
+ val: 'FIX_RATE',
|
|
|
|
+ title: '固定速度'
|
|
|
|
+ }],
|
|
|
|
+ routeStrategyEnum: [{ val: 'FIRST', title: '第一个' }, { val: 'LAST', title: '最后一个' },
|
|
|
|
+ { val: 'ROUND', title: '轮询' }, { val: 'RANDOM', title: '随机' },
|
|
|
|
+ { val: 'CONSISTENT_HASH', title: '一致性HASH' }, { val: 'LEAST_FREQUENTLY_USED', title: '最不经常使用' },
|
|
|
|
+ { val: 'LEAST_RECENTLY_USED', title: '最近最久未使用' }, { val: 'FAILOVER', title: '故障转移' },
|
|
|
|
+ { val: 'BUSYOVER', title: '忙碌转移' }, { val: 'SHARDING_BROADCAST', title: '分片广播' }],
|
|
|
|
+ blockStrategyEnum: [{ val: 'SERIAL_EXECUTION', title: '单机串行' }, { val: 'DISCARD_LATER', title: '丢弃后续调度' },
|
|
|
|
+ { val: 'COVER_EARLY', title: '覆盖之前调度' }],
|
|
|
|
+ failStrategyEnum: [{ val: 'DO_NOTHING', title: '忽略' }, { val: 'FIRE_ONCE_NOW', title: '立即执行一次' }],
|
|
|
|
+ triggerStatusEnum: [{ val: -1, title: '全部' }, { val: 1, title: '启动' }, { val: 0, title: '停止' }],
|
|
|
|
+ total: null,
|
|
|
|
+ jobList: null,
|
|
|
|
+ listLoading: true,
|
|
|
|
+
|
|
|
|
+ dialogFormVisible: false,
|
|
|
|
+ runOnceDialogVisible: false,
|
|
|
|
+
|
|
|
|
+ tableQuery: {
|
|
|
|
+ jobGroup: null,
|
|
|
|
+ triggerStatus: -1,
|
|
|
|
+ jobDesc: '',
|
|
|
|
+ executorHandler: '',
|
|
|
|
+ author: '',
|
|
|
|
+ length: 10,
|
|
|
|
+ start: 0,
|
|
|
|
+ currentPage: 1
|
|
|
|
+ },
|
|
|
|
+ //执行器查询
|
|
|
|
+ groupQuery: {
|
|
|
|
+ title: '',
|
|
|
|
+ start: 0,
|
|
|
|
+ length: 100
|
|
|
|
+ },
|
|
|
|
+ jobForm: {
|
|
|
|
+ id: null,
|
|
|
|
+ //执行器
|
|
|
|
+ jobGroup: null,
|
|
|
|
+ //负责人
|
|
|
|
+ author: '',
|
|
|
|
+ //任务描述
|
|
|
|
+ jobDesc: '',
|
|
|
|
+ alarmEmail: '',
|
|
|
|
+ //调度类型
|
|
|
|
+ scheduleType: '',
|
|
|
|
+ scheduleConf: '',
|
|
|
|
+ //运行模式
|
|
|
|
+ glueType: null,
|
|
|
|
+ //jobHandler
|
|
|
|
+ executorHandler: '',
|
|
|
|
+ //任务参数
|
|
|
|
+ executorParam: '',
|
|
|
|
+ //路由策略
|
|
|
|
+ executorRouteStrategy: '',
|
|
|
|
+ //调度过期策略
|
|
|
|
+ misfireStrategy: '',
|
|
|
|
+ //任务超时时间
|
|
|
|
+ executorTimeout: null,
|
|
|
|
+ childJobId: null,
|
|
|
|
+ //阻塞处理策略
|
|
|
|
+ executorBlockStrategy: '',
|
|
|
|
+ //失败重试次数
|
|
|
|
+ executorFailRetryCount: null
|
|
|
|
+ },
|
|
|
|
+ rules: {
|
|
|
|
+ jobGroup: [{ required: true, message: '请选择执行器', trigger: 'blur' }],
|
|
|
|
+ author: [{ required: true, message: '请输入负责人', trigger: 'blur' }],
|
|
|
|
+ jobDesc: [{ required: true, message: '请输入任务描述', trigger: 'blur' }],
|
|
|
|
+
|
|
|
|
+ scheduleType: [{ required: true, message: '请选择调度类型', trigger: 'blur' }],
|
|
|
|
+ scheduleConf: [{ required: true, message: '请输入Cron表达式', trigger: 'blur' }],
|
|
|
|
+
|
|
|
|
+ glueType: [{ required: true, message: '请选择运行模式', trigger: 'blur' }],
|
|
|
|
+ executorHandler: [{ required: true, message: '请输入执行器BEAN名称', trigger: 'blur' }],
|
|
|
|
+
|
|
|
|
+ misfireStrategy: [{ required: false, message: '请选择失败策略', trigger: 'blur' }],
|
|
|
|
+ alarmEmail: [{ required: false, message: '请输入邮箱地址', trigger: 'blur' }, {
|
|
|
|
+ type: 'email',
|
|
|
|
+ message: '请输入正确的邮箱地址',
|
|
|
|
+ trigger: ['blur', 'change']
|
|
|
|
+ }]
|
|
|
|
+ },
|
|
|
|
+ runOnceForm: {
|
|
|
|
+ id: null,
|
|
|
|
+ //任务参数
|
|
|
|
+ executorParam: '',
|
|
|
|
+ addressList: ''
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ registerAddrList: [],
|
|
|
|
+ pageBoolean: {
|
|
|
|
+ delColor: 'primary',
|
|
|
|
+ delText: '批量删除',
|
|
|
|
+ addColor: 'success',
|
|
|
|
+ addText: '添加任务'
|
|
|
|
+ },
|
|
|
|
+ operateText: ['执行', '暂停', '删除']
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ mounted() {
|
|
|
|
+ // this.initEnums()
|
|
|
|
+ this.fetchGroupList()
|
|
|
|
+ },
|
|
|
|
+ methods: {
|
|
|
|
+ /** cron表达式按钮操作 */
|
|
|
|
+ handleShowCron() {
|
|
|
|
+ this.expression = this.jobForm.scheduleConf
|
|
|
|
+ this.openCron = true
|
|
|
|
+ },
|
|
|
|
+ /** 确定后回传值 */
|
|
|
|
+ crontabFill(value) {
|
|
|
|
+ this.jobForm.scheduleConf = value
|
|
|
|
+ },
|
|
|
|
+ //获取执行器
|
|
|
|
+ fetchGroupList() {
|
|
|
|
+ getGroupList(this.groupQuery).then(res => {
|
|
|
|
+ this.$nextTick(() => {
|
|
|
|
+ this.groupListData = res.data
|
|
|
|
+ if (res.recordsTotal === 0) {
|
|
|
|
+ this.$message({
|
|
|
|
+ message: '执行器列表为空,需要先创建执行器',
|
|
|
|
+ type: 'warning'
|
|
|
|
+ })
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+ this.tableQuery.jobGroup = res.data[0].id
|
|
|
|
+ this.jobForm.jobGroup = res.data[0].id
|
|
|
|
+ //回调获取job
|
|
|
|
+ this.getJobList()
|
|
|
|
+ })
|
|
|
|
+ }).catch(function(err) {
|
|
|
|
+ console.log(err)
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+ //任务列表
|
|
|
|
+ getJobList() {
|
|
|
|
+ this.listLoading = false
|
|
|
|
+ getJobPageList(this.tableQuery).then(res => {
|
|
|
|
+ const { data, recordsTotal } = res
|
|
|
|
+ this.total = recordsTotal
|
|
|
|
+ this.jobList = data
|
|
|
|
+ this.listLoading = false
|
|
|
|
+ }).catch(reject => {
|
|
|
|
+ this.listLoading = false
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+ refreshJobList() {
|
|
|
|
+ this.tableQuery.start = 0
|
|
|
|
+ this.tableQuery.currentPage = 1
|
|
|
|
+ this.getJobList()
|
|
|
|
+ },
|
|
|
|
+ //操作按钮处理函数,根据操作类型再进行分发
|
|
|
|
+ handleRowOp(op, row) {
|
|
|
|
+ switch (op) {
|
|
|
|
+ case 'jobCreate': {
|
|
|
|
+ this.jobCreate()
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ case 'editJob': {
|
|
|
|
+ this.editJob(row)
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ case 'beforeRunOnce': {
|
|
|
|
+ this.beforeRunOnce(row)
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ case 'regNode': {
|
|
|
|
+ this.regNode(row.id)
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ case 'nextTriggerTime': {
|
|
|
|
+ this.nextTriggerTime(row.scheduleType, row.scheduleConf)
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ case 'startOrStop': {
|
|
|
|
+ this.startOrStop(row)
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ case 'deleteJob': {
|
|
|
|
+ this.deleteJob(row.id)
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ case 'copyJob': {
|
|
|
|
+ this.copyJob(row)
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ jobCreate() {
|
|
|
|
+ this.jobForm = {
|
|
|
|
+ id: null,
|
|
|
|
+ jobGroup: null,
|
|
|
|
+ executorRouteStrategy: 'RANDOM',
|
|
|
|
+ scheduleType: 'CRON',
|
|
|
|
+ glueType: 'BEAN',
|
|
|
|
+ executorParam: '',
|
|
|
|
+ executorBlockStrategy: 'SERIAL_EXECUTION',
|
|
|
|
+ executorTimeout: 0,
|
|
|
|
+ author: '',
|
|
|
|
+ jobDesc: '',
|
|
|
|
+ scheduleConf: '',
|
|
|
|
+ executorHandler: '',
|
|
|
|
+ childJobId: null,
|
|
|
|
+ misfireStrategy: 'DO_NOTHING',
|
|
|
|
+ alarmEmail: ''
|
|
|
|
+ }
|
|
|
|
+ this.dialogFormVisible = true
|
|
|
|
+ this.formDialogType = 'create'
|
|
|
|
+ },
|
|
|
|
+ //新增任务
|
|
|
|
+ executorAddForm() {
|
|
|
|
+ this.$refs['jobForm'].validate((valid) => {
|
|
|
|
+ if (valid) {
|
|
|
|
+ delete this.jobForm.id
|
|
|
|
+ create(this.jobForm).then(res => {
|
|
|
|
+ if (res.code === 200) {
|
|
|
|
+ this.dialogFormVisible = false
|
|
|
|
+ this.$message({
|
|
|
|
+ message: '新增成功',
|
|
|
|
+ type: 'success'
|
|
|
|
+ })
|
|
|
|
+ this.refreshJobList()
|
|
|
|
+ } else {
|
|
|
|
+ this.$message(res.msg)
|
|
|
|
+ }
|
|
|
|
+ }).catch(function(err) {
|
|
|
|
+ console.log(err.message)
|
|
|
|
+ })
|
|
|
|
+ } else {
|
|
|
|
+ return false
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+ editJob(row) {
|
|
|
|
+ // console.info('编辑任务',row)
|
|
|
|
+ this.dialogFormVisible = true
|
|
|
|
+ this.formDialogType = 'update'
|
|
|
|
+ this.jobForm = row
|
|
|
|
+ delete this.jobForm.addTime
|
|
|
|
+ delete this.jobForm.glueUpdatetime
|
|
|
|
+ delete this.jobForm.updateTime
|
|
|
|
+ //删除调度状态
|
|
|
|
+ delete this.jobForm.triggerStatus
|
|
|
|
+ //清除创建时产生的校验提示
|
|
|
|
+ this.resetForm('jobForm')
|
|
|
|
+ },
|
|
|
|
+ //修改任务
|
|
|
|
+ executorUpdateForm() {
|
|
|
|
+ this.$refs['jobForm'].validate((valid) => {
|
|
|
|
+ if (valid) {
|
|
|
|
+ if (this.jobForm.executorFailRetryCount == null) {
|
|
|
|
+ this.jobForm.executorFailRetryCount = 0
|
|
|
|
+ }
|
|
|
|
+ if (this.jobForm.executorTimeout == null) {
|
|
|
|
+ this.jobForm.executorTimeout = 0
|
|
|
|
+ }
|
|
|
|
+ update(this.jobForm).then(res => {
|
|
|
|
+ if (res.code === 200) {
|
|
|
|
+ this.dialogFormVisible = false
|
|
|
|
+ this.$message({
|
|
|
|
+ message: '更新成功',
|
|
|
|
+ type: 'success'
|
|
|
|
+
|
|
|
|
+ })
|
|
|
|
+ this.refreshJobList()
|
|
|
|
+ } else {
|
|
|
|
+ this.$message(res.msg)
|
|
|
|
+ }
|
|
|
|
+ }).catch(function(err) {
|
|
|
|
+ console.log(err.message)
|
|
|
|
+ })
|
|
|
|
+ } else {
|
|
|
|
+ return false
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+ beforeRunOnce(row) {
|
|
|
|
+ this.runOnceForm.id = row.id
|
|
|
|
+ this.runOnceForm.executorParam = row.executorParam
|
|
|
|
+ this.runOnceDialogVisible = true
|
|
|
|
+ },
|
|
|
|
+ runOnce() {
|
|
|
|
+ jobTrigger(this.runOnceForm).then(res => {
|
|
|
|
+ if (res.code === 200) {
|
|
|
|
+ this.$message({
|
|
|
|
+ message: '触发成功',
|
|
|
|
+ type: 'success'
|
|
|
|
+ })
|
|
|
|
+ } else {
|
|
|
|
+ this.$message(res.msg)
|
|
|
|
+ }
|
|
|
|
+ }).catch(function(err) {
|
|
|
|
+ this.$message(err)
|
|
|
|
+ })
|
|
|
|
+ this.runOnceDialogVisible = false
|
|
|
|
+ },
|
|
|
|
+ regNode(id) {
|
|
|
|
+ groupDetail(id).then(res => {
|
|
|
|
+ let innerHtml = ''
|
|
|
|
+ if (res.code === 200) {
|
|
|
|
+ let registryList = res.content.registryList
|
|
|
|
+ for (const index in registryList) {
|
|
|
|
+ innerHtml = innerHtml + '<span class="onlineNode">' + (Number(index) + 1) + '. ' + registryList[index] + '</span>'
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ this.$alert(innerHtml, '注册节点', {
|
|
|
|
+ dangerouslyUseHTMLString: true
|
|
|
|
+ })
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+ nextTriggerTime(scheduleType, scheduleConf) {
|
|
|
|
+ nextTriggerTime(scheduleType, scheduleConf).then(res => {
|
|
|
|
+ let innerHtml = ''
|
|
|
|
+ if (res.code === 200) {
|
|
|
|
+ let triggerTimeList = res.content
|
|
|
|
+ for (const index in triggerTimeList) {
|
|
|
|
+ innerHtml = innerHtml + '<span class="triggerTimeList">' + triggerTimeList[index] + '</span></br>'
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ this.$alert(innerHtml, '下次执行时间', {
|
|
|
|
+ dangerouslyUseHTMLString: true,
|
|
|
|
+ center: true
|
|
|
|
+ })
|
|
|
|
+ })
|
|
|
|
+ },
|
|
|
|
+ startOrStop(row) {
|
|
|
|
+ let status = row.triggerStatus
|
|
|
|
+ let statusDesc = status === 1 ? '停止' : '启动'
|
|
|
|
+ //当前运行,暂停
|
|
|
|
+ this.$confirm('确认' + statusDesc + '该任务?', '提示',
|
|
|
|
+ {
|
|
|
|
+ confirmButtonText: '确定',
|
|
|
|
+ cancelButtonText: '取消',
|
|
|
|
+ type: 'info'
|
|
|
|
+ }
|
|
|
|
+ ).then(res => {
|
|
|
|
+ if (status === 1) {
|
|
|
|
+ jobStop(row.id).then(res => {
|
|
|
|
+ if (res.code === 200) {
|
|
|
|
+ this.$message({ message: '操作成功', type: 'success' })
|
|
|
|
+ this.refreshJobList()
|
|
|
|
+ } else {
|
|
|
|
+ this.$message({ message: res.msg, type: 'error' })
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ } else if (status === 0) {
|
|
|
|
+ jobStart(row.id).then(res => {
|
|
|
|
+ if (res.code === 200) {
|
|
|
|
+ this.$message({ message: '操作成功', type: 'success' })
|
|
|
|
+ this.refreshJobList()
|
|
|
|
+ } else {
|
|
|
|
+ this.$message({ message: res.msg, type: 'error' })
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ }).catch(reject => console.log(reject))
|
|
|
|
+ },
|
|
|
|
+ deleteJob(id) {
|
|
|
|
+ this.$confirm('确认删除该任务?', '提示',
|
|
|
|
+ {
|
|
|
|
+ confirmButtonText: '确定',
|
|
|
|
+ cancelButtonText: '取消',
|
|
|
|
+ type: 'warn'
|
|
|
|
+ }
|
|
|
|
+ ).then(res => {
|
|
|
|
+ remove(id).then(res => {
|
|
|
|
+ if (res.code === 200) {
|
|
|
|
+ this.$message({
|
|
|
|
+ message: '删除成功',
|
|
|
|
+ type: 'success'
|
|
|
|
+ })
|
|
|
|
+ this.refreshJobList()
|
|
|
|
+ } else {
|
|
|
|
+ this.$message({
|
|
|
|
+ message: res.msg,
|
|
|
|
+ type: 'error'
|
|
|
|
+ })
|
|
|
|
+ }
|
|
|
|
+ }).catch(function(err) {
|
|
|
|
+ this.$message(err)
|
|
|
|
+ })
|
|
|
|
+ }).catch(reject => console.log(reject))
|
|
|
|
+ },
|
|
|
|
+ copyJob(row) {
|
|
|
|
+ this.jobForm = row
|
|
|
|
+ delete this.jobForm.addTime
|
|
|
|
+ delete this.jobForm.updateTime
|
|
|
|
+ delete this.jobForm.glueUpdatetime
|
|
|
|
+ delete this.jobForm.triggerLastTime
|
|
|
|
+ delete this.jobForm.triggerNextTime
|
|
|
|
+ delete this.jobForm.glueSource
|
|
|
|
+ delete this.jobForm.glueRemark
|
|
|
|
+ this.formDialogType = 'create'
|
|
|
|
+ this.dialogFormVisible = true
|
|
|
|
+ },
|
|
|
|
+
|
|
|
|
+ filterTriggerStatus(value, row) {
|
|
|
|
+ return row.triggerStatus === value
|
|
|
|
+ },
|
|
|
|
+ formatTriggerStatus(status) {
|
|
|
|
+ return status === 1 ? 'RUNNING' : 'STOP'
|
|
|
|
+ },
|
|
|
|
+ handleSizeChange(val) {
|
|
|
|
+ this.tableQuery.length = val
|
|
|
|
+ this.tableQuery.start = 0
|
|
|
|
+ this.getJobList()
|
|
|
|
+ },
|
|
|
|
+ handleCurrentChange(val) {
|
|
|
|
+ this.tableQuery.start = (val - 1) * this.tableQuery.length
|
|
|
|
+ this.tableQuery.currentPage = val
|
|
|
|
+ this.getJobList()
|
|
|
|
+ },
|
|
|
|
+ changeCronHandle(val) {
|
|
|
|
+ this.jobForm.scheduleConf = val
|
|
|
|
+ },
|
|
|
|
+ groupChange(item) {
|
|
|
|
+ this.tableQuery.jobGroup = item
|
|
|
|
+ this.jobForm.jobGroup = item
|
|
|
|
+ //触发查询
|
|
|
|
+ // this.refreshJobList()
|
|
|
|
+ }
|
|
|
|
+ },
|
|
|
|
+ computed: {}
|
|
|
|
+}
|
|
|
|
+</script>
|
|
|
|
+
|
|
|
|
+<style rel="stylesheet/scss" lang="scss" slot-scope>
|
|
|
|
+.top {
|
|
|
|
+ padding: 10px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.fitersLine {
|
|
|
|
+ .el-form-item__content {
|
|
|
|
+ margin-left: 0 !important;
|
|
|
|
+ width: 130px !important;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .el-form-item__label {
|
|
|
|
+ min-width: auto !important;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ .searchBtn {
|
|
|
|
+ width: 60px !important;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.el-dialog--center .el-dialog__body {
|
|
|
|
+ padding: 0px 25px 0px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.triggerCondition {
|
|
|
|
+ .el-form-item__content {
|
|
|
|
+ width: 100px !important;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.el-table .cell {
|
|
|
|
+ line-height: 1;
|
|
|
|
+ padding: 0 3px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.el-dialog {
|
|
|
|
+ max-width: 642px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.onlineNode {
|
|
|
|
+ background-color: springgreen;
|
|
|
|
+ border-radius: 10px;
|
|
|
|
+ padding: 3px 10px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.triggerTimeList {
|
|
|
|
+ margin-left: 20%;
|
|
|
|
+}
|
|
|
|
+</style>
|
|
|
|
+<style rel="stylesheet/scss" lang="scss">
|
|
|
|
+.el-button--mini {
|
|
|
|
+ padding: 7px 10px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.el-button + .el-button {
|
|
|
|
+ margin-left: 1px;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.el-upload {
|
|
|
|
+ text-align: left
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+.el-dialog__header {
|
|
|
|
+ padding-bottom: 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.el-steps--simple {
|
|
|
|
+ margin: 10px 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.border-none {
|
|
|
|
+ input {
|
|
|
|
+ border: none;
|
|
|
|
+ padding: 0;
|
|
|
|
+ text-align: center;
|
|
|
|
+
|
|
|
|
+ &:focus {
|
|
|
|
+ border: 1px solid #dcdfe6
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+.el-table--enable-row-hover {
|
|
|
|
+ .el-table__body {
|
|
|
|
+ tr:hover > td {
|
|
|
|
+ background: transparent;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+</style>
|