Skip to content

Commit 281cf28

Browse files
committed
feat: 实现远程部署推送、接收、应用功能;
1 parent 6327f52 commit 281cf28

File tree

8 files changed

+927
-23
lines changed

8 files changed

+927
-23
lines changed
+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import request from '@/utils/request'
2+
import axios from 'axios'
3+
/**
4+
* 创建部署令牌
5+
* @param {string[]} permissions 令牌权限: "policy" , "function"
6+
* @param {number} expire 过期时间,单位是小时
7+
* @param {string} source 标识部署来源名称
8+
* @returns
9+
*/
10+
export function createDeployToken({ permissions, expire, source }) {
11+
return request({
12+
url: '/deploy/create-token',
13+
method: 'post',
14+
data: {
15+
permissions,
16+
expire,
17+
source
18+
}
19+
})
20+
}
21+
22+
/**
23+
* 部署访问策略
24+
*/
25+
export async function deploy2remote(deploy_url, deploy_token, { policies, functions, comment }) {
26+
const _data = {
27+
deploy_token,
28+
policies: policies,
29+
functions: functions,
30+
comment
31+
}
32+
const res = await axios.post(deploy_url, _data)
33+
return res.data
34+
}
35+
36+
/**
37+
* 应用部署请求
38+
* @param {string} id 部署请求的 id
39+
* @returns
40+
*/
41+
export function applyDeployRequest(id) {
42+
return request({
43+
url: '/deploy/apply',
44+
method: 'post',
45+
data: {
46+
id
47+
}
48+
})
49+
}

packages/devops-admin/src/router/async.js

+34-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export const asyncRoutes = [
1010
component: Layout,
1111
redirect: '/development/functions',
1212
meta: {
13-
title: '开发控制台', icon: 'guide'
13+
title: '开发控制台', icon: 'example'
1414
},
1515
children: [
1616
{
@@ -138,6 +138,39 @@ export const asyncRoutes = [
138138
}
139139
]
140140
},
141+
{
142+
path: '/deploy',
143+
component: Layout,
144+
redirect: '/deploy/target',
145+
meta: {
146+
title: '远程部署', icon: 'guide'
147+
},
148+
children: [
149+
{
150+
path: 'targets',
151+
component: () => import('@/views/deploy/targets'),
152+
name: 'DeployTargetsListPage',
153+
meta: {
154+
title: '目标环境',
155+
icon: 'international',
156+
noCache: true
157+
// permissions: ['admin.read']
158+
}
159+
},
160+
{
161+
path: 'requests',
162+
component: () => import('@/views/deploy/requests'),
163+
name: 'DeployRequestsListPage',
164+
meta: {
165+
title: '部署请求',
166+
icon: 'skill',
167+
noCache: true
168+
169+
// permissions: ['role.edit', 'role.create']
170+
}
171+
}
172+
]
173+
},
141174
// 404 page must be placed at the end !!!
142175
{ path: '*', redirect: '/404', hidden: true }
143176
]

packages/devops-admin/src/views/database/policies.vue

+12-5
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,15 @@
99
class="filter-item"
1010
@keyup.enter.native="handleFilter"
1111
/>
12-
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="handleFilter">
12+
<el-button class="filter-item" type="default" icon="el-icon-search" @click="handleFilter">
1313
搜索
1414
</el-button>
15-
<el-button class="filter-item" type="primary" icon="el-icon-search" @click="showCreateForm">
15+
<el-button class="filter-item" type="default" icon="el-icon-search" @click="showCreateForm">
1616
新建
1717
</el-button>
18+
<el-button plain class="filter-item" type="primary" icon="el-icon-guide" @click="deployPanelVisible = true">
19+
远程部署
20+
</el-button>
1821
</div>
1922

2023
<!-- 表格 -->
@@ -126,12 +129,16 @@
126129
</el-button>
127130
</div>
128131
</el-dialog>
132+
133+
<!-- 部署面板 -->
134+
<DeployPanel v-model="deployPanelVisible" :policies="list" />
129135
</div>
130136
</template>
131137

132138
<script>
133139
import Pagination from '@/components/Pagination' // secondary package based on el-pagination
134140
import { db } from '../../api/cloud'
141+
import DeployPanel from '../deploy/components/deploy-panel.vue'
135142
136143
// 默认化创建表单的值
137144
function getDefaultFormValue() {
@@ -147,7 +154,6 @@ function getDefaultFormValue() {
147154
}
148155
}
149156
150-
// @TODO
151157
// 表单验证规则
152158
const formRules = {
153159
name: [{ required: true, message: '标识不可为空', trigger: 'blur' }],
@@ -156,7 +162,7 @@ const formRules = {
156162
157163
export default {
158164
name: 'PoliciesListPage',
159-
components: { Pagination },
165+
components: { Pagination, DeployPanel },
160166
filters: {
161167
statusFilter(status) {
162168
status = status ?? 0
@@ -188,7 +194,8 @@ export default {
188194
},
189195
rules: formRules,
190196
downloadLoading: false,
191-
functions: []
197+
functions: [],
198+
deployPanelVisible: false
192199
}
193200
},
194201
created() {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
<template>
2+
<div class="deploy-comp">
3+
<el-drawer
4+
title="部署面板"
5+
:visible="visible"
6+
direction="rtl"
7+
size="30%"
8+
:destroy-on-close="true"
9+
:show-close="true"
10+
:wrapper-closable="true"
11+
@close="onClose"
12+
>
13+
<div class="panel">
14+
<el-form ref="dataForm" :model="form" :rules="formRules" label-width="140px" :inline="false" size="normal">
15+
<el-form-item label="目标环境" prop="target">
16+
<el-select v-model="form.target" placeholder="请选择环境" filterable>
17+
<el-option
18+
v-for="item in targets"
19+
:key="item._id"
20+
:label="item.label"
21+
:value="item"
22+
/>
23+
</el-select>
24+
</el-form-item>
25+
<el-form-item v-if="policies && policies.length" label="部署策略" size="normal">
26+
<el-tag v-for="po in policies" :key="po._id" type="warning" size="medium" effect="dark" style="margin-right: 10px">
27+
{{ po.name }}
28+
</el-tag>
29+
</el-form-item>
30+
<el-form-item v-if="functions && functions.length" label="部署函数" size="normal">
31+
<el-tag v-for="func in functions" :key="func._id" type="default" size="mini" style="margin-right: 10px;">
32+
{{ func.name }} - {{ func.label }}
33+
</el-tag>
34+
</el-form-item>
35+
<el-form-item label="部署说明" prop="comment">
36+
<el-input
37+
v-model="form.comment"
38+
:autosize="{ minRows: 3, maxRows: 6}"
39+
type="textarea"
40+
placeholder="请说明本次部署修改了哪些信息"
41+
/>
42+
</el-form-item>
43+
44+
<el-form-item>
45+
<el-button size="small">取消</el-button>
46+
<el-button type="danger" plain size="small" @click="deploy">推送</el-button>
47+
</el-form-item>
48+
</el-form>
49+
</div>
50+
</el-drawer>
51+
52+
</div>
53+
</template>
54+
<script>
55+
import { db } from '@/api/cloud'
56+
import { deploy2remote } from '@/api/deploy'
57+
58+
// 表单验证规则
59+
const formRules = {
60+
target: [{ required: true, message: '目标环境不可为空', trigger: 'blur' }],
61+
comment: [{ required: true, message: '部署说明不可为空', trigger: 'blur' }]
62+
}
63+
64+
export default {
65+
name: 'DeployPanel',
66+
props: {
67+
value: {
68+
type: Boolean,
69+
default: false
70+
},
71+
policies: {
72+
type: Array,
73+
default: null
74+
},
75+
functions: {
76+
type: Array,
77+
default: null
78+
}
79+
},
80+
data() {
81+
return {
82+
form: this.defaultForm(),
83+
// 部署目标
84+
targets: [],
85+
formRules
86+
}
87+
},
88+
computed: {
89+
visible() {
90+
return this.value
91+
}
92+
},
93+
async mounted() {
94+
const r = await db.collection('deploy_targets').get()
95+
if (!r.ok) throw new Error('get targets failed')
96+
97+
this.targets = r.data
98+
},
99+
methods: {
100+
deploy() {
101+
this.$refs['dataForm'].validate(async(valid) => {
102+
if (!valid) { return }
103+
const data = {
104+
policies: this.policies,
105+
functions: this.functions,
106+
comment: this.form.comment
107+
}
108+
const target = this.form.target
109+
const r = await deploy2remote(target.url, target.token, data)
110+
if (r.code === 0) {
111+
this.$message.success('操作成功!')
112+
}
113+
})
114+
},
115+
defaultForm() {
116+
return {
117+
target: null,
118+
comment: ''
119+
}
120+
},
121+
onClose() {
122+
this.$emit('input', false)
123+
}
124+
}
125+
}
126+
</script>
127+
128+
<style scoped>
129+
.deploy-comp {
130+
131+
}
132+
</style>

0 commit comments

Comments
 (0)