index.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. <script setup lang="ts" name="Job">
  2. import apis from "@a"
  3. import message from "@@/utils/message"
  4. import dayjs from "dayjs"
  5. const jobTypeOptions = computed(() => {
  6. return [
  7. { label: "接口", value: "1" },
  8. { label: "函数", value: "2" }
  9. ]
  10. })
  11. const misfirePolicyOptions = computed(() => {
  12. return [
  13. { label: "立即执行", value: "1" },
  14. { label: "执行一次", value: "2" },
  15. { label: "放弃执行", value: "3" }
  16. ]
  17. })
  18. const concurrentOptions = computed(() => {
  19. return [
  20. { label: "允许", value: "2" },
  21. { label: "禁止", value: "1" }
  22. ]
  23. })
  24. const jobKeysOptions = ref<any[]>([])
  25. const tableRef = ref()
  26. const modalRef = ref()
  27. const opts = reactive<any>({
  28. columns: [
  29. { field: "jobId", name: "编码", width: 100, visible: false, isSort: false, tooltip: true },
  30. { field: "jobName", name: "名称", width: "auto", isSort: true, visible: true },
  31. { field: "jobGroup", name: "任务分组", width: 100, isSort: true, visible: true },
  32. { field: "cronExpression", name: "Cron表达式", width: "auto", isSort: false, visible: true },
  33. { field: "invokeTarget", name: "调用目标", width: "auto", isSort: false, visible: true },
  34. { field: "status", name: "状态", width: 100, isSort: true, visible: true },
  35. { field: "execCount", name: "执行次数", width: 100, isSort: true, visible: true },
  36. { field: "failCount", name: "失败次数", width: 100, isSort: true, visible: true },
  37. { field: "lastExecTime", name: "上次执行时间", width: 155, isSort: true, visible: true },
  38. { field: "nextExecTime", name: "下一次执行时间", width: 155, isSort: true, visible: true },
  39. { field: "createdAt", name: "创建时间", width: 185, isSort: true, visible: true },
  40. { field: "actions", name: `操作`, width: 150 }
  41. ],
  42. queryParams: {
  43. jobName: undefined,
  44. jobType: undefined,
  45. invokeTarget: undefined,
  46. status: undefined
  47. },
  48. searchFormItems: [
  49. {
  50. field: "jobName",
  51. label: "名称",
  52. class: "w-100",
  53. component: "I",
  54. listeners: {
  55. keyup: (e: KeyboardEvent) => {
  56. if (e.code == "Enter") {
  57. handleQuery()
  58. }
  59. }
  60. }
  61. },
  62. {
  63. field: "jobGroup",
  64. label: "任务分组",
  65. class: "w-100",
  66. component: "Dict",
  67. props: {
  68. showAll: true,
  69. type: "select",
  70. clearable: true,
  71. placeholder: "请选择任务分组",
  72. dictType: "sys_job_group"
  73. }
  74. },
  75. {
  76. field: "jobType",
  77. label: "调用类型",
  78. class: "w-100",
  79. component: "VS",
  80. placeholder: "请选择调用类型",
  81. data: () => jobTypeOptions.value,
  82. props: {
  83. showAll: true,
  84. valueIsNumber: true,
  85. type: "select",
  86. clearable: true
  87. }
  88. },
  89. {
  90. field: "invokeTarget",
  91. label: "调用目标",
  92. class: "w-100",
  93. component: "I",
  94. listeners: {
  95. keyup: (e: KeyboardEvent) => {
  96. if (e.code == "Enter") {
  97. handleQuery()
  98. }
  99. }
  100. }
  101. },
  102. {
  103. field: "status",
  104. label: "状态",
  105. class: "w-100",
  106. component: "Dict",
  107. props: {
  108. showAll: true,
  109. type: "select",
  110. clearable: true,
  111. valueIsNumber: true,
  112. placeholder: "请选择状态",
  113. dictType: "sys_job_status"
  114. }
  115. }
  116. ] as any,
  117. permission: "schedule:job",
  118. handleFuns: {},
  119. customBtns: [],
  120. tableListFun: apis.schedule.jobApi.listJob,
  121. getEntityFun: apis.schedule.jobApi.getJob,
  122. deleteEntityFun: apis.schedule.jobApi.delJob,
  123. formItems: [
  124. {
  125. field: "jobName",
  126. label: "名称",
  127. class: "w-100",
  128. component: "I",
  129. required: true
  130. },
  131. {
  132. field: "jobGroup",
  133. label: "任务分组",
  134. class: "w-100",
  135. required: true,
  136. component: "Dict",
  137. props: {
  138. type: "select",
  139. clearable: true,
  140. placeholder: "请选择任务分组",
  141. dictType: "sys_job_group"
  142. }
  143. },
  144. {
  145. field: "jobType",
  146. label: "调用类型",
  147. class: "w-100",
  148. required: true,
  149. component: "VS",
  150. placeholder: "请选择调用类型",
  151. data: () => jobTypeOptions.value,
  152. props: {
  153. type: "radio",
  154. valueIsNumber: true,
  155. clearable: true
  156. },
  157. listeners: {
  158. change: () => {
  159. form.value.invokeTarget = ""
  160. }
  161. }
  162. },
  163. {
  164. show: () => form.value.jobType == 1,
  165. field: "invokeTarget",
  166. label: "调用目标",
  167. class: "w-100",
  168. component: "I",
  169. required: true,
  170. placeholder: "请填写调用接口"
  171. },
  172. {
  173. show: () => form.value.jobType == 2,
  174. field: "invokeTarget",
  175. label: "调用目标",
  176. class: "w-100",
  177. component: "VS",
  178. required: true,
  179. data: () => jobKeysOptions.value,
  180. props: {
  181. type: "select",
  182. clearable: true,
  183. placeholder: "请选择调用函数"
  184. }
  185. },
  186. {
  187. field: "args",
  188. label: "目标参数",
  189. class: "w-100",
  190. component: "I",
  191. required: false
  192. },
  193. {
  194. field: "cronExpression",
  195. label: "Cron表达式",
  196. class: "w-100",
  197. component: "I",
  198. required: true
  199. },
  200. {
  201. field: "misfirePolicy",
  202. label: "执行策略",
  203. class: "w-100",
  204. required: false,
  205. component: "VS",
  206. placeholder: "请选择执行策略",
  207. data: () => misfirePolicyOptions.value,
  208. props: {
  209. type: "radio",
  210. valueIsNumber: true,
  211. clearable: true
  212. }
  213. },
  214. {
  215. field: "concurrent",
  216. label: "是否并发",
  217. class: "w-100",
  218. required: false,
  219. component: "VS",
  220. placeholder: "请选择是否并发",
  221. data: () => concurrentOptions.value,
  222. props: {
  223. type: "radio",
  224. valueIsNumber: true,
  225. clearable: true
  226. }
  227. }
  228. ] as any,
  229. resetForm: () => {
  230. form.value = emptyFormData.value
  231. },
  232. emptyFormData: {
  233. jobId: undefined,
  234. jobName: undefined,
  235. jobGroup: "DEFAULT",
  236. jobType: 1,
  237. cronExpression: undefined,
  238. invokeTarget: undefined,
  239. args: undefined,
  240. misfirePolicy: 1,
  241. concurrent: undefined,
  242. status: 2
  243. }
  244. })
  245. const { emptyFormData } = toRefs(opts)
  246. const queryParams = ref(Object.assign({}, opts.queryParams))
  247. const form = ref<any>(emptyFormData.value)
  248. /** 修改按钮操作 */
  249. function handleUpdate(row: any) {
  250. tableRef.value.defaultHandleFuns.handleUpdate("", row)
  251. }
  252. /** 删除按钮操作 */
  253. function handleDelete(rows: any[]) {
  254. tableRef.value.defaultHandleFuns.handleDelete("", rows)
  255. }
  256. /** 提交按钮 */
  257. function submitForm() {
  258. if (form.value.jobId != undefined) {
  259. apis.schedule.jobApi.updateJob(form.value).then(() => {
  260. message.msgSuccess("修改成功")
  261. handleQuery()
  262. })
  263. } else {
  264. apis.schedule.jobApi.addJob(form.value).then(() => {
  265. message.msgSuccess("新增成功")
  266. handleQuery()
  267. })
  268. }
  269. }
  270. /** 查询按钮 */
  271. function handleQuery() {
  272. tableRef.value?.search()
  273. }
  274. /** 查询重置按钮 */
  275. function resetQuery() {
  276. queryParams.value = opts.queryParams
  277. }
  278. function handleStart(row: any) {
  279. message
  280. .confirm("是否确认启动任务?", "提示", {
  281. confirmButtonText: "确定",
  282. cancelButtonText: "取消",
  283. type: "warning"
  284. })
  285. .then(() => {
  286. apis.schedule.jobApi.startJob(row.jobId).then(() => {
  287. message.msgSuccess("启动成功")
  288. handleQuery()
  289. })
  290. })
  291. }
  292. function handleStop(row: any) {
  293. message
  294. .confirm("是否确认停止任务?", "提示", {
  295. confirmButtonText: "确定",
  296. cancelButtonText: "取消",
  297. type: "warning"
  298. })
  299. .then(() => {
  300. apis.schedule.jobApi.stopJob(row.jobId).then(() => {
  301. message.msgSuccess("停止成功")
  302. handleQuery()
  303. })
  304. })
  305. }
  306. function init() {
  307. apis.schedule.jobApi.getJobKeys().then((res: any) => {
  308. if (res.data) {
  309. jobKeysOptions.value = Object.keys(res.data).map((key: any) => {
  310. return {
  311. value: key,
  312. label: res.data[key]
  313. }
  314. })
  315. }
  316. })
  317. }
  318. onMounted(() => setTimeout(init, 100))
  319. </script>
  320. <template>
  321. <div class="app-container">
  322. <VbDataTable
  323. ref="tableRef"
  324. :handle-perm="opts.permission"
  325. :handle-funs="opts.handleFuns"
  326. :search-form-items="opts.searchFormItems"
  327. :columns="opts.columns"
  328. :custom-btns="opts.customBtns"
  329. :remote-fun="opts.tableListFun"
  330. :get-entity-fun="opts.getEntityFun"
  331. :delete-entity-fun="opts.deleteEntityFun"
  332. sortField="createdAt"
  333. sort-order="desc"
  334. :modal="modalRef"
  335. :reset-form-fun="opts.resetForm"
  336. v-model:form-data="form"
  337. :query-params="queryParams"
  338. :check-multiple="true"
  339. :has-checkbox="true"
  340. :reset-search-form-fun="resetQuery"
  341. :custom-search-fun="handleQuery">
  342. <template #jobGroup="{ row }">
  343. <DictTag :value="row.jobGroup" type="sys_job_group"></DictTag>
  344. </template>
  345. <template #status="{ row }">
  346. <DictTag :value="row.status" valueIsNumber type="sys_job_status"></DictTag>
  347. </template>
  348. <template #createdAt="{ row }">
  349. <span>{{ dayjs(row.createdAt).format("YYYY-MM-DD HH:mm:ss") }}</span>
  350. </template>
  351. <template #lastExecTime="{ row }">
  352. <span>
  353. {{
  354. row.lastExecTime < 20240000000000
  355. ? "-"
  356. : dayjs(row.lastExecTime + "", "YYYYMMDDHHmmss").format("YYYY-MM-DD HH:mm:ss")
  357. }}
  358. </span>
  359. </template>
  360. <template #nextExecTime="{ row }">
  361. <span>
  362. {{
  363. row.nextExecTime < 20240000000000
  364. ? "-"
  365. : dayjs(row.nextExecTime + "", "YYYYMMDDHHmmss").format("YYYY-MM-DD HH:mm:ss")
  366. }}
  367. </span>
  368. </template>
  369. <template #actions="{ row }">
  370. <vb-tooltip content="修改" placement="top">
  371. <el-button link type="primary" @click="handleUpdate(row)">
  372. <template #icon>
  373. <VbIcon icon-name="notepad-edit" icon-type="duotone" class="fs-3"></VbIcon>
  374. </template>
  375. </el-button>
  376. </vb-tooltip>
  377. <vb-tooltip v-if="row.status == 1" content="启动任务" placement="top">
  378. <el-button link type="success" @click="handleStart(row)">
  379. <template #icon>
  380. <VbIcon icon-name="right-square" icon-type="duotone" class="fs-3"></VbIcon>
  381. </template>
  382. </el-button>
  383. </vb-tooltip>
  384. <vb-tooltip v-if="row.status == 2" content="停止任务" placement="top">
  385. <el-button link type="danger" @click="handleStop(row)">
  386. <template #icon>
  387. <VbIcon icon-name="cross-square" icon-type="duotone" class="fs-3"></VbIcon>
  388. </template>
  389. </el-button>
  390. </vb-tooltip>
  391. <vb-tooltip content="删除" placement="top">
  392. <el-button link type="primary" @click="handleDelete([row])">
  393. <template #icon>
  394. <VbIcon icon-name="trash-square" icon-type="duotone" class="fs-3"></VbIcon>
  395. </template>
  396. </el-button>
  397. </vb-tooltip>
  398. </template>
  399. </VbDataTable>
  400. <VbModal
  401. v-model:modal="modalRef"
  402. :title="opts.modalTitle"
  403. :form-items="opts.formItems as any"
  404. :form-data="form"
  405. @confirm="submitForm"
  406. append-to-body></VbModal>
  407. </div>
  408. </template>