Commit 92bcaa04d1b1d603ac7410c9a8f827fadcbb931a
1 parent
562282b2
refactor: job vxe
Showing
6 changed files
with
358 additions
and
402 deletions
yudao-ui-admin-vue3/src/api/infra/job/index.ts
| 1 | import request from '@/config/axios' | 1 | import request from '@/config/axios' |
| 2 | -import type { JobVO } from './types' | 2 | + |
| 3 | +export type JobVO = { | ||
| 4 | + id: number | ||
| 5 | + name: string | ||
| 6 | + status: number | ||
| 7 | + handlerName: string | ||
| 8 | + handlerParam: string | ||
| 9 | + cronExpression: string | ||
| 10 | + retryCount: number | ||
| 11 | + retryInterval: number | ||
| 12 | + monitorTimeout: number | ||
| 13 | +} | ||
| 3 | 14 | ||
| 4 | // 任务列表 | 15 | // 任务列表 |
| 5 | export const getJobPageApi = (params) => { | 16 | export const getJobPageApi = (params) => { |
yudao-ui-admin-vue3/src/api/infra/jobLog/index.ts
| 1 | import request from '@/config/axios' | 1 | import request from '@/config/axios' |
| 2 | 2 | ||
| 3 | +export type JobLogVO = { | ||
| 4 | + id: number | ||
| 5 | + jobId: number | ||
| 6 | + handlerName: string | ||
| 7 | + handlerParam: string | ||
| 8 | + cronExpression: string | ||
| 9 | + executeIndex: string | ||
| 10 | + beginTime: string | ||
| 11 | + endTime: string | ||
| 12 | + duration: string | ||
| 13 | + status: number | ||
| 14 | + createTime: string | ||
| 15 | +} | ||
| 16 | + | ||
| 3 | // 任务日志列表 | 17 | // 任务日志列表 |
| 4 | export const getJobLogPageApi = (params) => { | 18 | export const getJobLogPageApi = (params) => { |
| 5 | return request.get({ url: '/infra/job-log/page', params }) | 19 | return request.get({ url: '/infra/job-log/page', params }) |
yudao-ui-admin-vue3/src/views/infra/job/JobLog.vue
| 1 | -<script setup lang="ts"> | ||
| 2 | -import { onMounted, ref } from 'vue' | ||
| 3 | -import dayjs from 'dayjs' | ||
| 4 | -import * as JobLogApi from '@/api/infra/jobLog' | ||
| 5 | -import { JobLogVO } from '@/api/infra/jobLog/types' | ||
| 6 | -import { DICT_TYPE } from '@/utils/dict' | ||
| 7 | -import { useTable } from '@/hooks/web/useTable' | ||
| 8 | -import { useI18n } from '@/hooks/web/useI18n' | ||
| 9 | -import { useRoute } from 'vue-router' | ||
| 10 | -import { allSchemas } from './jobLog.data' | ||
| 11 | -const { t } = useI18n() // 国际化 | ||
| 12 | -const { query } = useRoute() | ||
| 13 | -// ========== 列表相关 ========== | ||
| 14 | -const { register, tableObject, methods } = useTable<JobLogVO>({ | ||
| 15 | - getListApi: JobLogApi.getJobLogPageApi, | ||
| 16 | - exportListApi: JobLogApi.exportJobLogApi | ||
| 17 | -}) | ||
| 18 | -const { getList, setSearchParams, exportList } = methods | ||
| 19 | -const getTableList = async () => { | ||
| 20 | - const id = (query.id as unknown as number) && (query.jobId as unknown as number) | ||
| 21 | - tableObject.params = { | ||
| 22 | - jobId: id | ||
| 23 | - } | ||
| 24 | - await getList() | ||
| 25 | -} | ||
| 26 | - | ||
| 27 | -// ========== CRUD 相关 ========== | ||
| 28 | -const dialogVisible = ref(false) // 是否显示弹出层 | ||
| 29 | -const dialogTitle = ref('') // 弹出层标题 | ||
| 30 | - | ||
| 31 | -// ========== 详情相关 ========== | ||
| 32 | -const detailRef = ref() // 详情 Ref | ||
| 33 | - | ||
| 34 | -// 详情操作 | ||
| 35 | -const handleDetail = async (row: JobLogVO) => { | ||
| 36 | - // 设置数据 | ||
| 37 | - const res = JobLogApi.getJobLogApi(row.id) | ||
| 38 | - detailRef.value = res | ||
| 39 | - dialogTitle.value = t('action.detail') | ||
| 40 | - dialogVisible.value = true | ||
| 41 | -} | ||
| 42 | - | ||
| 43 | -// ========== 初始化 ========== | ||
| 44 | -onMounted(() => { | ||
| 45 | - getTableList() | ||
| 46 | -}) | ||
| 47 | -</script> | ||
| 48 | <template> | 1 | <template> |
| 49 | - <!-- 搜索工作区 --> | ||
| 50 | - <ContentWrap> | ||
| 51 | - <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" /> | ||
| 52 | - </ContentWrap> | ||
| 53 | <ContentWrap> | 2 | <ContentWrap> |
| 54 | - <!-- 操作工具栏 --> | ||
| 55 | - <div class="mb-10px"> | ||
| 56 | - <el-button | ||
| 57 | - type="warning" | ||
| 58 | - v-hasPermi="['infra:job:export']" | ||
| 59 | - :loading="tableObject.exportLoading" | ||
| 60 | - @click="exportList('定时任务日志.xls')" | ||
| 61 | - > | ||
| 62 | - <Icon icon="ep:download" class="mr-5px" /> {{ t('action.export') }} | ||
| 63 | - </el-button> | ||
| 64 | - </div> | ||
| 65 | <!-- 列表 --> | 3 | <!-- 列表 --> |
| 66 | - <Table | ||
| 67 | - :columns="allSchemas.tableColumns" | ||
| 68 | - :selection="false" | ||
| 69 | - :data="tableObject.tableList" | ||
| 70 | - :loading="tableObject.loading" | ||
| 71 | - :pagination="{ | ||
| 72 | - total: tableObject.total | ||
| 73 | - }" | ||
| 74 | - v-model:pageSize="tableObject.pageSize" | ||
| 75 | - v-model:currentPage="tableObject.currentPage" | ||
| 76 | - @register="register" | ||
| 77 | - > | ||
| 78 | - <template #beginTime="{ row }"> | 4 | + <vxe-grid ref="xGrid" v-bind="gridOptions" class="xtable-scrollbar"> |
| 5 | + <template #toolbar_buttons> | ||
| 6 | + <XButton | ||
| 7 | + type="warning" | ||
| 8 | + preIcon="ep:download" | ||
| 9 | + :title="t('action.export')" | ||
| 10 | + v-hasPermi="['infra:job:export']" | ||
| 11 | + @click="handleExport()" | ||
| 12 | + /> | ||
| 13 | + </template> | ||
| 14 | + <template #beginTime_default="{ row }"> | ||
| 79 | <span>{{ | 15 | <span>{{ |
| 80 | dayjs(row.beginTime).format('YYYY-MM-DD HH:mm:ss') + | 16 | dayjs(row.beginTime).format('YYYY-MM-DD HH:mm:ss') + |
| 81 | ' ~ ' + | 17 | ' ~ ' + |
| 82 | dayjs(row.endTime).format('YYYY-MM-DD HH:mm:ss') | 18 | dayjs(row.endTime).format('YYYY-MM-DD HH:mm:ss') |
| 83 | }}</span> | 19 | }}</span> |
| 84 | </template> | 20 | </template> |
| 85 | - <template #duration="{ row }"> | 21 | + <template #duration_default="{ row }"> |
| 86 | <span>{{ row.duration + ' 毫秒' }}</span> | 22 | <span>{{ row.duration + ' 毫秒' }}</span> |
| 87 | </template> | 23 | </template> |
| 88 | - <template #status="{ row }"> | ||
| 89 | - <DictTag :type="DICT_TYPE.INFRA_JOB_LOG_STATUS" :value="row.status" /> | ||
| 90 | - </template> | ||
| 91 | - <template #action="{ row }"> | ||
| 92 | - <el-button link type="primary" v-hasPermi="['infra:job:query']" @click="handleDetail(row)"> | ||
| 93 | - <Icon icon="ep:view" class="mr-1px" /> {{ t('action.detail') }} | ||
| 94 | - </el-button> | 24 | + <template #actionbtns_default="{ row }"> |
| 25 | + <XTextButton | ||
| 26 | + preIcon="ep:view" | ||
| 27 | + :title="t('action.detail')" | ||
| 28 | + v-hasPermi="['infra:job:query']" | ||
| 29 | + @click="handleDetail(row)" | ||
| 30 | + /> | ||
| 95 | </template> | 31 | </template> |
| 96 | - </Table> | 32 | + </vxe-grid> |
| 97 | </ContentWrap> | 33 | </ContentWrap> |
| 98 | <XModal v-model="dialogVisible" :title="dialogTitle"> | 34 | <XModal v-model="dialogVisible" :title="dialogTitle"> |
| 99 | <!-- 对话框(详情) --> | 35 | <!-- 对话框(详情) --> |
| @@ -111,3 +47,42 @@ onMounted(() => { | @@ -111,3 +47,42 @@ onMounted(() => { | ||
| 111 | </template> | 47 | </template> |
| 112 | </XModal> | 48 | </XModal> |
| 113 | </template> | 49 | </template> |
| 50 | + | ||
| 51 | +<script setup lang="ts"> | ||
| 52 | +import { ref } from 'vue' | ||
| 53 | +import dayjs from 'dayjs' | ||
| 54 | +import { useI18n } from '@/hooks/web/useI18n' | ||
| 55 | +import { useVxeGrid } from '@/hooks/web/useVxeGrid' | ||
| 56 | +import { VxeGridInstance } from 'vxe-table' | ||
| 57 | +import * as JobLogApi from '@/api/infra/jobLog' | ||
| 58 | +import { JobLogVO } from '@/api/infra/jobLog/types' | ||
| 59 | +import { allSchemas } from './jobLog.data' | ||
| 60 | + | ||
| 61 | +const { t } = useI18n() // 国际化 | ||
| 62 | +// 列表相关的变量 | ||
| 63 | +const xGrid = ref<VxeGridInstance>() // 列表 Grid Ref | ||
| 64 | +const { gridOptions, exportList } = useVxeGrid<JobLogApi.JobLogVO>({ | ||
| 65 | + allSchemas: allSchemas, | ||
| 66 | + getListApi: JobLogApi.getJobLogPageApi, | ||
| 67 | + exportListApi: JobLogApi.exportJobLogApi | ||
| 68 | +}) | ||
| 69 | +// ========== CRUD 相关 ========== | ||
| 70 | +const dialogVisible = ref(false) // 是否显示弹出层 | ||
| 71 | +const dialogTitle = ref('') // 弹出层标题 | ||
| 72 | + | ||
| 73 | +// ========== 详情相关 ========== | ||
| 74 | +const detailRef = ref() // 详情 Ref | ||
| 75 | + | ||
| 76 | +// 详情操作 | ||
| 77 | +const handleDetail = async (row: JobLogVO) => { | ||
| 78 | + // 设置数据 | ||
| 79 | + const res = JobLogApi.getJobLogApi(row.id) | ||
| 80 | + detailRef.value = res | ||
| 81 | + dialogTitle.value = t('action.detail') | ||
| 82 | + dialogVisible.value = true | ||
| 83 | +} | ||
| 84 | +// 导出操作 | ||
| 85 | +const handleExport = async () => { | ||
| 86 | + await exportList(xGrid, '定时任务详情.xls') | ||
| 87 | +} | ||
| 88 | +</script> |
yudao-ui-admin-vue3/src/views/infra/job/index.vue
| 1 | +<template> | ||
| 2 | + <ContentWrap> | ||
| 3 | + <!-- 列表 --> | ||
| 4 | + <vxe-grid ref="xGrid" v-bind="gridOptions" class="xtable-scrollbar"> | ||
| 5 | + <template #toolbar_buttons> | ||
| 6 | + <!-- 操作:新增 --> | ||
| 7 | + <XButton | ||
| 8 | + type="primary" | ||
| 9 | + preIcon="ep:zoom-in" | ||
| 10 | + :title="t('action.add')" | ||
| 11 | + v-hasPermi="['infra:job:create']" | ||
| 12 | + @click="handleCreate()" | ||
| 13 | + /> | ||
| 14 | + <!-- 操作:导出 --> | ||
| 15 | + <XButton | ||
| 16 | + type="warning" | ||
| 17 | + preIcon="ep:download" | ||
| 18 | + :title="t('action.export')" | ||
| 19 | + v-hasPermi="['infra:job:export']" | ||
| 20 | + @click="handleExport()" | ||
| 21 | + /> | ||
| 22 | + <XButton | ||
| 23 | + type="info" | ||
| 24 | + preIcon="ep:zoom-in" | ||
| 25 | + title="执行日志" | ||
| 26 | + v-hasPermi="['infra:job:query']" | ||
| 27 | + @click="handleJobLog" | ||
| 28 | + /> | ||
| 29 | + </template> | ||
| 30 | + <template #actionbtns_default="{ row }"> | ||
| 31 | + <!-- 操作:修改 --> | ||
| 32 | + <XTextButton | ||
| 33 | + preIcon="ep:edit" | ||
| 34 | + :title="t('action.edit')" | ||
| 35 | + v-hasPermi="['infra:job:update']" | ||
| 36 | + @click="handleUpdate(row.id)" | ||
| 37 | + /> | ||
| 38 | + <el-button | ||
| 39 | + link | ||
| 40 | + type="primary" | ||
| 41 | + v-hasPermi="['infra:job:update']" | ||
| 42 | + @click="handleChangeStatus(row)" | ||
| 43 | + > | ||
| 44 | + <Icon icon="ep:edit" class="mr-1px" /> | ||
| 45 | + {{ row.status === InfraJobStatusEnum.STOP ? '开启' : '暂停' }} | ||
| 46 | + </el-button> | ||
| 47 | + <!-- 操作:详情 --> | ||
| 48 | + <XTextButton | ||
| 49 | + preIcon="ep:view" | ||
| 50 | + :title="t('action.detail')" | ||
| 51 | + v-hasPermi="['infra:job:query']" | ||
| 52 | + @click="handleDetail(row.id)" | ||
| 53 | + /> | ||
| 54 | + <!-- 操作:删除 --> | ||
| 55 | + <XTextButton | ||
| 56 | + preIcon="ep:delete" | ||
| 57 | + :title="t('action.del')" | ||
| 58 | + v-hasPermi="['infra:job:delete']" | ||
| 59 | + @click="handleDelete(row.id)" | ||
| 60 | + /> | ||
| 61 | + <XTextButton | ||
| 62 | + preIcon="ep:view" | ||
| 63 | + title="执行一次" | ||
| 64 | + v-hasPermi="['infra:job:trigger']" | ||
| 65 | + @click="handleRun(row)" | ||
| 66 | + /> | ||
| 67 | + <XTextButton | ||
| 68 | + preIcon="ep:view" | ||
| 69 | + title="调度日志" | ||
| 70 | + v-hasPermi="['infra:job:query']" | ||
| 71 | + @click="handleJobLog(row.id)" | ||
| 72 | + /> | ||
| 73 | + </template> | ||
| 74 | + </vxe-grid> | ||
| 75 | + </ContentWrap> | ||
| 76 | + <XModal v-model="dialogVisible" :title="dialogTitle"> | ||
| 77 | + <!-- 对话框(添加 / 修改) --> | ||
| 78 | + <Form | ||
| 79 | + v-if="['create', 'update'].includes(actionType)" | ||
| 80 | + :schema="allSchemas.formSchema" | ||
| 81 | + :rules="rules" | ||
| 82 | + ref="formRef" | ||
| 83 | + > | ||
| 84 | + <template #cronExpression> | ||
| 85 | + <Crontab v-model="cronExpression" :shortcuts="shortcuts" /> | ||
| 86 | + </template> | ||
| 87 | + </Form> | ||
| 88 | + <!-- 对话框(详情) --> | ||
| 89 | + <Descriptions | ||
| 90 | + v-if="actionType === 'detail'" | ||
| 91 | + :schema="allSchemas.detailSchema" | ||
| 92 | + :data="detailRef" | ||
| 93 | + > | ||
| 94 | + <template #retryInterval="{ row }"> | ||
| 95 | + <span>{{ row.retryInterval + '毫秒' }} </span> | ||
| 96 | + </template> | ||
| 97 | + <template #monitorTimeout="{ row }"> | ||
| 98 | + <span>{{ row.monitorTimeout > 0 ? row.monitorTimeout + ' 毫秒' : '未开启' }}</span> | ||
| 99 | + </template> | ||
| 100 | + </Descriptions> | ||
| 101 | + <!-- 操作按钮 --> | ||
| 102 | + <template #footer> | ||
| 103 | + <!-- 按钮:保存 --> | ||
| 104 | + <XButton | ||
| 105 | + v-if="['create', 'update'].includes(actionType)" | ||
| 106 | + type="primary" | ||
| 107 | + :title="t('action.save')" | ||
| 108 | + :loading="actionLoading" | ||
| 109 | + @click="submitForm()" | ||
| 110 | + /> | ||
| 111 | + <!-- 按钮:关闭 --> | ||
| 112 | + <XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" /> | ||
| 113 | + </template> | ||
| 114 | + </XModal> | ||
| 115 | +</template> | ||
| 116 | + | ||
| 1 | <script setup lang="ts"> | 117 | <script setup lang="ts"> |
| 2 | -import { Crontab } from '@/components/Crontab' | ||
| 3 | import { ref, unref } from 'vue' | 118 | import { ref, unref } from 'vue' |
| 4 | -import * as JobApi from '@/api/infra/job' | ||
| 5 | -import { JobVO } from '@/api/infra/job/types' | ||
| 6 | -import { DICT_TYPE } from '@/utils/dict' | ||
| 7 | -import { useTable } from '@/hooks/web/useTable' | 119 | +import { useRouter } from 'vue-router' |
| 8 | import { useI18n } from '@/hooks/web/useI18n' | 120 | import { useI18n } from '@/hooks/web/useI18n' |
| 121 | +import { useMessage } from '@/hooks/web/useMessage' | ||
| 122 | +import { useVxeGrid } from '@/hooks/web/useVxeGrid' | ||
| 123 | +import { VxeGridInstance } from 'vxe-table' | ||
| 9 | import { FormExpose } from '@/components/Form' | 124 | import { FormExpose } from '@/components/Form' |
| 125 | +import { Crontab } from '@/components/Crontab' | ||
| 126 | +import * as JobApi from '@/api/infra/job' | ||
| 10 | import { rules, allSchemas } from './job.data' | 127 | import { rules, allSchemas } from './job.data' |
| 11 | -import { useRouter } from 'vue-router' | ||
| 12 | -import { useMessage } from '@/hooks/web/useMessage' | ||
| 13 | import { InfraJobStatusEnum } from '@/utils/constants' | 128 | import { InfraJobStatusEnum } from '@/utils/constants' |
| 14 | -const message = useMessage() | 129 | + |
| 15 | const { t } = useI18n() // 国际化 | 130 | const { t } = useI18n() // 国际化 |
| 131 | +const message = useMessage() // 消息弹窗 | ||
| 16 | const { push } = useRouter() | 132 | const { push } = useRouter() |
| 17 | -// ========== 列表相关 ========== | ||
| 18 | -const { register, tableObject, methods } = useTable<JobVO>({ | 133 | + |
| 134 | +// 列表相关的变量 | ||
| 135 | +const xGrid = ref<VxeGridInstance>() // 列表 Grid Ref | ||
| 136 | +const { gridOptions, getList, deleteData, exportList } = useVxeGrid<JobApi.JobVO>({ | ||
| 137 | + allSchemas: allSchemas, | ||
| 19 | getListApi: JobApi.getJobPageApi, | 138 | getListApi: JobApi.getJobPageApi, |
| 20 | - delListApi: JobApi.deleteJobApi, | 139 | + deleteApi: JobApi.deleteJobApi, |
| 21 | exportListApi: JobApi.exportJobApi | 140 | exportListApi: JobApi.exportJobApi |
| 22 | }) | 141 | }) |
| 23 | -const { getList, setSearchParams, delList, exportList } = methods | ||
| 24 | 142 | ||
| 25 | // ========== CRUD 相关 ========== | 143 | // ========== CRUD 相关 ========== |
| 26 | const actionLoading = ref(false) // 遮罩层 | 144 | const actionLoading = ref(false) // 遮罩层 |
| @@ -28,6 +146,7 @@ const actionType = ref('') // 操作按钮的类型 | @@ -28,6 +146,7 @@ const actionType = ref('') // 操作按钮的类型 | ||
| 28 | const dialogVisible = ref(false) // 是否显示弹出层 | 146 | const dialogVisible = ref(false) // 是否显示弹出层 |
| 29 | const dialogTitle = ref('edit') // 弹出层标题 | 147 | const dialogTitle = ref('edit') // 弹出层标题 |
| 30 | const formRef = ref<FormExpose>() // 表单 Ref | 148 | const formRef = ref<FormExpose>() // 表单 Ref |
| 149 | +const detailRef = ref() // 详情 Ref | ||
| 31 | const cronExpression = ref('') | 150 | const cronExpression = ref('') |
| 32 | const shortcuts = ref([ | 151 | const shortcuts = ref([ |
| 33 | { | 152 | { |
| @@ -47,16 +166,31 @@ const handleCreate = () => { | @@ -47,16 +166,31 @@ const handleCreate = () => { | ||
| 47 | cronExpression.value = '' | 166 | cronExpression.value = '' |
| 48 | setDialogTile('create') | 167 | setDialogTile('create') |
| 49 | } | 168 | } |
| 50 | - | 169 | +// 导出操作 |
| 170 | +const handleExport = async () => { | ||
| 171 | + await exportList(xGrid, '定时任务.xls') | ||
| 172 | +} | ||
| 51 | // 修改操作 | 173 | // 修改操作 |
| 52 | -const handleUpdate = async (row: JobVO) => { | 174 | +const handleUpdate = async (rowId: number) => { |
| 53 | setDialogTile('update') | 175 | setDialogTile('update') |
| 54 | // 设置数据 | 176 | // 设置数据 |
| 55 | - const res = await JobApi.getJobApi(row.id) | 177 | + const res = await JobApi.getJobApi(rowId) |
| 56 | cronExpression.value = res.cronExpression | 178 | cronExpression.value = res.cronExpression |
| 57 | unref(formRef)?.setValues(res) | 179 | unref(formRef)?.setValues(res) |
| 58 | } | 180 | } |
| 59 | -const handleChangeStatus = async (row: JobVO) => { | 181 | + |
| 182 | +// 详情操作 | ||
| 183 | +const handleDetail = async (rowId: number) => { | ||
| 184 | + // 设置数据 | ||
| 185 | + const res = await JobApi.getJobApi(rowId) | ||
| 186 | + detailRef.value = res | ||
| 187 | + setDialogTile('detail') | ||
| 188 | +} | ||
| 189 | +// 删除操作 | ||
| 190 | +const handleDelete = async (rowId: number) => { | ||
| 191 | + await deleteData(xGrid, rowId) | ||
| 192 | +} | ||
| 193 | +const handleChangeStatus = async (row: JobApi.JobVO) => { | ||
| 60 | const text = row.status === InfraJobStatusEnum.STOP ? '开启' : '关闭' | 194 | const text = row.status === InfraJobStatusEnum.STOP ? '开启' : '关闭' |
| 61 | const status = | 195 | const status = |
| 62 | row.status === InfraJobStatusEnum.STOP ? InfraJobStatusEnum.NORMAL : InfraJobStatusEnum.STOP | 196 | row.status === InfraJobStatusEnum.STOP ? InfraJobStatusEnum.NORMAL : InfraJobStatusEnum.STOP |
| @@ -69,7 +203,7 @@ const handleChangeStatus = async (row: JobVO) => { | @@ -69,7 +203,7 @@ const handleChangeStatus = async (row: JobVO) => { | ||
| 69 | : InfraJobStatusEnum.STOP | 203 | : InfraJobStatusEnum.STOP |
| 70 | await JobApi.updateJobStatusApi(row.id, status) | 204 | await JobApi.updateJobStatusApi(row.id, status) |
| 71 | message.success(text + '成功') | 205 | message.success(text + '成功') |
| 72 | - await getList() | 206 | + await getList(xGrid) |
| 73 | }) | 207 | }) |
| 74 | .catch(() => { | 208 | .catch(() => { |
| 75 | row.status = | 209 | row.status = |
| @@ -79,19 +213,19 @@ const handleChangeStatus = async (row: JobVO) => { | @@ -79,19 +213,19 @@ const handleChangeStatus = async (row: JobVO) => { | ||
| 79 | }) | 213 | }) |
| 80 | } | 214 | } |
| 81 | // 执行日志 | 215 | // 执行日志 |
| 82 | -const handleJobLog = (row: JobVO) => { | ||
| 83 | - if (row.id) { | ||
| 84 | - push('/job/job-log?id=' + row.id) | 216 | +const handleJobLog = (rowId: number) => { |
| 217 | + if (rowId) { | ||
| 218 | + push('/job/job-log?id=' + rowId) | ||
| 85 | } else { | 219 | } else { |
| 86 | push('/job/job-log') | 220 | push('/job/job-log') |
| 87 | } | 221 | } |
| 88 | } | 222 | } |
| 89 | // 执行一次 | 223 | // 执行一次 |
| 90 | -const handleRun = (row: JobVO) => { | 224 | +const handleRun = (row: JobApi.JobVO) => { |
| 91 | message.confirm('确认要立即执行一次' + row.name + '?', t('common.reminder')).then(async () => { | 225 | message.confirm('确认要立即执行一次' + row.name + '?', t('common.reminder')).then(async () => { |
| 92 | await JobApi.runJobApi(row.id) | 226 | await JobApi.runJobApi(row.id) |
| 93 | message.success('执行成功') | 227 | message.success('执行成功') |
| 94 | - getList() | 228 | + await getList(xGrid) |
| 95 | }) | 229 | }) |
| 96 | } | 230 | } |
| 97 | // 提交按钮 | 231 | // 提交按钮 |
| @@ -103,7 +237,7 @@ const submitForm = async () => { | @@ -103,7 +237,7 @@ const submitForm = async () => { | ||
| 103 | actionLoading.value = true | 237 | actionLoading.value = true |
| 104 | // 提交请求 | 238 | // 提交请求 |
| 105 | try { | 239 | try { |
| 106 | - const data = unref(formRef)?.formModel as JobVO | 240 | + const data = unref(formRef)?.formModel as JobApi.JobVO |
| 107 | data.cronExpression = cronExpression.value | 241 | data.cronExpression = cronExpression.value |
| 108 | if (actionType.value === 'create') { | 242 | if (actionType.value === 'create') { |
| 109 | await JobApi.createJobApi(data) | 243 | await JobApi.createJobApi(data) |
| @@ -112,139 +246,12 @@ const submitForm = async () => { | @@ -112,139 +246,12 @@ const submitForm = async () => { | ||
| 112 | await JobApi.updateJobApi(data) | 246 | await JobApi.updateJobApi(data) |
| 113 | message.success(t('common.updateSuccess')) | 247 | message.success(t('common.updateSuccess')) |
| 114 | } | 248 | } |
| 115 | - // 操作成功,重新加载列表 | ||
| 116 | dialogVisible.value = false | 249 | dialogVisible.value = false |
| 117 | - await getList() | ||
| 118 | } finally { | 250 | } finally { |
| 119 | actionLoading.value = false | 251 | actionLoading.value = false |
| 252 | + await getList(xGrid) | ||
| 120 | } | 253 | } |
| 121 | } | 254 | } |
| 122 | }) | 255 | }) |
| 123 | } | 256 | } |
| 124 | - | ||
| 125 | -// ========== 详情相关 ========== | ||
| 126 | -const detailRef = ref() // 详情 Ref | ||
| 127 | - | ||
| 128 | -// 详情操作 | ||
| 129 | -const handleDetail = async (row: JobVO) => { | ||
| 130 | - // 设置数据 | ||
| 131 | - const res = JobApi.getJobApi(row.id) | ||
| 132 | - detailRef.value = res | ||
| 133 | - setDialogTile('detail') | ||
| 134 | -} | ||
| 135 | - | ||
| 136 | -// ========== 初始化 ========== | ||
| 137 | -getList() | ||
| 138 | </script> | 257 | </script> |
| 139 | -<template> | ||
| 140 | - <!-- 搜索工作区 --> | ||
| 141 | - <ContentWrap> | ||
| 142 | - <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" /> | ||
| 143 | - </ContentWrap> | ||
| 144 | - <ContentWrap> | ||
| 145 | - <!-- 操作工具栏 --> | ||
| 146 | - <div class="mb-10px"> | ||
| 147 | - <el-button type="primary" v-hasPermi="['infra:job:create']" @click="handleCreate"> | ||
| 148 | - <Icon icon="ep:zoom-in" class="mr-5px" /> {{ t('action.add') }} | ||
| 149 | - </el-button> | ||
| 150 | - <el-button | ||
| 151 | - type="warning" | ||
| 152 | - v-hasPermi="['infra:job:export']" | ||
| 153 | - :loading="tableObject.exportLoading" | ||
| 154 | - @click="exportList('定时任务.xls')" | ||
| 155 | - > | ||
| 156 | - <Icon icon="ep:download" class="mr-5px" /> {{ t('action.export') }} | ||
| 157 | - </el-button> | ||
| 158 | - <el-button type="info" v-hasPermi="['infra:job:query']" @click="handleJobLog"> | ||
| 159 | - <Icon icon="ep:zoom-in" class="mr-5px" /> 执行日志 | ||
| 160 | - </el-button> | ||
| 161 | - </div> | ||
| 162 | - <!-- 列表 --> | ||
| 163 | - <Table | ||
| 164 | - :columns="allSchemas.tableColumns" | ||
| 165 | - :selection="false" | ||
| 166 | - :data="tableObject.tableList" | ||
| 167 | - :loading="tableObject.loading" | ||
| 168 | - :pagination="{ | ||
| 169 | - total: tableObject.total | ||
| 170 | - }" | ||
| 171 | - v-model:pageSize="tableObject.pageSize" | ||
| 172 | - v-model:currentPage="tableObject.currentPage" | ||
| 173 | - @register="register" | ||
| 174 | - > | ||
| 175 | - <template #status="{ row }"> | ||
| 176 | - <DictTag :type="DICT_TYPE.INFRA_JOB_STATUS" :value="row.status" /> | ||
| 177 | - </template> | ||
| 178 | - <template #action="{ row }"> | ||
| 179 | - <el-button link type="primary" v-hasPermi="['infra:job:update']" @click="handleUpdate(row)"> | ||
| 180 | - <Icon icon="ep:edit" class="mr-1px" /> {{ t('action.edit') }} | ||
| 181 | - </el-button> | ||
| 182 | - <el-button | ||
| 183 | - link | ||
| 184 | - type="primary" | ||
| 185 | - v-hasPermi="['infra:job:update']" | ||
| 186 | - @click="handleChangeStatus(row)" | ||
| 187 | - > | ||
| 188 | - <Icon icon="ep:edit" class="mr-1px" /> | ||
| 189 | - {{ row.status === InfraJobStatusEnum.STOP ? '开启' : '暂停' }} | ||
| 190 | - </el-button> | ||
| 191 | - <el-button link type="primary" v-hasPermi="['infra:job:query']" @click="handleDetail(row)"> | ||
| 192 | - <Icon icon="ep:view" class="mr-1px" /> {{ t('action.detail') }} | ||
| 193 | - </el-button> | ||
| 194 | - <el-button | ||
| 195 | - link | ||
| 196 | - type="primary" | ||
| 197 | - v-hasPermi="['infra:job:delete']" | ||
| 198 | - @click="delList(row.id, false)" | ||
| 199 | - > | ||
| 200 | - <Icon icon="ep:delete" class="mr-1px" /> {{ t('action.del') }} | ||
| 201 | - </el-button> | ||
| 202 | - <el-button link type="primary" v-hasPermi="['infra:job:trigger']" @click="handleRun(row)"> | ||
| 203 | - <Icon icon="ep:view" class="mr-1px" /> 执行一次 | ||
| 204 | - </el-button> | ||
| 205 | - <el-button link type="primary" v-hasPermi="['infra:job:query']" @click="handleJobLog(row)"> | ||
| 206 | - <Icon icon="ep:view" class="mr-1px" /> 调度日志 | ||
| 207 | - </el-button> | ||
| 208 | - </template> | ||
| 209 | - </Table> | ||
| 210 | - </ContentWrap> | ||
| 211 | - <XModal v-model="dialogVisible" :title="dialogTitle"> | ||
| 212 | - <!-- 对话框(添加 / 修改) --> | ||
| 213 | - <Form | ||
| 214 | - v-if="['create', 'update'].includes(actionType)" | ||
| 215 | - :schema="allSchemas.formSchema" | ||
| 216 | - :rules="rules" | ||
| 217 | - ref="formRef" | ||
| 218 | - > | ||
| 219 | - <template #cronExpression> | ||
| 220 | - <Crontab v-model="cronExpression" :shortcuts="shortcuts" /> | ||
| 221 | - </template> | ||
| 222 | - </Form> | ||
| 223 | - <!-- 对话框(详情) --> | ||
| 224 | - <Descriptions | ||
| 225 | - v-if="actionType === 'detail'" | ||
| 226 | - :schema="allSchemas.detailSchema" | ||
| 227 | - :data="detailRef" | ||
| 228 | - > | ||
| 229 | - <template #retryInterval="{ row }"> | ||
| 230 | - <span>{{ row.retryInterval + '毫秒' }} </span> | ||
| 231 | - </template> | ||
| 232 | - <template #monitorTimeout="{ row }"> | ||
| 233 | - <span>{{ row.monitorTimeout > 0 ? row.monitorTimeout + ' 毫秒' : '未开启' }}</span> | ||
| 234 | - </template> | ||
| 235 | - </Descriptions> | ||
| 236 | - <!-- 操作按钮 --> | ||
| 237 | - <template #footer> | ||
| 238 | - <!-- 按钮:保存 --> | ||
| 239 | - <XButton | ||
| 240 | - v-if="['create', 'update'].includes(actionType)" | ||
| 241 | - type="primary" | ||
| 242 | - :title="t('action.save')" | ||
| 243 | - :loading="actionLoading" | ||
| 244 | - @click="submitForm()" | ||
| 245 | - /> | ||
| 246 | - <!-- 按钮:关闭 --> | ||
| 247 | - <XButton :loading="actionLoading" :title="t('dialog.close')" @click="dialogVisible = false" /> | ||
| 248 | - </template> | ||
| 249 | - </XModal> | ||
| 250 | -</template> |
yudao-ui-admin-vue3/src/views/infra/job/job.data.ts
| @@ -2,9 +2,8 @@ import { reactive } from 'vue' | @@ -2,9 +2,8 @@ import { reactive } from 'vue' | ||
| 2 | import { DICT_TYPE } from '@/utils/dict' | 2 | import { DICT_TYPE } from '@/utils/dict' |
| 3 | import { required } from '@/utils/formRules' | 3 | import { required } from '@/utils/formRules' |
| 4 | import { useI18n } from '@/hooks/web/useI18n' | 4 | import { useI18n } from '@/hooks/web/useI18n' |
| 5 | -import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas' | ||
| 6 | -// 国际化 | ||
| 7 | -const { t } = useI18n() | 5 | +import { VxeCrudSchema, useVxeCrudSchemas } from '@/hooks/web/useVxeCrudSchemas' |
| 6 | +const { t } = useI18n() // 国际化 | ||
| 8 | // 表单校验 | 7 | // 表单校验 |
| 9 | export const rules = reactive({ | 8 | export const rules = reactive({ |
| 10 | name: [required], | 9 | name: [required], |
| @@ -14,87 +13,55 @@ export const rules = reactive({ | @@ -14,87 +13,55 @@ export const rules = reactive({ | ||
| 14 | retryInterval: [required] | 13 | retryInterval: [required] |
| 15 | }) | 14 | }) |
| 16 | // CrudSchema | 15 | // CrudSchema |
| 17 | -const crudSchemas = reactive<CrudSchema[]>([ | ||
| 18 | - { | ||
| 19 | - label: t('common.index'), | ||
| 20 | - field: 'id', | ||
| 21 | - type: 'index', | ||
| 22 | - form: { | ||
| 23 | - show: false | 16 | +const crudSchemas = reactive<VxeCrudSchema>({ |
| 17 | + primaryKey: 'id', | ||
| 18 | + primaryType: 'seq', | ||
| 19 | + action: true, | ||
| 20 | + actionWidth: '500px', | ||
| 21 | + columns: [ | ||
| 22 | + { | ||
| 23 | + title: '任务名称', | ||
| 24 | + field: 'name', | ||
| 25 | + search: { | ||
| 26 | + show: true | ||
| 27 | + } | ||
| 24 | }, | 28 | }, |
| 25 | - detail: { | ||
| 26 | - show: false | ||
| 27 | - } | ||
| 28 | - }, | ||
| 29 | - { | ||
| 30 | - label: '任务名称', | ||
| 31 | - field: 'name', | ||
| 32 | - search: { | ||
| 33 | - show: true | ||
| 34 | - } | ||
| 35 | - }, | ||
| 36 | - { | ||
| 37 | - label: t('common.status'), | ||
| 38 | - field: 'status', | ||
| 39 | - dictType: DICT_TYPE.INFRA_JOB_STATUS, | ||
| 40 | - dictClass: 'number', | ||
| 41 | - form: { | ||
| 42 | - show: false | 29 | + { |
| 30 | + title: t('common.status'), | ||
| 31 | + field: 'status', | ||
| 32 | + dictType: DICT_TYPE.INFRA_JOB_STATUS, | ||
| 33 | + dictClass: 'number', | ||
| 34 | + isForm: false | ||
| 43 | }, | 35 | }, |
| 44 | - detail: { | ||
| 45 | - show: false | ||
| 46 | - } | ||
| 47 | - }, | ||
| 48 | - { | ||
| 49 | - label: '处理器的名字', | ||
| 50 | - field: 'handlerName', | ||
| 51 | - search: { | ||
| 52 | - show: true | ||
| 53 | - } | ||
| 54 | - }, | ||
| 55 | - { | ||
| 56 | - label: '处理器的参数', | ||
| 57 | - field: 'handlerParam', | ||
| 58 | - table: { | ||
| 59 | - show: false | ||
| 60 | - } | ||
| 61 | - }, | ||
| 62 | - { | ||
| 63 | - label: 'CRON 表达式', | ||
| 64 | - field: 'cronExpression' | ||
| 65 | - }, | ||
| 66 | - { | ||
| 67 | - label: '重试次数', | ||
| 68 | - field: 'retryCount', | ||
| 69 | - table: { | ||
| 70 | - show: false | ||
| 71 | - } | ||
| 72 | - }, | ||
| 73 | - { | ||
| 74 | - label: '重试间隔', | ||
| 75 | - field: 'retryInterval', | ||
| 76 | - table: { | ||
| 77 | - show: false | ||
| 78 | - } | ||
| 79 | - }, | ||
| 80 | - { | ||
| 81 | - label: '监控超时时间', | ||
| 82 | - field: 'monitorTimeout', | ||
| 83 | - table: { | ||
| 84 | - show: false | ||
| 85 | - } | ||
| 86 | - }, | ||
| 87 | - { | ||
| 88 | - field: 'action', | ||
| 89 | - width: '500px', | ||
| 90 | - label: t('table.action'), | ||
| 91 | - form: { | ||
| 92 | - show: false | 36 | + { |
| 37 | + title: '处理器的名字', | ||
| 38 | + field: 'handlerName', | ||
| 39 | + isSearch: true | ||
| 40 | + }, | ||
| 41 | + { | ||
| 42 | + title: '处理器的参数', | ||
| 43 | + field: 'handlerParam', | ||
| 44 | + isTable: false | ||
| 45 | + }, | ||
| 46 | + { | ||
| 47 | + title: 'CRON 表达式', | ||
| 48 | + field: 'cronExpression' | ||
| 93 | }, | 49 | }, |
| 94 | - detail: { | ||
| 95 | - show: false | 50 | + { |
| 51 | + title: '重试次数', | ||
| 52 | + field: 'retryCount', | ||
| 53 | + isTable: false | ||
| 54 | + }, | ||
| 55 | + { | ||
| 56 | + title: '重试间隔', | ||
| 57 | + field: 'retryInterval', | ||
| 58 | + isTable: false | ||
| 59 | + }, | ||
| 60 | + { | ||
| 61 | + title: '监控超时时间', | ||
| 62 | + field: 'monitorTimeout', | ||
| 63 | + isTable: false | ||
| 96 | } | 64 | } |
| 97 | - } | ||
| 98 | -]) | ||
| 99 | - | ||
| 100 | -export const { allSchemas } = useCrudSchemas(crudSchemas) | 65 | + ] |
| 66 | +}) | ||
| 67 | +export const { allSchemas } = useVxeCrudSchemas(crudSchemas) |
yudao-ui-admin-vue3/src/views/infra/job/jobLog.data.ts
| 1 | import { reactive } from 'vue' | 1 | import { reactive } from 'vue' |
| 2 | import { DICT_TYPE } from '@/utils/dict' | 2 | import { DICT_TYPE } from '@/utils/dict' |
| 3 | import { useI18n } from '@/hooks/web/useI18n' | 3 | import { useI18n } from '@/hooks/web/useI18n' |
| 4 | -import { CrudSchema, useCrudSchemas } from '@/hooks/web/useCrudSchemas' | 4 | +import { VxeCrudSchema, useVxeCrudSchemas } from '@/hooks/web/useVxeCrudSchemas' |
| 5 | // 国际化 | 5 | // 国际化 |
| 6 | const { t } = useI18n() | 6 | const { t } = useI18n() |
| 7 | // CrudSchema | 7 | // CrudSchema |
| 8 | -const crudSchemas = reactive<CrudSchema[]>([ | ||
| 9 | - { | ||
| 10 | - label: t('common.index'), | ||
| 11 | - field: 'id', | ||
| 12 | - type: 'index', | ||
| 13 | - form: { | ||
| 14 | - show: false | 8 | +const crudSchemas = reactive<VxeCrudSchema>({ |
| 9 | + primaryKey: 'id', | ||
| 10 | + primaryType: 'seq', | ||
| 11 | + action: true, | ||
| 12 | + columns: [ | ||
| 13 | + { | ||
| 14 | + title: '任务编号', | ||
| 15 | + field: 'jobId', | ||
| 16 | + isSearch: true | ||
| 15 | }, | 17 | }, |
| 16 | - detail: { | ||
| 17 | - show: false | ||
| 18 | - } | ||
| 19 | - }, | ||
| 20 | - { | ||
| 21 | - label: '任务编号', | ||
| 22 | - field: 'jobId', | ||
| 23 | - search: { | ||
| 24 | - show: true | ||
| 25 | - } | ||
| 26 | - }, | ||
| 27 | - { | ||
| 28 | - label: '处理器的名字', | ||
| 29 | - field: 'handlerName', | ||
| 30 | - search: { | ||
| 31 | - show: true | ||
| 32 | - } | ||
| 33 | - }, | ||
| 34 | - { | ||
| 35 | - label: '处理器的参数', | ||
| 36 | - field: 'handlerParam' | ||
| 37 | - }, | ||
| 38 | - { | ||
| 39 | - label: '第几次执行', | ||
| 40 | - field: 'executeIndex' | ||
| 41 | - }, | ||
| 42 | - { | ||
| 43 | - label: '开始执行时间', | ||
| 44 | - field: 'beginTime', | ||
| 45 | - search: { | ||
| 46 | - show: true, | ||
| 47 | - component: 'DatePicker', | ||
| 48 | - componentProps: { | ||
| 49 | - type: 'date', | ||
| 50 | - valueFormat: 'YYYY-MM-DD HH:mm:ss' | 18 | + { |
| 19 | + title: '处理器的名字', | ||
| 20 | + field: 'handlerName', | ||
| 21 | + isSearch: true | ||
| 22 | + }, | ||
| 23 | + { | ||
| 24 | + title: '处理器的参数', | ||
| 25 | + field: 'handlerParam' | ||
| 26 | + }, | ||
| 27 | + { | ||
| 28 | + title: '第几次执行', | ||
| 29 | + field: 'executeIndex' | ||
| 30 | + }, | ||
| 31 | + { | ||
| 32 | + title: '开始执行时间', | ||
| 33 | + field: 'beginTime', | ||
| 34 | + formatter: 'formatDate', | ||
| 35 | + table: { | ||
| 36 | + slots: { | ||
| 37 | + default: 'beginTime_default' | ||
| 38 | + } | ||
| 39 | + }, | ||
| 40 | + search: { | ||
| 41 | + show: true, | ||
| 42 | + itemRender: { | ||
| 43 | + name: 'XDataTimePicker' | ||
| 44 | + } | ||
| 51 | } | 45 | } |
| 52 | - } | ||
| 53 | - }, | ||
| 54 | - { | ||
| 55 | - label: '结束执行时间', | ||
| 56 | - field: 'endTime', | ||
| 57 | - search: { | ||
| 58 | - show: true, | ||
| 59 | - component: 'DatePicker', | ||
| 60 | - componentProps: { | ||
| 61 | - type: 'date', | ||
| 62 | - valueFormat: 'YYYY-MM-DD HH:mm:ss' | 46 | + }, |
| 47 | + { | ||
| 48 | + title: '结束执行时间', | ||
| 49 | + field: 'endTime', | ||
| 50 | + formatter: 'formatDate', | ||
| 51 | + isTable: false, | ||
| 52 | + search: { | ||
| 53 | + show: true, | ||
| 54 | + itemRender: { | ||
| 55 | + name: 'XDataTimePicker' | ||
| 56 | + } | ||
| 63 | } | 57 | } |
| 64 | }, | 58 | }, |
| 65 | - table: { | ||
| 66 | - show: false | ||
| 67 | - } | ||
| 68 | - }, | ||
| 69 | - { | ||
| 70 | - label: '执行时长', | ||
| 71 | - field: 'duration' | ||
| 72 | - }, | ||
| 73 | - { | ||
| 74 | - label: t('common.status'), | ||
| 75 | - field: 'status', | ||
| 76 | - dictType: DICT_TYPE.INFRA_JOB_LOG_STATUS, | ||
| 77 | - dictClass: 'number', | ||
| 78 | - search: { | ||
| 79 | - show: true | ||
| 80 | - } | ||
| 81 | - }, | ||
| 82 | - { | ||
| 83 | - field: 'action', | ||
| 84 | - width: '100px', | ||
| 85 | - label: t('table.action'), | ||
| 86 | - form: { | ||
| 87 | - show: false | 59 | + { |
| 60 | + title: '执行时长', | ||
| 61 | + field: 'duration', | ||
| 62 | + table: { | ||
| 63 | + slots: { | ||
| 64 | + default: 'duration_default' | ||
| 65 | + } | ||
| 66 | + } | ||
| 88 | }, | 67 | }, |
| 89 | - detail: { | ||
| 90 | - show: false | 68 | + { |
| 69 | + title: t('common.status'), | ||
| 70 | + field: 'status', | ||
| 71 | + dictType: DICT_TYPE.INFRA_JOB_LOG_STATUS, | ||
| 72 | + dictClass: 'number', | ||
| 73 | + isSearch: true | ||
| 91 | } | 74 | } |
| 92 | - } | ||
| 93 | -]) | ||
| 94 | - | ||
| 95 | -export const { allSchemas } = useCrudSchemas(crudSchemas) | 75 | + ] |
| 76 | +}) | ||
| 77 | +export const { allSchemas } = useVxeCrudSchemas(crudSchemas) |