index.vue 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. <script lang="ts" setup>
  2. import { Crontab } from '@/components/Crontab'
  3. 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'
  8. import { useI18n } from '@/hooks/web/useI18n'
  9. import { FormExpose } from '@/components/Form'
  10. 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'
  14. const message = useMessage()
  15. const { t } = useI18n() // 国际化
  16. const { push } = useRouter()
  17. // ========== 列表相关 ==========
  18. const { register, tableObject, methods } = useTable<JobVO>({
  19. getListApi: JobApi.getJobPageApi,
  20. delListApi: JobApi.deleteJobApi,
  21. exportListApi: JobApi.exportJobApi
  22. })
  23. const { getList, setSearchParams, delList, exportList } = methods
  24. // ========== CRUD 相关 ==========
  25. const actionLoading = ref(false) // 遮罩层
  26. const actionType = ref('') // 操作按钮的类型
  27. const dialogVisible = ref(false) // 是否显示弹出层
  28. const dialogTitle = ref('edit') // 弹出层标题
  29. const formRef = ref<FormExpose>() // 表单 Ref
  30. const cronExpression = ref('')
  31. const shortcuts = ref([
  32. {
  33. text: '每天8点和12点 (自定义追加)',
  34. value: '0 0 8,12 * * ?'
  35. }
  36. ])
  37. // 设置标题
  38. const setDialogTile = (type: string) => {
  39. dialogTitle.value = t('action.' + type)
  40. actionType.value = type
  41. dialogVisible.value = true
  42. }
  43. // 新增操作
  44. const handleCreate = () => {
  45. cronExpression.value = ''
  46. setDialogTile('create')
  47. // 重置表单
  48. unref(formRef)?.getElFormRef()?.resetFields()
  49. }
  50. // 修改操作
  51. const handleUpdate = async (row: JobVO) => {
  52. setDialogTile('update')
  53. // 设置数据
  54. const res = await JobApi.getJobApi(row.id)
  55. cronExpression.value = res.cronExpression
  56. unref(formRef)?.setValues(res)
  57. }
  58. const handleChangeStatus = async (row: JobVO) => {
  59. const text = row.status === InfraJobStatusEnum.STOP ? '开启' : '关闭'
  60. const status =
  61. row.status === InfraJobStatusEnum.STOP ? InfraJobStatusEnum.NORMAL : InfraJobStatusEnum.STOP
  62. message
  63. .confirm('确认要' + text + '定时任务编号为"' + row.id + '"的数据项?', t('common.reminder'))
  64. .then(async () => {
  65. row.status =
  66. row.status === InfraJobStatusEnum.NORMAL
  67. ? InfraJobStatusEnum.NORMAL
  68. : InfraJobStatusEnum.STOP
  69. await JobApi.updateJobStatusApi(row.id, status)
  70. message.success(text + '成功')
  71. await getList()
  72. })
  73. .catch(() => {
  74. row.status =
  75. row.status === InfraJobStatusEnum.NORMAL
  76. ? InfraJobStatusEnum.STOP
  77. : InfraJobStatusEnum.NORMAL
  78. })
  79. }
  80. // 执行日志
  81. const handleJobLog = (row: JobVO) => {
  82. if (row.id) {
  83. push('/job/job-log?id=' + row.id)
  84. } else {
  85. push('/job/job-log')
  86. }
  87. }
  88. // 执行一次
  89. const handleRun = (row: JobVO) => {
  90. message.confirm('确认要立即执行一次' + row.name + '?', t('common.reminder')).then(async () => {
  91. await JobApi.runJobApi(row.id)
  92. message.success('执行成功')
  93. getList()
  94. })
  95. }
  96. // 提交按钮
  97. const submitForm = async () => {
  98. actionLoading.value = true
  99. // 提交请求
  100. try {
  101. const data = unref(formRef)?.formModel as JobVO
  102. data.cronExpression = cronExpression.value
  103. if (actionType.value === 'create') {
  104. await JobApi.createJobApi(data)
  105. message.success(t('common.createSuccess'))
  106. } else {
  107. await JobApi.updateJobApi(data)
  108. message.success(t('common.updateSuccess'))
  109. }
  110. // 操作成功,重新加载列表
  111. dialogVisible.value = false
  112. await getList()
  113. } finally {
  114. actionLoading.value = false
  115. }
  116. }
  117. // ========== 详情相关 ==========
  118. const detailRef = ref() // 详情 Ref
  119. // 详情操作
  120. const handleDetail = async (row: JobVO) => {
  121. // 设置数据
  122. const res = JobApi.getJobApi(row.id)
  123. detailRef.value = res
  124. setDialogTile('detail')
  125. }
  126. // ========== 初始化 ==========
  127. getList()
  128. </script>
  129. <template>
  130. <!-- 搜索工作区 -->
  131. <ContentWrap>
  132. <Search :schema="allSchemas.searchSchema" @search="setSearchParams" @reset="setSearchParams" />
  133. </ContentWrap>
  134. <ContentWrap>
  135. <!-- 操作工具栏 -->
  136. <div class="mb-10px">
  137. <el-button type="primary" v-hasPermi="['infra:job:create']" @click="handleCreate">
  138. <Icon icon="ep:zoom-in" class="mr-5px" /> {{ t('action.add') }}
  139. </el-button>
  140. <el-button
  141. type="warning"
  142. v-hasPermi="['infra:job:export']"
  143. :loading="tableObject.exportLoading"
  144. @click="exportList('定时任务.xls')"
  145. >
  146. <Icon icon="ep:download" class="mr-5px" /> {{ t('action.export') }}
  147. </el-button>
  148. <el-button type="info" v-hasPermi="['infra:job:query']" @click="handleJobLog">
  149. <Icon icon="ep:zoom-in" class="mr-5px" /> 执行日志
  150. </el-button>
  151. </div>
  152. <!-- 列表 -->
  153. <Table
  154. :columns="allSchemas.tableColumns"
  155. :selection="false"
  156. :data="tableObject.tableList"
  157. :loading="tableObject.loading"
  158. :pagination="{
  159. total: tableObject.total
  160. }"
  161. v-model:pageSize="tableObject.pageSize"
  162. v-model:currentPage="tableObject.currentPage"
  163. @register="register"
  164. >
  165. <template #status="{ row }">
  166. <DictTag :type="DICT_TYPE.INFRA_JOB_STATUS" :value="row.status" />
  167. </template>
  168. <template #action="{ row }">
  169. <el-button link type="primary" v-hasPermi="['infra:job:update']" @click="handleUpdate(row)">
  170. <Icon icon="ep:edit" class="mr-1px" /> {{ t('action.edit') }}
  171. </el-button>
  172. <el-button
  173. link
  174. type="primary"
  175. v-hasPermi="['infra:job:update']"
  176. @click="handleChangeStatus(row)"
  177. >
  178. <Icon icon="ep:edit" class="mr-1px" />
  179. {{ row.status === InfraJobStatusEnum.STOP ? '开启' : '暂停' }}
  180. </el-button>
  181. <el-button link type="primary" v-hasPermi="['infra:job:query']" @click="handleDetail(row)">
  182. <Icon icon="ep:view" class="mr-1px" /> {{ t('action.detail') }}
  183. </el-button>
  184. <el-button
  185. link
  186. type="primary"
  187. v-hasPermi="['infra:job:delete']"
  188. @click="delList(row.id, false)"
  189. >
  190. <Icon icon="ep:delete" class="mr-1px" /> {{ t('action.del') }}
  191. </el-button>
  192. <el-button link type="primary" v-hasPermi="['infra:job:trigger']" @click="handleRun(row)">
  193. <Icon icon="ep:view" class="mr-1px" /> 执行一次
  194. </el-button>
  195. <el-button link type="primary" v-hasPermi="['infra:job:query']" @click="handleJobLog(row)">
  196. <Icon icon="ep:view" class="mr-1px" /> 调度日志
  197. </el-button>
  198. </template>
  199. </Table>
  200. </ContentWrap>
  201. <Dialog v-model="dialogVisible" :title="dialogTitle">
  202. <!-- 对话框(添加 / 修改) -->
  203. <Form
  204. v-if="['create', 'update'].includes(actionType)"
  205. :schema="allSchemas.formSchema"
  206. :rules="rules"
  207. ref="formRef"
  208. >
  209. <template #cronExpression>
  210. <Crontab v-model="cronExpression" :shortcuts="shortcuts" />
  211. </template>
  212. </Form>
  213. <!-- 对话框(详情) -->
  214. <Descriptions
  215. v-if="actionType === 'detail'"
  216. :schema="allSchemas.detailSchema"
  217. :data="detailRef"
  218. >
  219. <template #status="{ row }">
  220. <DictTag :type="DICT_TYPE.INFRA_JOB_STATUS" :value="row.status" />
  221. </template>
  222. <template #retryInterval="{ row }">
  223. <span>{{ row.retryInterval + '毫秒' }} </span>
  224. </template>
  225. <template #monitorTimeout="{ row }">
  226. <span>{{ row.monitorTimeout > 0 ? row.monitorTimeout + ' 毫秒' : '未开启' }}</span>
  227. </template>
  228. </Descriptions>
  229. <!-- 操作按钮 -->
  230. <template #footer>
  231. <el-button
  232. v-if="['create', 'update'].includes(actionType)"
  233. type="primary"
  234. :loading="actionLoading"
  235. @click="submitForm"
  236. >
  237. {{ t('action.save') }}
  238. </el-button>
  239. <el-button @click="dialogVisible = false">{{ t('dialog.close') }}</el-button>
  240. </template>
  241. </Dialog>
  242. </template>