blob: fe4d397fcaa2f954ae0967bd8946e54a7d5f3246 [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="we-steps">
<Row class="we-steps-row-first">
<Col
span="2"
class="we-steps-title"
>{{ $t('message.common.steps.title') + ':'}}</Col>
<Col
span="22"
class="we-steps-child-col"
>
<div
class="we-steps-child"
v-for="(child, index) in renderList"
:key="index">
<span class="we-steps-child-wrapper">
<span
class="we-steps-circle"
:class="getClasses(child)"
v-if="!child.isFinish">
</span>
<Icon
v-else
size="25"
:color="getIconColor(child, index)"
:type="getIconType(child)"></Icon>
<Tooltip
placement="right"
theme="light"
v-if="child.value==='FailedToGetResult'">
<span
style="cursor: pointer;"
class="we-steps-label"
:class="getClasses(child)">{{ child.label }}</span>
<div
slot="content"
style="padding: 6px 10px;">
<p style="font-weight: bold;line-height: 24px;">{{ $t('message.common.detail') }}</p>
<p
v-for="(p, index1) in hoverList"
:key="index1"
:style="{'color': p.includes('失败') ? 'red' : '#67c23a'}"
style="line-height: 24px;">{{ p }}</p>
</div>
</Tooltip>
<span
class="we-steps-label"
:class="getClasses(child)"
v-else>{{ child.label }}</span>
</span>
<Icon
:color="getArrowColor(child, index)"
type="md-arrow-round-forward"
size="26"
v-if="index !== renderList.length - 1 && child.isFinish"/>
</div>
</Col>
</Row>
</div>
</template>
<script>
import { cloneDeep } from 'lodash';
export default {
props: {
stepList: {
type: Array,
default: () => [],
},
},
data() {
return {
// completed is the completed state, no other state will be generated after the completed state;(completed 是完成状态,完成状态后不会有其他状态产生;)
// special is the derived state of the result set, which is used to determine which of the three steps of the result set has an error;(special 是结果集衍生状态,用于判断结果集三个步骤中哪个步骤发生错误;)
// failure is the error state, used to mark errors, highlighted in red(failure 是错误状态,用于标记错误,红色高亮)
// retry is a retry state, which needs to be preceded by two states: application resource failure or execution failure(retry 是重试状态,需要在前面追加申请资源失败或执行失败两个状态)
stepsInfo: [
{ label: this.$t('message.common.steps.stepsInfo.Submitted'), value: 'Submitted', status: ['running'], isFinish: false },
// websocket does not return Inited, so the first received execute interface is used as Inited(websocket不返回Inited,所以把第一个接收的execute接口作为Inited)
// This is to prevent the front desk from actively requesting the Inited state when the http method is requested, or when the state has not been returned for a long time.(这里是为了防止http方式去请求时,或者长时间未返回状态时,前台去主动请求到Inited状态的情况)
{ label: this.$t('message.common.steps.stepsInfo.Inited'), value: 'Inited', status: ['running'], isFinish: false },
{ label: '...', value: 'ellipsis', status: ['running'], isFinish: false },
{ label: this.$t('message.common.steps.stepsInfo.Scheduled'), value: 'Scheduled', status: ['running'], isFinish: false },
{ label: this.$t('message.common.steps.stepsInfo.Running'), value: 'Running', status: ['running'], isFinish: false },
{ label: this.$t('message.common.steps.stepsInfo.Succeed'), value: 'Succeed', status: ['running'], isFinish: false },
{ label: this.$t('message.common.steps.stepsInfo.ResultLoading'), value: 'ResultLoading', status: ['running'], isFinish: false },
{ label: this.$t('message.common.steps.stepsInfo.Completed'), value: 'Completed', status: ['completed'], isFinish: false },
{ label: this.$t('message.common.steps.stepsInfo.Failed'), value: 'Failed', status: ['completed', 'failure'], isFinish: false },
{ label: this.$t('message.common.steps.stepsInfo.Cancelled'), value: 'Cancelled', status: ['completed', 'warning'], isFinish: false },
{ label: this.$t('message.common.steps.stepsInfo.FailedToGetResult'), value: 'FailedToGetResult', status: ['completed', 'failure'], isFinish: true },
{ label: this.$t('message.common.steps.stepsInfo.FailedToGetResultPath'), value: 'FailedToGetResultPath', status: ['special'], step: 1 },
{ label: this.$t('message.common.steps.stepsInfo.FailedToGetResultList'), value: 'FailedToGetResultList', status: ['special'], step: 2 },
{ label: this.$t('message.common.steps.stepsInfo.FailedToGetResultFirst'), value: 'FailedToGetResultFirst', status: ['special'], step: 3 },
{ label: this.$t('message.common.steps.stepsInfo.WaitForRetry'), value: 'WaitForRetry', status: ['retry'], isFinish: false },
{ label: this.$t('message.common.steps.stepsInfo.FailedToApply'), value: 'FailedToApply', status: ['failure'], isFinish: true },
{ label: this.$t('message.common.steps.stepsInfo.FailedToExecute'), value: 'FailedToExecute', status: ['failure'], isFinish: true }
],
renderList: [],
hoverList: [],
};
},
watch: {
stepList: {
handler() {
this.renderSteps();
},
deep: true,
},
},
mounted() {
this.renderSteps();
},
methods: {
renderSteps() {
this.stepListData = [ ...this.stepList ]
this.renderList = [];
const IS_FINISH = { isFinish: true };
const IS_LOADING = { isLoading: false };
const RETRY_STATUS = 'WaitForRetry';
const FAILED_TO_GET_RESULT_STATUS = 'FailedToGetResult';
const SCHEDULED_STATUS = 'Scheduled';
const stepsInfoValue = this.stepsInfo.map(item => item.value)
if(this.stepListData && this.stepListData.toString() && this.stepListData[0] !== 'Submitted' && this.stepListData[0] !== 'ellipsis') {
let index = this.stepsInfo.findIndex((i) => i.value === this.stepListData[0]);
let list = stepsInfoValue.slice(0, index + 1);
if(!this.stepListData.includes(SCHEDULED_STATUS)) list.splice(2, 1)
this.stepListData = list
}
this.stepListData.forEach((status, index) => {
// It is necessary to put each step is not an address reference, otherwise there will be a state error of isFinish(要放每个步骤都不是地址引用,否则会出现isFinish这个状态错误)
const step = cloneDeep(this.findStep(status));
if (step) {
// If it is a special state, set the list of hovers, and display their parent state when rendering: FailedToGetResult(如果是特殊态的情况,要设置hover的列表,渲染的时候要显示它们的父状态:FailedToGetResult)
if (step.status.indexOf('special') !== -1) {
const FailedToGetResult = this.findStep(FAILED_TO_GET_RESULT_STATUS);
this.renderList.push(FailedToGetResult);
this.setHoverList(step);
// If it is a retry state, insert the failed state before(如果是重试态,则要在之前插入失败的状态)
} else if (step.value === RETRY_STATUS) {
const prevOne = this.stepListData[index - 1];
const completionValue = prevOne === SCHEDULED_STATUS ? 'FailedToApply' : 'FailedToExecute';
const completion = this.findStep(completionValue);
this.renderList.push(completion);
this.renderList.push(Object.assign(step, IS_FINISH, IS_LOADING));
} else {
this.renderList.push(Object.assign(step, IS_FINISH, IS_LOADING));
}
// last state(最后一个状态)
if (index === this.stepListData.length - 1) {
// If it belongs to the running state, insert its next state at the end(如果属于运行态,就在最后插入它的下一个状态)
if (step.status.indexOf('running') !== -1) {
step.isLoading = true;
const findIndex = this.stepsInfo.findIndex((i) => i.value === status);
if (findIndex !== -1) {
this.renderList.push(this.stepsInfo[findIndex + 1]);
}
// If it is a retry state, insert this state in the "resource application" later(如果是重试态,就在后面插入“资源申请”中这个状态)
} else if (step.value === RETRY_STATUS) {
step.isLoading = true;
const scheduled = this.findStep(SCHEDULED_STATUS);
this.renderList.push(scheduled);
}
}
}
});
},
findStep(arg) {
return this.stepsInfo.find((i) => i.value === arg);
},
setHoverList(item) {
switch (item.step) {
case 1:
this.hoverList = [`1.${item.label}`];
break;
case 2:
this.hoverList = [this.$t('message.common.steps.hoverList.first'), `2.${item.label}`];
break;
case 3:
this.hoverList = [this.$t('message.common.steps.hoverList.first'), this.$t('message.common.steps.hoverList.second'), `3.${item.label}`];
break;
}
},
getArrowColor(child, index) {
const nextOne = this.renderList[index + 1];
return this.getIconColor(nextOne);
},
getIconColor(child) {
const COMPLETED_COLOR = '#67c23a';
const ERROR_COLOR = '#ed4014';
const CALCELLED_COLOR = '#ddd';
const UN_FINISHED_COLOR = 'orange';
if (child.status.indexOf('failure') !== -1) {
return ERROR_COLOR;
} else if (child.status.indexOf('warning') !== -1) {
return CALCELLED_COLOR;
} else if (child.isFinish && !child.isLoading) {
return COMPLETED_COLOR;
}
return UN_FINISHED_COLOR;
},
getIconType(child) {
const FINISHED = 'md-checkmark-circle';
const FAILED = 'md-close-circle';
const WARNING = 'md-alert';
const LOADING = 'ios-navigate';
if (child.status.indexOf('failure') !== -1) {
return FAILED;
} else if (child.status.indexOf('warning') !== -1) {
return WARNING;
} else if (child.isFinish && child.isLoading) {
return LOADING;
}
return FINISHED;
},
getClasses(child) {
let className = '';
if (child.label === '...') {
className = 'ellipsis '
}
if (child.status.indexOf('failure') !== -1) {
className += 'error';
} else if (child.status.indexOf('warning') !== -1) {
className += 'cancelled';
} else if (child.isFinish && !child.isLoading) {
className += 'completed';
} else if (child.isFinish && child.isLoading) {
className += 'loading';
}
return className;
},
},
};
</script>
<style lang="scss" scoped>
@import '@/common/style/variables.scss';
.we-steps {
.we-steps-row-first {
width: 100%;
padding: 20px 0 10px;
display: flex;
align-items: center;
.we-steps-title {
text-align: center;
color: $title-color;
}
.we-steps-child-col {
height: 50px;
display: inline-flex;
justify-content: flex-start;
align-items: center;
.we-steps-child {
display: flex;
align-items: center;
.we-steps-child-wrapper {
display: inline-flex;
flex-direction: column;
align-items: center;
padding: 0 8px;
.we-steps-circle {
width: 20px;
height: 20px;
border-radius: 10px;
display: inline-block;
background: $subsidiary-color;
text-align: center;
.we-steps-circle-checkmark {
color: $body-background;
}
&.loading {
background: orange;
}
&.completed {
background: #67c23a;
}
&.error {
background: #ed4014;
}
&.cancelled {
background: #ddd
}
}
.we-steps-label {
display: inline-block;
margin-top: 6px;
&.ellipsis {
font-weight: bold;
font-size: 19px;
display: inline-block;
line-height: 17px;
height: 17px;
}
&.loading {
color: orange;
}
&.completed {
color: #67c23a;
}
&.error {
color: #ed4014;
}
&.cancelled {
color: $pink-color
}
}
}
}
}
}
}
</style>