forked from JointCloud/JCC-RIP
merge from primary branch
This commit is contained in:
parent
cdb24ade09
commit
2316e37d83
|
@ -3,6 +3,6 @@ ENV = 'production'
|
|||
|
||||
# base api
|
||||
VUE_APP_BASE_API = 'prod-api'
|
||||
VUE_APP_FUNCTION_API = 'api'
|
||||
VUE_APP_FUNCTION_API = 'apis/v1'
|
||||
VUE_APP_PUBLIC_SOURCE_API = '/monitor'
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ export function putHostYaml(name, yaml) {
|
|||
// 虚拟机管理-虚拟机列表
|
||||
export function getVirtualMachines() {
|
||||
return request({
|
||||
url: '/virtual/v1/kubevirt.io.virtualmachine',
|
||||
url: '/virtual/v1/harvester/kubevirt.io.virtualmachines',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
@ -223,6 +223,13 @@ export function deleteImage(name) {
|
|||
method: 'delete'
|
||||
})
|
||||
}
|
||||
export function editImage(name, data) {
|
||||
return request({
|
||||
url: '/virtual/v1/harvester/harvesterhci.io.virtualmachineimages/default/' + name,
|
||||
method: 'put',
|
||||
data: data
|
||||
})
|
||||
}
|
||||
export function getImagesYaml(name) {
|
||||
return request({
|
||||
url: '/virtual/apis/harvesterhci.io/v1beta1/namespaces/default/virtualmachineimages/' + name,
|
||||
|
@ -293,7 +300,7 @@ export function createVirtualMachine(data) {
|
|||
|
||||
export function virtualMachineACtion(name, action) {
|
||||
return request({
|
||||
url: '/virtual/v1/kubevirt.io.virtualmachines/default/' + name + '?action=' + action,
|
||||
url: '/virtual/v1/harvester/kubevirt.io.virtualmachines/default/' + name + '?action=' + action,
|
||||
method: 'post',
|
||||
data: {}
|
||||
})
|
||||
|
@ -317,14 +324,14 @@ export function getVirtualNode() {
|
|||
|
||||
export function moveVirtualNode(id, data) {
|
||||
return request({
|
||||
url: `/virtual/v1/kubevirt.io.virtualmachines/default/${id}?action=migrate`,
|
||||
url: `/virtual/v1/harvester/kubevirt.io.virtualmachines/default/${id}?action=migrate`,
|
||||
method: 'Post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function deleteVirtualMachine(name, data) {
|
||||
var newUrl = '/virtual/v1/kubevirt.io.virtualmachines/default/' + name + '?'
|
||||
var newUrl = '/virtual/v1/harvester/kubevirt.io.virtualmachines/default/' + name + '?'
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
newUrl += 'removedDisks=' + data[i] + '&'
|
||||
}
|
||||
|
|
|
@ -223,6 +223,30 @@ export default {
|
|||
})
|
||||
},
|
||||
|
||||
// http://119.45.100.73:30880/api/v1/namespaces/jh-test1/configmaps
|
||||
// http://119.45.100.73:30880/api/v1/namespaces/jh-test1/secrets
|
||||
// 获取配置文件列表
|
||||
getConfigmapList(clusterName, namespaces) {
|
||||
return request({
|
||||
url: process.env.VUE_APP_BASE_API + `/api${clusterName}/v1/namespaces/${namespaces}/configmaps`,
|
||||
method: 'get',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 获取密钥列表
|
||||
getSecretList(clusterName, namespaces) {
|
||||
return request({
|
||||
url: process.env.VUE_APP_BASE_API + `/api${clusterName}/v1/namespaces/${namespaces}/secrets`,
|
||||
method: 'get',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
},
|
||||
|
||||
// 工作负载提交前check
|
||||
getWorkloadCheck(clusterName, namespaces, type, name) {
|
||||
// http://10.105.20.3:30880/apis/clusters/fedjcce-ten002/apps/v1/namespaces/test-zhangjie/deployments?labelSelector=app%3Dasd
|
||||
|
@ -371,34 +395,40 @@ export default {
|
|||
})
|
||||
},
|
||||
// 函数
|
||||
checkFunctionName(functionName) {
|
||||
return request({
|
||||
url: process.env.VUE_APP_FUNCTION_API + `/jcc-faas-manager/function/exist/${functionName}`,
|
||||
method: 'get'
|
||||
})
|
||||
},
|
||||
createFunction(query) {
|
||||
return request({
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/function/createFunction',
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/jcc-faas-manager/function/createFunction',
|
||||
method: 'post',
|
||||
data: query
|
||||
})
|
||||
},
|
||||
deleteFunctionByName() {
|
||||
return request({
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/function/delete/functionByName',
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/jcc-faas-manager/function/delete/functionByName',
|
||||
method: 'delete'
|
||||
})
|
||||
},
|
||||
deleteFunction(functionId) {
|
||||
return request({
|
||||
url: process.env.VUE_APP_FUNCTION_API + `/function/deleteFunction/${functionId}`,
|
||||
url: process.env.VUE_APP_FUNCTION_API + `/jcc-faas-manager/function/deleteFunction/${functionId}`,
|
||||
method: 'delete'
|
||||
})
|
||||
},
|
||||
getFunctionByFunctionName() {
|
||||
return request({
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/function/delete/functionByName',
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/jcc-faas-manager/function/delete/functionByName',
|
||||
method: 'get'
|
||||
})
|
||||
},
|
||||
invokeFunction(params, query) {
|
||||
return request({
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/function/invokeFunction',
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/jcc-faas-manager/function/invokeFunction',
|
||||
method: 'post',
|
||||
params: params,
|
||||
data: query
|
||||
|
@ -406,7 +436,7 @@ export default {
|
|||
},
|
||||
listFunctions(query) {
|
||||
return request({
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/function/lists',
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/jcc-faas-manager/function/lists',
|
||||
method: 'get',
|
||||
params: query || { page: 1, size: 10 }
|
||||
})
|
||||
|
@ -419,41 +449,41 @@ export default {
|
|||
// },
|
||||
getFunctionOverview() {
|
||||
return request({
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/function/selectFunctionOverview',
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/jcc-faas-manager/function/selectFunctionOverview',
|
||||
method: 'get'
|
||||
})
|
||||
},
|
||||
getFunctionMap() {
|
||||
return request({
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/function/selectFunctionList',
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/jcc-faas-manager/function/selectFunctionList',
|
||||
method: 'get'
|
||||
})
|
||||
},
|
||||
// 大屏总营收接口
|
||||
getRevenue() {
|
||||
return request({
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/queryRevenue',
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/jcc-mall/order/queryRevenue',
|
||||
method: 'get'
|
||||
})
|
||||
},
|
||||
// 大屏地球查询
|
||||
getMapArea() {
|
||||
return request({
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/function/device/queryByArea',
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/jcc-faas-manager/function/device/queryByArea',
|
||||
method: 'get'
|
||||
})
|
||||
},
|
||||
// 大屏云厂商服务器数量查询接口
|
||||
getCloudServerCount() {
|
||||
return request({
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/function/device/queryByManufacturer',
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/jcc-faas-manager/function/device/queryByManufacturer',
|
||||
method: 'get'
|
||||
})
|
||||
},
|
||||
// 大屏服务器数量统计接口
|
||||
getServerDeviceCount() {
|
||||
return request({
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/function/device/queryDeviceCount',
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/jcc-faas-manager/function/device/queryDeviceCount',
|
||||
method: 'get'
|
||||
})
|
||||
},
|
||||
|
@ -461,7 +491,7 @@ export default {
|
|||
// 大屏服务器数量统计接口
|
||||
getOrderStatus() {
|
||||
return request({
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/countOrderStatus',
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/jcc-mall/order/countOrderStatus',
|
||||
method: 'get'
|
||||
})
|
||||
},
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
// 大屏云厂商服务器数量查询接口
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function getTotalName() {
|
||||
return request({
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/jcc-faas-manager/function/device/queryByManufacturer',
|
||||
method: 'get',
|
||||
data: JSON,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
}
|
||||
// 大屏服务器数量统计接口
|
||||
export function getTotalNum() {
|
||||
return request({
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/jcc-faas-manager/function/device/queryDeviceCount',
|
||||
method: 'get',
|
||||
data: JSON,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 大屏地球地区查询接口
|
||||
export function getEarthRegion() {
|
||||
return request({
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/jcc-faas-manager/function/device/queryByArea',
|
||||
method: 'get',
|
||||
data: JSON,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 大屏地球各个区域服务器资源详细接口
|
||||
export function getEarthDetails(area) {
|
||||
return request({
|
||||
url: process.env.VUE_APP_FUNCTION_API + '/jcc-faas-manager/function/device/queryResDetailByArea?area=' + area,
|
||||
method: 'get',
|
||||
data: JSON,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// CPU平均使用率接口
|
||||
export function getCpuAverage(start, end, step) {
|
||||
return request({
|
||||
url: '/monitoringscreen/api/v1/query_range?query=avg(1%20-%20avg(rate(node_cpu_seconds_total%7Borigin_prometheus%3D~%22%22%2Cjob%3D~%22node-exporter%22%2Cmode%3D%22idle%22%7D%5B2m%5D))%20by%20(instance))%20*%20100' + '&start=' + start + '&end=' + end + '&step=' + step + '&_=1642578431700',
|
||||
method: 'get',
|
||||
data: JSON,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 内存平均使用率接口
|
||||
export function getRamAverage(start, end, step) {
|
||||
return request({
|
||||
url: '/monitoringscreen/api/v1/query_range?query=(sum(node_memory_MemTotal_bytes%7Borigin_prometheus%3D~%22%22%2Cjob%3D~%22node-exporter%22%7D%20-%20node_memory_MemAvailable_bytes%7Borigin_prometheus%3D~%22%22%2Cjob%3D~%22node-exporter%22%7D)%20%2F%20sum(node_memory_MemTotal_bytes%7Borigin_prometheus%3D~%22%22%2Cjob%3D~%22node-exporter%22%7D))*100' + '&start=' + start + '&end=' + end + '&step=' + step + '&_=1642578431700',
|
||||
method: 'get',
|
||||
data: JSON,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 计量计费接口总价格
|
||||
export function getMeasure(start, end, step) {
|
||||
return request({
|
||||
url: process.env.VUE_APP_BASE_API + '/kapis/clusters/host/metering.kubesphere.io/v1alpha1/cluster' + '?start=' + start + '&end=' + end + '&step=' + step + 's&metrics_filter=meter_cluster_cpu_usage%7Cmeter_cluster_memory_usage%7Cmeter_cluster_net_bytes_transmitted%7Cmeter_cluster_net_bytes_received%7Cmeter_cluster_pvc_bytes_total&resources_filter=host',
|
||||
method: 'get',
|
||||
data: JSON,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 内存整体负载接口
|
||||
export function getRamLoad(start, end, step) {
|
||||
return request({
|
||||
url: '/monitoringscreen/api/v1/query_range?query=sum(node_memory_MemTotal_bytes%7Borigin_prometheus%3D~%22%22%2Cjob%3D~%22node-exporter%22%7D%20-%20node_memory_MemAvailable_bytes%7Borigin_prometheus%3D~%22%22%2Cjob%3D~%22node-exporter%22%7D)&start=' + start + '&end=' + end + '&step=' + step + '&_=1642669327729',
|
||||
method: 'get',
|
||||
data: JSON,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 计量计费列表接口
|
||||
export function getMeteringList(start, end, step) {
|
||||
return request({
|
||||
url: process.env.VUE_APP_BASE_API + '/kapis/clusters/host/metering.kubesphere.io/v1alpha1/cluster' + '?start=' + start + '&end=' + end + '&step=' + step + 's&metrics_filter=meter_cluster_cpu_usage%7Cmeter_cluster_memory_usage%7Cmeter_cluster_net_bytes_transmitted%7Cmeter_cluster_net_bytes_received%7Cmeter_cluster_pvc_bytes_total&resources_filter=host',
|
||||
method: 'get',
|
||||
data: JSON,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// CPU整体负载接口
|
||||
export function getCpuAllload(start, end) {
|
||||
return request({
|
||||
url: '/monitoringscreen/api/v1/query_range?query=node_load15%7Binstance%3D~%22k8s-master%22%7D&start=' + start + '&end=' + end + '&step=900&_=1645409802467',
|
||||
method: 'get',
|
||||
data: JSON,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
})
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<!-- 添加容器镜像 -->
|
||||
<!-- 初始容器 和 其他 -->
|
||||
<el-dialog v-if="dialogVisible" width="80%" :title="(!createContainerForm.name?'添加':'编辑')+'容器'" :visible.sync="dialogVisible">
|
||||
<el-dialog v-if="dialogVisible" width="80%" :title="(!createContainerForm.name?'添加':'编辑')+'容器'" :visible.sync="dialogVisible" append-to-body>
|
||||
|
||||
<el-form ref="createContainerForm" :model="createContainerForm">
|
||||
<div class="border">
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
<template>
|
||||
<!-- 添加存储卷 -->
|
||||
<el-dialog v-if="dialogVisible" width="80%" title="存储卷" :visible.sync="dialogVisible">
|
||||
<el-form ref="createVolumesForm" :model="createVolumesForm">
|
||||
<el-dialog v-if="dialogVisible" width="80%" title="存储卷" :visible.sync="dialogVisible" append-to-body>
|
||||
<el-form ref="volumeData" :model="volumeData">
|
||||
<el-tabs v-model="activeName" type="card" @tab-click="handleClick">
|
||||
<el-tab-pane label="已有存储卷" name="first">
|
||||
<el-select v-model="createVolumesForm.volumes" class="selectPro" placeholder="选择已有存储卷">
|
||||
<el-form-item
|
||||
v-if="activeName==='first'"
|
||||
prop="firstName"
|
||||
label=""
|
||||
required
|
||||
>
|
||||
<el-select v-model="volumeData.firstName" class="selectPro" placeholder="选择已有存储卷">
|
||||
<el-option
|
||||
v-for="item in volumesList"
|
||||
:key="item.label"
|
||||
|
@ -16,14 +22,16 @@
|
|||
<span style="width:40%; display:block;float:left; text-align:right">访问模式:{{ item.accessModes }}</span>
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="临时存储卷" name="second">
|
||||
<el-form-item
|
||||
prop="volumesName"
|
||||
v-if="activeName==='second'"
|
||||
prop="secondName"
|
||||
label="存储卷名称"
|
||||
required
|
||||
>
|
||||
<el-input v-model="createVolumesForm.volumesName" :maxlength="63" />
|
||||
<el-input v-model="volumeData.secondName" :maxlength="63" />
|
||||
<span class="tips">最长 63 个字符,只能包含小写字母、数字及分隔符("-"),且必须以小写字母或数字开头及结尾</span>
|
||||
</el-form-item>
|
||||
</el-tab-pane>
|
||||
|
@ -33,19 +41,21 @@
|
|||
type="warning"
|
||||
/>
|
||||
<el-form-item
|
||||
prop="volumesName"
|
||||
v-if="activeName==='third'"
|
||||
prop="thirdName"
|
||||
label="存储卷名称"
|
||||
required
|
||||
>
|
||||
<el-input v-model="createVolumesForm.volumesName" :maxlength="63" />
|
||||
<el-input v-model="volumeData.thirdName" :maxlength="63" />
|
||||
<span class="tips">最长 63 个字符,只能包含小写字母、数字及分隔符("-"),且必须以小写字母或数字开头及结尾</span>
|
||||
</el-form-item>
|
||||
<el-form-item
|
||||
v-if="activeName==='third'"
|
||||
prop="hostPath"
|
||||
label="HostPath"
|
||||
required
|
||||
>
|
||||
<el-input v-model="createVolumesForm.volumesName" :maxlength="63" />
|
||||
<el-input v-model="volumeData.path" :maxlength="63" />
|
||||
<span class="tips">最长 63 个字符,只能包含小写字母、数字及分隔符("-"),且必须以小写字母或数字开头及结尾</span>
|
||||
</el-form-item>
|
||||
</el-tab-pane>
|
||||
|
@ -53,9 +63,9 @@
|
|||
<table v-if="formData.spec.template.spec.containers">
|
||||
<tr v-for="(item, index) in formData.spec.template.spec.containers" :key="index" class="dataList">
|
||||
<td>容器</td>
|
||||
<td>{{ item }}</td>
|
||||
<td>{{ item.name }}</td>
|
||||
<td>
|
||||
<el-select v-model="createVolumesForm.readOnly">
|
||||
<el-select v-model="createVolumesForm[index].readOnly">
|
||||
<el-option
|
||||
v-for="it in mountOptions"
|
||||
:key="it.value"
|
||||
|
@ -64,7 +74,7 @@
|
|||
/>
|
||||
</el-select>
|
||||
</td>
|
||||
<td><el-input v-model="createVolumesForm.mountPath" :disabled="!createVolumesForm.readOnly || createVolumesForm.readOnly === 'null'" placeholder="容器挂载路径, 例如: /data" /></td>
|
||||
<td><el-input v-model="createVolumesForm[index].mountPath" :disabled="createVolumesForm[index].readOnly == null" placeholder="容器挂载路径, 例如: /data" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
</el-form>
|
||||
|
@ -77,6 +87,7 @@
|
|||
|
||||
<script>
|
||||
import { mountOptions } from '@/utils/map'
|
||||
import generate from 'nanoid/generate'
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
|
@ -94,7 +105,13 @@ export default {
|
|||
},
|
||||
data() {
|
||||
return {
|
||||
createVolumesForm: {},
|
||||
createVolumesForm: [],
|
||||
volumeData: {
|
||||
firstName: '',
|
||||
secondName: '',
|
||||
thirdName: '',
|
||||
hostPath: ''
|
||||
},
|
||||
volumesList: [],
|
||||
activeName: 'first',
|
||||
mountOptions
|
||||
|
@ -126,6 +143,15 @@ export default {
|
|||
// }
|
||||
},
|
||||
watch: {
|
||||
'formData.spec.template.spec.containers': {
|
||||
handler(val) {
|
||||
this.createVolumesForm = []
|
||||
for (let i = 0; i < this.formData.spec.template.spec.containers.length; i++) {
|
||||
this.createVolumesForm.push({ readOnly: null, mountPath: '' })
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
// code(val) {
|
||||
// this.codeData = val
|
||||
// }
|
||||
|
@ -141,22 +167,49 @@ export default {
|
|||
})
|
||||
},
|
||||
ok() {
|
||||
const val = {}
|
||||
this.$refs.volumeData.validate((valid) => {
|
||||
if (valid) {
|
||||
// 存在容器挂载
|
||||
// if(this.createVolumesForm.readOnly !== 'null'){
|
||||
// this.formData.spec.template.spec.containers.forEach(e=>{
|
||||
|
||||
// })
|
||||
// }
|
||||
const newFormData = Object.assign({}, this.formData)
|
||||
let newSpecVolume = {}
|
||||
switch (this.activeName) {
|
||||
case 'first':
|
||||
|
||||
newSpecVolume = {
|
||||
name: `volume-${generate('0123456789abcdefghijklmnopqrstuvwxyz', 6)}`,
|
||||
persistentVolumeClaim: { claimName: this.volumeData[this.activeName + 'Name'] }
|
||||
}
|
||||
break
|
||||
case 'second':
|
||||
newSpecVolume = {
|
||||
name: this.volumeData[this.activeName + 'Name'],
|
||||
emptyDir: {}
|
||||
}
|
||||
break
|
||||
case 'third':
|
||||
newSpecVolume = {
|
||||
name: this.volumeData[this.activeName + 'Name'],
|
||||
hostPath: {
|
||||
path: this.volumeData.hostPath
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
newFormData.spec.template.spec.containers.forEach((e, index) => {
|
||||
if (this.createVolumesForm[index]?.readOnly !== null) {
|
||||
if (!e.volumeMounts) { e.volumeMounts = [] }
|
||||
e.volumeMounts.push({
|
||||
name: newSpecVolume.name,
|
||||
readOnly: this.createVolumesForm[index]?.readOnly,
|
||||
mountPath: this.createVolumesForm[index]?.mountPath
|
||||
})
|
||||
}
|
||||
})
|
||||
newFormData.spec.template.spec.volumes.push(newSpecVolume)
|
||||
|
||||
return this.$emit('addVolumes', val)
|
||||
this.$emit('addVolumes', newFormData)
|
||||
this.dialogVisible = false
|
||||
}
|
||||
})
|
||||
},
|
||||
handleClick() {}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,201 @@
|
|||
<template>
|
||||
<!-- 配置文件和密钥 -->
|
||||
<el-dialog v-if="dialogVisible" width="80%" title="配置文件和密钥" :visible.sync="dialogVisible" append-to-body>
|
||||
<el-form ref="settingForm" :model="settingForm">
|
||||
<el-tabs v-model="activeName" type="card" @tab-click="handleClick">
|
||||
<el-tab-pane label="配置" name="first">
|
||||
<el-form-item
|
||||
v-if="activeName==='first'"
|
||||
prop="firstName"
|
||||
label=""
|
||||
required
|
||||
>
|
||||
<el-select v-model="settingForm.firstName" class="selectPro" placeholder="请选择配置文件">
|
||||
<el-option
|
||||
v-for="item in configmapList"
|
||||
:key="item.label"
|
||||
:label="item.label"
|
||||
:value="item.label"
|
||||
>
|
||||
{{ item.label }}
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane label="密钥" name="second">
|
||||
<el-form-item
|
||||
v-if="activeName==='second'"
|
||||
prop="secondName"
|
||||
label=""
|
||||
required
|
||||
>
|
||||
<el-select v-model="settingForm.secondName" class="selectPro" placeholder="请选择配置文件">
|
||||
<el-option
|
||||
v-for="item in secretList"
|
||||
:key="item.label"
|
||||
:label="item.label"
|
||||
:value="item.label"
|
||||
>
|
||||
{{ item.label }}
|
||||
</el-option>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<table v-if="formData.spec.template.spec.containers">
|
||||
<tr v-for="(item, index) in formData.spec.template.spec.containers" :key="index" class="dataList">
|
||||
<td>容器</td>
|
||||
<td>{{ item.name }}</td>
|
||||
<td>
|
||||
<el-select v-model="createVolumesForm[index].readOnly">
|
||||
<el-option
|
||||
v-for="it in settingMountOptions"
|
||||
:key="it.value"
|
||||
:label="it.label"
|
||||
:value="it.value"
|
||||
/>
|
||||
</el-select>
|
||||
</td>
|
||||
<td><el-input v-model="createVolumesForm[index].mountPath" :disabled="createVolumesForm[index].readOnly == null" placeholder="容器挂载路径, 例如: /data" /></td>
|
||||
</tr>
|
||||
</table>
|
||||
</el-form>
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button icon="el-icon-close" circle @click="dialogVisible = false" />
|
||||
<el-button icon="el-icon-check" circle @click="ok" />
|
||||
</div>
|
||||
</el-dialog>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { settingMountOptions } from '@/utils/map'
|
||||
import generate from 'nanoid/generate'
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
formData: {
|
||||
type: Object,
|
||||
default: () => {}
|
||||
},
|
||||
isEdit: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
createVolumesForm: [],
|
||||
settingForm: {
|
||||
firstName: '',
|
||||
secondName: ''
|
||||
},
|
||||
configmapList: [],
|
||||
secretList: [],
|
||||
activeName: 'first',
|
||||
settingMountOptions
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
clusterName() {
|
||||
if (localStorage.getItem('clusterName') === 'default') {
|
||||
return ''
|
||||
} else {
|
||||
return '/clusters/' + localStorage.getItem('clusterName')
|
||||
}
|
||||
},
|
||||
dialogVisible: {
|
||||
get() {
|
||||
return this.value
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('input', value)
|
||||
}
|
||||
}
|
||||
// codeData: {
|
||||
// get() {
|
||||
// return this.code + ''
|
||||
// },
|
||||
// set(value) {
|
||||
// this.$emit('code', value)
|
||||
// }
|
||||
// }
|
||||
},
|
||||
watch: {
|
||||
'formData.spec.template.spec.containers': {
|
||||
handler(val) {
|
||||
this.createVolumesForm = []
|
||||
for (let i = 0; i < this.formData.spec.template.spec.containers.length; i++) {
|
||||
this.createVolumesForm.push({ readOnly: null, mountPath: '' })
|
||||
}
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
// code(val) {
|
||||
// this.codeData = val
|
||||
// }
|
||||
},
|
||||
mounted() {
|
||||
this.getConfigmapList()
|
||||
this.getSecretList()
|
||||
},
|
||||
methods: {
|
||||
getConfigmapList() {
|
||||
this.$Api.getConfigmapList(this.clusterName, this.formData.metadata.namespace).then(res => {
|
||||
const arr = res.items.map(e => { return { label: e.metadata.name } })
|
||||
this.configmapList = arr
|
||||
})
|
||||
},
|
||||
getSecretList() {
|
||||
this.$Api.getSecretList(this.clusterName, this.formData.metadata.namespace).then(res => {
|
||||
const arr = res.items.map(e => { return { label: e.metadata.name } })
|
||||
this.secretList = arr
|
||||
})
|
||||
},
|
||||
ok() {
|
||||
this.$refs.settingForm.validate((valid) => {
|
||||
if (valid) {
|
||||
// 存在容器挂载
|
||||
const newFormData = Object.assign({}, this.formData)
|
||||
let newSpecVolume = {}
|
||||
switch (this.activeName) {
|
||||
case 'first':
|
||||
newSpecVolume = {
|
||||
name: `volume-${generate('0123456789abcdefghijklmnopqrstuvwxyz', 6)}`,
|
||||
configMap: { name: this.settingForm[this.activeName + 'Name'] }
|
||||
}
|
||||
break
|
||||
case 'second':
|
||||
newSpecVolume = {
|
||||
name: `volume-${generate('0123456789abcdefghijklmnopqrstuvwxyz', 6)}`,
|
||||
secret: { secretName: this.settingForm[this.activeName + 'Name'] }
|
||||
}
|
||||
break
|
||||
}
|
||||
newFormData.spec.template.spec.containers.forEach((e, index) => {
|
||||
if (this.createVolumesForm[index]?.readOnly !== null) {
|
||||
if (!e.volumeMounts) { e.volumeMounts = [] }
|
||||
e.volumeMounts.push({
|
||||
name: newSpecVolume.name,
|
||||
readOnly: this.createVolumesForm[index]?.readOnly,
|
||||
mountPath: this.createVolumesForm[index]?.mountPath
|
||||
})
|
||||
}
|
||||
})
|
||||
newFormData.spec.template.spec.volumes.push(newSpecVolume)
|
||||
|
||||
this.$emit('addSettingOrKey', newFormData)
|
||||
this.dialogVisible = false
|
||||
}
|
||||
})
|
||||
},
|
||||
handleClick() {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
|
@ -265,10 +265,7 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
addImage(data) {
|
||||
console.log(this.editInfoForm.spec.template.spec.containers)
|
||||
this.editInfoForm.spec.template.spec.containers.push(data)
|
||||
console.log(this.editInfoForm.spec.template.spec.containers.length)
|
||||
// console.log(data)
|
||||
this.containerForm = undefined
|
||||
},
|
||||
editImage(data) {
|
||||
|
@ -303,8 +300,10 @@ export default {
|
|||
border: 1px solid #DCDFE6;
|
||||
margin-top: 10px;
|
||||
padding:10px;
|
||||
line-height: 1.4em;
|
||||
.el-button{
|
||||
float:right;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
.selectRadio{
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<mountVolumes v-if="stepNum===2" v-model="metaData" />
|
||||
<advancedSettings v-if="stepNum===3" v-model="metaData" />
|
||||
<div slot="footer" class="dialog-footer">
|
||||
<el-button @click="createFormVisible = false">取 消</el-button>
|
||||
<el-button @click="createFormVisible = false;transformYaml()">取 消</el-button>
|
||||
<el-button v-if="stepNum!==0" type="primary" @click="prev">上一步</el-button>
|
||||
<el-button v-if="stepNum!==3" type="primary" @click="next">下一步</el-button>
|
||||
<el-button v-else type="primary" @click="createWorkload">创建</el-button>
|
||||
|
@ -111,6 +111,7 @@ spec:
|
|||
this.$Api.postWorkload(this.clusterName, this.metaData.metadata.namespace, this.classification, this.metaData).then(() => {
|
||||
this.$message.success('创建成功!')
|
||||
this.createFormVisible = false
|
||||
this.transformYaml()
|
||||
this.$emit('getList')
|
||||
})
|
||||
})
|
||||
|
@ -118,6 +119,7 @@ spec:
|
|||
})
|
||||
},
|
||||
transformYaml() {
|
||||
this.stepNum = 0
|
||||
this.metaData = JSON.parse(JSON.stringify(yaml.load(this.baseYaml), null, 2))
|
||||
},
|
||||
prev() {
|
||||
|
|
|
@ -1,30 +1,51 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="mountVolumes">
|
||||
<p>挂载存储</p>
|
||||
|
||||
<!-- dataList -->
|
||||
|
||||
<!-- <i class="el-icon-receiving" />
|
||||
<i class="el-icon-setting" />
|
||||
<i class="el-icon-key" /> -->
|
||||
|
||||
<div v-if="editInfoForm.spec.template.spec.volumes">
|
||||
<div v-for="(item, index) in editInfoForm.spec.template.spec.volumes" :key="index" class="dataList">
|
||||
<el-button icon="el-icon-delete" circle @click.prevent="removeVolume(index)" />
|
||||
<el-button icon="el-icon-edit" circle @click.prevent="editVolume(item)" />
|
||||
<div><i class="el-icon-receiving" />{{ item.name }}</div>
|
||||
<div>类型:{{ item.emptyDir ? ' 临时存储卷': item.hostPath ? 'HostPath' : item.configMap ? '配置' : item.secret ? '密钥' : '已有存储卷' }}</div>
|
||||
<div v-for="(it, ind) in editInfoForm.spec.template.spec.containers" :key="ind">
|
||||
<div v-if="it.volumeMounts">
|
||||
<div v-for="(ii, dd) in it.volumeMounts" :key="dd">
|
||||
<div v-if="ii.name === item.name" class="volumeList">
|
||||
<span><i class="el-icon-c-scale-to-original" />{{ it.name }}</span>
|
||||
<span><i class="el-icon-reading" />{{ ii.mountPath }}({{ ii.readOnly==='true'?'只读':'读写' }})</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<el-button-group>
|
||||
<el-button ton @click="createFormVisible=true">
|
||||
添加存储卷
|
||||
<span class="tips">支持临时存储卷以及持久化存储卷</span>
|
||||
</el-button>
|
||||
<el-button>挂载配置文件或密钥
|
||||
<el-button @click="mountSettingFormVisible=true">
|
||||
挂载配置文件或密钥
|
||||
<span class="tips">将配置文件或密钥挂载至指定目录</span>
|
||||
</el-button>
|
||||
</el-button-group>
|
||||
<addVolumesForm v-model="createFormVisible" :form-data="editInfoForm" @addVolumes="addVolumes" />
|
||||
<addVolumesForm v-if="createFormVisible" v-model="createFormVisible" :form-data="editInfoForm" @addVolumes="addVolumes" />
|
||||
<mountSettingForm v-if="mountSettingFormVisible" v-model="mountSettingFormVisible" :form-data="editInfoForm" @addSettingOrKey="addSettingOrKey" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import addVolumesForm from '@/components/Actions/addVolumesForm.vue'
|
||||
import mountSettingForm from '@/components/Actions/mountSettingOrKey.vue'
|
||||
export default {
|
||||
components: { addVolumesForm },
|
||||
components: { addVolumesForm, mountSettingForm },
|
||||
props: {
|
||||
value: {
|
||||
type: Object,
|
||||
|
@ -34,8 +55,7 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
createFormVisible: false,
|
||||
createVolumesForm: {},
|
||||
formData: {}
|
||||
mountSettingFormVisible: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
@ -49,12 +69,53 @@ export default {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
addVolumes() {}
|
||||
addSettingOrKey(e) {
|
||||
this.editInfoForm = e
|
||||
},
|
||||
addVolumes(e) {
|
||||
this.editInfoForm = e
|
||||
},
|
||||
editVolume() {},
|
||||
removeVolume(index) {
|
||||
const name = this.editInfoForm.spec.template.spec.volumes[index].name
|
||||
this.editInfoForm.spec.template.spec.containers.forEach(e => {
|
||||
for (let i = 0; i < e.volumeMounts?.length || 0; i++) {
|
||||
if (e.volumeMounts[i].name === name) {
|
||||
e.volumeMounts.splice(i, 1)
|
||||
}
|
||||
}
|
||||
})
|
||||
this.editInfoForm.spec.template.spec.volumes.splice(index, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.mountVolumes{
|
||||
.dataList{
|
||||
border: 1px solid #DCDFE6;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
padding:10px;
|
||||
line-height: 1.4em;
|
||||
.el-button{
|
||||
float:right;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.volumeList{
|
||||
padding: 5px;
|
||||
background-color: #eeeeee;
|
||||
margin-top:5px;
|
||||
span{
|
||||
i {display: inline-block; margin-right:10px}
|
||||
display:inline-block;
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.selectPro{
|
||||
width: 100%;
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import { getVolume } from '@/api/one-class-page/storageManagement'
|
|||
import { getNodeMessage, getNodeStatus } from '@/api/one-class-page/nodeManagement'
|
||||
import { getByValue } from '@/utils/data-process'
|
||||
import { getDaemonSets, getDeployments, getPods, getServices, getStatefulSets } from '@/api/one-class-page/workloadManagement'
|
||||
import { getUsageStatus, getVirtualHosts, getVirtualMachinesInstances, getDataVolumeNew, getImages } from '@/api/one-class-page/virtualMachine'
|
||||
import { getUsageStatus, getVirtualHosts, getVirtualMachinesInstances, getVirtualMachines, getDataVolumeNew, getImages, getDashboardInfo, getStorageStatus } from '@/api/one-class-page/virtualMachine'
|
||||
// import { getImages } from '@/api/one-class-page/virtualMachine'
|
||||
import {
|
||||
getBriefSystemProject,
|
||||
|
@ -11,6 +11,8 @@ import {
|
|||
getDetailUserProject
|
||||
} from '@/api/one-class-page/projectManagement'
|
||||
import { getHostNum, getMemberNum } from '@/api/one-class-page/cluster'
|
||||
|
||||
import { parseSi } from '@/utils'
|
||||
// import { strToNumber } from '@/utils/data-process'
|
||||
|
||||
function getStatus(readyReplicas, replicas) {
|
||||
|
@ -273,12 +275,25 @@ const getHostVirtualMachineList = (clusterName, params) => {
|
|||
}
|
||||
const getVirtualMachineList = (clusterName, params) => {
|
||||
return new Promise(function(resolve) {
|
||||
const listResult = []
|
||||
getVirtualMachinesInstances().then((res) => {
|
||||
for (let item = 0; item < res.data.length; item++) {
|
||||
const obj = {}
|
||||
obj.index = item
|
||||
obj.name = res.data[item].metadata.fields[0]
|
||||
let listResult = []
|
||||
Promise.all([
|
||||
getVirtualMachines(),
|
||||
getVirtualMachinesInstances()
|
||||
]).then(res => {
|
||||
const vm = res[0]
|
||||
const vmIn = res[1]
|
||||
listResult = vm.data.map((i, index) => ({
|
||||
index: index,
|
||||
name: i.metadata.fields[0],
|
||||
state: i.metadata.annotations['harvesterhci.io/migrationState'] || i.metadata.fields[2],
|
||||
operator: i.metadata.fields[5],
|
||||
aliveTime: i.metadata.fields[1].replace('d', '天').replace('h', '小时'),
|
||||
cpu: i.spec.template.spec.domain.resources.limits.cpu,
|
||||
memory: i.spec.template.spec.domain.resources.limits.memory,
|
||||
ipAddress: vmIn.data.filter(n => n.id === i.id)?.[0]?.metadata?.fields[3] || '',
|
||||
node: vmIn.data.filter(n => n.id === i.id)?.[0]?.metadata?.fields[4] || '',
|
||||
label: i.metadata.labels['harvesterhci.io/creator']
|
||||
})
|
||||
// TODO: 虚拟机状态显示
|
||||
// var running = res.data[item].spec.running
|
||||
// if (running) {
|
||||
|
@ -286,21 +301,10 @@ const getVirtualMachineList = (clusterName, params) => {
|
|||
// } else {
|
||||
// obj.state = 'Off'
|
||||
// }
|
||||
obj.state = res.data[item].metadata.annotations['harvesterhci.io/migrationState'] || res.data[item].metadata.fields[2]
|
||||
obj.operator = res.data[item].metadata.fields[5]
|
||||
obj.aliveTime = res.data[item].metadata.fields[1]
|
||||
obj.aliveTime = obj.aliveTime.replace('d', '天')
|
||||
obj.aliveTime = obj.aliveTime.replace('h', '小时')
|
||||
obj.aliveTime = obj.aliveTime.replace('h', '小时')
|
||||
obj.cpu = res.data[item].spec.domain.cpu.cores
|
||||
obj.memory = res.data[item].spec.domain.memory.guest
|
||||
obj.ipAddress = res.data[item].metadata.fields[3]
|
||||
obj.node = res.data[item].metadata.fields[4]
|
||||
obj.label = res.data[item].metadata.labels['harvesterhci.io/creator']
|
||||
// obj.memoryused = res.data[item].status.capacity.ephemeral-storage - res.data[item].status.allocatable.memory
|
||||
// obj.memoryall = res.data[item].status.capacity.memory
|
||||
listResult[item] = obj
|
||||
}
|
||||
// listResult[item] = obj
|
||||
)
|
||||
resolve({ total: 10, rows: listResult })
|
||||
})
|
||||
})
|
||||
|
@ -309,38 +313,77 @@ const getVirtualMachineList = (clusterName, params) => {
|
|||
const getVirtualHostList = () => {
|
||||
return new Promise(function(resolve) {
|
||||
const listResult = []
|
||||
getUsageStatus().then(usage => {
|
||||
getVirtualHosts().then((res) => {
|
||||
for (let item = 0; item < res.data.length; item++) {
|
||||
|
||||
Promise.all([
|
||||
getDashboardInfo(), // cpu 内存 总量
|
||||
getUsageStatus(), // cpu 内存 使用量
|
||||
getStorageStatus(),
|
||||
getVirtualHosts()]).then(res => {
|
||||
for (let item = 0; item < res[3].data.length; item++) {
|
||||
let cpuAll = 0
|
||||
let memoryAll = 0
|
||||
let storageAll = 0
|
||||
let cpuUsed = 0
|
||||
let memoryUsed = 0
|
||||
let storageUsage = 0
|
||||
res[0].data.forEach(element => {
|
||||
if (res[3].data[item].metadata.name === element.id) {
|
||||
cpuAll += Number(element.status.capacity.cpu)
|
||||
memoryAll += Number(element.status.capacity.memory.replace('Ki', ''))
|
||||
}
|
||||
})
|
||||
res[1].data.forEach(element => {
|
||||
if (res[3].data[item].metadata.name === element.spec.nodeName) {
|
||||
const containers = element.spec.containers || []
|
||||
containers.forEach(e => {
|
||||
memoryUsed += parseSi(e?.resources?.requests?.memory || '0m', { increment: 1024 })
|
||||
cpuUsed += parseSi(e?.resources?.requests?.cpu || '0m')
|
||||
})
|
||||
}
|
||||
})
|
||||
res[2].data.forEach(element => {
|
||||
if (res[3].data[item].metadata.name === element.spec.name) {
|
||||
const diskStatus = element.status?.diskStatus || {}
|
||||
Object.values(diskStatus).map((disk) => {
|
||||
if (disk?.conditions?.Schedulable?.status === 'True' && disk?.storageAvailable && disk?.storageMaximum) {
|
||||
storageUsage += (disk.storageMaximum - disk.storageAvailable)
|
||||
}
|
||||
if (disk?.storageMaximum) {
|
||||
storageAll += disk.storageMaximum
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
var obj = {}
|
||||
obj.index = item
|
||||
obj.customName = res.data[item].metadata.annotations['harvesterhci.io/host-custom-name']
|
||||
obj.name = res.data[item].metadata.name
|
||||
obj.state = res.data[item].metadata.state.name
|
||||
obj.customName = res[3].data[item].metadata.annotations['harvesterhci.io/host-custom-name']
|
||||
obj.name = res[3].data[item].metadata.name
|
||||
obj.state = res[3].data[item].metadata.state.name
|
||||
obj.state = obj.state.charAt(0).toUpperCase() + obj.state.slice(1)
|
||||
obj.hostIP = res.data[item].metadata.fields[5]
|
||||
obj.aliveTime = res.data[item].metadata.fields[3]
|
||||
obj.hostIP = res[3].data[item].metadata.fields[5]
|
||||
obj.aliveTime = res[3].data[item].metadata.fields[3]
|
||||
obj.aliveTime = obj.aliveTime.replace('d', '天')
|
||||
obj.aliveTime = obj.aliveTime.replace('h', '小时')
|
||||
obj.cpuUsed = parseFloat((parseInt(usage?.data[item]?.usage?.cpu || 0) / 1000000000).toFixed(2))
|
||||
obj.cpuAll = parseInt(res.data[item].status.capacity.cpu)
|
||||
obj.cpuUsePercentage = parseFloat((obj.cpuUsed / obj.cpuAll).toFixed(2)) * 100
|
||||
obj.memoryUsed = parseFloat((parseInt(usage.data[item].usage.memory) / 1024 / 1024).toFixed(2))
|
||||
obj.memoryAll = parseFloat((parseFloat(res.data[item].status.capacity.memory) / 1024 / 1024).toFixed(2))
|
||||
obj.memoryUsePercentage = parseFloat((obj.memoryUsed / obj.memoryAll).toFixed(2)) * 100
|
||||
obj.storageUsed = parseFloat((parseFloat(res.data[item].status.capacity['ephemeral-storage']) / 1024 / 1024 / 1024 - parseFloat(res.data[item].status.allocatable['ephemeral-storage']) / 1024 / 1024 / 1024 / 1024).toFixed(2))
|
||||
obj.storageAll = parseFloat((parseFloat(res.data[item].status.capacity['ephemeral-storage']) / 1024 / 1024 / 1024).toFixed(2))
|
||||
obj.storageUsePercentage = parseFloat((obj.storageUsed / obj.storageAll).toFixed(2)) * 100
|
||||
// obj.memoryall = res.data[item].status.capacity.memory
|
||||
obj.cpuUsed = cpuUsed.toFixed(2)
|
||||
obj.cpuAll = cpuAll
|
||||
obj.cpuUsePercentage = (parseFloat((obj.cpuUsed / obj.cpuAll)) * 100).toFixed(0)
|
||||
obj.memoryUsed = (memoryUsed / 1024 / 1024 / 1024).toFixed(2)
|
||||
obj.memoryAll = (memoryAll / 1024 / 1024).toFixed(0)
|
||||
obj.memoryUsePercentage = (parseFloat((obj.memoryUsed / obj.memoryAll)) * 100).toFixed(1)
|
||||
obj.storageUsed = (storageUsage / 1024 / 1024 / 1024 / 1024).toFixed(2)
|
||||
obj.storageAll = (storageAll / 1024 / 1024 / 1024 / 1024).toFixed(2)
|
||||
obj.storageUsePercentage = (parseFloat((obj.storageUsed / obj.storageAll)) * 100).toFixed(1)
|
||||
// obj.memoryall = hostRes.data[item].status.capacity.memory
|
||||
var n, e
|
||||
obj.isMaintenance = (((n = res.data[item].metadata) === null || void 0 === n || (e = n.annotations) === null || void 0 === e ? void 0 : e['harvesterhci.io/maintain-status']) === 'completed')
|
||||
obj.isMaintenance = (((n = res[3].data[item].metadata) === null || void 0 === n || (e = n.annotations) === null || void 0 === e ? void 0 : e['harvesterhci.io/maintain-status']) === 'completed')
|
||||
if (obj.isMaintenance) {
|
||||
obj.state = 'Maintenance mode'
|
||||
}
|
||||
|
||||
listResult[item] = obj
|
||||
}
|
||||
resolve({ total: res.data.length, rows: listResult })
|
||||
})
|
||||
resolve({ total: res[3].data.length, rows: listResult })
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
@ -360,3 +360,58 @@ export function newEval(str) {
|
|||
var Fn = Function
|
||||
return new Fn('return ' + str)()
|
||||
}
|
||||
|
||||
const UNITS = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
|
||||
const FRACTIONAL = ['', 'm', 'u', 'n', 'p', 'f', 'a', 'z', 'y'] // milli micro nano pico femto
|
||||
|
||||
export function parseSi(inValue, opt) {
|
||||
opt = opt || {}
|
||||
let increment = opt.increment
|
||||
const allowFractional = opt.allowFractional !== false
|
||||
|
||||
if (!inValue || typeof inValue !== 'string' || !inValue.length) {
|
||||
return NaN
|
||||
}
|
||||
|
||||
inValue = inValue.replace(/,/g, '')
|
||||
|
||||
// eslint-disable-next-line prefer-const
|
||||
let [, valStr, unit, incStr] = inValue.match(/^([0-9.-]+)\s*([^0-9.-]?)([^0-9.-]?)/)
|
||||
const val = parseFloat(valStr)
|
||||
|
||||
if (!unit) {
|
||||
return val
|
||||
}
|
||||
|
||||
// micro "mu" symbol -> u
|
||||
if (unit.charCodeAt(0) === 181) {
|
||||
unit = 'u'
|
||||
}
|
||||
|
||||
const divide = FRACTIONAL.includes(unit)
|
||||
const multiply = UNITS.includes(unit.toUpperCase())
|
||||
|
||||
if (!increment) {
|
||||
// Automatically handle 1 KB = 1000B, 1 KiB = 1024B if no increment set
|
||||
if ((multiply || divide) && incStr === 'i') {
|
||||
increment = 1024
|
||||
} else {
|
||||
increment = 1000
|
||||
}
|
||||
}
|
||||
|
||||
if (divide && allowFractional) {
|
||||
const exp = FRACTIONAL.indexOf(unit)
|
||||
|
||||
return val / (increment ** exp)
|
||||
}
|
||||
|
||||
if (multiply) {
|
||||
const exp = UNITS.indexOf(unit.toUpperCase())
|
||||
|
||||
return val * (increment ** exp)
|
||||
}
|
||||
|
||||
// Unrecognized unit character
|
||||
return val
|
||||
}
|
||||
|
|
|
@ -17,9 +17,13 @@ const policysTypeOptions = [
|
|||
]
|
||||
|
||||
const mountOptions = [
|
||||
{ label: '读写', value: 'false' },
|
||||
{ label: '只读', value: 'true' },
|
||||
{ label: '不挂载', value: 'null' }
|
||||
{ label: '读写', value: false },
|
||||
{ label: '只读', value: true },
|
||||
{ label: '不挂载', value: null }
|
||||
]
|
||||
const settingMountOptions = [
|
||||
{ label: '只读', value: true },
|
||||
{ label: '不挂载', value: null }
|
||||
]
|
||||
|
||||
const imagePullPolicyOptions = [
|
||||
|
@ -57,6 +61,7 @@ export {
|
|||
policysOptions,
|
||||
policysTypeOptions,
|
||||
mountOptions,
|
||||
settingMountOptions,
|
||||
imagePullPolicyOptions,
|
||||
protocolOptions
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<el-tab-pane label="证书查验" name="1" />
|
||||
<el-tab-pane label="身份查验" name="2" />
|
||||
</el-tabs>
|
||||
<el-input v-model="content" placeholder="请输入您想要校验的内容">
|
||||
<el-input v-model="content" :placeholder="`${activeName === '1' ? '请输入您想要校验的内容' : '请输入身份指纹'}`">
|
||||
<el-button slot="append" icon="el-icon-search" type="primary" @click="search">校验查询</el-button>
|
||||
</el-input>
|
||||
<List
|
||||
|
@ -22,7 +22,7 @@
|
|||
<el-dialog width="70%" title="交易证书" :visible.sync="dialogCertVisible">
|
||||
<div class="certification">
|
||||
<p>兹证明:<br>
|
||||
申请人 {{ certificationData.buyerName }} 于 {{ certificationData.transTime }} 通过 {{ certificationData.sellerName }} 平台提交了以下电子数据及信息:
|
||||
申请人 {{ certificationData.buyerName }} 于 {{ new Date(certificationData.transTime).toLocaleString() }} 通过 {{ certificationData.sellerName }} 平台提交了以下电子数据及信息:
|
||||
</p>
|
||||
<FormData :column="1" :data="certificationData" :data-map="certDataMap" />
|
||||
</div>
|
||||
|
@ -47,7 +47,9 @@ export default {
|
|||
columns: [
|
||||
{ prop: 'certNum', label: '证书编号' },
|
||||
{ prop: 'fingerPrint', label: '身份指纹' },
|
||||
{ prop: 'createDate', label: '创建时间' },
|
||||
{ prop: 'createDate', label: '创建时间', formatter: (row) => {
|
||||
return <div>{new Date(row.createDate).toLocaleString() || '-'}</div>
|
||||
} },
|
||||
{ prop: 'more', label: '操作', formatter: (row) => {
|
||||
return <div>
|
||||
<el-button onClick={() => this.viewCredential(row)} type='text' size='small'>查看</el-button>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div>
|
||||
<el-card shadow="never">
|
||||
<el-page-header content="区块列表" @back="goBack" />
|
||||
<el-page-header content="区块列表(最近一个月的数据)" @back="goBack" />
|
||||
<List
|
||||
v-if="listData.length>=1"
|
||||
ref="multipleTable"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="functionList">
|
||||
<el-button class="opr-btn" size="middle" type="primary" @click="dialogCreateVisible=true">创建函数</el-button>
|
||||
<el-button class="opr-btn" size="middle" type="primary" @click="form={runEnv: 'python3'};dialogCreateVisible=true">创建函数</el-button>
|
||||
<el-row :gutter="20">
|
||||
<el-col v-for="(item,index) in functionList" :key="index" :span="6">
|
||||
<el-card shadow="never" class="functionCard">
|
||||
|
@ -31,6 +31,7 @@
|
|||
background
|
||||
:hide-on-single-page="true"
|
||||
:current-page="page"
|
||||
:page-size="size"
|
||||
layout="prev, pager, next"
|
||||
:total="total"
|
||||
@current-change="currentChange"
|
||||
|
@ -91,15 +92,15 @@
|
|||
<td>Function Name:</td>
|
||||
<td :colspan="3">{{ form.functionName }}</td>
|
||||
<td>Created Time:</td>
|
||||
<td>{{ form.createTime }}</td>
|
||||
<td>{{ form.createdTime }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Env:</td>
|
||||
<td>{{ form.runEnv }}</td>
|
||||
<td>Memory Size:</td>
|
||||
<td>{{ form.memorySize }}</td>
|
||||
<td>{{ form.memorySize }}MB</td>
|
||||
<td>Timeout:</td>
|
||||
<td>{{ form.timeout }}</td>
|
||||
<td>{{ form.timeout }}s</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Code Size:</td>
|
||||
|
@ -107,7 +108,7 @@
|
|||
<td>Code Checksum:</td>
|
||||
<td :colspan="3">{{ form.codeChecksum }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<!-- <tr>
|
||||
<td>Description</td>
|
||||
<td :colspan="5">{{ form.description }}</td>
|
||||
</tr>
|
||||
|
@ -115,13 +116,8 @@
|
|||
<td>EnviromentVariable:</td>
|
||||
<td :colspan="2">{{ form.envVar }}</td>
|
||||
<td :colspan="3">
|
||||
<!-- Enable Native Serverless:
|
||||
<el-switch
|
||||
v-model="form.enableNS"
|
||||
size="small">
|
||||
</el-switch> -->
|
||||
</td>
|
||||
</tr>
|
||||
</tr> -->
|
||||
</table>
|
||||
<el-row style="margin-bottom:30px" :gutter="30">
|
||||
<el-col :span="9">
|
||||
|
@ -263,10 +259,16 @@ export default {
|
|||
// this.form = val;
|
||||
// this.activeName = '2';
|
||||
this.form = val
|
||||
this.result = ''
|
||||
this.dialogExecuteVisible = true
|
||||
},
|
||||
createFunc() {
|
||||
// 新建函数
|
||||
|
||||
this.$Api.checkFunctionName(this.form.functionName).then(res => {
|
||||
if (res.data.exist) {
|
||||
this.$message.warning('名称已存在')
|
||||
} else {
|
||||
const funcForm = { code: { zipFile: this.form.runEnv === 'java8' ? this.fileList[0].code : this.transBase64(this.code) }, ...this.form }
|
||||
this.$Api.createFunction(funcForm).then((res) => {
|
||||
if (res) {
|
||||
|
@ -275,6 +277,8 @@ export default {
|
|||
this.getList()
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
},
|
||||
transBase64(code) {
|
||||
return Buffer.from(code).toString('base64')
|
||||
|
|
|
@ -55,13 +55,11 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
const UNITS = ['', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
|
||||
const FRACTIONAL = ['', 'm', 'u', 'n', 'p', 'f', 'a', 'z', 'y'] // milli micro nano pico femto
|
||||
|
||||
import List from '@/components/list'
|
||||
import * as echarts from 'echarts'
|
||||
import { getDashboardCounts, getDashboardEvents, getDashboardInfo, getUsageStatus, getStorageStatus } from '@/api/one-class-page/virtualMachine'
|
||||
import moment from 'moment'
|
||||
import { parseSi } from '@/utils'
|
||||
export default {
|
||||
components: { List },
|
||||
data() {
|
||||
|
@ -132,8 +130,8 @@ export default {
|
|||
let memoryCounts = 0
|
||||
let cpuCounts = 0
|
||||
containers.forEach(e => {
|
||||
memoryCounts += this.parseSi(e?.resources?.requests?.memory || '0m', { increment: 1024 })
|
||||
cpuCounts += this.parseSi(e?.resources?.requests?.cpu || '0m')
|
||||
memoryCounts += parseSi(e?.resources?.requests?.memory || '0m', { increment: 1024 })
|
||||
cpuCounts += parseSi(e?.resources?.requests?.cpu || '0m')
|
||||
})
|
||||
this.memoryUsage += memoryCounts
|
||||
this.cpuUsage += cpuCounts
|
||||
|
@ -156,57 +154,6 @@ export default {
|
|||
})
|
||||
},
|
||||
methods: {
|
||||
parseSi(inValue, opt) {
|
||||
opt = opt || {}
|
||||
let increment = opt.increment
|
||||
const allowFractional = opt.allowFractional !== false
|
||||
|
||||
if (!inValue || typeof inValue !== 'string' || !inValue.length) {
|
||||
return NaN
|
||||
}
|
||||
|
||||
inValue = inValue.replace(/,/g, '')
|
||||
|
||||
// eslint-disable-next-line prefer-const
|
||||
let [, valStr, unit, incStr] = inValue.match(/^([0-9.-]+)\s*([^0-9.-]?)([^0-9.-]?)/)
|
||||
const val = parseFloat(valStr)
|
||||
|
||||
if (!unit) {
|
||||
return val
|
||||
}
|
||||
|
||||
// micro "mu" symbol -> u
|
||||
if (unit.charCodeAt(0) === 181) {
|
||||
unit = 'u'
|
||||
}
|
||||
|
||||
const divide = FRACTIONAL.includes(unit)
|
||||
const multiply = UNITS.includes(unit.toUpperCase())
|
||||
|
||||
if (!increment) {
|
||||
// Automatically handle 1 KB = 1000B, 1 KiB = 1024B if no increment set
|
||||
if ((multiply || divide) && incStr === 'i') {
|
||||
increment = 1024
|
||||
} else {
|
||||
increment = 1000
|
||||
}
|
||||
}
|
||||
|
||||
if (divide && allowFractional) {
|
||||
const exp = FRACTIONAL.indexOf(unit)
|
||||
|
||||
return val / (increment ** exp)
|
||||
}
|
||||
|
||||
if (multiply) {
|
||||
const exp = UNITS.indexOf(unit.toUpperCase())
|
||||
|
||||
return val * (increment ** exp)
|
||||
}
|
||||
|
||||
// Unrecognized unit character
|
||||
return val
|
||||
},
|
||||
formatDate(t) {
|
||||
return moment(t).local().format('YYYY-MM-DD hh:mm:ss')
|
||||
},
|
||||
|
@ -214,7 +161,7 @@ export default {
|
|||
const cpuGauge = echarts.init(this.$refs.cpuGauge)
|
||||
cpuGauge.setOption(this.returnGaugeOption((this.cpuUsage / this.cpuTotal).toFixed(4) * 100))
|
||||
const memoryGauge = echarts.init(this.$refs.memoryGauge)
|
||||
memoryGauge.setOption(this.returnGaugeOption((parseInt(this.memoryUsage / 1024 / 1024 / 1024) / parseInt(this.memoryTotal / 1024 / 1024)).toFixed(4) * 100))
|
||||
memoryGauge.setOption(this.returnGaugeOption(((parseInt(this.memoryUsage / 1024 / 1024 / 1024) / parseInt(this.memoryTotal / 1024 / 1024)) * 100).toFixed(2)))
|
||||
const storageGauge = echarts.init(this.$refs.storageGauge)
|
||||
storageGauge.setOption(this.returnGaugeOption(((this.storageUsage / 1024 / 1024 / 1024 / 1024).toFixed(2) / (this.storageTotal / 1024 / 1024 / 1024 / 1024).toFixed(2)).toFixed(4) * 100))
|
||||
},
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="formcontainer">
|
||||
<el-form ref="formData" :rules="rules" :model="formData" label-position="top">
|
||||
<el-form ref="formData" :model="formData" label-position="top">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="名称"><el-input
|
||||
|
@ -78,37 +78,11 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { getImages, getDataVolumeNew, editDataVolume } from '@/api/one-class-page/virtualMachine'
|
||||
import { createDataVolume } from '@/api/one-class-page/virtualMachine'
|
||||
import { getImages, getDataVolumeNew, editDataVolume, createDataVolume } from '@/api/one-class-page/virtualMachine'
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
volumeData: {
|
||||
type: 'cdi.kubevirt.io.datavolume',
|
||||
metadata: {
|
||||
namespace: 'default',
|
||||
annotations: {
|
||||
'field.cattle.io/description': ''
|
||||
// 'harvesterhci.io/imageId': null
|
||||
},
|
||||
labels: {},
|
||||
name: ''
|
||||
},
|
||||
spec: {
|
||||
pvc: {
|
||||
resources: {
|
||||
requests: {
|
||||
storage: ''
|
||||
}
|
||||
},
|
||||
volumeMode: 'Block',
|
||||
accessModes: ['ReadWriteMany']
|
||||
},
|
||||
source: {
|
||||
blank: {}
|
||||
}
|
||||
}
|
||||
},
|
||||
volumeData: {},
|
||||
Data: {},
|
||||
tagNum: 0,
|
||||
disableConfig: true,
|
||||
|
@ -198,15 +172,31 @@ export default {
|
|||
this.$router.push({ path: '/virtual/dataVolume' })
|
||||
},
|
||||
create() {
|
||||
this.volumeData.metadata.annotations['field.cattle.io/description'] = this.formData.description
|
||||
if (this.formData.resourceType === 'VM Image') this.volumeData.metadata.annotations['harvesterhci.io/imageId'] = this.formData.imageId
|
||||
for (let item = 0; item < this.formData.tag.length; item++) {
|
||||
this.volumeData.metadata.labels[this.formData.tag[item].key] = this.formData.tag[item].value
|
||||
this.volumeData = {
|
||||
apiVersion: 'v1',
|
||||
kind: 'PersistentVolumeClaim',
|
||||
metadata: {
|
||||
annotations: {
|
||||
'field.cattle.io/description': this.formData.description || '',
|
||||
'harvesterhci.io/imageId': this.formData.resourceType === 'VM Image' ? this.formData.imageId : undefined
|
||||
},
|
||||
name: this.formData.name || '',
|
||||
namespace: 'default'
|
||||
},
|
||||
spec: {
|
||||
accessModes: ['ReadWriteMany'],
|
||||
resources: {
|
||||
requests: {
|
||||
storage: this.formData.size + 'Gi'
|
||||
}
|
||||
},
|
||||
storageClassName: this.formData.resourceType === 'VM Image' ? `longhorn-${this.formData.imageId.replace('default/', '')}` : 'longhorn',
|
||||
volumeMode: 'Block',
|
||||
volumeName: ''
|
||||
},
|
||||
type: 'persistentvolumeclaim'
|
||||
}
|
||||
this.volumeData.metadata.name = this.formData.name
|
||||
this.volumeData.spec.pvc.resources.requests.storage = this.formData.size + 'Gi'
|
||||
createDataVolume(this.volumeData).then(res => {
|
||||
console.log(res)
|
||||
this.$message.success('创建成功')
|
||||
this.goBack()
|
||||
})
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
<script>
|
||||
import {
|
||||
getHostYaml,
|
||||
getHostNetwork,
|
||||
// getHostNetwork,
|
||||
putHostYaml,
|
||||
putHostNetwork,
|
||||
getNodeNetworks
|
||||
|
@ -139,11 +139,11 @@ export default {
|
|||
this.formData.customName = res.metadata.annotations['harvesterhci.io/host-custom-name']
|
||||
this.yamlData = res
|
||||
})
|
||||
getHostNetwork(this.$route.query.name).then(res => {
|
||||
this.formData.type = res.spec.type
|
||||
this.formData.physicalNIC = res.spec.nic
|
||||
this.vlanData = res
|
||||
})
|
||||
// getHostNetwork(this.$route.query.name).then(res => {
|
||||
// this.formData.type = res.spec.type
|
||||
// this.formData.physicalNIC = res.spec.nic
|
||||
// this.vlanData = res
|
||||
// })
|
||||
getNodeNetworks().then(res => {
|
||||
this.physicalNICList = res.data[this.$route.query.index].status.physicalNICs
|
||||
})
|
||||
|
|
|
@ -194,15 +194,15 @@ export default {
|
|||
this.formData.lastUpdateTime = res.data[this.formData.index].status.conditions[0].lastUpdateTime
|
||||
this.formData.uuid = res.data[this.formData.index].status.nodeInfo.systemUUID
|
||||
|
||||
this.formData.cpuUsed = parseFloat((parseInt(usage.usage.cpu) / 1000000000).toFixed(2))
|
||||
this.formData.cpuAll = parseInt(res.data[this.formData.index].status.capacity.cpu)
|
||||
this.formData.cpuUsePercentage = parseFloat((this.formData.cpuUsed / this.formData.cpuAll).toFixed(2)) * 100
|
||||
this.formData.memoryUsed = parseFloat((parseInt(usage.usage.memory) / 1024 / 1024).toFixed(2))
|
||||
this.formData.memoryAll = parseFloat((parseFloat(res.data[this.formData.index].status.capacity.memory) / 1024 / 1024).toFixed(2))
|
||||
this.formData.memoryUsePercentage = parseFloat((this.formData.memoryUsed / this.formData.memoryAll).toFixed(2)) * 100
|
||||
this.formData.storageUsed = parseFloat((parseFloat(res.data[this.formData.index].status.capacity['ephemeral-storage']) / 1024 / 1024 / 1024 - parseFloat(res.data[this.formData.index].status.allocatable['ephemeral-storage']) / 1024 / 1024 / 1024 / 1024).toFixed(2))
|
||||
this.formData.storageAll = parseFloat((parseFloat(res.data[this.formData.index].status.capacity['ephemeral-storage']) / 1024 / 1024 / 1024).toFixed(2))
|
||||
this.formData.storageUsePercentage = parseFloat((this.formData.storageUsed / this.formData.storageAll).toFixed(2)) * 100
|
||||
this.formData.cpuUsed = this.$route.query.cpuUsed
|
||||
this.formData.cpuAll = this.$route.query.cpuAll
|
||||
this.formData.cpuUsePercentage = this.$route.query.cpuUsePercentage
|
||||
this.formData.memoryUsed = this.$route.query.memoryUsed
|
||||
this.formData.memoryAll = this.$route.query.memoryAll
|
||||
this.formData.memoryUsePercentage = this.$route.query.memoryUsePercentage
|
||||
this.formData.storageUsed = this.$route.query.storageUsed
|
||||
this.formData.storageAll = this.$route.query.storageAll
|
||||
this.formData.storageUsePercentage = this.$route.query.storageUsePercentage
|
||||
})
|
||||
})
|
||||
},
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
:columns="columns"
|
||||
func-name="getImagesList"
|
||||
:cluster-name="clusterName"
|
||||
:pagination="true"
|
||||
:pagination="false"
|
||||
tooltip-effect="dark"
|
||||
/>
|
||||
</el-card>
|
||||
|
@ -78,7 +78,6 @@ export default {
|
|||
<el-dropdown-menu slot='dropdown'>
|
||||
<span onClick={() => this.clickOption(row, 1)}> <el-dropdown-item><i class='el-icon-edit'></i> 编辑配置 </el-dropdown-item> </span>
|
||||
<span onClick={() => this.clickOption(row, 2)}> <el-dropdown-item><i class='el-icon-tickets'></i> 克隆 </el-dropdown-item> </span>
|
||||
<span onClick={() => this.clickOption(row, 3)}> <el-dropdown-item><i class='el-icon-document'></i> 创建虚拟机 </el-dropdown-item> </span>
|
||||
<span onClick={() => this.clickOption(row, 4)}> <el-dropdown-item><i class='el-icon-download'></i> 下载YAML </el-dropdown-item> </span>
|
||||
<span onClick={() => this.clickOption(row, 5)}> <el-dropdown-item divided><i class='el-icon-delete'></i> 删除 </el-dropdown-item> </span>
|
||||
</el-dropdown-menu>
|
||||
|
@ -132,7 +131,7 @@ export default {
|
|||
this.$router.push({ path: `virtual-machine/create`, query: row })
|
||||
break
|
||||
case 4:
|
||||
this.downloadHostYaml(row.name)
|
||||
this.downloadHostYaml(row)
|
||||
break
|
||||
case 5:
|
||||
this.deleteDialogVisible = true
|
||||
|
@ -151,8 +150,8 @@ export default {
|
|||
viewVMDetail(row) {
|
||||
this.$router.push({ path: `virtual-machine/detail`, query: row })
|
||||
},
|
||||
downloadHostYaml(name) {
|
||||
getImagesYaml(name).then(res => {
|
||||
downloadHostYaml(row) {
|
||||
getImagesYaml(row.name).then(res => {
|
||||
var data = JSON.stringify(res)
|
||||
// encodeURIComponent解决中文乱码
|
||||
const uri = 'data:text/csv;charset=utf-8,\ufeff' + encodeURIComponent(data)
|
||||
|
@ -160,7 +159,7 @@ export default {
|
|||
const link = document.createElement('a')
|
||||
link.href = uri
|
||||
// 对下载的文件命名
|
||||
link.download = name + '.json'
|
||||
link.download = row.displayName + '.json'
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div>
|
||||
<div class="formcontainer">
|
||||
<el-form ref="formData" :rules="rules" :model="formData" label-position="top">
|
||||
<el-form ref="formData" :model="formData" label-position="top">
|
||||
<el-row :gutter="10">
|
||||
<el-col :span="12">
|
||||
<el-form-item label="名称"><el-input
|
||||
|
@ -22,26 +22,24 @@
|
|||
<el-tab-pane label="基本信息">
|
||||
<h4>基本信息</h4>
|
||||
<el-form-item label="镜像地址">
|
||||
<el-select v-model="formData.resourceType" :disabled="!clone">
|
||||
<el-option
|
||||
v-for="item in options1"
|
||||
:key="item.value"
|
||||
:label="item.label"
|
||||
:value="item.value"
|
||||
<el-input
|
||||
v-model="formData.url"
|
||||
:hide-required-asterisk="true"
|
||||
:disabled="!clone"
|
||||
placeholder="镜像地址"
|
||||
/>
|
||||
</el-select>
|
||||
</el-form-item>
|
||||
</el-tab-pane>
|
||||
|
||||
<el-tab-pane label="标签">
|
||||
<h4>标签</h4>
|
||||
<div v-for="(item, index) in formData.tag" :key="item.id">
|
||||
<div v-for="(item, i) in formData.tag" :key="item.id">
|
||||
<el-form-item>
|
||||
<el-row v-if="index=='0'" :gutter="20"><el-col :span="6"><h5>键</h5></el-col><el-col :span="6"><h5>值</h5></el-col></el-row>
|
||||
<el-row v-if="i=='0'" :gutter="20"><el-col :span="6"><h5>键</h5></el-col><el-col :span="6"><h5>值</h5></el-col></el-row>
|
||||
<el-row :gutter="20">
|
||||
<el-col :span="6"><el-input v-model="item.key" placeholder="例如:test" /></el-col>
|
||||
<el-col :span="6"> <el-input v-model="item.value" placeholder="例如:test" /></el-col>
|
||||
<el-col :span="5"><el-button type="danger" icon="el-icon-delete" @click="removeTag(index)" /></el-col>
|
||||
<el-col v-if="!isDisabled" :span="5"><el-button type="danger" icon="el-icon-delete" @click="removeTag(i)" /></el-col>
|
||||
</el-row>
|
||||
</el-form-item>
|
||||
</div>
|
||||
|
@ -54,25 +52,28 @@
|
|||
<el-row type="flex" justify="end">
|
||||
<el-col :span="2.5">
|
||||
<el-button v-if="!isDisabled" type="info" @click="goBack">取消</el-button>
|
||||
<el-button v-if="!isDisabled" type="primary">创建</el-button>
|
||||
<el-button v-if="clone" type="primary" @click="create">创建</el-button>
|
||||
<el-button v-if="!clone && !isDisabled" type="primary" @click="edit">保存</el-button>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getImages, editImage, createImages } from '@/api/one-class-page/virtualMachine'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
tagNum: 0,
|
||||
index: '',
|
||||
disableConfig: true,
|
||||
clone: false,
|
||||
currentData: '',
|
||||
formData: {
|
||||
name: '',
|
||||
description: '',
|
||||
size: '',
|
||||
resourceType: 'https://github.com/rancher/k3os/releases/download/v0.11.1/k3os-amd64.iso',
|
||||
image: '',
|
||||
tag: []
|
||||
}
|
||||
|
@ -83,6 +84,9 @@ export default {
|
|||
return this.disableConfig && !this.clone
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.index = this.$route.query.index
|
||||
},
|
||||
mounted() {
|
||||
this.getFormData()
|
||||
if (this.$route.query.disableConfig != null && typeof (this.$route.query.disableConfig) !== 'undefined') {
|
||||
|
@ -94,10 +98,22 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
getFormData() {
|
||||
this.formData.name = this.$route.query.name
|
||||
this.formData.size = this.$route.query.size.slice(0, -2)
|
||||
// this.formData.description = this.$route.query.description,
|
||||
// this.formData.resourceType = this.$route.query.resourceType
|
||||
getImages().then(res => {
|
||||
var data = res.data[this.index]
|
||||
this.currentData = data
|
||||
this.formData = {
|
||||
name: this.$route.query.displayName,
|
||||
description: data.metadata.annotations['field.cattle.io/description'],
|
||||
size: Number((data.status.size / 1024 / 1024).toString().match(/^\d+(?:\.\d{0,2})?/)) + 'MB',
|
||||
url: data.spec.url,
|
||||
image: data.spec.url
|
||||
}
|
||||
const arry = []
|
||||
for (const i in data.metadata.labels) {
|
||||
arry.push({ 'key': i, 'value': data.metadata.labels[i] })
|
||||
}
|
||||
this.formData.tag = arry
|
||||
})
|
||||
},
|
||||
addTag() {
|
||||
this.formData.tag.push(
|
||||
|
@ -108,11 +124,53 @@ export default {
|
|||
}
|
||||
)
|
||||
},
|
||||
create() {
|
||||
this.imagesData = {
|
||||
'apiVersion': this.currentData.apiVersion,
|
||||
'kind': this.currentData.kind,
|
||||
'metadata': {
|
||||
annotations: {
|
||||
'field.cattle.io/description': this.formData.description
|
||||
},
|
||||
finalizers: this.currentData.metadata.finalizers,
|
||||
generateName: 'image-',
|
||||
labels: {},
|
||||
name: '',
|
||||
namespace: 'default'
|
||||
},
|
||||
'spec': {
|
||||
'displayName': this.formData.name,
|
||||
'url': this.formData.url,
|
||||
checksum: '',
|
||||
pvcName: '',
|
||||
pvcNamespace: '',
|
||||
sourceType: 'download'
|
||||
},
|
||||
'type': this.currentData.type
|
||||
}
|
||||
for (let item = 0; item < this.formData.tag.length; item++) {
|
||||
this.imagesData.metadata.labels[this.formData.tag[item].key] = this.formData.tag[item].value
|
||||
}
|
||||
createImages(this.imagesData).then(res => {
|
||||
this.$message.success('创建成功')
|
||||
this.goBack()
|
||||
})
|
||||
},
|
||||
edit() {
|
||||
this.currentData.metadata.annotations['field.cattle.io/description'] = this.formData.description
|
||||
for (let item = 0; item < this.formData.tag.length; item++) {
|
||||
this.currentData.metadata.labels[this.formData.tag[item].key] = this.formData.tag[item].value
|
||||
}
|
||||
editImage(this.$route.query.name, this.currentData).then(res => {
|
||||
this.$message.success('修改成功')
|
||||
this.goBack()
|
||||
})
|
||||
},
|
||||
removeTag(index) {
|
||||
this.formData.tag.splice(index, 1)
|
||||
},
|
||||
goBack() {
|
||||
this.$router.push({ path: '/virtual/images.vue' })
|
||||
this.$router.push({ path: '/virtual/images' })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
<script>
|
||||
import { FormData } from '@/components/FormData'
|
||||
import { getImages } from '@/api/one-class-page/virtualMachine'
|
||||
export default {
|
||||
components: { FormData },
|
||||
data() {
|
||||
|
@ -23,7 +24,7 @@ export default {
|
|||
formData1: {
|
||||
description: ' ',
|
||||
size: this.$route.query.size,
|
||||
resourceType: 'https://github.com/rancher/k3os/releases/download/v0.11.1/k3os-amd64.iso'
|
||||
resourceType: ''
|
||||
},
|
||||
dataMap1: {
|
||||
description: '描述',
|
||||
|
@ -64,7 +65,16 @@ export default {
|
|||
this.getFormData()
|
||||
},
|
||||
methods: {
|
||||
getFormData() {}
|
||||
getFormData() {
|
||||
getImages().then(res => {
|
||||
var data = res.data[this.index]
|
||||
this.formData1 = {
|
||||
description: 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
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -33,14 +33,14 @@
|
|||
width="30%"
|
||||
>
|
||||
<p>您试图删除 虚拟机 {{ deleteName }} .</p>
|
||||
<p>Select the volume you want to delete:</p>
|
||||
<p>选择您需要删除的卷:</p>
|
||||
<el-checkbox-group v-model="selectDeleteVolumeList">
|
||||
<el-checkbox
|
||||
v-for="data in deleteVolumeList"
|
||||
:key="data.name"
|
||||
:label="data.name"
|
||||
:key="data"
|
||||
:label="data"
|
||||
>
|
||||
{{ data.name }}
|
||||
{{ data }}
|
||||
</el-checkbox>
|
||||
</el-checkbox-group>
|
||||
|
||||
|
@ -103,6 +103,8 @@ export default {
|
|||
formatter: row => {
|
||||
if (row.state === 'Running') {
|
||||
return <el-tag disable-transitions type='success'>{row.state}</el-tag>
|
||||
} else if (row.state === 'Stopped') {
|
||||
return <el-tag disable-transitions type='info'>Off</el-tag>
|
||||
} else {
|
||||
return <span>
|
||||
<el-tag disable-transitions>{row.state}</el-tag>
|
||||
|
@ -169,10 +171,9 @@ export default {
|
|||
// },
|
||||
deleteVirtualMachine() {
|
||||
this.deleteDialogVisible = false
|
||||
console.log(this.selectDeleteVolumeList)
|
||||
deleteVirtualMachine(this.deleteName, this.selectDeleteVolumeList).then(res => {
|
||||
alert('删除成功')
|
||||
location.reload()
|
||||
this.$message.success('删除成功')
|
||||
this.$refs.multipleTable.getList()
|
||||
})
|
||||
},
|
||||
createVirtualMachine() {
|
||||
|
@ -219,9 +220,9 @@ export default {
|
|||
getVirtualMachines().then(res => {
|
||||
var data = res.data[row.index]
|
||||
this.deleteVolumeList = []
|
||||
for (let i = 0; i < data.spec.template.spec.volumes.length; i++) {
|
||||
if (data.spec.template.spec.volumes[i].dataVolume != null) {
|
||||
this.deleteVolumeList.push(data.spec.template.spec.volumes[i])
|
||||
for (let i = 0; i < data.status?.volumeSnapshotStatuses?.length; i++) {
|
||||
if (data.status.volumeSnapshotStatuses[i].name !== 'cloudinitdisk') {
|
||||
this.deleteVolumeList.push(data.status.volumeSnapshotStatuses[i].name)
|
||||
}
|
||||
}
|
||||
this.deleteName = row.name
|
||||
|
|
|
@ -137,7 +137,7 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { getImages, postSSHKey, getDataVolume, getSSHKey } from '@/api/one-class-page/virtualMachine'
|
||||
import { getImages, postSSHKey, getDataVolumeNew, getSSHKey } from '@/api/one-class-page/virtualMachine'
|
||||
import ConfigVolume from './virtualMachineConfig/configVolume'
|
||||
import ConfigImage from './virtualMachineConfig/configImage'
|
||||
import ConfigExistedVolume from './virtualMachineConfig/configExistedVolume'
|
||||
|
@ -347,7 +347,7 @@ export default {
|
|||
this.getSSHKeys()
|
||||
getImages().then(res => {
|
||||
this.imageList = res.data
|
||||
getDataVolume().then(res => {
|
||||
getDataVolumeNew().then(res => {
|
||||
this.volumeList = res.data
|
||||
this.show = true
|
||||
})
|
||||
|
@ -363,15 +363,14 @@ export default {
|
|||
getImages().then(res => {
|
||||
images = res.data
|
||||
this.imageList = res.data
|
||||
getDataVolume().then(res => {
|
||||
getDataVolumeNew().then(res => {
|
||||
dataVolumeData = res.data
|
||||
this.volumeList = dataVolumeData
|
||||
// getVirtualMachines().then(res => {
|
||||
var data = this.instanceData // res.data[this.$route.query.index]
|
||||
var dataImageName = null
|
||||
for (let item = 0; item < data.spec.template.spec.volumes.length; item++) {
|
||||
var dataVolumeTemplate = data.spec.template.spec.volumes[item]
|
||||
var volumeName = dataVolumeTemplate.name
|
||||
data.spec.template.spec.volumes.forEach(item => {
|
||||
var volumeName = item.name
|
||||
dataImageName = null
|
||||
var bus = null
|
||||
var bootOrder = null
|
||||
|
@ -380,16 +379,14 @@ export default {
|
|||
var componentType = null
|
||||
var dataVolumeName = null
|
||||
var imageId = null
|
||||
if (dataVolumeTemplate.dataVolume != null) {
|
||||
dataVolumeName = dataVolumeTemplate.dataVolume.name
|
||||
} else if (dataVolumeTemplate.containerDisk != null) {
|
||||
dataVolumeName = dataVolumeTemplate.containerDisk.image
|
||||
if (item.dataVolume != null) {
|
||||
dataVolumeName = item.dataVolume.name
|
||||
} else if (item.containerDisk != null) {
|
||||
dataVolumeName = item.containerDisk.image
|
||||
componentType = 'Container'
|
||||
} else if (dataVolumeTemplate.cloudInitNoCloud != null) {
|
||||
this.formData.userData = dataVolumeTemplate.cloudInitNoCloud.userData
|
||||
continue
|
||||
} else {
|
||||
continue
|
||||
} else if (item.cloudInitNoCloud != null) {
|
||||
this.formData.userData = item.cloudInitNoCloud.userData
|
||||
return
|
||||
}
|
||||
for (let item1 = 0; item1 < dataVolumeData.length; item1++) {
|
||||
if (dataVolumeName === dataVolumeData[item1].metadata.fields[0]) {
|
||||
|
@ -412,7 +409,7 @@ export default {
|
|||
break
|
||||
}
|
||||
}
|
||||
for (let item1 = 0; item1 < data.spec.dataVolumeTemplates.length; item1++) {
|
||||
for (let item1 = 0; item1 < data.spec?.dataVolumeTemplates?.length; item1++) {
|
||||
if (data.spec.dataVolumeTemplates[item1].metadata.name !== dataVolumeName) {
|
||||
continue
|
||||
}
|
||||
|
@ -436,7 +433,7 @@ export default {
|
|||
// Name,type,Image,Size,Bus,BootOrder,docker,isCreate, disableConfig, volumeList, imageId
|
||||
this.childLists.push([volumeName, type, dataImageName, size, bus, bootOrder, dataVolumeName, null, true, this.volumeList, imageId])
|
||||
this.allComponents.push(componentType)
|
||||
}
|
||||
})
|
||||
this.formData.name = data.metadata.name
|
||||
this.formData.description = data.metadata.annotations['field.cattle.io/description']
|
||||
this.formData.customName = data.metadata.annotations['harvesterhci.io/host-custom-name']
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
<h4>网络</h4>
|
||||
<VirtualMachineDetailCard v-for="(item, ind) in allNetworkCard" :key="ind" card-name="网络" :data-map="dataMap5" :form-data="item" />
|
||||
</el-tab-pane>
|
||||
<el-tab-pane key="4" label="SSH 秘钥">
|
||||
<el-tab-pane key="4" label="SSH 密钥">
|
||||
<h4>SSH Keys</h4>
|
||||
<div v-for="(item,index) in sshkeyLists" :key="index">
|
||||
{{ item.name }}
|
||||
|
@ -72,7 +72,7 @@
|
|||
<script>
|
||||
import { FormData } from '@/components/FormData'
|
||||
import List from '@/components/list'
|
||||
import { getVirtualMachines, getImages, getDataVolume, getSSHKey } from '@/api/one-class-page/virtualMachine'
|
||||
import { getVirtualMachines, getImages, getDataVolumeNew, getSSHKey, getVirtualMachinesInstances } from '@/api/one-class-page/virtualMachine'
|
||||
import VirtualMachineDetailCard from './virtualMachineConfig/virtualMachineDetailCard'
|
||||
export default {
|
||||
name: 'VirtualMachineDetail',
|
||||
|
@ -125,8 +125,8 @@ export default {
|
|||
dataMap: {
|
||||
name: '名称',
|
||||
image: '镜像',
|
||||
hostname: '主机名',
|
||||
node: '节点',
|
||||
node: '节点名称',
|
||||
hostname: '主机',
|
||||
IPAddress: 'IP地址',
|
||||
created: '创建时间'
|
||||
},
|
||||
|
@ -175,7 +175,7 @@ export default {
|
|||
dataMap8: {
|
||||
Name: '名称',
|
||||
Type: '类型',
|
||||
Volume: '卷名称',
|
||||
// Volume: '卷名称',
|
||||
Size: '大小',
|
||||
Bus: '总线',
|
||||
BootOrder: '驱动顺序'
|
||||
|
@ -207,15 +207,17 @@ export default {
|
|||
// TODO Basics 面板的Image, Node IP Address 字段都未知
|
||||
var images = null
|
||||
var dataVolumeData = null
|
||||
getImages().then(res => {
|
||||
images = res.data
|
||||
getDataVolume().then(res => {
|
||||
dataVolumeData = res.data
|
||||
getVirtualMachines().then(res => {
|
||||
var data = res.data[this.$route.query.index]
|
||||
for (let item = 0; item < data.spec.template.spec.volumes.length; item++) {
|
||||
var dataVolumeTemplate = data.spec.template.spec.volumes[item]
|
||||
var volumeName = dataVolumeTemplate.name
|
||||
Promise.all([
|
||||
getImages(),
|
||||
getDataVolumeNew(),
|
||||
getVirtualMachines(),
|
||||
getVirtualMachinesInstances()]).then(res => {
|
||||
images = res[0].data
|
||||
dataVolumeData = res[1].data
|
||||
var data = res[2].data[this.index]
|
||||
var currentVm = res[3].data.filter(n => n.id === data.id)?.[0]
|
||||
data.spec?.template?.spec?.volumes?.forEach(item => {
|
||||
var volumeName = item.name
|
||||
var dataImageName = null
|
||||
var bus = null
|
||||
var bootOrder = null
|
||||
|
@ -223,16 +225,14 @@ export default {
|
|||
var size = null
|
||||
var componentType = null
|
||||
var dataVolumeName = null
|
||||
if (dataVolumeTemplate.dataVolume != null) {
|
||||
dataVolumeName = dataVolumeTemplate.dataVolume.name
|
||||
} else if (dataVolumeTemplate.containerDisk != null) {
|
||||
dataVolumeName = dataVolumeTemplate.containerDisk.image
|
||||
if (item.dataVolume != null) {
|
||||
dataVolumeName = item.dataVolume.name
|
||||
} else if (item.containerDisk != null) {
|
||||
dataVolumeName = item.containerDisk.image
|
||||
componentType = '容器镜像'
|
||||
} else if (dataVolumeTemplate.cloudInitNoCloud != null) {
|
||||
this.formData.userData = dataVolumeTemplate.cloudInitNoCloud.userData
|
||||
continue
|
||||
} else {
|
||||
continue
|
||||
} else if (item.cloudInitNoCloud != null) {
|
||||
this.formData.userData = item.cloudInitNoCloud.userData
|
||||
return
|
||||
}
|
||||
for (let item1 = 0; item1 < dataVolumeData.length; item1++) {
|
||||
if (dataVolumeName === dataVolumeData[item1].metadata.fields[0]) {
|
||||
|
@ -255,7 +255,7 @@ export default {
|
|||
break
|
||||
}
|
||||
}
|
||||
for (let item1 = 0; item1 < data.spec.dataVolumeTemplates.length; item1++) {
|
||||
for (let item1 = 0; item1 < data.spec?.dataVolumeTemplates?.length; item1++) {
|
||||
if (data.spec.dataVolumeTemplates[item1].metadata.name !== dataVolumeName) {
|
||||
continue
|
||||
}
|
||||
|
@ -312,7 +312,7 @@ export default {
|
|||
}
|
||||
}
|
||||
this.allDetailCard.push(itemObjct)
|
||||
}
|
||||
})
|
||||
this.allNetworkCard = this.getNetworkRows(data.spec)
|
||||
|
||||
this.formData.name = data.metadata.name
|
||||
|
@ -322,8 +322,12 @@ export default {
|
|||
this.formData.cpu = data.spec.template.spec.domain.cpu.cores
|
||||
this.formData.memory = data.spec.template.spec.domain.resources.requests.memory
|
||||
this.formData.memory = this.formData.memory.replace('Gi', '')
|
||||
this.formData.hostname = data.spec.template.spec.hostname
|
||||
data = res.data[this.index]
|
||||
this.formData.hostname = currentVm?.metadata.fields[4]
|
||||
this.formData.IPAddress = currentVm?.metadata.fields[3]
|
||||
this.formData.node = currentVm?.metadata.fields[0]
|
||||
this.formData.KernelRelease = currentVm?.status?.guestOSInfo?.kernelRelease
|
||||
this.formData.OperatingSystem = currentVm?.status?.guestOSInfo?.prettyName
|
||||
// data = res.data[this.index]
|
||||
this.formData.name = data.metadata.fields[0]
|
||||
this.formData.created = data.metadata.creationTimestamp
|
||||
this.formData.MachineType = data.spec.template.spec.domain.machine.type
|
||||
|
@ -349,27 +353,25 @@ export default {
|
|||
this.formData.bootOrder += i + '. ' + disksarr[i] + ' \n'
|
||||
}
|
||||
}
|
||||
var cpucore = data.spec.template.spec.domain.cpu.cores
|
||||
var memory = data.spec.template.spec.domain.resources.requests.memory
|
||||
this.formData.Flavor += cpucore + ' vCPU, ' + memory + ' Memory'
|
||||
var cpucore = data.spec.template.spec.domain.resources.limits.cpu
|
||||
var memory = data.spec.template.spec.domain.resources.limits.memory
|
||||
this.formData.Flavor += cpucore + ' vCPU, ' + memory + ' 内存'
|
||||
this.formData2.Name = data.spec.template.spec.domain.devices.interfaces[0].name
|
||||
this.formData2.Model = data.spec.template.spec.domain.devices.interfaces[0].model
|
||||
var str = data.spec.template.metadata.annotations['harvesterhci.io/sshNames']
|
||||
var arr = JSON.parse(str)
|
||||
getSSHKey().then(res => {
|
||||
getSSHKey().then(n => {
|
||||
this.sshkeyLists = []
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
for (let j = 0; j < res.data.length; j++) {
|
||||
console.log(res.data[j])
|
||||
if (res.data[j].metadata.name === arr[i]) {
|
||||
this.sshkeyLists.push({ name: arr[i], sshKey: res.data[j].spec.publicKey })
|
||||
for (let j = 0; j < n.data.length; j++) {
|
||||
console.log(n.data[j])
|
||||
if (n.data[j].id === arr[i]) {
|
||||
this.sshkeyLists.push({ name: arr[i], sshKey: n.data[j].spec.publicKey })
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
getNetworkRows(n) {
|
||||
|
|
|
@ -108,7 +108,7 @@ export default {
|
|||
</span>
|
||||
} },
|
||||
{ prop: 'project', label: '项目' },
|
||||
{ prop: 'updateTime', label: '更新时间', formatter: (row) => new Date(row.updateTime).toLocaleString() },
|
||||
{ prop: 'updateTime', label: '更新时间', formatter: (row) => new Date(row.data.status.conditions[1].lastUpdateTime).toLocaleString() || '-' },
|
||||
{ prop: 'more', label: '操作', formatter: (row) => {
|
||||
return <div>
|
||||
<el-dropdown>
|
||||
|
|
|
@ -99,9 +99,14 @@ module.exports = {
|
|||
changeOrigin: true,
|
||||
secure: false
|
||||
},
|
||||
'^/function': {
|
||||
'^/jcc-faas-manager': {
|
||||
ws: false,
|
||||
target: 'https://jointcloud.net/api/'
|
||||
target: 'https://jointcloud.net/apis/v1'
|
||||
// changeOrigin: true,
|
||||
},
|
||||
'^/jcc-mall': {
|
||||
ws: false,
|
||||
target: 'https://jointcloud.net/apis/v1'
|
||||
// changeOrigin: true,
|
||||
},
|
||||
'/kapis/terminal.kubesphere.io': {
|
||||
|
|
Loading…
Reference in New Issue