merge from primary branch

This commit is contained in:
jhnine 2022-03-23 15:41:27 +08:00
parent cdb24ade09
commit 2316e37d83
29 changed files with 1063 additions and 472 deletions

View File

@ -3,6 +3,6 @@ ENV = 'production'
# base api # base api
VUE_APP_BASE_API = 'prod-api' VUE_APP_BASE_API = 'prod-api'
VUE_APP_FUNCTION_API = 'api' VUE_APP_FUNCTION_API = 'apis/v1'
VUE_APP_PUBLIC_SOURCE_API = '/monitor' VUE_APP_PUBLIC_SOURCE_API = '/monitor'

View File

@ -92,7 +92,7 @@ export function putHostYaml(name, yaml) {
// 虚拟机管理-虚拟机列表 // 虚拟机管理-虚拟机列表
export function getVirtualMachines() { export function getVirtualMachines() {
return request({ return request({
url: '/virtual/v1/kubevirt.io.virtualmachine', url: '/virtual/v1/harvester/kubevirt.io.virtualmachines',
method: 'get' method: 'get'
}) })
} }
@ -223,6 +223,13 @@ export function deleteImage(name) {
method: 'delete' 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) { export function getImagesYaml(name) {
return request({ return request({
url: '/virtual/apis/harvesterhci.io/v1beta1/namespaces/default/virtualmachineimages/' + name, url: '/virtual/apis/harvesterhci.io/v1beta1/namespaces/default/virtualmachineimages/' + name,
@ -293,7 +300,7 @@ export function createVirtualMachine(data) {
export function virtualMachineACtion(name, action) { export function virtualMachineACtion(name, action) {
return request({ 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', method: 'post',
data: {} data: {}
}) })
@ -317,14 +324,14 @@ export function getVirtualNode() {
export function moveVirtualNode(id, data) { export function moveVirtualNode(id, data) {
return request({ 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', method: 'Post',
data data
}) })
} }
export function deleteVirtualMachine(name, 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++) { for (let i = 0; i < data.length; i++) {
newUrl += 'removedDisks=' + data[i] + '&' newUrl += 'removedDisks=' + data[i] + '&'
} }

View File

@ -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 // 工作负载提交前check
getWorkloadCheck(clusterName, namespaces, type, name) { getWorkloadCheck(clusterName, namespaces, type, name) {
// http://10.105.20.3:30880/apis/clusters/fedjcce-ten002/apps/v1/namespaces/test-zhangjie/deployments?labelSelector=app%3Dasd // 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) { createFunction(query) {
return request({ 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', method: 'post',
data: query data: query
}) })
}, },
deleteFunctionByName() { deleteFunctionByName() {
return request({ 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' method: 'delete'
}) })
}, },
deleteFunction(functionId) { deleteFunction(functionId) {
return request({ 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' method: 'delete'
}) })
}, },
getFunctionByFunctionName() { getFunctionByFunctionName() {
return request({ 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' method: 'get'
}) })
}, },
invokeFunction(params, query) { invokeFunction(params, query) {
return request({ 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', method: 'post',
params: params, params: params,
data: query data: query
@ -406,7 +436,7 @@ export default {
}, },
listFunctions(query) { listFunctions(query) {
return request({ 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', method: 'get',
params: query || { page: 1, size: 10 } params: query || { page: 1, size: 10 }
}) })
@ -419,41 +449,41 @@ export default {
// }, // },
getFunctionOverview() { getFunctionOverview() {
return request({ 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' method: 'get'
}) })
}, },
getFunctionMap() { getFunctionMap() {
return request({ 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' method: 'get'
}) })
}, },
// 大屏总营收接口 // 大屏总营收接口
getRevenue() { getRevenue() {
return request({ return request({
url: process.env.VUE_APP_FUNCTION_API + '/queryRevenue', url: process.env.VUE_APP_FUNCTION_API + '/jcc-mall/order/queryRevenue',
method: 'get' method: 'get'
}) })
}, },
// 大屏地球查询 // 大屏地球查询
getMapArea() { getMapArea() {
return request({ 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' method: 'get'
}) })
}, },
// 大屏云厂商服务器数量查询接口 // 大屏云厂商服务器数量查询接口
getCloudServerCount() { getCloudServerCount() {
return request({ 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' method: 'get'
}) })
}, },
// 大屏服务器数量统计接口 // 大屏服务器数量统计接口
getServerDeviceCount() { getServerDeviceCount() {
return request({ 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' method: 'get'
}) })
}, },
@ -461,7 +491,7 @@ export default {
// 大屏服务器数量统计接口 // 大屏服务器数量统计接口
getOrderStatus() { getOrderStatus() {
return request({ return request({
url: process.env.VUE_APP_FUNCTION_API + '/countOrderStatus', url: process.env.VUE_APP_FUNCTION_API + '/jcc-mall/order/countOrderStatus',
method: 'get' method: 'get'
}) })
}, },

View File

@ -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'
}
})
}

View File

@ -1,7 +1,7 @@
<template> <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"> <el-form ref="createContainerForm" :model="createContainerForm">
<div class="border"> <div class="border">

View File

@ -1,29 +1,37 @@
<template> <template>
<!-- 添加存储卷 --> <!-- 添加存储卷 -->
<el-dialog v-if="dialogVisible" width="80%" title="存储卷" :visible.sync="dialogVisible"> <el-dialog v-if="dialogVisible" width="80%" title="存储卷" :visible.sync="dialogVisible" append-to-body>
<el-form ref="createVolumesForm" :model="createVolumesForm"> <el-form ref="volumeData" :model="volumeData">
<el-tabs v-model="activeName" type="card" @tab-click="handleClick"> <el-tabs v-model="activeName" type="card" @tab-click="handleClick">
<el-tab-pane label="已有存储卷" name="first"> <el-tab-pane label="已有存储卷" name="first">
<el-select v-model="createVolumesForm.volumes" class="selectPro" placeholder="选择已有存储卷"> <el-form-item
<el-option v-if="activeName==='first'"
v-for="item in volumesList" prop="firstName"
:key="item.label" label=""
:label="item.label" required
:value="item.label" >
> <el-select v-model="volumeData.firstName" class="selectPro" placeholder="选择已有存储卷">
<span style="width:50%; display:block;float:left">{{ item.label }}{{ item.alias?'('+item.alias+')':'' }}存储类型{{ item.storageClassName }}</span> <el-option
<span style="width:10%;display:block;float:left; color: #8492a6; font-size: 13px">容量{{ item.storage }}</span> v-for="item in volumesList"
<span style="width:40%; display:block;float:left; text-align:right">访问模式{{ item.accessModes }}</span> :key="item.label"
</el-option> :label="item.label"
</el-select> :value="item.label"
>
<span style="width:50%; display:block;float:left">{{ item.label }}{{ item.alias?'('+item.alias+')':'' }}存储类型{{ item.storageClassName }}</span>
<span style="width:10%;display:block;float:left; color: #8492a6; font-size: 13px">容量{{ item.storage }}</span>
<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>
<el-tab-pane label="临时存储卷" name="second"> <el-tab-pane label="临时存储卷" name="second">
<el-form-item <el-form-item
prop="volumesName" v-if="activeName==='second'"
prop="secondName"
label="存储卷名称" label="存储卷名称"
required required
> >
<el-input v-model="createVolumesForm.volumesName" :maxlength="63" /> <el-input v-model="volumeData.secondName" :maxlength="63" />
<span class="tips">最长 63 个字符只能包含小写字母数字及分隔符("-")且必须以小写字母或数字开头及结尾</span> <span class="tips">最长 63 个字符只能包含小写字母数字及分隔符("-")且必须以小写字母或数字开头及结尾</span>
</el-form-item> </el-form-item>
</el-tab-pane> </el-tab-pane>
@ -33,19 +41,21 @@
type="warning" type="warning"
/> />
<el-form-item <el-form-item
prop="volumesName" v-if="activeName==='third'"
prop="thirdName"
label="存储卷名称" label="存储卷名称"
required required
> >
<el-input v-model="createVolumesForm.volumesName" :maxlength="63" /> <el-input v-model="volumeData.thirdName" :maxlength="63" />
<span class="tips">最长 63 个字符只能包含小写字母数字及分隔符("-")且必须以小写字母或数字开头及结尾</span> <span class="tips">最长 63 个字符只能包含小写字母数字及分隔符("-")且必须以小写字母或数字开头及结尾</span>
</el-form-item> </el-form-item>
<el-form-item <el-form-item
v-if="activeName==='third'"
prop="hostPath" prop="hostPath"
label="HostPath" label="HostPath"
required required
> >
<el-input v-model="createVolumesForm.volumesName" :maxlength="63" /> <el-input v-model="volumeData.path" :maxlength="63" />
<span class="tips">最长 63 个字符只能包含小写字母数字及分隔符("-")且必须以小写字母或数字开头及结尾</span> <span class="tips">最长 63 个字符只能包含小写字母数字及分隔符("-")且必须以小写字母或数字开头及结尾</span>
</el-form-item> </el-form-item>
</el-tab-pane> </el-tab-pane>
@ -53,9 +63,9 @@
<table v-if="formData.spec.template.spec.containers"> <table v-if="formData.spec.template.spec.containers">
<tr v-for="(item, index) in formData.spec.template.spec.containers" :key="index" class="dataList"> <tr v-for="(item, index) in formData.spec.template.spec.containers" :key="index" class="dataList">
<td>容器</td> <td>容器</td>
<td>{{ item }}</td> <td>{{ item.name }}</td>
<td> <td>
<el-select v-model="createVolumesForm.readOnly"> <el-select v-model="createVolumesForm[index].readOnly">
<el-option <el-option
v-for="it in mountOptions" v-for="it in mountOptions"
:key="it.value" :key="it.value"
@ -64,7 +74,7 @@
/> />
</el-select> </el-select>
</td> </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> </tr>
</table> </table>
</el-form> </el-form>
@ -77,6 +87,7 @@
<script> <script>
import { mountOptions } from '@/utils/map' import { mountOptions } from '@/utils/map'
import generate from 'nanoid/generate'
export default { export default {
props: { props: {
value: { value: {
@ -94,7 +105,13 @@ export default {
}, },
data() { data() {
return { return {
createVolumesForm: {}, createVolumesForm: [],
volumeData: {
firstName: '',
secondName: '',
thirdName: '',
hostPath: ''
},
volumesList: [], volumesList: [],
activeName: 'first', activeName: 'first',
mountOptions mountOptions
@ -126,6 +143,15 @@ export default {
// } // }
}, },
watch: { 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) { // code(val) {
// this.codeData = val // this.codeData = val
// } // }
@ -141,22 +167,49 @@ export default {
}) })
}, },
ok() { 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)
// }) this.$emit('addVolumes', newFormData)
// } this.dialogVisible = false
switch (this.activeName) { }
case 'first': })
break
case 'second':
break
}
return this.$emit('addVolumes', val)
}, },
handleClick() {} handleClick() {}
} }

View File

@ -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>

View File

@ -265,10 +265,7 @@ export default {
}, },
methods: { methods: {
addImage(data) { addImage(data) {
console.log(this.editInfoForm.spec.template.spec.containers)
this.editInfoForm.spec.template.spec.containers.push(data) this.editInfoForm.spec.template.spec.containers.push(data)
console.log(this.editInfoForm.spec.template.spec.containers.length)
// console.log(data)
this.containerForm = undefined this.containerForm = undefined
}, },
editImage(data) { editImage(data) {
@ -303,8 +300,10 @@ export default {
border: 1px solid #DCDFE6; border: 1px solid #DCDFE6;
margin-top: 10px; margin-top: 10px;
padding:10px; padding:10px;
line-height: 1.4em;
.el-button{ .el-button{
float:right; float:right;
margin-right: 10px;
} }
} }
.selectRadio{ .selectRadio{

View File

@ -11,7 +11,7 @@
<mountVolumes v-if="stepNum===2" v-model="metaData" /> <mountVolumes v-if="stepNum===2" v-model="metaData" />
<advancedSettings v-if="stepNum===3" v-model="metaData" /> <advancedSettings v-if="stepNum===3" v-model="metaData" />
<div slot="footer" class="dialog-footer"> <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!==0" type="primary" @click="prev">上一步</el-button>
<el-button v-if="stepNum!==3" type="primary" @click="next">下一步</el-button> <el-button v-if="stepNum!==3" type="primary" @click="next">下一步</el-button>
<el-button v-else type="primary" @click="createWorkload">创建</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.$Api.postWorkload(this.clusterName, this.metaData.metadata.namespace, this.classification, this.metaData).then(() => {
this.$message.success('创建成功!') this.$message.success('创建成功!')
this.createFormVisible = false this.createFormVisible = false
this.transformYaml()
this.$emit('getList') this.$emit('getList')
}) })
}) })
@ -118,6 +119,7 @@ spec:
}) })
}, },
transformYaml() { transformYaml() {
this.stepNum = 0
this.metaData = JSON.parse(JSON.stringify(yaml.load(this.baseYaml), null, 2)) this.metaData = JSON.parse(JSON.stringify(yaml.load(this.baseYaml), null, 2))
}, },
prev() { prev() {

View File

@ -1,30 +1,51 @@
<template> <template>
<div> <div class="mountVolumes">
<p>挂载存储</p> <p>挂载存储</p>
<!-- dataList --> <!-- dataList -->
<!-- <i class="el-icon-receiving" /> <!-- <i class="el-icon-receiving" />
<i class="el-icon-setting" /> <i class="el-icon-setting" />
<i class="el-icon-key" /> --> <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-group>
<el-button ton @click="createFormVisible=true"> <el-button ton @click="createFormVisible=true">
添加存储卷 添加存储卷
<span class="tips">支持临时存储卷以及持久化存储卷</span> <span class="tips">支持临时存储卷以及持久化存储卷</span>
</el-button> </el-button>
<el-button>挂载配置文件或密钥 <el-button @click="mountSettingFormVisible=true">
挂载配置文件或密钥
<span class="tips">将配置文件或密钥挂载至指定目录</span> <span class="tips">将配置文件或密钥挂载至指定目录</span>
</el-button> </el-button>
</el-button-group> </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> </div>
</template> </template>
<script> <script>
import addVolumesForm from '@/components/Actions/addVolumesForm.vue' import addVolumesForm from '@/components/Actions/addVolumesForm.vue'
import mountSettingForm from '@/components/Actions/mountSettingOrKey.vue'
export default { export default {
components: { addVolumesForm }, components: { addVolumesForm, mountSettingForm },
props: { props: {
value: { value: {
type: Object, type: Object,
@ -34,8 +55,7 @@ export default {
data() { data() {
return { return {
createFormVisible: false, createFormVisible: false,
createVolumesForm: {}, mountSettingFormVisible: false
formData: {}
} }
}, },
computed: { computed: {
@ -49,12 +69,53 @@ export default {
} }
}, },
methods: { 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> </script>
<style lang="scss"> <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{ .selectPro{
width: 100%; width: 100%;

View File

@ -2,7 +2,7 @@ import { getVolume } from '@/api/one-class-page/storageManagement'
import { getNodeMessage, getNodeStatus } from '@/api/one-class-page/nodeManagement' import { getNodeMessage, getNodeStatus } from '@/api/one-class-page/nodeManagement'
import { getByValue } from '@/utils/data-process' import { getByValue } from '@/utils/data-process'
import { getDaemonSets, getDeployments, getPods, getServices, getStatefulSets } from '@/api/one-class-page/workloadManagement' 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 { getImages } from '@/api/one-class-page/virtualMachine'
import { import {
getBriefSystemProject, getBriefSystemProject,
@ -11,6 +11,8 @@ import {
getDetailUserProject getDetailUserProject
} from '@/api/one-class-page/projectManagement' } from '@/api/one-class-page/projectManagement'
import { getHostNum, getMemberNum } from '@/api/one-class-page/cluster' import { getHostNum, getMemberNum } from '@/api/one-class-page/cluster'
import { parseSi } from '@/utils'
// import { strToNumber } from '@/utils/data-process' // import { strToNumber } from '@/utils/data-process'
function getStatus(readyReplicas, replicas) { function getStatus(readyReplicas, replicas) {
@ -273,12 +275,25 @@ const getHostVirtualMachineList = (clusterName, params) => {
} }
const getVirtualMachineList = (clusterName, params) => { const getVirtualMachineList = (clusterName, params) => {
return new Promise(function(resolve) { return new Promise(function(resolve) {
const listResult = [] let listResult = []
getVirtualMachinesInstances().then((res) => { Promise.all([
for (let item = 0; item < res.data.length; item++) { getVirtualMachines(),
const obj = {} getVirtualMachinesInstances()
obj.index = item ]).then(res => {
obj.name = res.data[item].metadata.fields[0] 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: 虚拟机状态显示 // TODO: 虚拟机状态显示
// var running = res.data[item].spec.running // var running = res.data[item].spec.running
// if (running) { // if (running) {
@ -286,21 +301,10 @@ const getVirtualMachineList = (clusterName, params) => {
// } else { // } else {
// obj.state = 'Off' // 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.memoryused = res.data[item].status.capacity.ephemeral-storage - res.data[item].status.allocatable.memory
// obj.memoryall = res.data[item].status.capacity.memory // obj.memoryall = res.data[item].status.capacity.memory
listResult[item] = obj // listResult[item] = obj
} )
resolve({ total: 10, rows: listResult }) resolve({ total: 10, rows: listResult })
}) })
}) })
@ -309,38 +313,77 @@ const getVirtualMachineList = (clusterName, params) => {
const getVirtualHostList = () => { const getVirtualHostList = () => {
return new Promise(function(resolve) { return new Promise(function(resolve) {
const listResult = [] const listResult = []
getUsageStatus().then(usage => {
getVirtualHosts().then((res) => { Promise.all([
for (let item = 0; item < res.data.length; item++) { getDashboardInfo(), // cpu 内存 总量
var obj = {} getUsageStatus(), // cpu 内存 使用量
obj.index = item getStorageStatus(),
obj.customName = res.data[item].metadata.annotations['harvesterhci.io/host-custom-name'] getVirtualHosts()]).then(res => {
obj.name = res.data[item].metadata.name for (let item = 0; item < res[3].data.length; item++) {
obj.state = res.data[item].metadata.state.name let cpuAll = 0
obj.state = obj.state.charAt(0).toUpperCase() + obj.state.slice(1) let memoryAll = 0
obj.hostIP = res.data[item].metadata.fields[5] let storageAll = 0
obj.aliveTime = res.data[item].metadata.fields[3] let cpuUsed = 0
obj.aliveTime = obj.aliveTime.replace('d', '天') let memoryUsed = 0
obj.aliveTime = obj.aliveTime.replace('h', '小时') let storageUsage = 0
obj.cpuUsed = parseFloat((parseInt(usage?.data[item]?.usage?.cpu || 0) / 1000000000).toFixed(2)) res[0].data.forEach(element => {
obj.cpuAll = parseInt(res.data[item].status.capacity.cpu) if (res[3].data[item].metadata.name === element.id) {
obj.cpuUsePercentage = parseFloat((obj.cpuUsed / obj.cpuAll).toFixed(2)) * 100 cpuAll += Number(element.status.capacity.cpu)
obj.memoryUsed = parseFloat((parseInt(usage.data[item].usage.memory) / 1024 / 1024).toFixed(2)) memoryAll += Number(element.status.capacity.memory.replace('Ki', ''))
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
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')
if (obj.isMaintenance) {
obj.state = 'Maintenance mode'
} }
listResult[item] = obj })
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[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[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 = 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[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'
} }
resolve({ total: res.data.length, rows: listResult })
}) listResult[item] = obj
}
resolve({ total: res[3].data.length, rows: listResult })
}) })
}) })
} }

View File

@ -360,3 +360,58 @@ export function newEval(str) {
var Fn = Function var Fn = Function
return new Fn('return ' + str)() 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
}

View File

@ -17,9 +17,13 @@ const policysTypeOptions = [
] ]
const mountOptions = [ const mountOptions = [
{ label: '读写', value: 'false' }, { label: '读写', value: false },
{ label: '只读', value: 'true' }, { label: '只读', value: true },
{ label: '不挂载', value: 'null' } { label: '不挂载', value: null }
]
const settingMountOptions = [
{ label: '只读', value: true },
{ label: '不挂载', value: null }
] ]
const imagePullPolicyOptions = [ const imagePullPolicyOptions = [
@ -57,6 +61,7 @@ export {
policysOptions, policysOptions,
policysTypeOptions, policysTypeOptions,
mountOptions, mountOptions,
settingMountOptions,
imagePullPolicyOptions, imagePullPolicyOptions,
protocolOptions protocolOptions
} }

View File

@ -6,7 +6,7 @@
<el-tab-pane label="证书查验" name="1" /> <el-tab-pane label="证书查验" name="1" />
<el-tab-pane label="身份查验" name="2" /> <el-tab-pane label="身份查验" name="2" />
</el-tabs> </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-button slot="append" icon="el-icon-search" type="primary" @click="search">校验查询</el-button>
</el-input> </el-input>
<List <List
@ -22,7 +22,7 @@
<el-dialog width="70%" title="交易证书" :visible.sync="dialogCertVisible"> <el-dialog width="70%" title="交易证书" :visible.sync="dialogCertVisible">
<div class="certification"> <div class="certification">
<p>兹证明<br> <p>兹证明<br>
申请人 {{ certificationData.buyerName }} {{ certificationData.transTime }} 通过 {{ certificationData.sellerName }} 平台提交了以下电子数据及信息 申请人 {{ certificationData.buyerName }} {{ new Date(certificationData.transTime).toLocaleString() }} 通过 {{ certificationData.sellerName }} 平台提交了以下电子数据及信息
</p> </p>
<FormData :column="1" :data="certificationData" :data-map="certDataMap" /> <FormData :column="1" :data="certificationData" :data-map="certDataMap" />
</div> </div>
@ -47,7 +47,9 @@ export default {
columns: [ columns: [
{ prop: 'certNum', label: '证书编号' }, { prop: 'certNum', label: '证书编号' },
{ prop: 'fingerPrint', 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) => { { prop: 'more', label: '操作', formatter: (row) => {
return <div> return <div>
<el-button onClick={() => this.viewCredential(row)} type='text' size='small'>查看</el-button> <el-button onClick={() => this.viewCredential(row)} type='text' size='small'>查看</el-button>

View File

@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<el-card shadow="never"> <el-card shadow="never">
<el-page-header content="区块列表" @back="goBack" /> <el-page-header content="区块列表(最近一个月的数据)" @back="goBack" />
<List <List
v-if="listData.length>=1" v-if="listData.length>=1"
ref="multipleTable" ref="multipleTable"

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="functionList"> <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-row :gutter="20">
<el-col v-for="(item,index) in functionList" :key="index" :span="6"> <el-col v-for="(item,index) in functionList" :key="index" :span="6">
<el-card shadow="never" class="functionCard"> <el-card shadow="never" class="functionCard">
@ -31,6 +31,7 @@
background background
:hide-on-single-page="true" :hide-on-single-page="true"
:current-page="page" :current-page="page"
:page-size="size"
layout="prev, pager, next" layout="prev, pager, next"
:total="total" :total="total"
@current-change="currentChange" @current-change="currentChange"
@ -91,15 +92,15 @@
<td>Function Name:</td> <td>Function Name:</td>
<td :colspan="3">{{ form.functionName }}</td> <td :colspan="3">{{ form.functionName }}</td>
<td>Created Time:</td> <td>Created Time:</td>
<td>{{ form.createTime }}</td> <td>{{ form.createdTime }}</td>
</tr> </tr>
<tr> <tr>
<td>Env:</td> <td>Env:</td>
<td>{{ form.runEnv }}</td> <td>{{ form.runEnv }}</td>
<td>Memory Size:</td> <td>Memory Size:</td>
<td>{{ form.memorySize }}</td> <td>{{ form.memorySize }}MB</td>
<td>Timeout:</td> <td>Timeout:</td>
<td>{{ form.timeout }}</td> <td>{{ form.timeout }}s</td>
</tr> </tr>
<tr> <tr>
<td>Code Size:</td> <td>Code Size:</td>
@ -107,7 +108,7 @@
<td>Code Checksum:</td> <td>Code Checksum:</td>
<td :colspan="3">{{ form.codeChecksum }}</td> <td :colspan="3">{{ form.codeChecksum }}</td>
</tr> </tr>
<tr> <!-- <tr>
<td>Description</td> <td>Description</td>
<td :colspan="5">{{ form.description }}</td> <td :colspan="5">{{ form.description }}</td>
</tr> </tr>
@ -115,13 +116,8 @@
<td>EnviromentVariable:</td> <td>EnviromentVariable:</td>
<td :colspan="2">{{ form.envVar }}</td> <td :colspan="2">{{ form.envVar }}</td>
<td :colspan="3"> <td :colspan="3">
<!-- Enable Native Serverless:
<el-switch
v-model="form.enableNS"
size="small">
</el-switch> -->
</td> </td>
</tr> </tr> -->
</table> </table>
<el-row style="margin-bottom:30px" :gutter="30"> <el-row style="margin-bottom:30px" :gutter="30">
<el-col :span="9"> <el-col :span="9">
@ -263,16 +259,24 @@ export default {
// this.form = val; // this.form = val;
// this.activeName = '2'; // this.activeName = '2';
this.form = val this.form = val
this.result = ''
this.dialogExecuteVisible = true this.dialogExecuteVisible = true
}, },
createFunc() { createFunc() {
// //
const funcForm = { code: { zipFile: this.form.runEnv === 'java8' ? this.fileList[0].code : this.transBase64(this.code) }, ...this.form }
this.$Api.createFunction(funcForm).then((res) => { this.$Api.checkFunctionName(this.form.functionName).then(res => {
if (res) { if (res.data.exist) {
this.$message.success('创建函数成功') this.$message.warning('名称已存在')
this.goDetail(this.form) } else {
this.getList() 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) {
this.$message.success('创建函数成功')
this.goDetail(this.form)
this.getList()
}
})
} }
}) })
}, },

View File

@ -55,13 +55,11 @@
</template> </template>
<script> <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 List from '@/components/list'
import * as echarts from 'echarts' import * as echarts from 'echarts'
import { getDashboardCounts, getDashboardEvents, getDashboardInfo, getUsageStatus, getStorageStatus } from '@/api/one-class-page/virtualMachine' import { getDashboardCounts, getDashboardEvents, getDashboardInfo, getUsageStatus, getStorageStatus } from '@/api/one-class-page/virtualMachine'
import moment from 'moment' import moment from 'moment'
import { parseSi } from '@/utils'
export default { export default {
components: { List }, components: { List },
data() { data() {
@ -132,8 +130,8 @@ export default {
let memoryCounts = 0 let memoryCounts = 0
let cpuCounts = 0 let cpuCounts = 0
containers.forEach(e => { containers.forEach(e => {
memoryCounts += this.parseSi(e?.resources?.requests?.memory || '0m', { increment: 1024 }) memoryCounts += parseSi(e?.resources?.requests?.memory || '0m', { increment: 1024 })
cpuCounts += this.parseSi(e?.resources?.requests?.cpu || '0m') cpuCounts += parseSi(e?.resources?.requests?.cpu || '0m')
}) })
this.memoryUsage += memoryCounts this.memoryUsage += memoryCounts
this.cpuUsage += cpuCounts this.cpuUsage += cpuCounts
@ -156,57 +154,6 @@ export default {
}) })
}, },
methods: { 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) { formatDate(t) {
return moment(t).local().format('YYYY-MM-DD hh:mm:ss') return moment(t).local().format('YYYY-MM-DD hh:mm:ss')
}, },
@ -214,7 +161,7 @@ export default {
const cpuGauge = echarts.init(this.$refs.cpuGauge) const cpuGauge = echarts.init(this.$refs.cpuGauge)
cpuGauge.setOption(this.returnGaugeOption((this.cpuUsage / this.cpuTotal).toFixed(4) * 100)) cpuGauge.setOption(this.returnGaugeOption((this.cpuUsage / this.cpuTotal).toFixed(4) * 100))
const memoryGauge = echarts.init(this.$refs.memoryGauge) 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) 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)) storageGauge.setOption(this.returnGaugeOption(((this.storageUsage / 1024 / 1024 / 1024 / 1024).toFixed(2) / (this.storageTotal / 1024 / 1024 / 1024 / 1024).toFixed(2)).toFixed(4) * 100))
}, },

View File

@ -4,8 +4,8 @@
<script> <script>
import * as Three from 'three' import * as Three from 'three'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls' import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { getEarthRegion } from '@/api/screen -one-class-page/TotalNum' import { getEarthRegion } from '@/api/screen-one-class-page/TotalNum'
import { getEarthDetails } from '@/api/screen -one-class-page/TotalNum' import { getEarthDetails } from '@/api/screen-one-class-page/TotalNum'
export default { export default {
data() { data() {
return { return {

View File

@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<div class="formcontainer"> <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-row :gutter="10">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="名称"><el-input <el-form-item label="名称"><el-input
@ -78,37 +78,11 @@
</template> </template>
<script> <script>
import { getImages, getDataVolumeNew, editDataVolume } from '@/api/one-class-page/virtualMachine' import { getImages, getDataVolumeNew, editDataVolume, createDataVolume } from '@/api/one-class-page/virtualMachine'
import { createDataVolume } from '@/api/one-class-page/virtualMachine'
export default { export default {
data() { data() {
return { return {
volumeData: { 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: {}
}
}
},
Data: {}, Data: {},
tagNum: 0, tagNum: 0,
disableConfig: true, disableConfig: true,
@ -198,15 +172,31 @@ export default {
this.$router.push({ path: '/virtual/dataVolume' }) this.$router.push({ path: '/virtual/dataVolume' })
}, },
create() { create() {
this.volumeData.metadata.annotations['field.cattle.io/description'] = this.formData.description this.volumeData = {
if (this.formData.resourceType === 'VM Image') this.volumeData.metadata.annotations['harvesterhci.io/imageId'] = this.formData.imageId apiVersion: 'v1',
for (let item = 0; item < this.formData.tag.length; item++) { kind: 'PersistentVolumeClaim',
this.volumeData.metadata.labels[this.formData.tag[item].key] = this.formData.tag[item].value 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 => { createDataVolume(this.volumeData).then(res => {
console.log(res)
this.$message.success('创建成功') this.$message.success('创建成功')
this.goBack() this.goBack()
}) })

View File

@ -62,7 +62,7 @@
<script> <script>
import { import {
getHostYaml, getHostYaml,
getHostNetwork, // getHostNetwork,
putHostYaml, putHostYaml,
putHostNetwork, putHostNetwork,
getNodeNetworks getNodeNetworks
@ -139,11 +139,11 @@ export default {
this.formData.customName = res.metadata.annotations['harvesterhci.io/host-custom-name'] this.formData.customName = res.metadata.annotations['harvesterhci.io/host-custom-name']
this.yamlData = res this.yamlData = res
}) })
getHostNetwork(this.$route.query.name).then(res => { // getHostNetwork(this.$route.query.name).then(res => {
this.formData.type = res.spec.type // this.formData.type = res.spec.type
this.formData.physicalNIC = res.spec.nic // this.formData.physicalNIC = res.spec.nic
this.vlanData = res // this.vlanData = res
}) // })
getNodeNetworks().then(res => { getNodeNetworks().then(res => {
this.physicalNICList = res.data[this.$route.query.index].status.physicalNICs this.physicalNICList = res.data[this.$route.query.index].status.physicalNICs
}) })

View File

@ -194,15 +194,15 @@ export default {
this.formData.lastUpdateTime = res.data[this.formData.index].status.conditions[0].lastUpdateTime 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.uuid = res.data[this.formData.index].status.nodeInfo.systemUUID
this.formData.cpuUsed = parseFloat((parseInt(usage.usage.cpu) / 1000000000).toFixed(2)) this.formData.cpuUsed = this.$route.query.cpuUsed
this.formData.cpuAll = parseInt(res.data[this.formData.index].status.capacity.cpu) this.formData.cpuAll = this.$route.query.cpuAll
this.formData.cpuUsePercentage = parseFloat((this.formData.cpuUsed / this.formData.cpuAll).toFixed(2)) * 100 this.formData.cpuUsePercentage = this.$route.query.cpuUsePercentage
this.formData.memoryUsed = parseFloat((parseInt(usage.usage.memory) / 1024 / 1024).toFixed(2)) this.formData.memoryUsed = this.$route.query.memoryUsed
this.formData.memoryAll = parseFloat((parseFloat(res.data[this.formData.index].status.capacity.memory) / 1024 / 1024).toFixed(2)) this.formData.memoryAll = this.$route.query.memoryAll
this.formData.memoryUsePercentage = parseFloat((this.formData.memoryUsed / this.formData.memoryAll).toFixed(2)) * 100 this.formData.memoryUsePercentage = this.$route.query.memoryUsePercentage
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.storageUsed = this.$route.query.storageUsed
this.formData.storageAll = parseFloat((parseFloat(res.data[this.formData.index].status.capacity['ephemeral-storage']) / 1024 / 1024 / 1024).toFixed(2)) this.formData.storageAll = this.$route.query.storageAll
this.formData.storageUsePercentage = parseFloat((this.formData.storageUsed / this.formData.storageAll).toFixed(2)) * 100 this.formData.storageUsePercentage = this.$route.query.storageUsePercentage
}) })
}) })
}, },

View File

@ -22,7 +22,7 @@
:columns="columns" :columns="columns"
func-name="getImagesList" func-name="getImagesList"
:cluster-name="clusterName" :cluster-name="clusterName"
:pagination="true" :pagination="false"
tooltip-effect="dark" tooltip-effect="dark"
/> />
</el-card> </el-card>
@ -78,7 +78,6 @@ export default {
<el-dropdown-menu slot='dropdown'> <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, 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, 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, 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> <span onClick={() => this.clickOption(row, 5)}> <el-dropdown-item divided><i class='el-icon-delete'></i> 删除 </el-dropdown-item> </span>
</el-dropdown-menu> </el-dropdown-menu>
@ -132,7 +131,7 @@ export default {
this.$router.push({ path: `virtual-machine/create`, query: row }) this.$router.push({ path: `virtual-machine/create`, query: row })
break break
case 4: case 4:
this.downloadHostYaml(row.name) this.downloadHostYaml(row)
break break
case 5: case 5:
this.deleteDialogVisible = true this.deleteDialogVisible = true
@ -151,8 +150,8 @@ export default {
viewVMDetail(row) { viewVMDetail(row) {
this.$router.push({ path: `virtual-machine/detail`, query: row }) this.$router.push({ path: `virtual-machine/detail`, query: row })
}, },
downloadHostYaml(name) { downloadHostYaml(row) {
getImagesYaml(name).then(res => { getImagesYaml(row.name).then(res => {
var data = JSON.stringify(res) var data = JSON.stringify(res)
// encodeURIComponent // encodeURIComponent
const uri = 'data:text/csv;charset=utf-8,\ufeff' + encodeURIComponent(data) const uri = 'data:text/csv;charset=utf-8,\ufeff' + encodeURIComponent(data)
@ -160,7 +159,7 @@ export default {
const link = document.createElement('a') const link = document.createElement('a')
link.href = uri link.href = uri
// //
link.download = name + '.json' link.download = row.displayName + '.json'
document.body.appendChild(link) document.body.appendChild(link)
link.click() link.click()
document.body.removeChild(link) document.body.removeChild(link)

View File

@ -1,7 +1,7 @@
<template> <template>
<div> <div>
<div class="formcontainer"> <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-row :gutter="10">
<el-col :span="12"> <el-col :span="12">
<el-form-item label="名称"><el-input <el-form-item label="名称"><el-input
@ -22,26 +22,24 @@
<el-tab-pane label="基本信息"> <el-tab-pane label="基本信息">
<h4>基本信息</h4> <h4>基本信息</h4>
<el-form-item label="镜像地址"> <el-form-item label="镜像地址">
<el-select v-model="formData.resourceType" :disabled="!clone"> <el-input
<el-option v-model="formData.url"
v-for="item in options1" :hide-required-asterisk="true"
:key="item.value" :disabled="!clone"
:label="item.label" placeholder="镜像地址"
:value="item.value" />
/>
</el-select>
</el-form-item> </el-form-item>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="标签"> <el-tab-pane label="标签">
<h4>标签</h4> <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-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-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.key" placeholder="例如test" /></el-col>
<el-col :span="6"> <el-input v-model="item.value" 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-row>
</el-form-item> </el-form-item>
</div> </div>
@ -54,25 +52,28 @@
<el-row type="flex" justify="end"> <el-row type="flex" justify="end">
<el-col :span="2.5"> <el-col :span="2.5">
<el-button v-if="!isDisabled" type="info" @click="goBack">取消</el-button> <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-col>
</el-row> </el-row>
</div> </div>
</template> </template>
<script> <script>
import { getImages, editImage, createImages } from '@/api/one-class-page/virtualMachine'
export default { export default {
data() { data() {
return { return {
tagNum: 0, tagNum: 0,
index: '',
disableConfig: true, disableConfig: true,
clone: false, clone: false,
currentData: '',
formData: { formData: {
name: '', name: '',
description: '', description: '',
size: '', size: '',
resourceType: 'https://github.com/rancher/k3os/releases/download/v0.11.1/k3os-amd64.iso',
image: '', image: '',
tag: [] tag: []
} }
@ -83,6 +84,9 @@ export default {
return this.disableConfig && !this.clone return this.disableConfig && !this.clone
} }
}, },
created() {
this.index = this.$route.query.index
},
mounted() { mounted() {
this.getFormData() this.getFormData()
if (this.$route.query.disableConfig != null && typeof (this.$route.query.disableConfig) !== 'undefined') { if (this.$route.query.disableConfig != null && typeof (this.$route.query.disableConfig) !== 'undefined') {
@ -94,10 +98,22 @@ export default {
}, },
methods: { methods: {
getFormData() { getFormData() {
this.formData.name = this.$route.query.name getImages().then(res => {
this.formData.size = this.$route.query.size.slice(0, -2) var data = res.data[this.index]
// this.formData.description = this.$route.query.description, this.currentData = data
// this.formData.resourceType = this.$route.query.resourceType 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() { addTag() {
this.formData.tag.push( 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) { removeTag(index) {
this.formData.tag.splice(index, 1) this.formData.tag.splice(index, 1)
}, },
goBack() { goBack() {
this.$router.push({ path: '/virtual/images.vue' }) this.$router.push({ path: '/virtual/images' })
} }
} }
} }

View File

@ -15,6 +15,7 @@
<script> <script>
import { FormData } from '@/components/FormData' import { FormData } from '@/components/FormData'
import { getImages } from '@/api/one-class-page/virtualMachine'
export default { export default {
components: { FormData }, components: { FormData },
data() { data() {
@ -23,7 +24,7 @@ export default {
formData1: { formData1: {
description: ' ', description: ' ',
size: this.$route.query.size, size: this.$route.query.size,
resourceType: 'https://github.com/rancher/k3os/releases/download/v0.11.1/k3os-amd64.iso' resourceType: ''
}, },
dataMap1: { dataMap1: {
description: '描述', description: '描述',
@ -64,7 +65,16 @@ export default {
this.getFormData() this.getFormData()
}, },
methods: { 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> </script>

View File

@ -33,14 +33,14 @@
width="30%" width="30%"
> >
<p>您试图删除 虚拟机 {{ deleteName }} .</p> <p>您试图删除 虚拟机 {{ deleteName }} .</p>
<p>Select the volume you want to delete:</p> <p>选择您需要删除的卷:</p>
<el-checkbox-group v-model="selectDeleteVolumeList"> <el-checkbox-group v-model="selectDeleteVolumeList">
<el-checkbox <el-checkbox
v-for="data in deleteVolumeList" v-for="data in deleteVolumeList"
:key="data.name" :key="data"
:label="data.name" :label="data"
> >
{{ data.name }} {{ data }}
</el-checkbox> </el-checkbox>
</el-checkbox-group> </el-checkbox-group>
@ -103,6 +103,8 @@ export default {
formatter: row => { formatter: row => {
if (row.state === 'Running') { if (row.state === 'Running') {
return <el-tag disable-transitions type='success'>{row.state}</el-tag> 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 { } else {
return <span> return <span>
<el-tag disable-transitions>{row.state}</el-tag> <el-tag disable-transitions>{row.state}</el-tag>
@ -169,10 +171,9 @@ export default {
// }, // },
deleteVirtualMachine() { deleteVirtualMachine() {
this.deleteDialogVisible = false this.deleteDialogVisible = false
console.log(this.selectDeleteVolumeList)
deleteVirtualMachine(this.deleteName, this.selectDeleteVolumeList).then(res => { deleteVirtualMachine(this.deleteName, this.selectDeleteVolumeList).then(res => {
alert('删除成功') this.$message.success('删除成功')
location.reload() this.$refs.multipleTable.getList()
}) })
}, },
createVirtualMachine() { createVirtualMachine() {
@ -219,9 +220,9 @@ export default {
getVirtualMachines().then(res => { getVirtualMachines().then(res => {
var data = res.data[row.index] var data = res.data[row.index]
this.deleteVolumeList = [] this.deleteVolumeList = []
for (let i = 0; i < data.spec.template.spec.volumes.length; i++) { for (let i = 0; i < data.status?.volumeSnapshotStatuses?.length; i++) {
if (data.spec.template.spec.volumes[i].dataVolume != null) { if (data.status.volumeSnapshotStatuses[i].name !== 'cloudinitdisk') {
this.deleteVolumeList.push(data.spec.template.spec.volumes[i]) this.deleteVolumeList.push(data.status.volumeSnapshotStatuses[i].name)
} }
} }
this.deleteName = row.name this.deleteName = row.name

View File

@ -137,7 +137,7 @@
</template> </template>
<script> <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 ConfigVolume from './virtualMachineConfig/configVolume'
import ConfigImage from './virtualMachineConfig/configImage' import ConfigImage from './virtualMachineConfig/configImage'
import ConfigExistedVolume from './virtualMachineConfig/configExistedVolume' import ConfigExistedVolume from './virtualMachineConfig/configExistedVolume'
@ -347,7 +347,7 @@ export default {
this.getSSHKeys() this.getSSHKeys()
getImages().then(res => { getImages().then(res => {
this.imageList = res.data this.imageList = res.data
getDataVolume().then(res => { getDataVolumeNew().then(res => {
this.volumeList = res.data this.volumeList = res.data
this.show = true this.show = true
}) })
@ -363,15 +363,14 @@ export default {
getImages().then(res => { getImages().then(res => {
images = res.data images = res.data
this.imageList = res.data this.imageList = res.data
getDataVolume().then(res => { getDataVolumeNew().then(res => {
dataVolumeData = res.data dataVolumeData = res.data
this.volumeList = dataVolumeData this.volumeList = dataVolumeData
// getVirtualMachines().then(res => { // getVirtualMachines().then(res => {
var data = this.instanceData // res.data[this.$route.query.index] var data = this.instanceData // res.data[this.$route.query.index]
var dataImageName = null var dataImageName = null
for (let item = 0; item < data.spec.template.spec.volumes.length; item++) { data.spec.template.spec.volumes.forEach(item => {
var dataVolumeTemplate = data.spec.template.spec.volumes[item] var volumeName = item.name
var volumeName = dataVolumeTemplate.name
dataImageName = null dataImageName = null
var bus = null var bus = null
var bootOrder = null var bootOrder = null
@ -380,16 +379,14 @@ export default {
var componentType = null var componentType = null
var dataVolumeName = null var dataVolumeName = null
var imageId = null var imageId = null
if (dataVolumeTemplate.dataVolume != null) { if (item.dataVolume != null) {
dataVolumeName = dataVolumeTemplate.dataVolume.name dataVolumeName = item.dataVolume.name
} else if (dataVolumeTemplate.containerDisk != null) { } else if (item.containerDisk != null) {
dataVolumeName = dataVolumeTemplate.containerDisk.image dataVolumeName = item.containerDisk.image
componentType = 'Container' componentType = 'Container'
} else if (dataVolumeTemplate.cloudInitNoCloud != null) { } else if (item.cloudInitNoCloud != null) {
this.formData.userData = dataVolumeTemplate.cloudInitNoCloud.userData this.formData.userData = item.cloudInitNoCloud.userData
continue return
} else {
continue
} }
for (let item1 = 0; item1 < dataVolumeData.length; item1++) { for (let item1 = 0; item1 < dataVolumeData.length; item1++) {
if (dataVolumeName === dataVolumeData[item1].metadata.fields[0]) { if (dataVolumeName === dataVolumeData[item1].metadata.fields[0]) {
@ -412,7 +409,7 @@ export default {
break 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) { if (data.spec.dataVolumeTemplates[item1].metadata.name !== dataVolumeName) {
continue continue
} }
@ -436,7 +433,7 @@ export default {
// Name,type,Image,Size,Bus,BootOrder,docker,isCreate, disableConfig, volumeList, imageId // 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.childLists.push([volumeName, type, dataImageName, size, bus, bootOrder, dataVolumeName, null, true, this.volumeList, imageId])
this.allComponents.push(componentType) this.allComponents.push(componentType)
} })
this.formData.name = data.metadata.name this.formData.name = data.metadata.name
this.formData.description = data.metadata.annotations['field.cattle.io/description'] this.formData.description = data.metadata.annotations['field.cattle.io/description']
this.formData.customName = data.metadata.annotations['harvesterhci.io/host-custom-name'] this.formData.customName = data.metadata.annotations['harvesterhci.io/host-custom-name']

View File

@ -19,7 +19,7 @@
<h4>网络</h4> <h4>网络</h4>
<VirtualMachineDetailCard v-for="(item, ind) in allNetworkCard" :key="ind" card-name="网络" :data-map="dataMap5" :form-data="item" /> <VirtualMachineDetailCard v-for="(item, ind) in allNetworkCard" :key="ind" card-name="网络" :data-map="dataMap5" :form-data="item" />
</el-tab-pane> </el-tab-pane>
<el-tab-pane key="4" label="SSH 钥"> <el-tab-pane key="4" label="SSH 钥">
<h4>SSH Keys</h4> <h4>SSH Keys</h4>
<div v-for="(item,index) in sshkeyLists" :key="index"> <div v-for="(item,index) in sshkeyLists" :key="index">
{{ item.name }} {{ item.name }}
@ -72,7 +72,7 @@
<script> <script>
import { FormData } from '@/components/FormData' import { FormData } from '@/components/FormData'
import List from '@/components/list' 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' import VirtualMachineDetailCard from './virtualMachineConfig/virtualMachineDetailCard'
export default { export default {
name: 'VirtualMachineDetail', name: 'VirtualMachineDetail',
@ -125,8 +125,8 @@ export default {
dataMap: { dataMap: {
name: '名称', name: '名称',
image: '镜像', image: '镜像',
hostname: '主机名', node: '节点名称',
node: '节点', hostname: '主机',
IPAddress: 'IP地址', IPAddress: 'IP地址',
created: '创建时间' created: '创建时间'
}, },
@ -175,7 +175,7 @@ export default {
dataMap8: { dataMap8: {
Name: '名称', Name: '名称',
Type: '类型', Type: '类型',
Volume: '卷名称', // Volume: '',
Size: '大小', Size: '大小',
Bus: '总线', Bus: '总线',
BootOrder: '驱动顺序' BootOrder: '驱动顺序'
@ -207,167 +207,169 @@ export default {
// TODO Basics Image, Node IP Address // TODO Basics Image, Node IP Address
var images = null var images = null
var dataVolumeData = null var dataVolumeData = null
getImages().then(res => { Promise.all([
images = res.data getImages(),
getDataVolume().then(res => { getDataVolumeNew(),
dataVolumeData = res.data getVirtualMachines(),
getVirtualMachines().then(res => { getVirtualMachinesInstances()]).then(res => {
var data = res.data[this.$route.query.index] images = res[0].data
for (let item = 0; item < data.spec.template.spec.volumes.length; item++) { dataVolumeData = res[1].data
var dataVolumeTemplate = data.spec.template.spec.volumes[item] var data = res[2].data[this.index]
var volumeName = dataVolumeTemplate.name var currentVm = res[3].data.filter(n => n.id === data.id)?.[0]
var dataImageName = null data.spec?.template?.spec?.volumes?.forEach(item => {
var bus = null var volumeName = item.name
var bootOrder = null var dataImageName = null
var type = null var bus = null
var size = null var bootOrder = null
var componentType = null var type = null
var dataVolumeName = null var size = null
if (dataVolumeTemplate.dataVolume != null) { var componentType = null
dataVolumeName = dataVolumeTemplate.dataVolume.name var dataVolumeName = null
} else if (dataVolumeTemplate.containerDisk != null) { if (item.dataVolume != null) {
dataVolumeName = dataVolumeTemplate.containerDisk.image dataVolumeName = item.dataVolume.name
componentType = '容器镜像' } else if (item.containerDisk != null) {
} else if (dataVolumeTemplate.cloudInitNoCloud != null) { dataVolumeName = item.containerDisk.image
this.formData.userData = dataVolumeTemplate.cloudInitNoCloud.userData componentType = '容器镜像'
continue } else if (item.cloudInitNoCloud != null) {
} else { this.formData.userData = item.cloudInitNoCloud.userData
continue return
} }
for (let item1 = 0; item1 < dataVolumeData.length; item1++) { for (let item1 = 0; item1 < dataVolumeData.length; item1++) {
if (dataVolumeName === dataVolumeData[item1].metadata.fields[0]) { if (dataVolumeName === dataVolumeData[item1].metadata.fields[0]) {
size = dataVolumeData[item1].spec.pvc.resources.requests.storage size = dataVolumeData[item1].spec.pvc.resources.requests.storage
size = size.replace('Gi', '') size = size.replace('Gi', '')
break break
}
}
for (let item1 = 0; item1 < data.spec.template.spec.domain.devices.disks.length; item1++) {
var disk = data.spec.template.spec.domain.devices.disks[item1]
if (volumeName === disk.name) {
if (disk.cdrom != null && typeof (disk.cdrom) !== 'undefined') {
type = 'cd-rom'
bus = disk.cdrom.bus
} else {
type = 'disk'
bus = disk.disk.bus
}
bootOrder = disk.bootOrder
break
}
}
for (let item1 = 0; item1 < data.spec.dataVolumeTemplates.length; item1++) {
if (data.spec.dataVolumeTemplates[item1].metadata.name !== dataVolumeName) {
continue
}
if (data.spec.dataVolumeTemplates[item1].metadata.annotations != null && typeof (data.spec.dataVolumeTemplates[item1].metadata.annotations) !== 'undefined') {
var imageId = data.spec.dataVolumeTemplates[item1].metadata.annotations['harvesterhci.io/imageId']
for (let item2 = 0; item2 < images.length; item2++) {
if (imageId === images[item2].id) {
dataImageName = images[item1].spec.displayName
if (item1 === 0) {
this.formData.image = dataImageName
}
break
}
}
componentType = 'VM镜像'
} else {
componentType = '卷'
}
}
var formData2 = {
Name: volumeName,
Type: type,
Image: dataImageName,
Size: size,
Bus: bus,
BootOrder: bootOrder,
dockerMirror: dataVolumeName,
Volume: dataVolumeName
}
var itemObjct = null
if (componentType === 'VM镜像') {
itemObjct = {
formData: formData2,
name: componentType,
dataMap: this.dataMap3
}
} else if (componentType === '卷') {
itemObjct = {
formData: formData2,
name: componentType,
dataMap: this.dataMap4
}
} else if (componentType === '容器镜像') {
itemObjct = {
formData: formData2,
name: componentType,
dataMap: this.dataMap7
}
} else {
itemObjct = {
formData: formData2,
name: '现存卷',
dataMap: this.dataMap8
}
}
this.allDetailCard.push(itemObjct)
} }
this.allNetworkCard = this.getNetworkRows(data.spec) }
for (let item1 = 0; item1 < data.spec.template.spec.domain.devices.disks.length; item1++) {
var disk = data.spec.template.spec.domain.devices.disks[item1]
if (volumeName === disk.name) {
if (disk.cdrom != null && typeof (disk.cdrom) !== 'undefined') {
type = 'cd-rom'
bus = disk.cdrom.bus
} else {
type = 'disk'
bus = disk.disk.bus
}
bootOrder = disk.bootOrder
break
}
}
for (let item1 = 0; item1 < data.spec?.dataVolumeTemplates?.length; item1++) {
if (data.spec.dataVolumeTemplates[item1].metadata.name !== dataVolumeName) {
continue
}
if (data.spec.dataVolumeTemplates[item1].metadata.annotations != null && typeof (data.spec.dataVolumeTemplates[item1].metadata.annotations) !== 'undefined') {
var imageId = data.spec.dataVolumeTemplates[item1].metadata.annotations['harvesterhci.io/imageId']
for (let item2 = 0; item2 < images.length; item2++) {
if (imageId === images[item2].id) {
dataImageName = images[item1].spec.displayName
if (item1 === 0) {
this.formData.image = dataImageName
}
break
}
}
componentType = 'VM镜像'
} else {
componentType = '卷'
}
}
var formData2 = {
Name: volumeName,
Type: type,
Image: dataImageName,
Size: size,
Bus: bus,
BootOrder: bootOrder,
dockerMirror: dataVolumeName,
Volume: dataVolumeName
}
var itemObjct = null
if (componentType === 'VM镜像') {
itemObjct = {
formData: formData2,
name: componentType,
dataMap: this.dataMap3
}
} else if (componentType === '卷') {
itemObjct = {
formData: formData2,
name: componentType,
dataMap: this.dataMap4
}
} else if (componentType === '容器镜像') {
itemObjct = {
formData: formData2,
name: componentType,
dataMap: this.dataMap7
}
} else {
itemObjct = {
formData: formData2,
name: '现存卷',
dataMap: this.dataMap8
}
}
this.allDetailCard.push(itemObjct)
})
this.allNetworkCard = this.getNetworkRows(data.spec)
this.formData.name = data.metadata.name this.formData.name = data.metadata.name
this.formData.description = data.metadata.annotations['field.cattle.io/description'] this.formData.description = data.metadata.annotations['field.cattle.io/description']
this.formData.customName = data.metadata.annotations['harvesterhci.io/host-custom-name'] this.formData.customName = data.metadata.annotations['harvesterhci.io/host-custom-name']
this.formData.machineType = data.spec.template.spec.domain.machine.type this.formData.machineType = data.spec.template.spec.domain.machine.type
this.formData.cpu = data.spec.template.spec.domain.cpu.cores this.formData.cpu = data.spec.template.spec.domain.cpu.cores
this.formData.memory = data.spec.template.spec.domain.resources.requests.memory this.formData.memory = data.spec.template.spec.domain.resources.requests.memory
this.formData.memory = this.formData.memory.replace('Gi', '') this.formData.memory = this.formData.memory.replace('Gi', '')
this.formData.hostname = data.spec.template.spec.hostname this.formData.hostname = currentVm?.metadata.fields[4]
data = res.data[this.index] this.formData.IPAddress = currentVm?.metadata.fields[3]
this.formData.name = data.metadata.fields[0] this.formData.node = currentVm?.metadata.fields[0]
this.formData.created = data.metadata.creationTimestamp this.formData.KernelRelease = currentVm?.status?.guestOSInfo?.kernelRelease
this.formData.MachineType = data.spec.template.spec.domain.machine.type this.formData.OperatingSystem = currentVm?.status?.guestOSInfo?.prettyName
var disks = data.spec.template.spec.domain.devices.disks // data = res.data[this.index]
var disksarr = [] this.formData.name = data.metadata.fields[0]
var cdroms = [] this.formData.created = data.metadata.creationTimestamp
this.formData.CDROMs = '' this.formData.MachineType = data.spec.template.spec.domain.machine.type
var maxIndex = 0 var disks = data.spec.template.spec.domain.devices.disks
for (let item = 0; item < disks.length; item++) { var disksarr = []
if (disks[item].name !== 'cloudinitdisk' && disks[item].bootOrder != null) { var cdroms = []
disksarr[disks[item].bootOrder] = disks[item].name this.formData.CDROMs = ''
maxIndex = Math.max(maxIndex, disks[item].bootOrder) var maxIndex = 0
} for (let item = 0; item < disks.length; item++) {
if (disks[item].cdrom != null) { if (disks[item].name !== 'cloudinitdisk' && disks[item].bootOrder != null) {
cdroms.push(disks[item].name) disksarr[disks[item].bootOrder] = disks[item].name
this.formData.CDROMs += disks[item].name + ' \n' maxIndex = Math.max(maxIndex, disks[item].bootOrder)
}
if (disks[item].cdrom != null) {
cdroms.push(disks[item].name)
this.formData.CDROMs += disks[item].name + ' \n'
}
}
this.formData.bootOrder = ''
this.formData.Flavor = ''
for (var i = 0; i <= maxIndex; i++) {
if (disksarr[i] != null || typeof (disksarr[i]) !== 'undefined') {
this.formData.bootOrder += i + '. ' + disksarr[i] + ' \n'
}
}
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(n => {
this.sshkeyLists = []
for (let i = 0; i < arr.length; i++) {
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 })
} }
} }
this.formData.bootOrder = '' }
this.formData.Flavor = ''
for (var i = 0; i <= maxIndex; i++) {
if (disksarr[i] != null || typeof (disksarr[i]) !== 'undefined') {
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'
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 => {
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 })
}
}
}
})
})
}) })
}) })
}, },

View File

@ -108,7 +108,7 @@ export default {
</span> </span>
} }, } },
{ prop: 'project', label: '项目' }, { 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) => { { prop: 'more', label: '操作', formatter: (row) => {
return <div> return <div>
<el-dropdown> <el-dropdown>

View File

@ -99,9 +99,14 @@ module.exports = {
changeOrigin: true, changeOrigin: true,
secure: false secure: false
}, },
'^/function': { '^/jcc-faas-manager': {
ws: false, 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, // changeOrigin: true,
}, },
'/kapis/terminal.kubesphere.io': { '/kapis/terminal.kubesphere.io': {