Переглянути джерело

:sparkles: 添加新特性。 增加quartz 定时任务管理

冷冷 6 роки тому
батько
коміт
64c763a305

+ 96 - 0
src/api/daemon/sysjob.js

@@ -0,0 +1,96 @@
+import request from '@/router/axios'
+
+export function fetchList(query) {
+  return request({
+    url: '/job/sysjob/page',
+    method: 'get',
+    params: query
+  })
+}
+
+export function getJobLogList(query) {
+  return request({
+    url: '/job/sysjob/getJobLog',
+    method: 'get',
+    params: query
+  })
+}
+
+export function shutdownJobsRa() {
+  return request({
+    url: '/job/sysjob/shutdownJobs',
+    method: 'post'
+  })
+}
+
+export function startJobsRa() {
+  return request({
+    url: '/job/sysjob/startJobs',
+    method: 'post'
+  })
+}
+
+export function refreshJobsRa() {
+  return request({
+    url: '/job/sysjob/refreshJobs',
+    method: 'post'
+  })
+}
+
+export function startJobRa(jobId) {
+  return request({
+    url: '/job/sysjob/startJob/' + jobId,
+    method: 'get'
+  })
+}
+
+export function shutDownJobRa(jobId) {
+  return request({
+    url: '/job/sysjob/shutdownJob/' + jobId,
+    method: 'get'
+  })
+}
+
+export function addObj(obj) {
+  return request({
+    url: '/job/sysjob',
+    method: 'post',
+    data: obj
+  })
+}
+
+export function getObj(id) {
+  return request({
+    url: '/job/sysjob/' + id,
+    method: 'get'
+  })
+}
+
+export function delObj(id) {
+  return request({
+    url: '/job/sysjob/' + id,
+    method: 'delete'
+  })
+}
+
+export function putObj(obj) {
+  return request({
+    url: '/job/sysjob',
+    method: 'put',
+    data: obj
+  })
+}
+
+export function isValidCron(obj) {
+  return request({
+    url: "/job/sysjob/isValidCron?cronExpression=" + obj,
+    method: 'post',
+  })
+}
+
+export function isValidTaskName(jobName, jobGroup) {
+  return request({
+    url: "/job/sysjob/isValidTaskName?jobName=" + jobName + "&jobGroup=" + jobGroup,
+    method: 'post',
+  })
+}

+ 10 - 0
src/api/daemon/sysjoblog.js

@@ -0,0 +1,10 @@
+import request from '@/router/axios'
+
+export function fetchList(query) {
+  return request({
+    url: '/job/sysjoblog/page',
+    method: 'get',
+    params: query
+  })
+}
+

+ 462 - 0
src/const/crud/daemon/sysjob.js

@@ -0,0 +1,462 @@
+import {isValidCron} from '@/api/daemon/sysjob'
+
+var validateCron = (rule, value, callback) => {
+  isValidCron(value).then(response => {
+    let result = response.data.data;
+    if (result != 0) {
+      callback(new Error('cron表达式错误'))
+    } else {
+      callback();
+    }
+  })
+}
+export const tableOption = {
+    border: true,
+    card: true,
+    index: true,
+    indexLabel: '序号',
+    stripe: true,
+    menu: true,
+    menuAlign: 'center',
+    filterBtn: false,
+    menuWidth: 300,
+    align: 'left',
+    viewBtn: false,
+    editBtn: false,
+    delBtn: false,
+    addBtn: false,
+    dialogWidth: '85%',
+    labelWidth: 130,
+    dialogHeight: '78%',
+    column: [
+      {
+        label: 'jobId',
+        prop: 'jobId',
+        hide: true,
+        addVisdiplay: false,
+        editVisdiplay: false,
+        rules:
+          [{
+            required: true,
+            message: '请输入任务类型',
+            trigger: 'blur'
+          }]
+      },
+      {
+        label: '任务名称',
+        prop: 'jobName',
+        search: true,
+        placeholder: "任务名称",
+        rules: [{
+          required: true,
+          message: '请输入任务名称',
+          trigger: 'blur'
+        }],
+        editDisabled: true
+      },
+      {
+        label: '任务组名',
+        prop:
+          'jobGroup',
+        search:
+          true,
+        rules:
+          [{
+            required: true,
+            message: '请输入任务组名',
+            trigger: 'blur'
+          }],
+        editDisabled: true
+      },
+      {
+        label: '任务状态',
+        prop: 'jobStatus',
+        type: 'select',
+        dicUrl: '/admin/dict/type/job_status',
+        dicMethod: 'get',
+        addVisdiplay: false,
+        search:
+          true,
+        slot:
+          true
+      }
+      ,
+      {
+        label: '执行状态',
+        prop: 'jobExecuteStatus',
+        type: 'select',
+        dicUrl: '/admin/dict/type/job_execute_status',
+        dicMethod: 'get',
+        addVisdiplay: false,
+        search: true,
+        slot: true
+      }
+      ,
+      {
+        label: '创建者',
+        prop:
+          'createBy',
+        hide:
+          true,
+        addVisdiplay:
+          false,
+        editVisdiplay:
+          false
+      }
+      ,
+      {
+        label: '创建时间',
+        prop:
+          'createTime',
+        type:
+          'datetime',
+        hide:
+          true,
+        format:
+          'yyyy-MM-dd HH:mm:ss',
+        valueFormat:
+          'yyyy-MM-dd HH:mm:ss',
+        width:
+          120,
+        addVisdiplay:
+          false,
+        editVisdiplay:
+          false
+      }
+      ,
+      {
+        label: '更新者',
+        prop:
+          'updateBy',
+        hide:
+          true,
+        addVisdiplay:
+          false,
+        editVisdiplay:
+          false
+      }
+      ,
+      {
+        label: '更新时间',
+        prop:
+          'updateTime',
+        type:
+          'datetime',
+        hide:
+          true,
+        format:
+          'yyyy-MM-dd HH:mm:ss',
+        valueFormat:
+          'yyyy-MM-dd HH:mm:ss',
+        width:
+          160,
+        addVisdiplay:
+          false,
+        editVisdiplay:
+          false
+      }
+      ,
+      {
+        label: '首次执行时间',
+        prop:
+          'starttime',
+        type:
+          'datetime',
+        format:
+          'yyyy-MM-dd HH:mm:ss',
+        valueFormat:
+          'yyyy-MM-dd HH:mm:ss',
+        width:
+          160,
+        addVisdiplay:
+          false,
+        editDisabled:
+          true
+      }
+      ,
+      {
+        label: '上次执行时间',
+        prop:
+          'previoustime',
+        type:
+          'datetime',
+        format:
+          'yyyy-MM-dd HH:mm:ss',
+        valueFormat:
+          'yyyy-MM-dd HH:mm:ss',
+        width:
+          160,
+        addVisdiplay:
+          false,
+        editDisabled:
+          true
+      }
+      ,
+      {
+        label: '下次执行时间',
+        prop:
+          'nexttime',
+        type:
+          'datetime',
+        format:
+          'yyyy-MM-dd HH:mm:ss',
+        valueFormat:
+          'yyyy-MM-dd HH:mm:ss',
+        width:
+          160,
+        addVisdiplay:
+          false,
+        editDisabled:
+          true
+      }
+      ,
+      {
+        label: '组内顺序',
+        prop:
+          'jobOrder',
+        hide: true,
+        addDisplay: false,
+        editDisplay: false,
+        rules: [{ validator: (rule, value, callback) => {
+            if(value>9){
+              callback(new Error('请输入1-9数字') );
+            }
+            callback();
+
+          }, trigger: 'blur' }],
+      }
+      ,
+      {
+        label: '类型',
+        prop:
+          'jobType',
+        type:
+          'select',
+        dicUrl:
+          '/admin/dict/type/job_type',
+        dicMethod:
+          'get',
+        width: 100,
+        rules:
+          [{
+            required: true,
+            message: '请输入任务类型',
+            trigger: 'blur'
+          }]
+      }
+      ,
+      {
+        label: '执行路径',
+        prop:
+          'executePath',
+        overHidden:
+          true,
+      }
+      ,
+      {
+        label: '执行文件',
+        prop:
+          'className',
+        overHidden:
+          true
+      }
+      ,
+      {
+        label: '执行方法',
+        prop:
+          'methodName',
+        overHidden:
+          true,
+        width:
+          120
+      }
+      ,
+      {
+        label: '执行参数值',
+        prop:
+          'methodParamsValue',
+        width:
+          100,
+        overHidden:
+          true,
+      }
+      ,
+      {
+        label: 'cron表达式',
+        prop:
+          'cronExpression',
+        width:
+          100,
+        overHidden:
+          true,
+        rules:
+          [{
+            required: true,
+            max: 200,
+            message: '请输入cron表达式',
+            trigger: 'blur'
+          }, {validator: validateCron, trigger: 'blur'}]
+
+      }
+      ,
+      {
+        label: '错失执行策略',
+        prop:
+          'misfirePolicy',
+        type:
+          'select',
+        dicUrl:
+          '/admin/dict/type/misfire_policy',
+        dicMethod:
+          'get',
+        width:
+          120,
+        rules:
+          [{
+            required: true,
+            message: '请输入任务错失执行策略',
+            trigger: 'blur'
+          }]
+      }
+      ,
+      {
+        label: '租户',
+        prop:
+          'tenantId',
+        hide: true,
+        addVisdiplay:
+          false,
+        editVisdiplay:
+          false
+      }
+      ,
+      {
+        label: '备注信息',
+        prop:
+          'remark',
+        type:
+          'textarea',
+        span:
+          20,
+        overHidden:
+          true,
+        rules:
+          [{
+            max: 500,
+            message: '备注信息不得超过500',
+            trigger: 'blur'
+          }]
+      }
+    ]
+  }
+;
+
+export const tableLogOption = {
+  border: true,
+  index: false,
+  menu: false,
+  page: true,
+  indexLabel: '序号',
+  stripe: true,
+  filterBtn: false,
+  editBtn: false,
+  delBtn: false,
+  addBtn: false,
+  columnBtn: false,
+  column: [
+    {
+      label: 'id',
+      prop: 'jobLogId',
+      hide: true
+    },
+    {
+      label: '任务id',
+      prop: 'jobId',
+      hide: true
+    },
+    {
+      label: '任务名称',
+      prop: 'jobName'
+    },
+    {
+      label: '任务组名',
+      prop: 'jobGroup'
+    },
+    {
+      label: '状态',
+      prop: 'jobLogStatus',
+      type: 'select',
+      dicUrl: '/admin/dict/type/job_execute_status',
+      dicMethod: 'get',
+      slot: true,
+    },
+    {
+      label: '组内顺序',
+      prop: 'jobOrder',
+      hide: true
+    },
+    {
+      label: '类型',
+      prop: 'jobType',
+      type: 'select',
+      dicUrl: '/admin/dict/type/job_type',
+      dicMethod: 'get',
+      width: 100,
+    },
+    {
+      label: '执行路径',
+      prop: 'executePath',
+      overHidden: true
+    },
+    {
+      label: '执行文件',
+      prop: 'className',
+      overHidden: true
+    },
+    {
+      label: '执行方法',
+      prop: 'methodName',
+      overHidden: true,
+      width: 120
+    },
+    {
+      label: '执行参数值',
+      prop: 'methodParamsValue',
+      width: 100,
+      overHidden: true
+    },
+    {
+      label: 'cron表达式',
+      prop: 'cronExpression',
+      width: 100,
+      overHidden: true
+    },
+    {
+      label: '状态描述',
+      prop: 'jobMessage'
+    },
+    {
+      label: '执行时间(ms)',
+      prop: 'executeTime',
+      width: 120
+    },
+    {
+      label: '异常信息',
+      prop: 'exceptionInfo',
+      overHidden: true
+    },
+    {
+      label: '开始时间',
+      prop: 'createTime',
+      type: 'datetime',
+      format: 'yyyy-MM-dd HH:mm:ss',
+      valueFormat: 'yyyy-MM-dd HH:mm:ss',
+      width: 160
+    },
+    {
+      label: '租户',
+      prop: 'tenantId',
+      hide: true
+    }
+  ]
+};

+ 119 - 0
src/const/crud/daemon/sysjoblog.js

@@ -0,0 +1,119 @@
+export const tableOption = {
+  border: true,
+  index: true,
+  menu: false,
+  page: true,
+  indexLabel: '序号',
+  stripe: true,
+  menuAlign: 'right',
+  align: 'center',
+  filterBtn: false,
+  editBtn: false,
+  delBtn: false,
+  addBtn: false,
+  column: [
+    {
+      label: 'id',
+      prop: 'jobLogId',
+      hide: true,
+    },
+    {
+      label: '任务id',
+      prop: 'jobId',
+      hide: true,
+    },
+    {
+      label: '任务名称',
+      prop: 'jobName',
+      search: true,
+    },
+    {
+      label: '任务组名',
+      prop: 'jobGroup',
+      search: true,
+    },
+    {
+      label: '组内顺序',
+      prop: 'jobOrder',
+      hide: true
+    },
+    {
+      label: '类型',
+      prop: 'jobType',
+      type:
+        'select',
+      dicUrl:
+        '/admin/dict/type/job_type',
+      dicMethod:
+        'get',
+      width: 100,
+    },
+    {
+      label: '执行路径',
+      prop: 'executePath',
+      overHidden: true,
+    },
+    {
+      label: '执行文件',
+      prop: 'className',
+      overHidden: true,
+    },
+    {
+      label: '执行方法',
+      prop: 'methodName',
+      overHidden: true,
+      width: 120,
+    },
+    {
+      label: '执行参数值',
+      prop: 'methodParamsValue',
+      width: 100,
+      overHidden: true,
+    },
+    {
+      label: 'cron表达式',
+      prop: 'cronExpression',
+      width: 100,
+      overHidden: true,
+    },
+    {
+      label: '状态',
+      prop: 'jobLogStatus',
+      search: true,
+      type:
+        'select',
+      dicUrl:
+        '/admin/dict/type/job_execute_status',
+      dicMethod:
+        'get',
+      slot: true
+    },
+    {
+      label: '状态描述',
+      prop: 'jobMessage'
+    },
+    {
+      label: '执行时间(ms)',
+      prop: 'executeTime',
+      width: 120,
+    },
+    {
+      label: '异常信息',
+      prop: 'exceptionInfo',
+      overHidden: true,
+    },
+    {
+      label: '开始时间',
+      prop: 'createTime',
+      type: 'datetime',
+      format: 'yyyy-MM-dd HH:mm:ss',
+      valueFormat: 'yyyy-MM-dd HH:mm:ss',
+      width: 160,
+    },
+    {
+      label: '租户',
+      prop: 'tenantId',
+      hide: true
+    }
+  ]
+};

+ 4 - 3
src/main.js

@@ -8,18 +8,19 @@ import './permission' // 权限
 import './error' // 日志
 import router from './router/router'
 import store from './store'
-import { loadStyle } from './util/util'
+import {loadStyle,filterForm} from './util/util'
 import * as urls from '@/config/env'
-import { iconfontUrl, iconfontVersion } from '@/config/env'
+import {iconfontUrl, iconfontVersion} from '@/config/env'
 import * as filters from './filters' // 全局filter
 import './styles/common.scss'
 import basicContainer from './components/basic-container/main'
 // 插件 json 展示
 import vueJsonTreeView from 'vue-json-tree-view'
 
-import { validatenull } from '@/util/validate'
+import {validatenull} from '@/util/validate'
 
 Vue.prototype.validatenull = validatenull
+Vue.prototype.filterForm = filterForm
 
 Vue.use(router)
 

+ 11 - 1
src/util/util.js

@@ -148,6 +148,7 @@ export const listenfullscreen = (callback) => {
   function listen() {
     callback()
   }
+
   document.addEventListener("fullscreenchange", function () {
     listen();
   });
@@ -311,7 +312,7 @@ export const openWindow = (url, title, w, h) => {
  * @returns {PromiseLike<T | never> | Promise<T | never>}
  */
 export function handleImg(fileName, id) {
-  return validatenull(fileName)?null: request({
+  return validatenull(fileName) ? null : request({
     url: '/admin/file/' + fileName,
     method: 'get',
     responseType: 'blob'
@@ -325,3 +326,12 @@ export function handleImg(fileName, id) {
   })
 }
 
+export const filterForm = (form) => {
+  let obj = {};
+  Object.keys(form).forEach(ele => {
+    if (!validatenull(form[ele])) {
+      obj[ele] = form[ele]
+    }
+  });
+  return obj;
+}

+ 1 - 1
src/views/admin/role/index.vue

@@ -168,7 +168,7 @@
       },
       handleFilter(param) {
         this.page.page = 1;
-        this.getList(this.page, param);
+        this.getList(this.page, this.filterForm(param));
       },
       handleCreate() {
         this.$refs.crud.rowAdd();

+ 1 - 1
src/views/admin/user/index.vue

@@ -206,7 +206,7 @@
       },
       handleFilter(param) {
         this.page.page = 1;
-        this.getList(this.page, param);
+        this.getList(this.page, this.filterForm(param));
       },
       handleRefreshChange() {
         this.getList(this.page)

+ 119 - 0
src/views/daemon/joblog/index.vue

@@ -0,0 +1,119 @@
+<template>
+  <div class="execution">
+    <basic-container>
+      <avue-crud ref="crud"
+                 :page="page"
+                 :data="tableData"
+                 :table-loading="tableLoading"
+                 :option="tableOption"
+                 @on-load="getList"
+                 @refresh-change="refreshChange"
+                 @search-change="handleFilter"
+                 @search-reset="handleSearchReset">
+        <template slot-scope="scope" slot="jobLogStatus">
+          <div v-if="scope.row.jobLogStatus == 0">
+            <el-tag type="success">{{getDicNameJobExecuteStatus(scope.row.jobLogStatus)}}</el-tag>
+          </div>
+          <div v-else>
+            <el-tag type="danger">{{getDicNameJobExecuteStatus(scope.row.jobLogStatus)}}</el-tag>
+          </div>
+        </template>
+      </avue-crud>
+    </basic-container>
+  </div>
+</template>
+
+<script>
+  import {fetchList} from '@/api/daemon/sysjoblog'
+  import {tableOption} from '@/const/crud/daemon/sysjoblog'
+  import {remote} from '@/api/admin/dict'
+  import {mapGetters} from 'vuex'
+
+  export default {
+    name: 'joblog',
+    data() {
+      return {
+        queryParams: [],//全局检索条件
+        tableData: [],
+        page: {
+          total: 0, // 总页数
+          currentPage: 1, // 当前页数
+          pageSize: 10, // 每页显示多少条,
+        },
+        tableLoading: false,
+        tableOption: tableOption,
+        JobExecuteStatusDicCache: []
+      }
+    },
+    created() {
+    },
+    mounted: function () {
+      this.getDicNameCache("job_execute_status");//获取定时任务运行时状态
+    },
+    computed: {
+      ...mapGetters(['permissions'])
+    },
+    methods: {
+      getList(page) {
+        this.tableLoading = true
+        fetchList(Object.assign({
+          descs: 'create_time',
+          current: page.currentPage,
+          size: page.pageSize
+        }, this.queryParams)).then(response => {
+          this.tableData = response.data.data.records
+          this.page.pageSize = response.data.data.pageSize
+          this.page.total = response.data.data.total
+          this.tableLoading = false
+        })
+      },
+      /**
+       * 清除全局检索条件
+       */
+      handleSearchReset() {
+        this.queryParams = [];
+      },
+      /**
+       * 检索查询
+       */
+      handleFilter(params) {
+        this.queryParams = this.filterForm(params)
+        this.getList(this.page)
+      },
+      /**
+       * 刷新回调
+       */
+      refreshChange() {
+        this.getList(this.page)
+      },
+      /**
+       * 获取字典显示名称并缓存
+       */
+      getDicNameCache(type) {
+        remote(type).then(response => {
+          let code = response.data.code;
+          if (code == 0) {
+            let _data = response.data.data;
+            this.JobExecuteStatusDicCache = _data;
+          }
+        });
+      },
+      /**
+       * 获取字典显示名称并缓存
+       */
+      getDicNameJobExecuteStatus(value) {
+        let re = '';
+        this.JobExecuteStatusDicCache.forEach(obj => {
+          if (obj.value == value) {
+            re = obj.label;
+            return
+          }
+        });
+        return re
+      },
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+</style>

+ 575 - 0
src/views/daemon/jobmanage/index.vue

@@ -0,0 +1,575 @@
+<template>
+  <div class="jobmanage">
+    <basic-container>
+      <avue-crud ref="crud"
+                 :page="page"
+                 :data="tableData"
+                 :table-loading="tableLoading"
+                 :option="tableOption"
+                 @on-load="getList"
+                 @row-save="save"
+                 @row-update="update"
+                 @refresh-change="refreshChange"
+                 @search-change="handleFilter"
+                 @search-reset="handleSearchReset">
+        <template slot-scope="scope" slot="jobStatus">
+          <div v-if="scope.row.jobStatus == 1">
+            <el-tag type="info">{{getDicNameJobStatus(scope.row.jobStatus)}}</el-tag>
+          </div>
+          <div v-else-if="scope.row.jobStatus == 2">
+            <el-tag type="success">{{getDicNameJobStatus(scope.row.jobStatus)}}</el-tag>
+          </div>
+          <div v-else-if="scope.row.jobStatus == 3">
+            <el-tag type="danger">{{getDicNameJobStatus(scope.row.jobStatus)}}</el-tag>
+          </div>
+        </template>
+        <template slot-scope="scope" slot="jobExecuteStatus">
+          <div v-if="scope.row.jobExecuteStatus == 0">
+            <el-tag type="success">{{getDicNameJobExecuteStatus(scope.row.jobExecuteStatus)}}</el-tag>
+          </div>
+          <div v-else>
+            <el-tag type="danger">{{getDicNameJobExecuteStatus(scope.row.jobExecuteStatus)}}</el-tag>
+          </div>
+        </template>
+        <template slot="menuLeft">
+          <el-button type="primary" @click="handleAdd" size="small" v-if="permissions.job_sysjob_add">
+            新建任务
+          </el-button>
+          <el-tooltip content="暂停全部运行状态的定时任务" placement="top">
+            <el-button type="warning" @click="shutdownJobs" size="small" v-if="permissions.job_sysjob_shutdownJob">
+              暂停全部任务
+            </el-button>
+          </el-tooltip>
+          <el-tooltip content="启动全部暂停状态的定时任务" placement="top">
+            <el-button type="success" @click="startJobs" size="small" v-if="permissions.job_sysjob_startJob">
+              启动全部任务
+            </el-button>
+          </el-tooltip>
+          <el-tooltip content="谨慎使用" placement="top">
+            <el-button type="danger" @click="refreshJobs" size="small" v-if="permissions.job_sysjob_refreshJob">重置全部任务
+            </el-button>
+          </el-tooltip>
+        </template>
+        <template slot="menu"
+                  slot-scope="scope">
+          <el-button type="text"
+                     icon="el-icon-info"
+                     size="mini"
+                     plain
+                     @click="getJobLog(scope.row)">日志
+          </el-button>
+          <el-button type="text"
+                     icon="el-icon-caret-right"
+                     size="mini"
+                     v-if="permissions.job_sysjob_startJob"
+                     plain
+                     @click="handleStartJob(scope.row)">启动
+          </el-button>
+          <el-button type="text"
+                     icon="el-icon-error"
+                     size="mini"
+                     v-if="permissions.job_sysjob_shutdownJob"
+                     plain
+                     @click="handleShutDownJob(scope.row)">暂停
+          </el-button>
+          <el-button type="text"
+                     icon="el-icon-edit"
+                     size="mini"
+                     v-if="permissions.job_sysjob_edit"
+                     plain
+                     @click="handleUpdate(scope.row,scope.index)">修改
+          </el-button>
+          <el-button type="text"
+                     v-if="permissions.job_sysjob_del"
+                     icon="el-icon-delete"
+                     size="mini"
+                     plain
+                     @click="handleDelete(scope.row,scope.index)">删除
+          </el-button>
+        </template>
+      </avue-crud>
+    </basic-container>
+    <el-dialog title="执行日志" :visible.sync="dialogFormVisible" width="90%" @close="closeJobLogDialog">
+      <avue-crud ref="crudLog"
+                 :page="pageLog"
+                 @on-load="getJobLogList"
+                 :data="tableLogData"
+                 :option="tableLogOption"
+                 @refresh-change="getJobLogList"
+                 :table-loading="tableLogLoading">
+        <template slot-scope="scope" slot="jobLogStatus">
+          <div v-if="scope.row.jobLogStatus == 0">
+            <el-tag type="success">{{getDicNameJobExecuteStatus(scope.row.jobLogStatus)}}</el-tag>
+          </div>
+          <div v-else>
+            <el-tag type="danger">{{getDicNameJobExecuteStatus(scope.row.jobLogStatus)}}</el-tag>
+          </div>
+        </template>
+      </avue-crud>
+    </el-dialog>
+  </div>
+
+</template>
+
+<script>
+  import {
+    addObj,
+    delObj,
+    fetchList,
+    getJobLogList,
+    isValidTaskName,
+    putObj,
+    refreshJobsRa,
+    shutDownJobRa,
+    shutdownJobsRa,
+    startJobRa,
+    startJobsRa
+  } from '@/api/daemon/sysjob'
+  import {tableLogOption, tableOption} from '@/const/crud/daemon/sysjob'
+  import {remote} from '@/api/admin/dict'
+  import {mapGetters} from 'vuex'
+
+  export default {
+    name: 'sysmanage',
+    data() {
+      return {
+        queryParams: [],//全局检索条件
+        tableData: [],
+        tableLogData: [],
+        dialogFormVisible: false,
+        jobId: "",
+        page: {
+          total: 0, // 总页数
+          currentPage: 1, // 当前页数
+          pageSize: 10, // 每页显示多少条,
+        },
+        pageLog: {
+          total: 0, // 总页数
+          currentPage: 1, // 当前页数
+          pageSize: 10, // 每页显示多少条,
+        },
+        tableLoading: false,
+        tableLogLoading: false,
+        tableOption: tableOption,
+        tableLogOption: tableLogOption,
+        JobExecuteStatusDicCache: [],
+        JobStatusDicCache: [],
+      }
+    },
+    created() {
+
+    },
+    mounted: function () {
+      this.getDicJobExecuteStatusCache("job_execute_status");//获取定时任务运行时状态
+      this.getDicJobStatusCache("job_status");//获取定时任务状态
+    },
+    computed: {
+      ...mapGetters(['permissions'])
+    },
+    methods: {
+      /**
+       * 关闭执行日志对话框重置信息
+       */
+      closeJobLogDialog() {
+        this.jobId = ""
+        this.pageLog.total = 0
+        this.pageLog.currentPage = 1
+        this.pageLog.pageSize = 10
+      },
+      /**
+       * 定时任务分页查询
+       */
+      getList(page) {
+        this.tableLoading = true
+        fetchList(Object.assign({
+          descs: 'create_time',
+          current: this.page.currentPage,
+          size: this.page.pageSize
+        }, this.queryParams)).then(response => {
+          this.tableData = response.data.data.records
+          this.page.pageSize = response.data.data.pageSize
+          this.page.total = response.data.data.total
+          this.tableLoading = false
+        })
+      },
+      /**
+       * 清除全局检索条件
+       */
+      handleSearchReset() {
+        this.queryParams = [];
+      },
+      /**
+       * 定时任务检索查询分页查询
+       */
+      handleFilter(params) {
+        this.queryParams = this.filterForm(params)
+        this.getList(this.page);
+      },
+      /**
+       * 启动定时任务
+       */
+      handleStartJob(row) {
+        let jobStatus = row.jobStatus;
+        if ('1' == jobStatus || '3' == jobStatus) {
+          this.$confirm(
+            "即将发布或启动(任务名称:" + row.jobName + "), 是否继续?",
+            "提示",
+            {
+              confirmButtonText: "确定",
+              cancelButtonText: "取消",
+              type: "warning"
+            }
+          ).then(() => {
+            startJobRa(row.jobId).then(response => {
+              let code = response.data.code;
+              if ('0' == code) {
+                this.getList(this.page);
+                this.$notify({
+                  title: "成功",
+                  message: "启动成功",
+                  type: "success"
+                });
+              }
+            }).catch(() => {
+              this.$notify.error({
+                title: '错误',
+                message: '启动失败'
+              });
+            })
+          })
+        } else {
+          this.$notify.error({
+            title: '错误',
+            message: '定时任务已运行'
+          });
+        }
+      },
+      /**
+       * 新增定时任务
+       */
+      handleAdd() {
+        this.$refs.crud.rowAdd();
+      },
+      /**
+       * 修改定时任务
+       */
+      handleUpdate(row, index) {
+        let jobStatus = row.jobStatus;
+        if ('1' == jobStatus || '3' == jobStatus) {
+          this.$refs.crud.rowEdit(row, index);
+        } else {
+          this.$notify.error({
+            title: '错误',
+            message: '运行中定时任务不可修改,请先暂停后操作'
+          });
+        }
+      },
+      /**
+       * 暂停定时任务
+       */
+      handleShutDownJob(row) {
+        let jobStatus = row.jobStatus;
+        if ('2' == jobStatus) {
+          this.$confirm(
+            "即将暂停(任务名称:" + row.jobName + "), 是否继续?",
+            "提示",
+            {
+              confirmButtonText: "确定",
+              cancelButtonText: "取消",
+              type: "warning"
+            }
+          ).then(() => {
+            shutDownJobRa(row.jobId).then(response => {
+              let code = response.data.code;
+              if ('0' == code) {
+                this.getList(this.page);
+                this.$notify({
+                  title: "成功",
+                  message: "暂停成功",
+                  type: "success"
+                });
+              }
+            }).catch(() => {
+              this.$notify.error({
+                title: '错误',
+                message: '暂停失败'
+              });
+            })
+          })
+        } else {
+          this.$notify.error({
+            title: '错误',
+            message: '运行中定时任务可暂停'
+          });
+        }
+      },
+      /**
+       * 刷新回调
+       */
+      refreshChange() {
+        this.getList(this.page)
+      },
+      /**
+       * 获取定时任务执行日志
+       */
+      getJobLog(row) {
+        this.dialogFormVisible = true
+        this.tableLogLoading = true
+        this.jobId = row.jobId
+        this.getJobLogList(this.pageLog)
+      },
+      /**
+       * 获取定时任务执行日志
+       */
+      getJobLogList(page) {
+        getJobLogList(Object.assign({
+          descs: 'create_time',
+          current: page.currentPage,
+          size: page.pageSize
+        }, {jobId: this.jobId})).then(response => {
+          this.tableLogData = response.data.data.records
+          this.pageLog.total = response.data.data.total
+          this.pageLog.pageSize = response.data.data.pageSize
+          this.tableLogLoading = false
+        })
+      },
+      /**
+       * 暂停运行中定时任务
+       */
+      shutdownJobs() {
+        this.$confirm(
+          "即将暂停全部运行中定时任务, 是否继续?",
+          "提示",
+          {
+            confirmButtonText: "确定",
+            cancelButtonText: "取消",
+            type: "warning"
+          }
+        ).then(() => {
+          shutdownJobsRa().then(response => {
+            let code = response.data.code;
+            let msg = response.data.msg;
+            if ("0" == code) {
+              this.getList(this.page);
+              this.$notify({
+                title: "成功",
+                message: msg,
+                type: "success"
+              });
+            } else {
+              this.$notify.error({
+                title: '错误',
+                message: '暂停失败'
+              });
+            }
+          }).catch(() => {
+            this.$notify.error({
+              title: '错误',
+              message: '暂停失败'
+            });
+          })
+        })
+      },
+      /**
+       * 启动全部暂停定时任务
+       */
+      startJobs() {
+        this.$confirm(
+          "即将启动全部暂定中定时任务, 是否继续?",
+          "提示",
+          {
+            confirmButtonText: "确定",
+            cancelButtonText: "取消",
+            type: "warning"
+          }
+        ).then(() => {
+          startJobsRa().then(response => {
+            let code = response.data.code;
+            if ("0" == code) {
+              this.getList(this.page);
+              this.$notify({
+                title: "成功",
+                message: '启动成功',
+                type: "success"
+              });
+            } else {
+              this.$notify.error({
+                title: '错误',
+                message: '启动失败'
+              });
+            }
+          }).catch(() => {
+            this.$notify.error({
+              title: '错误',
+              message: '启动失败'
+            });
+          })
+        })
+      },
+      /**
+       * 刷新定时任务
+       */
+      refreshJobs() {
+        this.$confirm(
+          "即将刷新全部定时任务, 是否继续?",
+          "提示",
+          {
+            confirmButtonText: "确定",
+            cancelButtonText: "取消",
+            type: "warning"
+          }
+        ).then(() => {
+          refreshJobsRa().then(response => {
+            let code = response.data.code;
+            if ("0" == code) {
+              this.getList(this.page);
+              this.$notify({
+                title: "成功",
+                message: '重置成功',
+                type: "success"
+              });
+            } else {
+              this.$notify.error({
+                title: '错误',
+                message: '重置失败'
+              });
+            }
+          }).catch(() => {
+              this.$notify.error({
+                title: '错误',
+                message: '重置失败'
+              });
+            }
+          )
+        })
+      },
+      /**
+       * 新增定时任务持久化处理
+       */
+      save(row, done, loading) {
+        isValidTaskName(row.jobName, row.jobGroup).then(response => {
+          let result = response.data.data;
+          if (result != 0) {
+            this.$notify.error({
+              title: '错误',
+              message: '任务名称与任务组重复,请确认后重新添加'
+            });
+          } else {
+            addObj(row).then(() => {
+              this.$notify({
+                title: '成功',
+                message: '创建成功',
+                type: 'success',
+                duration: 2000
+              })
+            }).catch(() => {
+              loading();
+            });
+          }
+          this.getList(this.page)
+          done();
+        })
+      }
+      ,
+      /**
+       * 更新定时任务持久化处理
+       */
+      update(row, index, done, loading) {
+        putObj(row).then(() => {
+          this.getList(this.page)
+          done();
+          this.$notify({
+            title: '成功',
+            message: '修改成功',
+            type: 'success',
+            duration: 2000
+          })
+        }).catch(() => {
+          loading();
+        });
+      },
+      /**
+       * 删除定时任务持久化处理
+       */
+      handleDelete(row, index) {
+        let jobStatus = row.jobStatus;
+        if ('1' == jobStatus || '3' == jobStatus) {
+          this.$confirm('是否确认删除(任务名称:' + row.jobName + '), 是否继续?删除后不可恢复', '警告', {
+            confirmButtonText: '确定',
+            cancelButtonText: '取消',
+            type: 'warning'
+          }).then(function () {
+            return delObj(row.jobId)
+          }).then(() => {
+            this.getList(this.page)
+            this.$notify({
+              title: '成功',
+              message: '删除成功',
+              type: 'success',
+              duration: 2000
+            })
+          }).catch(function () {
+          })
+        } else {
+          this.$notify.error({
+            title: '错误',
+            message: '运行中定时任务不可删除,请先暂停后操作'
+          });
+        }
+      },
+      /**
+       * 获取字典显示名称并缓存
+       */
+      getDicJobExecuteStatusCache(type) {
+        remote(type).then(response => {
+          let code = response.data.code;
+          if (code == 0) {
+            let _data = response.data.data;
+            this.JobExecuteStatusDicCache = _data;
+          }
+        })
+      },
+      /**
+       * 获取字典显示名称并缓存
+       */
+      getDicJobStatusCache(type) {
+        remote(type).then(response => {
+          let code = response.data.code;
+          if (code == 0) {
+            let _data = response.data.data;
+            this.JobStatusDicCache = _data;
+          }
+        })
+      },
+      /**
+       * 获取字典定时任务执行状态字典值显示名称
+       */
+      getDicNameJobExecuteStatus(value) {
+        let re = '';
+        this.JobExecuteStatusDicCache.forEach(obj => {
+          if (obj.value == value) {
+            re = obj.label;
+            return
+          }
+        });
+        return re
+      },
+      /**
+       * 获取字典定时任务状态字典值显示名称
+       */
+      getDicNameJobStatus(value) {
+        let re = '';
+        this.JobStatusDicCache.forEach(obj => {
+          if (obj.value == value) {
+            re = obj.label;
+            return
+          }
+        });
+        return re
+      },
+    }
+  }
+</script>
+
+<style lang="scss" scoped>
+</style>

+ 7 - 0
vue.config.js

@@ -58,6 +58,13 @@ module.exports = {
           '^/daemon': '/daemon'
         }
       },
+      '/job': {
+        target: url,
+        ws: true,
+        pathRewrite: {
+          '^/job': '/job'
+        }
+      },
       '/tx': {
         target: url,
         ws: true,