This commit is contained in:
ann 2022-04-27 17:38:25 +08:00
parent 7f09933ff1
commit b27e978ecf
8 changed files with 252 additions and 60 deletions

View File

@ -252,6 +252,13 @@ export function postNamespace(data) {
})
}
export function deleteNamespace(namespace) {
return request({
url: '/virtual/v1/harvester/namespaces/' + namespace,
method: 'delete'
})
}
export function getHostNetwork(name) {
return request({
url: '/virtual/v1/network.harvesterhci.io.nodenetworks/harvester-system/' + name + '-vlan',
@ -281,9 +288,9 @@ export function createImages(data) {
data: data
})
}
export function deleteImage(name) {
export function deleteImage(name, namespace = 'default') {
return request({
url: '/virtual/v1/harvester/harvesterhci.io.virtualmachineimages/default/' + name,
url: `/virtual/v1/harvester/harvesterhci.io.virtualmachineimages/${namespace}/` + name,
method: 'delete'
})
}

View File

@ -164,11 +164,18 @@ const virtualMachineRouter = {
},
{
path: 'create',
component: () => import('@/views/virtualMachine/imagesCreate.vue'),
component: () => import('@/views/virtualMachine/image/edit'),
name: 'imagesCreate',
meta: { activeMenu: '/virtual/images' },
hidden: true
},
{
path: 'edit',
component: () => import('@/views/virtualMachine/image/edit'),
name: 'imagesEdit',
meta: { activeMenu: '/virtual/images' },
hidden: true
},
{
path: 'detail',
component: () => import('@/views/virtualMachine/image/detail'),

View File

@ -423,7 +423,7 @@ const getImagesList = () => {
obj.progress = res.data[item].status?.progress === 100 ? '已完成' : '未完成'
obj.creationTime = res.data[item].metadata.creationTimestamp
obj.aliveTime = res.data[item].metadata.fields[3]
obj.size = Number((res.data[item].status.size / 1024 / 1024).toString().match(/^\d+(?:\.\d{0,2})?/)) + 'MB'
obj.size = Number((res.data[item].status?.size / 1024 / 1024).toString().match(/^\d+(?:\.\d{0,2})?/)) + 'MB'
obj.aliveTime = obj.aliveTime.replace('d', '天')
obj.aliveTime = obj.aliveTime.replace('h', '小时')
obj.aliveTime = obj.aliveTime.replace('m', '分钟')

View File

@ -1,8 +1,8 @@
<template>
<div>
<el-card v-if="!clone">
<el-card>
<el-page-header content="详情" @back="goBack" />
<h2>镜像:{{ $route.query.displayName }} <el-tag type="success">{{ $route.query.state }} </el-tag> <el-dropdown @command="handleDropdown">
<h2>镜像:{{ formData.displayName }} <el-tag type="success">{{ formData.state }} </el-tag> <el-dropdown @command="handleDropdown">
<el-button class-name="el-dropdown-link" size="mini" icon="el-icon-more" circle />
<el-dropdown-menu slot="dropdown">
<el-dropdown-item command="1"> <i class="el-icon-edit" /> 编辑配置 </el-dropdown-item>
@ -13,17 +13,11 @@
<el-dropdown-item command="5"> <i class="el-icon-delete" /> 删除 </el-dropdown-item>
</el-dropdown-menu>
</el-dropdown> </h2>
<h6>存活时间{{ $route.query.aliveTime }}</h6>
<h6>标签 {{ formData.labels }}</h6>
<h6>存活时间{{ formData.aliveTime }}</h6>
<h5>基本信息</h5>
<el-text v-if="formData1.message" type="warning">{{ formData1.message }}</el-text>
<FormData :data="formData1" :data-map="dataMap1" />
</el-card>
<el-card v-if="clone">
<h2>镜像:{{ $route.query.displayName }}克隆</h2>
<el-divider />
<h5>基本信息</h5>
<el-text v-if="formData1.message" type="warning">{{ formData1.message }}</el-text>
<FormData :data="formData1" :data-map="dataMap1" />
<el-text v-if="formData.message" type="warning">{{ formData.message }}</el-text>
<FormData :data="formData" :data-map="dataMap" />
</el-card>
<Yaml v-if="dialogYamlFormVisible" v-model="dialogYamlFormVisible" :name="yamlName" :is-edit="editYaml" :get-yaml="getImagesYaml" :put-yaml="putImagesYaml" />
</div>
@ -47,15 +41,17 @@ export default {
getImagesYaml,
putImagesYaml,
index: '',
enableConfig: false,
clone: false,
formData1: {
formData: {
displayName: '',
state: '',
aliveTime: '',
description: ' ',
size: this.$route.query.size,
resourceType: '',
labels: {},
message: false
},
dataMap1: {
dataMap: {
resourceType: '镜像地址',
size: '大小',
description: '描述'
@ -68,12 +64,8 @@ export default {
}
},
created() {
this.index = this.$route.query.index
},
mounted() {
if (this.$route.query.clone != null && typeof (this.$route.query.clone) !== 'undefined') {
this.clone = this.$route.query.clone
}
this.getFormData()
},
methods: {
@ -82,21 +74,23 @@ export default {
},
getFormData() {
getImages().then(res => {
for (let i = 0; i < res.data.length; i++) {
if (this.$route.query.name.toString() === res.data[i].metadata.name) {
data = res.data[i]
this.index = i
break
}
}
var data = res.data[this.index]
// let message = false
// data.status.conditions.forEach(e => {
// console.log(data.status?.conditions?.message)
// if (data.status.conditions.error) {
// message = data.status?.conditions?.message
// console.log(message)
// }
// })
// console.log(message)
this.formData1 = {
this.formData = {
displayName: data.spec.displayName,
name: data.metadata.name,
state: data.metadata.state.name,
labels: data.metadata.labels,
aliveTime: data.metadata.fields[3].replace('d', '天').replace('h', '小时').replace('m', '分钟'),
description: data.metadata.annotations ? data.metadata.annotations['field.cattle.io/description'] : '-',
size: Number((data.status.size / 1024 / 1024).toString().match(/^\d+(?:\.\d{0,2})?/)) + 'MB',
resourceType: data.spec.url
// message: message
}
})
},

View File

@ -0,0 +1,171 @@
<template>
<el-card v-loading="loading">
<el-page-header :content="$route.query.clone ? '克隆' : $route.query.name ? '编辑' : '创建'" @back="goBack" />
<h2>镜像</h2>
<el-divider />
<div class="formcontainer">
<el-form ref="formData" :rules="rules" :model="formData" label-position="top">
<el-row :gutter="10">
<el-col :span="6">
<el-form-item label="命名空间" prop="namespace">
<el-select v-model="formData.namespace" :hide-required-asterisk="true" class="selectPro" placeholder="请选择命名空间">
<el-option
v-for="item in namespaceList"
:key="item"
:label="item"
:value="item"
>
{{ item }}
</el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="18">
<el-form-item label="名称" prop="name"><el-input
v-model="formData.name"
:hide-required-asterisk="true"
placeholder="请输入名称"
/></el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="描述"><el-input
v-model="formData.description"
:hide-required-asterisk="true"
placeholder="请输入一些内容更好地描述该资源"
/></el-form-item></el-col>
</el-row>
<h6>基本信息</h6>
<el-form-item prop="url"><el-input
v-model="formData.url"
:hide-required-asterisk="true"
placeholder="镜像地址"
/></el-form-item>
<h6>标签</h6>
<el-form-item
v-for="(tag, index) in formData.labels"
:key="'tag'+index"
label=""
>
<el-row :gutter="10">
<el-col :span="10"><el-input v-model.trim="tag.key" placeholder="键" /></el-col>
<el-col :span="10"><el-input v-model="tag.value" placeholder="值" /></el-col>
<el-col :span="4"><el-button icon="el-icon-delete" circle @click.prevent="removeTag(tag,index)" /></el-col>
</el-row>
</el-form-item>
<el-button type="primary" plain round :disabled="addTagNumCheck" @click="addTag">添加标签</el-button>
</el-form>
</div>
<el-row type="flex" justify="end">
<el-col :span="2.5">
<el-button type="info" @click="goBack">取消</el-button>
<el-button type="primary" @click="saveForm">保存</el-button>
</el-col>
</el-row>
</el-card>
</template>
<script>
import { createImages } from '@/api/one-class-page/virtualMachine'
export default {
data() {
return {
isEdit: false,
loading: false,
tagNum: 0,
formData: {
name: '',
description: '',
url: '',
labels: []
},
namespaceList: [],
imagesData: {},
//
rules: {
name: [
{
required: true, //
message: '名称不能为空', //
trigger: 'blur' //
}
],
url: [
{
required: true, //
message: '地址不能为空', //
trigger: 'blur' //
}
]
}
}
},
computed: {
addTagNumCheck() {
let flag = false
this.formData.labels.forEach(e => {
if (e.key === '') {
flag = true
}
})
return flag
}
},
mounted() {
this.isEdit = !!this.$route.query.name
this.$HandleFunc.getAllNamespace().then(e => {
this.namespaceList = e.rows.map(e => e.name)
})
},
methods: {
goBack() {
this.$router.push({ path: '/virtual/images' })
},
addTag() {
this.formData.labels.push({ key: '', value: '' })
},
removeTag(tag, index) {
this.formData.labels.splice(index, 1)
},
saveForm() {
this.$refs['formData'].validate((valid) => {
if (valid) {
const labels = {}
this.formData.labels.forEach(e => {
labels[e.key] = e.value
})
const data = {
type: 'harvesterhci.io.virtualmachineimage',
metadata: {
annotations: {
'field.cattle.io/description': this.formData.description
},
labels: labels,
'namespace': this.formData.namespace,
'generateName': 'image-'
},
spec: {
'sourceType': 'download',
'displayName': this.formData.name,
'url': this.formData.url
}
}
createImages(data).then(res => {
this.$message.success('创建成功')
this.goBack()
})
} else {
console.log('error submit!!')
return false
}
})
}
}
}
</script>
<style scoped>
.formcontainer{
margin-bottom: 10px;
}
</style>

View File

@ -107,7 +107,7 @@ export default {
},
methods: {
viewImagesDetail(row) {
this.$router.push({ path: `images/detail`, query: row })
this.$router.push({ path: `images/detail`, query: { name: row.name }})
},
creation() {
this.$router.push({ path: `images/create` })
@ -120,7 +120,7 @@ export default {
switch (command) {
case 1:
row.disableConfig = false
this.$router.push({ path: `images/detail/config`, query: row })
this.$router.push({ path: `images/edit`, query: row })
break
case 2:
row.clone = true

View File

@ -1,14 +1,14 @@
<template>
<div>
<el-card class="basicInfo">
<el-page-header content="详情" @back="goBack" />
<el-card v-loading="loading" class="basicInfo">
<el-page-header :content="$route.query.clone ? '克隆' : $route.query.name ? '编辑' : '创建'" @back="goBack" />
<el-form ref="formData" :rules="rules" :model="formData">
<el-row :gutter="10">
<el-col :span="12">
<el-form-item label="名称" prop="name"><el-input
v-model="formData.name"
placeholder="请输入名称"
:disabled="isEdit"
:disabled="isEdit&&!$route.query.clone"
:hide-required-asterisk="true"
/></el-form-item>
</el-col>
@ -49,20 +49,22 @@
</el-form>
<el-row>
<el-col :span="20"><div class="grid-content" /></el-col>
<el-col :span="4"><div class="button"><el-button type="primary" @click="saveForm()">保存</el-button><el-button type="primary">取消</el-button></div></el-col>
<el-col :span="4"><div class="button"><el-button type="primary" @click="saveForm()">保存</el-button><el-button type="primary" @click="goBack">取消</el-button></div></el-col>
</el-row>
</el-card>
</div>
</template>
<script>
import { getNamespaceYaml, postNamespace, putNamespace } from '@/api/one-class-page/virtualMachine'
import { getNamespaceYaml, postNamespace, putNamespaceYaml } from '@/api/one-class-page/virtualMachine'
import { set, get, pull } from 'lodash'
export default {
data() {
return {
isEdit: false,
loading: false,
orginFormData: {},
formData: {
name: '',
description: '',
@ -104,11 +106,14 @@ export default {
mounted() {
this.isEdit = !!this.$route.query.name
if (this.isEdit) {
this.loading = true
getNamespaceYaml(this.$route.query.name).then(res => {
this.formData.name = get(res, 'metadata.name')
this.formData.description = get(res, 'metadata.annotations')['field.cattle.io/description']
this.orginFormData = res
this.loading = false
this.formData.name = this.$route.query.clone ? '' : get(res, 'metadata.name')
this.formData.description = get(res, 'metadata.annotations') ? get(res, 'metadata.annotations')['field.cattle.io/description'] : ''
this.formData.labels = Object.keys(get(res, 'metadata.labels')).map(e => ({ key: e, value: res.metadata.labels[e] }))
this.formData.annotations = pull(Object.keys(get(res, 'metadata.annotations')), 'field.cattle.io/description').map(e => ({ key: e, value: res.metadata.annotations[e] }))
this.formData.annotations = get(res, 'metadata.annotations') ? pull(Object.keys(get(res, 'metadata.annotations')), 'field.cattle.io/description').map(e => ({ key: e, value: res.metadata.annotations[e] })) : []
})
}
},
@ -139,7 +144,7 @@ export default {
})
let data
if (this.isEdit) {
if (!this.isEdit || this.$route.query.clone) {
data = {
type: 'namespace',
disableOpenApiValidation: false
@ -151,7 +156,10 @@ export default {
set(data, 'metadata.name', this.formData.name)
set(data, 'metadata.labels', labels)
this.isEdit ? putNamespace(data) : postNamespace(data).then(res => {
this.isEdit && !this.$route.query.clone ? putNamespaceYaml(this.formData.name, data).then(res => {
this.$message.success('修改成功!')
this.goBack()
}) : postNamespace(data).then(res => {
this.$message.success('创建成功!')
this.goBack()
})

View File

@ -20,8 +20,9 @@
<script>
import List from '@/components/list'
import { getNamespaceYaml, putNamespaceYaml } from '@/api/one-class-page/virtualMachine'
import { getNamespaceYaml, putNamespaceYaml, deleteNamespace } from '@/api/one-class-page/virtualMachine'
import yaml from '@/mixin/yaml'
import { newEval } from '@/utils'
export default {
components: { List },
@ -32,14 +33,6 @@ export default {
return {
getNamespaceYaml,
putNamespaceYaml,
timeInterval: 1000,
clickrow: '',
disabled: false,
deleteDialogVisible: false,
dialogFormVisible: false,
yamlName: '',
yamlNamespace: '',
editYaml: false,
columns: [
{ prop: 'state', label: '状态', formatter: (row) => { return <el-tag type={row.state === 'NotReady' ? 'warning' : 'info'}>{row.phase}</el-tag> } },
{ prop: 'name', label: '名称' },
@ -72,13 +65,13 @@ export default {
this.$router.push({ path: `namespace/create` })
},
clickOption(row, command) {
const pattern = newEval('/' + row.name + '/')
switch (command) {
case 1:
this.$router.push({ path: `namespace/edit`, query: { name: row.name }})
this.loading()
break
case 2:
this.$router.push({ path: `dataVolume/edit`, query: { name: row.name }})
this.$router.push({ path: `namespace/edit`, query: { name: row.name, clone: true }})
break
case 6:
this.viewYamlFunc(row.name, row.namespace)
@ -90,8 +83,20 @@ export default {
this.downloadYamlFunc(row.name, getNamespaceYaml, row.namespace)
break
case 5:
this.deleteDialogVisible = true
this.clickrow = row
this.$prompt(`您在尝试删除 命名空间 ${row.name}.`, `${row.name}删除确认?`, {
confirmButtonText: '确定',
cancelButtonText: '取消',
inputPattern: pattern,
inputErrorMessage: '不匹配'
}).then(() => {
//
deleteNamespace(row.name).then(res => {
this.$message.success('删除成功')
this.$refs.multipleTable.getList()
setTimeout(() => this.$refs.multipleTable.getList(), 8000)
})
}).catch(() => {
})
break
default:
}