first commit
This commit is contained in:
415
orion-ops-vue/src/components/app/AppPipelineExecModal.vue
Normal file
415
orion-ops-vue/src/components/app/AppPipelineExecModal.vue
Normal file
@@ -0,0 +1,415 @@
|
||||
<template>
|
||||
<a-modal v-model="visible"
|
||||
:width="550"
|
||||
:maskStyle="{opacity: 0.8, animation: 'none'}"
|
||||
:dialogStyle="{top: '64px', padding: 0}"
|
||||
:bodyStyle="{padding: '8px'}"
|
||||
:maskClosable="false"
|
||||
:destroyOnClose="true">
|
||||
<!-- 页头 -->
|
||||
<template #title>
|
||||
<span v-if="selectPipelinePage">选择流水线</span>
|
||||
<span v-if="!selectPipelinePage">
|
||||
<a-icon class="mx4 pointer span-blue"
|
||||
title="重新选择"
|
||||
v-if="visibleReselect && id"
|
||||
@click="reselectPipelineList"
|
||||
type="arrow-left"/>
|
||||
执行流水线
|
||||
</span>
|
||||
</template>
|
||||
<!-- 初始化骨架 -->
|
||||
<a-skeleton v-if="initiating" active :paragraph="{rows: 8}"/>
|
||||
<!-- 主体 -->
|
||||
<a-spin v-else :spinning="loading">
|
||||
<!-- 流水线选择 -->
|
||||
<div class="pipeline-list-container" v-if="selectPipelinePage">
|
||||
<!-- 无流水线数据 -->
|
||||
<a-empty v-if="!pipelineList.length" description="请先配置应用流水线"/>
|
||||
<!-- 流水线列表 -->
|
||||
<div class="pipeline-list">
|
||||
<div class="pipeline-item" v-for="pipeline of pipelineList"
|
||||
:key="pipeline.id"
|
||||
@click="choosePipeline(pipeline.id)">
|
||||
<div class="pipeline-name">
|
||||
<a-icon class="mx8" type="code-sandbox"/>
|
||||
{{ pipeline.name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 执行配置 -->
|
||||
<div class="pipeline-container" v-else>
|
||||
<!-- 执行参数 -->
|
||||
<a-form-model v-bind="layout">
|
||||
<!-- 执行标题 -->
|
||||
<a-form-model-item class="exec-form-item" label="执行标题" required>
|
||||
<a-input class="name-input" v-model="submit.title" :maxLength="32" allowClear/>
|
||||
</a-form-model-item>
|
||||
<!-- 执行类型 -->
|
||||
<a-form-model-item class="exec-form-item" label="执行类型" required>
|
||||
<a-radio-group v-model="submit.timedExec" buttonStyle="solid">
|
||||
<a-radio-button :value="type.value" v-for="type in TIMED_TYPE" :key="type.value">
|
||||
{{ type.execLabel }}
|
||||
</a-radio-button>
|
||||
</a-radio-group>
|
||||
</a-form-model-item>
|
||||
<!-- 调度时间 -->
|
||||
<a-form-model-item class="exec-form-item" label="调度时间"
|
||||
v-if="submit.timedExec === TIMED_TYPE.TIMED.value" required>
|
||||
<a-date-picker v-model="submit.timedExecTime" :showTime="true" format="YYYY-MM-DD HH:mm:ss"/>
|
||||
</a-form-model-item>
|
||||
<!-- 执行描述 -->
|
||||
<a-form-model-item class="exec-form-item" label="执行描述">
|
||||
<a-textarea class="description-input" v-model="submit.description" :maxLength="64" allowClear/>
|
||||
</a-form-model-item>
|
||||
</a-form-model>
|
||||
<a-divider class="detail-divider">流水线操作</a-divider>
|
||||
<!-- 执行操作 -->
|
||||
<div class="pipeline-wrapper">
|
||||
<a-timeline>
|
||||
<a-timeline-item v-for="detail of details" :key="detail.id">
|
||||
<div class="pipeline-detail-wrapper">
|
||||
<!-- 操作名称 -->
|
||||
<div class="pipeline-stage-type span-blue">
|
||||
{{ detail.stageType | formatStageType('label') }}
|
||||
</div>
|
||||
<!-- 应用名称 -->
|
||||
<div class="pipeline-app-name">
|
||||
{{ detail.appName }}
|
||||
</div>
|
||||
<!-- 应用操作 -->
|
||||
<div class="pipeline-handler">
|
||||
<span class="pipeline-config-message auto-ellipsis-item"
|
||||
:title="getConfigMessage(detail)"
|
||||
v-text="getConfigMessage(detail)"/>
|
||||
<!-- 设置 -->
|
||||
<a-badge class="pipeline-set-badge" :dot="visibleConfigDot(detail)">
|
||||
<span class="span-blue pointer" title="设置" @click="openSetting(detail)">设置</span>
|
||||
</a-badge>
|
||||
</div>
|
||||
</div>
|
||||
</a-timeline-item>
|
||||
</a-timeline>
|
||||
</div>
|
||||
</div>
|
||||
</a-spin>
|
||||
<!-- 页脚 -->
|
||||
<template #footer>
|
||||
<!-- 关闭 -->
|
||||
<a-button @click="close">关闭</a-button>
|
||||
<!-- 执行 -->
|
||||
<a-button type="primary"
|
||||
:loading="loading"
|
||||
:disabled="selectPipelinePage || loading || initiating"
|
||||
@click="execPipeline">
|
||||
执行
|
||||
</a-button>
|
||||
</template>
|
||||
<!-- 事件 -->
|
||||
<div class="pipeline-event-container">
|
||||
<!-- 构建配置 -->
|
||||
<AppPipelineExecBuildModal ref="buildSetting" @ok="pipelineConfigured"/>
|
||||
<!-- 发布配置 -->
|
||||
<AppPipelineExecReleaseModal ref="releaseSetting" @ok="pipelineConfigured"/>
|
||||
</div>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { enumValueOf, STAGE_TYPE, TIMED_TYPE } from '@/lib/enum'
|
||||
import AppPipelineExecBuildModal from '@/components/app/AppPipelineExecBuildModal'
|
||||
import AppPipelineExecReleaseModal from '@/components/app/AppPipelineExecReleaseModal'
|
||||
|
||||
const layout = {
|
||||
labelCol: { span: 4 },
|
||||
wrapperCol: { span: 18 }
|
||||
}
|
||||
|
||||
export default {
|
||||
name: 'AppPipelineExecModal',
|
||||
components: {
|
||||
AppPipelineExecReleaseModal,
|
||||
AppPipelineExecBuildModal
|
||||
},
|
||||
props: {
|
||||
visibleReselect: Boolean
|
||||
},
|
||||
data: function() {
|
||||
return {
|
||||
TIMED_TYPE,
|
||||
selectPipelinePage: false,
|
||||
id: null,
|
||||
visible: false,
|
||||
initiating: false,
|
||||
loading: false,
|
||||
profileId: null,
|
||||
pipelineList: [],
|
||||
record: {},
|
||||
submit: {
|
||||
title: null,
|
||||
description: null,
|
||||
timedExec: null,
|
||||
timedExecTime: null
|
||||
},
|
||||
details: [],
|
||||
layout
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async openPipelineList(profileId) {
|
||||
this.profileId = profileId
|
||||
this.pipelineList = []
|
||||
this.selectPipelinePage = true
|
||||
this.loading = false
|
||||
this.initiating = true
|
||||
this.visible = true
|
||||
await this.loadPipelineList()
|
||||
this.initiating = false
|
||||
},
|
||||
async openPipeline(profileId, id) {
|
||||
this.profileId = profileId
|
||||
this.pipelineList = []
|
||||
this.cleanPipelineData()
|
||||
this.selectPipelinePage = false
|
||||
this.loading = false
|
||||
this.initiating = true
|
||||
this.visible = true
|
||||
await this.selectPipeline(id)
|
||||
this.initiating = false
|
||||
},
|
||||
async choosePipeline(id) {
|
||||
this.cleanPipelineData()
|
||||
this.selectPipelinePage = false
|
||||
this.loading = true
|
||||
await this.selectPipeline(id)
|
||||
this.loading = false
|
||||
},
|
||||
async loadPipelineList() {
|
||||
const { data: { rows } } = await this.$api.getAppPipelineList({
|
||||
profileId: this.profileId,
|
||||
limit: 10000
|
||||
})
|
||||
this.pipelineList = rows
|
||||
},
|
||||
async selectPipeline(id) {
|
||||
this.id = id
|
||||
await this.$api.getAppPipelineDetail({
|
||||
id
|
||||
}).then(({ data }) => {
|
||||
this.record = data
|
||||
this.details = data.details
|
||||
this.submit.title = `执行${data.name}`
|
||||
})
|
||||
},
|
||||
async reselectPipelineList() {
|
||||
this.selectPipelinePage = true
|
||||
if (this.pipelineList.length) {
|
||||
return
|
||||
}
|
||||
this.initiating = true
|
||||
await this.loadPipelineList()
|
||||
this.initiating = false
|
||||
},
|
||||
cleanPipelineData() {
|
||||
this.record = {}
|
||||
this.details = []
|
||||
this.submit.title = null
|
||||
this.submit.description = null
|
||||
this.submit.timedExec = TIMED_TYPE.NORMAL.value
|
||||
this.submit.timedExecTime = null
|
||||
},
|
||||
visibleConfigDot(detail) {
|
||||
if (detail.stageType === STAGE_TYPE.BUILD.value) {
|
||||
if (detail.repoId) {
|
||||
return !detail.branchName
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
},
|
||||
getConfigMessage(detail) {
|
||||
if (detail.stageType === STAGE_TYPE.BUILD.value) {
|
||||
// 构建
|
||||
if (detail.repoId) {
|
||||
if (detail.branchName) {
|
||||
return `${detail.branchName} ${detail.commitId.substring(0, 7)}`
|
||||
} else {
|
||||
return '请选择构建版本'
|
||||
}
|
||||
} else {
|
||||
return '无需配置'
|
||||
}
|
||||
} else {
|
||||
// 发布
|
||||
if (detail.buildSeq) {
|
||||
return `发布版本: #${detail.buildSeq}`
|
||||
} else {
|
||||
return '发布版本: 最新版本'
|
||||
}
|
||||
}
|
||||
},
|
||||
openSetting(detail) {
|
||||
if (detail.stageType === STAGE_TYPE.BUILD.value) {
|
||||
this.$refs.buildSetting.open(detail)
|
||||
} else {
|
||||
this.$refs.releaseSetting.open(detail)
|
||||
}
|
||||
},
|
||||
pipelineConfigured(detailId, config) {
|
||||
this.details.filter(s => s.id === detailId).forEach((detail) => {
|
||||
for (const configKey in config) {
|
||||
detail[configKey] = config[configKey]
|
||||
}
|
||||
})
|
||||
this.$set(this.details, 0, this.details[0])
|
||||
},
|
||||
execPipeline() {
|
||||
// 检查参数
|
||||
if (!this.submit.title) {
|
||||
this.$message.warning('请输入执行标题')
|
||||
return
|
||||
}
|
||||
if (this.submit.timedExec === TIMED_TYPE.TIMED.value) {
|
||||
if (!this.submit.timedExecTime) {
|
||||
this.$message.warning('请选择调度时间')
|
||||
return
|
||||
}
|
||||
if (this.submit.timedExecTime.unix() * 1000 < Date.now()) {
|
||||
this.$message.warning('调度时间需要大于当前时间')
|
||||
return
|
||||
}
|
||||
} else {
|
||||
this.submit.timedExecTime = undefined
|
||||
}
|
||||
for (const detail of this.details) {
|
||||
if (detail.stageType === STAGE_TYPE.BUILD.value && detail.repoId && !detail.branchName) {
|
||||
this.$message.warning(`请选择 ${detail.appName} 构建版本`)
|
||||
return
|
||||
}
|
||||
}
|
||||
// 封装数据
|
||||
const request = {
|
||||
pipelineId: this.id,
|
||||
...this.submit,
|
||||
details: []
|
||||
}
|
||||
for (const detail of this.details) {
|
||||
request.details.push({
|
||||
id: detail.id,
|
||||
branchName: detail.branchName,
|
||||
commitId: detail.commitId,
|
||||
buildId: detail.buildId,
|
||||
title: detail.title,
|
||||
description: detail.description,
|
||||
machineIdList: detail.machineIdList
|
||||
})
|
||||
}
|
||||
this.loading = true
|
||||
this.$api.submitAppPipelineTask(request).then(() => {
|
||||
this.$message.success('已创建流水线任务')
|
||||
this.$emit('submit')
|
||||
this.visible = false
|
||||
}).catch(() => {
|
||||
this.loading = false
|
||||
})
|
||||
},
|
||||
close() {
|
||||
this.visible = false
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
filters: {
|
||||
formatStageType(type, f) {
|
||||
return enumValueOf(STAGE_TYPE, type)[f]
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
.pipeline-container {
|
||||
padding: 16px 16px 0 16px;
|
||||
}
|
||||
|
||||
.pipeline-list {
|
||||
margin: 0 4px 0 8px;
|
||||
height: 355px;
|
||||
overflow-y: auto;
|
||||
|
||||
.pipeline-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin: 4px;
|
||||
padding: 4px 4px 4px 8px;
|
||||
background: #F8F9FA;
|
||||
border-radius: 4px;
|
||||
height: 40px;
|
||||
cursor: pointer;
|
||||
|
||||
.pipeline-name {
|
||||
width: 300px;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
overflow-x: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
}
|
||||
|
||||
.pipeline-item:hover {
|
||||
background: #E7F5FF;
|
||||
}
|
||||
}
|
||||
|
||||
.exec-form-item {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.detail-divider {
|
||||
margin: 0 0 24px 0;
|
||||
}
|
||||
|
||||
.pipeline-detail-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.pipeline-stage-type {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
.pipeline-app-name {
|
||||
width: 250px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.pipeline-handler {
|
||||
width: 180px;
|
||||
margin-left: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
|
||||
.pipeline-config-message {
|
||||
margin-right: 8px;
|
||||
color: #000000;
|
||||
font-size: 12px;
|
||||
width: 144px;
|
||||
text-align: end;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .pipeline-set-badge .ant-badge-dot {
|
||||
margin: -2px;
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .ant-timeline-item-last {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user