blob: 21e33d4758875437384080a7ed2c86ce35bba5e6 [file] [log] [blame]
<!--
~ 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 class="global-history">
<div class="global-history-searchbar">
<div class="searchbar-items">
<div class="searchbar-item">
<label class="label">{{$t('message.linkis.jobId')}}</label>
<InputNumber
v-model="searchBar.id"
:placeholder="$t('message.linkis.formItems.id.placeholder')"
style="width:100px;"
:min="1"
></InputNumber>
</div>
<div v-if="isAdminModel" class="searchbar-item">
<label class="label">{{$t('message.linkis.userName')}}</label>
<Input
:maxlength="50"
v-model="searchBar.proxyUser"
:placeholder="$t('message.linkis.searchName')"
style="width:60px;"
/>
</div>
<div class="searchbar-item">
<label class="label">{{$t('message.linkis.formItems.date.label')}}</label>
<DatePicker
:transfer="true"
class="datepicker"
:options="shortcutOpt"
v-model="searchBar.shortcut"
type="daterange"
placement="bottom-start"
format="yyyy-MM-dd"
:placeholder="$t('message.linkis.formItems.date.placeholder')"
style="width: 160px"
:editable="false"
/>
</div>
<div class="searchbar-item">
<label class="label">{{$t('message.linkis.formItems.creator.label')}}</label>
<Input
:maxlength="50"
v-model.trim="searchBar.creator"
:placeholder="$t('message.linkis.formItems.creator.placeholder')"
style="width:80px;"
/>
</div>
<div class="searchbar-item">
<label class="label">{{$t('message.linkis.formItems.engine.label')}}</label>
<Select v-model="searchBar.engine" style="width: 70px">
<Option v-for="(item) in getEngineTypes" :label="item === 'all' ? $t('message.linkis.engineTypes.all'): item" :value="item" :key="item" />
</Select>
</div>
<div class="searchbar-item">
<label class="label">{{$t('message.linkis.formItems.status.label')}}</label>
<Select v-model="searchBar.status" style="width: 70px">
<Option
v-for="(item) in statusType"
:label="item.label"
:value="item.value"
:key="item.value"
/>
</Select>
</div>
<Form v-show="showAdvance" class="global-history-searchbar" :model="searchBar" inline>
<FormItem prop="instance" :label="$t('message.linkis.formItems.instance.label')">
<Input
v-model="searchBar.instance"
:placeholder="$t('message.linkis.formItems.instance.placeholder')"
style="width:150px;"
/>
</FormItem>
</Form>
</div>
<div class="search-btns">
<Button
class="search-btn"
type="primary"
@click="search"
style="margin-right: 10px;"
>{{ $t('message.linkis.search') }}</Button>
<Button
class="search-btn"
type="warning"
@click="reset"
style="margin-right: 10px;"
>{{ $t('message.linkis.clearSearch') }}</Button>
<Button class="search-btn" type="error" @click="stop" style="margin-right: 10px;">{{$t('message.linkis.stop')}}</Button>
<Button
class="search-btn"
type="primary"
@click="switchAdmin"
v-show="isLogAdmin || isHistoryAdmin"
style="margin-right: 10px;"
>{{ isAdminModel ? $t('message.linkis.generalView') : $t('message.linkis.manageView') }}</Button>
<Button
class="search-btn"
type="primary"
@click="clickAdvance"
>{{ showAdvance ? $t('message.linkis.hideAdvancedSearch') : $t('message.linkis.showAdvancedSearch') }}</Button>
</div>
</div>
<div class="global-history-table" :style="{width: '100%', 'height': moduleHeight +'px'}">
<Icon v-show="isLoading" type="ios-loading" size="30" class="global-history-loading" />
<history-table
v-if="!isLoading"
:columns="column"
:data="list"
:height="moduleHeight"
:no-data-text="$t('message.linkis.noDataText')"
border
stripe
@checkall="checkChange"
@select-change="selectChange"
/>
</div>
<div class="global-history-page">
<Page
:total="pageSetting.total"
:page-size="pageSetting.pageSize"
:current="pageSetting.current"
size="small"
show-total
show-elevator
:prev-text="$t('message.linkis.previousPage')" :next-text="$t('message.linkis.nextPage')"
@on-change="changePage"
/>
</div>
</div>
</template>
<script>
import storage from '@/common/helper/storage'
import table from '@/components/virtualTable'
import mixin from '@/common/service/mixin'
import api from '@/common/service/api'
export default {
name: 'GlobalHistory',
components: {
historyTable: table.historyTable
},
mixins: [mixin],
data() {
const today = new Date(new Date().toLocaleDateString())
return {
list: [],
column: [],
getEngineTypes: [],
isLoading: false,
showAdvance: false,
pageSetting: {
total: 0,
pageSize: 50,
current: 1
},
searchBar: {
id: null,
proxyUser: '',
creator: '',
engine: 'all',
status: '',
shortcut: [today, today]
},
inputType: 'number',
shortcutOpt: {
shortcuts: [
{
text: this.$t('message.linkis.shortcuts.week'),
value() {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 7)
return [start, end]
}
},
{
text: this.$t('message.linkis.shortcuts.month'),
value() {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 30)
return [start, end]
}
},
{
text: this.$t('message.linkis.shortcuts.threeMonths'),
value() {
const end = new Date()
const start = new Date()
start.setTime(start.getTime() - 3600 * 1000 * 24 * 90)
return [start, end]
}
}
]
},
statusType: [
{
label: this.$t('message.linkis.statusType.all'),
value: 'all'
},
{
label: this.$t('message.linkis.statusType.inited'),
value: 'Inited'
},
{
label: this.$t('message.linkis.statusType.running'),
value: 'Running'
},
{
label: this.$t('message.linkis.statusType.succeed'),
value: 'Succeed'
},
{
label: this.$t('message.linkis.statusType.cancelled'),
value: 'Cancelled'
},
{
label: this.$t('message.linkis.statusType.failed'),
value: 'Failed'
},
{
label: this.$t('message.linkis.statusType.scheduled'),
value: 'Scheduled'
},
{
label: this.$t('message.linkis.statusType.timeout'),
value: 'Timeout'
}
],
engineTypes: [
{
label: this.$t('message.linkis.engineTypes.all'),
value: 'all'
},
{
label: 'spark',
value: 'spark'
},
{
label: 'hive',
value: 'hive'
},
{
label: 'pipeline',
value: 'pipeline'
},
{
label: 'python',
value: 'python'
},
{
label: 'flowexecution',
value: 'flowexecution'
},
{
label: 'appjoint',
value: 'appjoint'
},
{
label: 'shell',
value: 'shell'
}
],
isLogAdmin: false,
isHistoryAdmin: false,
isAdminModel: false,
moduleHeight: 300
}
},
async created() {
// Get whether it is a historical administrator(获取是否是历史管理员权限)
await api.fetch('/jobhistory/governanceStationAdmin', 'get').then(res => {
this.isLogAdmin = res.admin
this.isHistoryAdmin = res.historyAdmin
})
await api.fetch('/configuration/engineType', 'get').then(res => {
this.getEngineTypes = ['all', ...res.engineType]
})
},
mounted() {
this.init()
this.moduleHeight = this.$parent.$el.clientHeight - 220
// Monitor window changes and get browser width and height(监听窗口变化,获取浏览器宽高)
window.addEventListener('resize', this.getHeight)
},
beforeDestroy() {
// Monitor window changes and get browser width and height(监听窗口变化,获取浏览器宽高)
storage.set('last-admin-model', this.isAdminModel)
// storage.set('last-searchbar-status', this.searchBar)
window.removeEventListener('resize', this.getHeight)
},
beforeRouteEnter(to, from, next) {
if(from.name !== 'viewHistory') {
sessionStorage.removeItem('last-admin-model');
sessionStorage.removeItem('last-searchbar-status');
sessionStorage.removeItem('last-pageSetting-status');
sessionStorage.removeItem('last-searchbar-advance');
}
next();
},
activated() {
this.init()
},
methods: {
getHeight() {
this.moduleHeight = this.$parent.$el.clientHeight - 228
if(this.showAdvance) {
this.moduleHeight -= 42
}
},
clickAdvance() {
this.showAdvance = !this.showAdvance
this.getHeight()
},
init() {
let isAdminModel = storage.get('last-admin-model')
const lastSearch = storage.get('last-searchbar-status')
const lastPage = storage.get('last-pageSetting-status')
this.showAdvance = storage.get('last-searchbar-advance')
this.getHeight()
if (lastSearch) {
if (lastSearch.shortcut[0] && lastSearch.shortcut[1]) {
lastSearch.shortcut = [new Date(lastSearch.shortcut[0]), new Date(lastSearch.shortcut[1])]
} else {
const today = new Date(new Date().toLocaleDateString())
lastSearch.shortcut = [today, today]
}
this.searchBar = lastSearch
}
if (lastPage) {
this.pageSetting = lastPage
}
if (isAdminModel) {
this.switchAdmin()
} else {
this.search()
}
storage.remove('last-pageSetting-status')
},
convertTimes(runningTime) {
const time = Math.floor(runningTime / 1000)
if (time < 0) {
return `0${this.$t('message.linkis.time.second')}`
} else if (time < 60) {
return `${time}${this.$t('message.linkis.time.second')}`
} else if (time < 3600) {
return `${(time / 60).toPrecision(2)}${this.$t(
'message.linkis.time.minute'
)}`
} else if (time < 86400) {
return `${(time / 3600).toPrecision(2)}${this.$t(
'message.linkis.time.hour'
)}`
}
return `${(time / 86400).toPrecision(2)}${this.$t(
'message.linkis.time.day'
)}`
},
// Click to view historical details log and return results(点击查看历史详情日志和返回结果)
async viewHistory(params) {
let sourceJson = params.row.sourceJson
if (typeof sourceJson === 'string') {
try {
sourceJson = JSON.parse(sourceJson)
} catch (error) {
window.console.log(sourceJson)
}
}
let fileName = ''
if (sourceJson && sourceJson.scriptPath) {
fileName = sourceJson.scriptPath.split('/').pop()
}
if (sourceJson && sourceJson.nodeName) {
fileName = sourceJson.nodeName
}
const query = {
taskID: params.row.taskID,
execID: params.row.strongerExecId,
status: params.row.status,
fileName,
engineInstance: params.row.engineInstance,
}
if (this.isAdminModel) {
query.proxyUser = params.row.executeUser
}
storage.set('last-searchbar-status', this.searchBar)
storage.set('last-pageSetting-status', this.pageSetting)
storage.set('last-searchbar-advance', this.showAdvance)
// Jump to view the history details page(跳转查看历史详情页面)
this.$router.push({
path: '/console/viewHistory',
query
})
},
getParams(page) {
const startDate = this.searchBar.shortcut[0] ? new Date(this.searchBar.shortcut[0].setHours(0, 0, 0, 0)) : this.searchBar.shortcut[0]
const endDate = this.searchBar.shortcut[1] ? new Date(this.searchBar.shortcut[1].setHours(23, 59, 59, 0)): this.searchBar.shortcut[1]
const params = {
taskID: this.searchBar.id,
creator: this.searchBar.creator,
executeApplicationName: this.searchBar.engine,
status: this.searchBar.status,
startDate: startDate && startDate.getTime(),
endDate: endDate && endDate.getTime(),
pageNow: page || this.pageSetting.current,
pageSize: this.pageSetting.pageSize,
proxyUser: this.searchBar.proxyUser,
isAdminView: this.isAdminModel,
instance: this.searchBar.instance?.replace(/ /g, '') || ''
}
if (!this.isAdminModel) {
delete params.proxyUser
}
if (this.searchBar.id) {
delete params.creator
delete params.executeApplicationName
delete params.status
delete params.startDate
delete params.endDate
delete params.proxyUser
delete params.instance
} else {
let { engine, status, shortcut } = this.searchBar
if (engine === 'all') {
delete params.executeApplicationName
}
if (status === 'all') {
delete params.status
}
if (!shortcut[0]) {
delete params.startDate
}
if (!shortcut[1]) {
delete params.endDate
}
delete params.taskID
}
return params
},
changePage(page) {
this.isLoading = true
const params = this.getParams(page)
this.column = this.getColumns()
api
.fetch('/jobhistory/list', params, 'get')
.then(rst => {
this.isLoading = false
this.list = this.getList(rst.tasks)
this.pageSetting.current = page
this.pageSetting.total = rst.totalPage
})
.catch(() => {
this.isLoading = false
this.list = []
})
},
search() {
this.isLoading = true
const params = this.getParams()
this.column = this.getColumns()
api
.fetch('/jobhistory/list', params, 'get')
.then(rst => {
this.pageSetting.total = rst.totalPage
this.isLoading = false
this.list = this.getList(rst.tasks)
})
.catch(() => {
this.list = []
this.isLoading = false
})
},
getList(list) {
const getFailedReason = item => {
return item.errCode && item.errDesc
? item.errCode + item.errDesc
: item.errCode || item.errDesc || ''
}
if (!this.isAdminModel) {
return list.map(item => {
return {
disabled: ['Submitted', 'Inited', 'Scheduled', 'Running'].indexOf(item.status) === -1,
taskID: item.taskID,
strongerExecId: item.strongerExecId,
source: item.sourceTailor,
executionCode: item.executionCode,
status: item.status,
costTime: item.costTime,
requestApplicationName: item.requestApplicationName,
executeApplicationName: item.executeApplicationName,
createdTime: item.createdTime,
progress: item.progress,
failedReason: getFailedReason(item),
runType: item.runType,
instance: item.instance,
engineInstance: item.engineInstance,
}
})
}
return list.map(item => {
return Object.assign(item, {
disabled:
['Submitted', 'Inited', 'Scheduled', 'Running'].indexOf(item.status) === -1,
failedReason: getFailedReason(item),
source: item.sourceTailor
})
})
},
checkChange(v) {
this.list = this.list.map(it => {
it.checked = !it.disabled && v
return it
})
},
selectChange() {
this.list = this.list.slice(0)
},
getColumns() {
const column = [
{
title: '',
key: 'checked',
align: 'center',
width: 60,
renderType: 'checkbox'
},
{
title: this.$t('message.linkis.tableColumns.control.title'),
key: 'control',
fixed: 'right',
align: 'center',
width: 60,
renderType: 'button',
renderParams: [
{
label: this.$t('message.linkis.tableColumns.control.label'),
action: this.viewHistory
}
]
},
{
title: this.$t('message.linkis.tableColumns.taskID'),
key: 'taskID',
align: 'center',
width: 90
},
{
title: this.$t('message.linkis.tableColumns.fileName'),
key: 'source',
align: 'center',
ellipsis: true,
width: 170
},
{
title: this.$t('message.linkis.tableColumns.executionCode'),
key: 'executionCode',
align: 'center',
width: 420,
// overflow to show(溢出以...显示)
ellipsis: true
// renderType: 'tooltip',
},
{
title: this.$t('message.linkis.tableColumns.status'),
key: 'status',
align: 'center',
width: 164,
renderType: 'if',
renderParams: {
action: this.setRenderType
}
},
{
title: this.$t('message.linkis.tableColumns.costTime'),
key: 'costTime',
align: 'center',
width: 100,
renderType: 'convertTime'
},
{
title: this.$t('message.linkis.tableColumns.failedReason'),
key: 'failedReason',
align: 'center',
className: 'history-failed',
width: 200,
renderType: 'a',
renderParams: {
hasDoc: this.checkIfHasDoc,
action: this.linkTo
}
},
{
title: this.$t('message.linkis.tableColumns.requestApplicationName') + ' / ' + this.$t('message.linkis.tableColumns.executeApplicationName'),
key: 'requestApplicationName',
align: 'center',
width: 130,
renderType: 'concat',
renderParams: {
concatKey: 'executeApplicationName'
}
},
{
title: this.$t('message.linkis.tableColumns.user'),
key: 'umUser',
align: 'center',
width: 80
},
{
title: this.$t('message.linkis.tableColumns.createdTime'),
key: 'createdTime',
align: 'center',
width: 150,
renderType: 'formatTime'
}
]
if (!this.isAdminModel) {
const index = column.findIndex(item => item.key === 'umUser')
column.splice(index, 1)
}
return column
},
reset() {
this.searchBar = {
id: null,
proxyUser: '',
creator: '',
engine: 'all',
status: 'all',
shortcut: ''
}
},
switchAdmin() {
if (!this.isLoading) {
if (this.isAdminModel) {
this.searchBar.id = null
this.searchBar.proxyUser = ''
}
this.isAdminModel = !this.isAdminModel
this.search()
}
},
linkTo(params) {
this.$router.push({
path: '/console/FAQ',
query: {
errCode: parseInt(params.row.failedReason),
isSkip: true
}
})
},
checkIfHasDoc(params) {
const errCodeList = [11011, 11012, 11013, 11014, 11015, 11016, 11017]
const errCode = parseInt(params.row.failedReason)
if (errCodeList.indexOf(errCode) !== -1) {
return true
}
return false
},
setRenderType(params) {
if (params.row.status === 'Running' && params.row.progress !== 0) {
return {
type: 'Progress',
value: params.row.progress
}
} else {
return {
type: 'Tag',
value: params.row.status
}
}
},
stop() {
const selected = this.list.filter(it => it.checked)
if (!selected.length) {
this.$Message.warning(this.$t('message.linkis.unselect'))
return;
}
this.$Modal.confirm({
title: this.$t('message.linkis.modal.modalTitle'),
content: this.$t('message.linkis.modal.modalDeleteTask'),
onOk: ()=>{
const inst = {}
selected.forEach(it => {
if (inst[it.instance]) {
inst[it.instance].taskIDList.push(it.taskID)
inst[it.instance].idList.push(it.strongerExecId)
} else {
inst[it.instance] = {
taskIDList: [it.taskID],
idList: [it.strongerExecId]
}
}
})
const p = []
Object.keys(inst).forEach(instkey => {
if (instkey) p.push(api.fetch(`/entrance/${inst[instkey].idList[0]}/killJobs`, { idList: inst[instkey].idList, taskIDList: inst[instkey].taskIDList }, 'post'))
})
Promise.all(p).then(()=> {
this.$Message.success(this.$t('message.linkis.udf.success'));
this.search()
})
}
})
}
}
}
</script>
<style src="./index.scss" lang="scss"></style>