| <!-- |
| ~ Licensed to the Apache Software Foundation (ASF) under one or more |
| ~ contributor license agreements. See the NOTICE file distributed with |
| ~ this work for additional information regarding copyright ownership. |
| ~ The ASF licenses this file to You under the Apache License, Version 2.0 |
| ~ (the "License"); you may not use this file except in compliance with |
| ~ the License. You may obtain a copy of the License at |
| ~ |
| ~ http://www.apache.org/licenses/LICENSE-2.0 |
| ~ |
| ~ Unless required by applicable law or agreed to in writing, software |
| ~ distributed under the License is distributed on an "AS IS" BASIS, |
| ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| ~ See the License for the specific language governing permissions and |
| ~ limitations under the License. |
| --> |
| |
| <template> |
| <div> |
| <Spin |
| v-if="loading" |
| size="large" |
| fix/> |
| <div class="job-manager"> |
| <div |
| class="job-manager-empty" |
| v-if="!jobList.length">{{ $t('message.common.resourceSimple.ZWSJ') }}</div> |
| <div |
| class="job-manager-type" |
| v-for="(type, index) in jobTypeList" |
| :key="index"> |
| <span |
| class="job-manager-title" |
| v-if="jobList.length && checkJobLength(type.en)">{{ type.cn }}</span> |
| <div |
| v-for="(item, subIndex) in jobList" |
| :key="subIndex"> |
| <div |
| v-if="item.requestApplicationName === type.en" |
| class="job-manager-item-wrapper" |
| :style="getClass(item)" |
| :class="{'actived': item.isActive}" |
| @click="handleItemClick(item)" |
| @contextmenu.prevent.stop="handleItemMenu($event, item)"> |
| <Icon |
| type="md-checkmark" |
| class="job-manager-item-active" |
| v-if="item.isActive" |
| ></Icon> |
| <span |
| class="job-manager-item-progress" |
| :style="{'width': item.progress ? (item.progress * 100).toFixed(2) + '%' : 0,}"></span> |
| <span class="job-manager-item-label" :style="{marginLeft: '16px'}">{{ getLabel(item) }}</span> |
| <span class="job-manager-item-progress-label">{{ item.progress ? (item.progress * 100).toFixed(2) + '%' : '' }}</span> |
| <Icon |
| size="16" |
| type="ios-close-circle-outline" |
| class="job-manager-item-close" |
| @click="openKillModal($t('message.common.resourceSimple.RW'))"/> |
| </div> |
| </div> |
| </div> |
| <we-menu |
| ref="contextMenu" |
| id="jobManager"> |
| <we-menu-item |
| @select="openKillModal($t('message.common.resourceSimple.YQRW'))" |
| v-if="lastClick && lastClick.status !== 'Inited'"> |
| <span>{{ $t('message.common.resourceSimple.JSYQRW') }}</span> |
| </we-menu-item> |
| <we-menu-item @select="openHistoryScript"> |
| <span>{{ $t('message.common.resourceSimple.CKJBXX') }}</span> |
| </we-menu-item> |
| <we-menu-item @select="copyInfos"> |
| <span>{{ $t('message.common.resourceSimple.FZJBXX') }}</span> |
| </we-menu-item> |
| </we-menu> |
| </div> |
| <detele-modal |
| ref="killModal" |
| :loading="loading" |
| @delete="kill"></detele-modal> |
| </div> |
| </template> |
| <script> |
| import { orderBy } from 'lodash'; |
| import util from '@/common/util'; |
| import api from '@/common/service/api'; |
| import deteleModal from '@/components/deleteDialog'; |
| import mixin from '@/common/service/mixin'; |
| export default { |
| name: 'Job', |
| components: { |
| deteleModal, |
| }, |
| mixins: [mixin], |
| data() { |
| return { |
| loading: false, |
| jobTypeList: [], |
| jobList: [], |
| lastClick: null, |
| }; |
| }, |
| watch: { |
| loading(val) { |
| this.$emit('change-loading', val); |
| }, |
| }, |
| methods: { |
| getJobList() { |
| if(this.loading) return; |
| this.jobList = []; |
| this.loading = true; |
| api.fetch('/jobhistory/listundonetasks', { |
| pageSize: 100, |
| status: 'Running,Inited,Scheduled', |
| }, 'get').then((rst) => { |
| this.loading = false; |
| // Eliminate tasks whose requestApplicationName is "nodeexecution"(剔除requestApplicationName为 "nodeexecution" 的task) |
| let tasks = rst.tasks.filter(item => item.requestApplicationName !== "nodeexecution" && item.requestApplicationName !== "CLI") |
| this.dispatch('Footer:updateRunningJob', tasks.length); |
| this.jobTypeList = [ |
| { 'en': 'IDE', 'cn': this.$t('message.common.resourceSimple.YS') }, |
| { 'en': 'Visualis', 'cn': this.$t('message.common.resourceSimple.ZH') }, |
| { 'en': 'flowexecution', 'cn': this.$t('message.common.resourceSimple.FLOW1') }, |
| { 'en': 'Scheduler', 'cn': this.$t('message.common.resourceSimple.FLOW2')}]; |
| tasks.forEach((item) => { |
| const tmpItem = Object.assign({}, item, { isActive: false, fileName: this.convertJson(item) }); |
| this.jobList.push(tmpItem); |
| }); |
| this.jobList = orderBy(this.jobList, ['status', 'fileName']); |
| this.$emit('update-job', tasks.length); |
| }).catch((err) => { |
| this.loading = false; |
| window.console.error(err) |
| }); |
| }, |
| // delete current job(删除当前工作) |
| killJob() { |
| const item = this.lastClick; |
| if (this.loading) return this.$Message.warning(this.$t('message.common.resourceSimple.DDJK')); |
| if (!item) return this.$Message.warning(this.$t('message.common.resourceSimple.QXZYTJL')); |
| if (!item.strongerExecId) return this.$Message.warning(this.$t('message.common.resourceSimple.WHQD')); |
| this.loading = true; |
| api.fetch(`/entrance/${item.strongerExecId}/kill`, {taskID: item.taskID},'get').then(() => { |
| this.loading = false; |
| this.$emit('close-modal'); |
| // stop execution(停止执行) |
| this.$Notice.close(item.scriptPath); |
| this.$Notice.warning({ |
| title: this.$t('message.common.resourceSimple.YXTS'), |
| desc: `${this.$t('message.common.resourceSimple.YJTZZXJB')}: ${item.fileName || ''} !`, |
| name: item.scriptPath, |
| duration: 3, |
| }); |
| }).catch(() => { |
| this.loading = false; |
| }); |
| }, |
| async killJobAndEngine() { |
| const item = this.lastClick; |
| if (this.loading) return this.$Message.warning(this.$t('message.common.resourceSimple.DDJK')); |
| if (!item.strongerExecId) return this.$Message.warning(this.$t('message.common.resourceSimple.WHQD')); |
| if (!item.engineInstance) return this.$Message.warning(this.$t('message.common.resourceSimple.WHQD')); |
| this.loading = true; |
| await api.fetch(`/entrance/${item.strongerExecId}/kill`, {taskID: item.taskID}, 'get'); |
| api.fetch('/resourcemanager/engines').then((res) => { |
| const engines = res.engines; |
| const engine = engines.find((e) => e.engineInstance === item.engineInstance); |
| if (engine) { |
| const params = [{ |
| ticketId: engine.ticketId, |
| moduleName: engine.moduleName, |
| engineManagerInstance: engine.engineManagerInstance, |
| creator: engine.creator, |
| }]; |
| api.fetch(`/resourcemanager/enginekill`, params).then(() => { |
| this.loading = false; |
| this.$emit('close-modal'); |
| this.$Notice.close(item.scriptPath); |
| this.$Notice.warning({ |
| title: this.$t('message.common.resourceSimple.YXTS'), |
| desc: this.$t('message.common.resourceSimple.JSYQHRWCG'), |
| name: item.scriptPath, |
| duration: 3, |
| }); |
| }).catch(() => { |
| this.loading = false; |
| }); |
| } |
| }).catch(() => { |
| this.loading = false; |
| }); |
| }, |
| openHistoryScript() { |
| const item = this.lastClick; |
| if (item.requestApplicationName === 'IDE') { |
| const supportModes = this.getSupportModes(); |
| const match = supportModes.find((s) => s.rule.test(item.fileName)); |
| const ext = match ? match.ext : '.hql'; |
| const name = `history_item_${item.taskID}${ext}`; |
| const md5Id = util.md5(name); |
| this.$emit('close-modal'); |
| if (this.$route.name === 'Home') { |
| this.dispatch('Workbench:add', { |
| id: md5Id, // Unique identification, even if the file name is changed, it can identify it as it is(唯一标识,就算文件名修改,它都能标识它是它) |
| taskID: item.taskID, |
| filename: name, |
| filepath: item.scriptPath, |
| // saveAs represents a temporary script that needs to be closed or saved when saved(saveAs表示临时脚本,需要关闭或保存时另存) |
| saveAs: true, |
| code: item.executionCode, |
| type: 'historyScript', |
| }, (f) => { |
| if (f) { |
| this.$Message.success(this.$t('message.common.resourceSimple.DKCG')); |
| } |
| }); |
| } else { |
| // After the module is split, there are two cases, one is with scripts, and the other is without the general log display.(模块拆分后分两种情况,一种是带scriptis的,一种是不带走通用日志展示) |
| const currentModules = util.currentModules(); |
| if (currentModules.hasScriptis) { |
| this.$router.push({ path: '/home', |
| query: { |
| id: md5Id, |
| taskID: item.taskID, |
| filename: name, |
| filepath: item.scriptPath, |
| saveAs: true, |
| type: 'historyScript', |
| code: item.executionCode, |
| } }); |
| } else { |
| this.$router.push({path: '/log', query: { taskID: item.taskID }}) |
| } |
| } |
| } |
| }, |
| getColor(item) { |
| let color = ''; |
| if (item.status === 'Inited') { |
| color = '#515a6e'; |
| } else if (item.status === 'Running') { |
| color = 'rgb(45, 140, 240)'; |
| } else { |
| color = 'rgba(243, 133, 243, 0.5)'; |
| } |
| return color; |
| }, |
| getClass(item) { |
| const color = this.getColor(item); |
| return { |
| // border: `1px solid ${color}`, |
| color, |
| }; |
| }, |
| getIconClass(script) { |
| let logos = this.getSupportModes().filter((item) => { |
| return item.rule.test(script.fileName) || item.runType === script.runType; |
| }); |
| if (logos.length > 0) { |
| return { |
| className: '', |
| icon: logos[0].logo, |
| color: logos[0].color |
| } |
| } else if (script.requestApplicationName === 'flowexecution' || script.requestApplicationName === 'Scheduler') { |
| return { |
| className: '', |
| icon: 'fi-workflow1', |
| color: '#00B0F0' |
| } |
| } else { |
| return { |
| className: '', |
| icon: 'fi-bi', |
| color: '#965DF2' |
| } |
| } |
| }, |
| handleItemClick(item) { |
| this.$emit('change-job-disabled', false); |
| if (!this.lastClick) { |
| this.lastClick = item; |
| item.isActive = true; |
| } else if (this.lastClick !== item) { |
| this.lastClick.isActive = false; |
| this.lastClick = item; |
| item.isActive = true; |
| } |
| }, |
| handleItemMenu(ev, item) { |
| this.handleItemClick(item); |
| this.$refs.contextMenu.open(ev); |
| }, |
| copyInfos() { |
| util.executeCopy(JSON.stringify(this.lastClick)); |
| this.$Message.success(this.$t('message.common.resourceSimple.JBFZDZTRB')); |
| }, |
| checkJobLength(type) { |
| const list = this.jobList.filter((item) => item.requestApplicationName === type); |
| return list.length; |
| }, |
| openKillModal(type) { |
| this.$refs.killModal.open({ type, name: '' }); |
| }, |
| kill(type) { |
| if (type === this.$t('message.common.resourceSimple.YQRW')) { |
| this.killJobAndEngine(); |
| } else { |
| this.killJob(); |
| } |
| }, |
| getLabel(item) { |
| if (item.fileName) { |
| return item.fileName; |
| } else { |
| // 取sourceJson里的值 |
| const nameJson = JSON.parse(item.sourceJson); |
| if (item.requestApplicationName === 'IDE') { |
| if (nameJson.fileName) { |
| return nameJson.fileName; |
| } else if (nameJson.scriptPath) { |
| const arr = nameJson.scriptPath.split('/'); |
| return arr[arr.length - 1]; |
| } else { |
| return this.$t('message.common.resourceSimple.WZJBMC') |
| } |
| } else if (item.requestApplicationName === 'flowexecution') { |
| if (nameJson.flowName) { |
| return nameJson.flowName; |
| } else { |
| return this.$t('message.common.resourceSimple.GZLJB'); |
| } |
| } else if (item.requestApplicationName === 'Scheduler') { |
| return this.$t('message.common.resourceSimple.GZLJB'); |
| } else { |
| return this.$t('message.common.resourceSimple.ZHJB'); |
| } |
| } |
| }, |
| convertJson(item) { |
| if (item.sourceJson) { |
| const json = JSON.parse(item.sourceJson); |
| return json.fileName || json.flowName; |
| } |
| return ''; |
| } |
| }, |
| }; |
| </script> |