zl程序教程

您现在的位置是:首页 >  后端

当前栏目

【GO】k8s 管理系统项目22[前端部分–工作负载-Deployment]

2023-09-14 09:02:04 时间

【GO】k8s 管理系统项目[前端部分–工作负载-Deployment]

1. Deployment页面设计

src/layout/Layout.vue

  1. 功能
    • 列表
    • 详情
    • 新增
    • 更新
    • 删除
    • 重启
    • 副本数
  2. Main的布局

请添加图片描述

2. 连接配置

src/views/common/Config.js

export default {
    //后端接口路径
    loginAuth: 'http://localhost:9091/api/login',
    k8sWorkflowCreate: 'http://localhost:9091/api/k8s/workflow/create',
    k8sWorkflowDetail: 'http://localhost:9091/api/k8s/workflow/detail',
    k8sWorkflowList: 'http://localhost:9091/api/k8s/workflows',
    k8sWorkflowDel: 'http://localhost:9091/api/k8s/workflow/del',
    k8sDeploymentList: 'http://localhost:9091/api/k8s/deployments',
    k8sDeploymentDetail: 'http://localhost:9091/api/k8s/deployment/detail',
    k8sDeploymentUpdate: 'http://localhost:9091/api/k8s/deployment/update',
    k8sDeploymentScale: 'http://localhost:9091/api/k8s/deployment/scale',
    k8sDeploymentRestart: 'http://localhost:9091/api/k8s/deployment/restart',
    k8sDeploymentDel: 'http://localhost:9091/api/k8s/deployment/del',
    k8sDeploymentCreate: 'http://localhost:9091/api/k8s/deployment/create',
    k8sDeploymentNumNp: 'http://localhost:9091/api/k8s/deployment/numnp',
    k8sPodList: 'http://localhost:9091/api/k8s/pods',
    k8sPodDetail: 'http://localhost:9091/api/k8s/pod/detail',
    k8sPodUpdate: 'http://localhost:9091/api/k8s/pod/update',
    k8sPodDel: 'http://localhost:9091/api/k8s/pod/del',
    k8sPodContainer: 'http://localhost:9091/api/k8s/pod/container',
    k8sPodLog: 'http://localhost:9091/api/k8s/pod/log',
    k8sPodNumNp: 'http://localhost:9091/api/k8s/pod/numnp',
    k8sDaemonSetList: 'http://localhost:9091/api/k8s/daemonsets',
    k8sDaemonSetDetail: 'http://localhost:9091/api/k8s/daemonset/detail',
    k8sDaemonSetUpdate: 'http://localhost:9091/api/k8s/daemonset/update',
    k8sDaemonSetDel: 'http://localhost:9091/api/k8s/daemonset/del',
    k8sStatefulSetList: 'http://localhost:9091/api/k8s/statefulsets',
    k8sStatefulSetDetail: 'http://localhost:9091/api/k8s/statefulset/detail',
    k8sStatefulSetUpdate: 'http://localhost:9091/api/k8s/statefulset/update',
    k8sStatefulSetDel: 'http://localhost:9091/api/k8s/statefulset/del',
    k8sServiceList: 'http://localhost:9091/api/k8s/services',
    k8sServiceDetail: 'http://localhost:9091/api/k8s/service/detail',
    k8sServiceUpdate: 'http://localhost:9091/api/k8s/service/update',
    k8sServiceDel: 'http://localhost:9091/api/k8s/service/del',
    k8sServiceCreate: 'http://localhost:9091/api/k8s/service/create',
    k8sIngressList: 'http://localhost:9091/api/k8s/ingresses',
    k8sIngressDetail: 'http://localhost:9091/api/k8s/ingress/detail',
    k8sIngressUpdate: 'http://localhost:9091/api/k8s/ingress/update',
    k8sIngressDel: 'http://localhost:9091/api/k8s/ingress/del',
    k8sIngressCreate: 'http://localhost:9091/api/k8s/ingress/create',
    k8sConfigMapList: 'http://localhost:9091/api/k8s/configmaps',
    k8sConfigMapDetail: 'http://localhost:9091/api/k8s/configmap/detail',
    k8sConfigMapUpdate: 'http://localhost:9091/api/k8s/configmap/update',
    k8sConfigMapDel: 'http://localhost:9091/api/k8s/configmap/del',
    k8sSecretList: 'http://localhost:9091/api/k8s/secrets',
    k8sSecretDetail: 'http://localhost:9091/api/k8s/secret/detail',
    k8sSecretUpdate: 'http://localhost:9091/api/k8s/secret/update',
    k8sSecretDel: 'http://localhost:9091/api/k8s/secret/del',
    k8sPvcList: 'http://localhost:9091/api/k8s/pvcs',
    k8sPvcDetail: 'http://localhost:9091/api/k8s/pvc/detail',
    k8sPvcUpdate: 'http://localhost:9091/api/k8s/pvc/update',
    k8sPvcDel: 'http://localhost:9091/api/k8s/pvc/del',
    k8sNodeList: 'http://localhost:9091/api/k8s/nodes',
    k8sNodeDetail: 'http://localhost:9091/api/k8s/node/detail',
    k8sNamespaceList: 'http://localhost:9091/api/k8s/namespaces',
    k8sNamespaceDetail: 'http://localhost:9091/api/k8s/namespace/detail',
    k8sNamespaceDel: 'http://localhost:9091/api/k8s/namespace/del',
    k8sPvList: 'http://localhost:9091/api/k8s/pvs',
    k8sPvDetail: 'http://localhost:9091/api/k8s/pv/detail',
    k8sTerminalWs: 'ws://localhost:8081/ws',
    //编辑器配置
    cmOptions: {
        // 语言及语法模式
        mode: 'text/yaml',
        // 主题
        theme: 'idea',
        // 显示行数
        lineNumbers: true,
        smartIndent: true, //智能缩进
        indentUnit: 4, // 智能缩进单元长度为 4 个空格
        styleActiveLine: true, // 显示选中行的样式
        matchBrackets: true, //每当光标位于匹配的方括号旁边时,都会使其高亮显示
        readOnly: false,
        lineWrapping: true //自动换行
    }
}

3. Deployment

3.1 Deployment.vue

src/views/workload/Deployment.vue

<template>
  <div class="deploy">
    <el-row>
      <!-- 头部1 -->
      <el-col :span="24">
        <div>
          <!-- 包一层卡片 -->
          <el-card class="deploy-head-card" shadow="never" :body-style="{padding:'10px'}">
            <el-row>
              <!-- 命名空间的下拉框 -->
              <el-col :span="6">
                <div>
                  <span>命名空间:</span>
                  <!-- 下拉框 -->
                  <!-- filterable:带搜索功能 -->
                  <!-- placeholder 默认提示 -->
                  <!-- label 显示内容 -->
                  <!-- value 绑定到v-model的值中 -->
                  <el-select v-model="namespaceValue" filterable placeholder="请选择" class="deploy-head-card-select">
                    <el-option
                        v-for="(item, index) in namespaceList"
                        :key="index"
                        :label="item.metadata.name"
                        :value="item.metadata.name">
                    </el-option>
                  </el-select>
                </div>
              </el-col>
              <!-- 刷新按钮 -->
              <el-col :span="2" :offset="16">
                <div>
                  <!-- 每次刷新,都重新调一次list接口,刷新表格中的数据 -->
                  <el-button style="border-radius:2px;" icon="Refresh" plain @click="getDeployments()">刷新</el-button>
                </div>
              </el-col>
            </el-row>
          </el-card>
        </div>
      </el-col>
      <!-- 头部2 -->
      <el-col :span="24">
        <div>
          <!-- 包一层卡片 -->
          <el-card class="deploy-head-card" shadow="never" :body-style="{padding:'10px'}">
            <el-row>
              <!-- 创建按钮 -->
              <el-col :span="2">
                <div>
                  <!-- 点击后打开抽屉,填入创建deployment需要的数据 -->
                  <el-button style="border-radius:2px;" icon="Edit" type="primary" @click="createDeploymentDrawer = true" v-loading.fullscreen.lock="fullscreenLoading">创建</el-button>
                </div>
              </el-col>
              <!-- 搜索框和搜索按钮 -->
              <el-col :span="6">
                <div>
                  <el-input class="deploy-head-search" clearable placeholder="请输入" v-model="searchInput"></el-input>
                  <el-button style="border-radius:2px;" icon="Search" type="primary" plain @click="getDeployments()">搜索</el-button>
                </div>
              </el-col>
            </el-row>
          </el-card>
        </div>
      </el-col>
      <!-- 数据表格 -->
      <el-col :span="24">
        <div>
          <!-- 包一层卡片 -->
          <el-card class="deploy-body-card" shadow="never" :body-style="{padding:'5px'}">
            <!-- 数据表格 -->
            <!-- v-loading用于加载时的loading动画 -->
            <el-table
                style="width:100%;font-size:12px;margin-bottom:10px;"
                :data="deploymentList"
                v-loading="appLoading">
              <!-- 最左侧留出20px的宽度,更加没关 -->
              <el-table-column width="20"></el-table-column>
              <!-- deployment名字 -->
              <el-table-column align=left label="Deployment名">
                <!-- 插槽,scope.row获取当前行的数据 -->
                <template v-slot="scope">
                  <a class="deploy-body-deployname">{{ scope.row.metadata.name }}</a>
                </template>
              </el-table-column>
              <!-- 标签 -->
              <el-table-column align=center label="标签">
                <template v-slot="scope">
                  <!-- for循环,每个label只显示固定长度,鼠标悬停后气泡弹出框显示完整长度 -->
                  <div v-for="(val, key) in scope.row.metadata.labels" :key="key">
                    <!-- 气泡弹出框 -->
                    <!-- placement 弹出位置 -->
                    <!-- trigger 触发条件 -->
                    <!-- content 弹出框内容 -->
                    <el-popover
                        placement="right"
                        :width="200"
                        trigger="hover"
                        :content="key + ':' + val">
                      <template #reference>
                        <!-- ellipsis方法用于剪裁字符串 -->
                        <el-tag style="margin-bottom: 5px" type="warning">{{ ellipsis(key + ":" + val) }}</el-tag>
                      </template>
                    </el-popover>
                  </div>
                </template>
              </el-table-column>
              <!-- 容器组 -->
              <el-table-column align=center label="容器组">
                <!-- 可用数量/总数量,三元运算,若值大于0则显示值,否则显示0 -->
                <template v-slot="scope">
                  <span>{{ scope.row.status.availableReplicas>0?scope.row.status.availableReplicas:0  }} / {{ scope.row.spec.replicas>0?scope.row.spec.replicas:0 }} </span>
                </template>
              </el-table-column>
              <!-- 创建时间 -->
              <el-table-column align=center min-width="100" label="创建时间">
                <!-- timeTrans函数用于将格林威治时间转成北京时间 -->
                <template v-slot="scope">
                  <el-tag type="info">{{ timeTrans(scope.row.metadata.creationTimestamp) }} </el-tag>
                </template>
              </el-table-column>
              <!-- 容器镜像 -->
              <el-table-column align=center label="镜像">
                <!-- 与label的显示逻辑一致 -->
                <template v-slot="scope">
                  <div v-for="(val, key) in scope.row.spec.template.spec.containers" :key="key">
                    <el-popover
                        placement="right"
                        :width="200"
                        trigger="hover"
                        :content="val.image">
                      <template #reference>
                        <el-tag style="margin-bottom: 5px">{{ ellipsis(val.image.split('/')[2]==undefined?val.image:val.image.split('/')[2]) }}</el-tag>
                      </template>
                    </el-popover>
                  </div>
                </template>
              </el-table-column>
              <!-- 操作列,放按钮 -->
              <el-table-column align=center label="操作" width="400">
                <template v-slot="scope">
                  <el-button size="small" style="border-radius:2px;" icon="Edit" type="primary" plain @click="getDeploymentDetail(scope)">YAML</el-button>
                  <el-button size="small" style="border-radius:2px;" icon="Plus" type="primary" @click="handleScale(scope)">扩缩</el-button>
                  <el-button size="small" style="border-radius:2px;" icon="RefreshLeft" type="primary" @click="handleConfirm(scope, '重启', restartDeployment)">重启</el-button>
                  <el-button size="small" style="border-radius:2px;" icon="Delete" type="danger" @click="handleConfirm(scope, '删除', delDeployment)">删除</el-button>
                </template>
              </el-table-column>
            </el-table>
            <!-- 分页配置 -->
            <!-- background 背景色灰 -->
            <!-- size-change 单页大小改变后触发 -->
            <!-- current-change 页数改变后触发 -->
            <!-- current-page 当前页 -->
            <!-- page-size 单页大小 -->
            <!-- layout 分页器支持的功能 -->
            <!-- total 数据总条数 -->
            <el-pagination
                class="deploy-body-pagination"
                background
                @size-change="handleSizeChange"
                @current-change="handleCurrentChange"
                :current-page="currentPage"
                :page-sizes="pagesizeList"
                :page-size="pagesize"
                layout="total, sizes, prev, pager, next, jumper"
                :total="deploymentTotal">
            </el-pagination>
          </el-card>
        </div>
      </el-col>
    </el-row>
    <!-- 抽屉:创建Deployment的表单 -->
    <!-- v-model 值是bool,用于显示与隐藏 -->
    <!-- direction 显示的位置 -->
    <!-- before-close 关闭时触发,点击关闭或者点击空白都会触发 -->
    <el-drawer
        v-model="createDeploymentDrawer"
        :direction="direction"
        :before-close="handleClose">
      <!-- 插槽,抽屉标题 -->
      <template #title>
        <h4>创建Deployment</h4>
      </template>
      <!-- 插槽,抽屉body -->
      <template #default>
        <!-- flex布局,居中 -->
        <el-row type="flex" justify="center">
          <el-col :span="20">
            <!-- ref绑定控件后,js中才能用this.$ref获取该控件 -->
            <!-- rules 定义form表单校验规则 -->
            <el-form ref="createDeployment" :rules="createDeploymentRules" :model="createDeployment" label-width="80px">
              <!-- prop用于rules中的校验规则的key -->
              <el-form-item class="deploy-create-form" label="名称" prop="name">
                <el-input v-model="createDeployment.name"></el-input>
              </el-form-item>
              <el-form-item class="deploy-create-form" label="命名空间" prop="namespace">
                <el-select v-model="createDeployment.namespace" filterable placeholder="请选择">
                  <el-option
                      v-for="(item, index) in namespaceList"
                      :key="index"
                      :label="item.metadata.name"
                      :value="item.metadata.name">
                  </el-option>
                </el-select>
              </el-form-item>
              <!-- 数字输入框,最小为1,最大为10 -->
              <el-form-item class="deploy-create-form" label="副本数" prop="replicas">
                <el-input-number v-model="createDeployment.replicas" :min="1" :max="10"></el-input-number>
                <!-- 气泡弹出框用于提醒上限 -->
                <el-popover
                    placement="top"
                    :width="100"
                    trigger="hover"
                    content="申请副本数上限为10个">
                  <template #reference>
                    <el-icon style="width:2em;font-size:18px;color:#4795EE"><WarningFilled/></el-icon>
                  </template>
                </el-popover>
              </el-form-item>
              <el-form-item class="deploy-create-form" label="镜像" prop="image">
                <el-input v-model="createDeployment.image"></el-input>
              </el-form-item>
              <el-form-item class="deploy-create-form" label="标签" prop="label_str">
                <el-input v-model="createDeployment.label_str" placeholder="示例: project=ms,app=gateway"></el-input>
              </el-form-item>
              <!-- 下拉框,用于规格的选择,之后用/分割,得到cpu和内存 -->
              <el-form-item class="deploy-create-form" label="资源配额" prop="resource">
                <el-select v-model="createDeployment.resource" placeholder="请选择">
                  <el-option value="0.5/1" label="0.5C1G"></el-option>
                  <el-option value="1/2" label="1C2G"></el-option>
                  <el-option value="2/4" label="2C4G"></el-option>
                  <el-option value="4/8" label="4C8G"></el-option>
                </el-select>
              </el-form-item>
              <el-form-item class="deploy-create-form" label="容器端口" prop="container_port">
                <el-input v-model="createDeployment.container_port" placeholder="示例: 80"></el-input>
              </el-form-item>
              <el-form-item class="deploy-create-form" label="健康检查" prop="health">
                <el-switch v-model="createDeployment.health_check" />
              </el-form-item>
              <el-form-item class="deploy-create-form" label="检查路径" prop="healthPath">
                <el-input v-model="createDeployment.health_path" placeholder="示例: /health"></el-input>
              </el-form-item>
            </el-form>
          </el-col>
        </el-row>
      </template>
      <!-- 插槽,抽屉footer -->
      <template #footer>
        <!-- 点击后赋值false,隐藏抽屉 -->
        <el-button @click="createDeploymentDrawer = false">取消</el-button>
        <el-button type="primary" @click="submitForm('createDeployment')">立即创建</el-button>
      </template>
    </el-drawer>
    <!-- 展示YAML信息的弹框 -->
    <el-dialog title="YAML信息" v-model="yamlDialog" width="45%" top="2%">
      <!-- codemirror编辑器 -->
      <!-- border 带边框 -->
      <!-- options  编辑器配置 -->
      <!-- change 编辑器中的内容变化时触发 -->
      <codemirror
          :value="contentYaml"
          border
          :options="cmOptions"
          height="500"
          style="font-size:14px;"
          @change="onChange"
      ></codemirror>
      <template #footer>
                <span class="dialog-footer">
                    <el-button @click="this.yamlDialog = false">取 消</el-button>
                    <el-button type="primary" @click="updateDeployment()">更 新</el-button>
                </span>
      </template>
    </el-dialog>
    <!-- 调整副本数的弹框 -->
    <el-dialog title="副本数调整" v-model="scaleDialog" width="25%">
      <div style="text-align:center">
        <span>实例数: </span>
        <el-input-number :step="1" v-model="scaleNum" :min="0" :max="30" label="描述文字"></el-input-number>
      </div>
      <template #footer>
                <span class="dialog-footer">
                    <el-button @click="scaleDialog = false">取 消</el-button>
                    <el-button type="primary" @click="scaleDeployment()">更 新</el-button>
                </span>
      </template>
    </el-dialog>
  </div>
</template>

<script>
import common from "../common/Config.js";
import httpClient from '../../utils/request';
import yaml2obj from 'js-yaml';
import json2yaml from 'json2yaml';
export default {
  data() {
    return {
      //编辑器配置
      cmOptions: common.cmOptions,
      contentYaml: '',
      //分页
      currentPage: 1,
      pagesize: 10,
      pagesizeList: [10, 20, 30],
      //搜索框内容
      searchInput: '',
      //命名空间
      namespaceValue: 'default',
      namespaceList: [],
      namespaceListUrl: common.k8sNamespaceList,
      //列表
      appLoading: false,
      deploymentList: [],
      deploymentTotal: 0,
      getDeploymentsData: {
        url: common.k8sDeploymentList,
        params: {
          filter_name: '',
          namespace: '',
          page: '',
          limit: '',
        }
      },
      //创建
      fullscreenLoading: false,
      direction: 'rtl',
      createDeploymentDrawer: false,
      createDeployment: {
        name: '',
        namespace: '',
        replicas: 1,
        image: '',
        resource: '',
        health_check: false,
        health_path: '',
        label_str: '',
        label: {},
        container_port: ''
      },
      //创建请求的参数
      createDeploymentData: {
        url: common.k8sDeploymentCreate,
        params: {}
      },
      //创建deployment的表单校验规则
      createDeploymentRules: {
        name: [{
          required: true,
          message: '请填写名称',
          trigger: 'change'
        }],
        image: [{
          required: true,
          message: '请填写镜像',
          trigger: 'change'
        }],
        namespace: [{
          required: true,
          message: '请选择命名空间',
          trigger: 'change'
        }],
        resource: [{
          required: true,
          message: '请选择配额',
          trigger: 'change'
        }],
        label_str: [{
          required: true,
          message: '请填写标签',
          trigger: 'change'
        }],
        container_port: [{
          required: true,
          message: '请填写容器端口',
          trigger: 'change'
        }],
      },
      //详情
      deploymentDetail: {},
      getDeploymentDetailData: {
        url: common.k8sDeploymentDetail,
        params: {
          deployment_name: '',
          namespace: ''
        }
      },
      //yaml更新
      yamlDialog: false,
      updateDeploymentData: {
        url: common.k8sDeploymentUpdate,
        params: {
          namespace: '',
          content: ''
        }
      },
      //扩缩容
      scaleNum: 0,
      scaleDialog: false,
      scaleDeploymentData: {
        url: common.k8sDeploymentScale,
        params: {
          deployment_name: '',
          namespace: '',
          scale_num: ''
        }
      },
      //重启
      restartDeploymentData: {
        url: common.k8sDeploymentRestart,
        params: {
          deployment_name: '',
          namespace: '',
        }
      },
      //删除
      delDeploymentData: {
        url: common.k8sDeploymentDel,
        params: {
          deployment_name: '',
          namespace: '',
        }
      },
    }
  },
  methods: {
    //json转yaml方法
    transYaml(content) {
      return json2yaml.stringify(content)
    },
    //yaml转对象
    transObj(content) {
      return yaml2obj.load(content)
    },
    //编辑器内容变化时触发的方式,用于将更新的内容复制到变量中
    onChange(val) {
      this.contentYaml = val
    },
    //页面大小发生变化时触发,赋值并重新获取列表
    handleSizeChange(size) {
      this.pagesize = size;
      this.getDeployments()
    },
    //页数发生变化时触发,复制并重新获取列表
    handleCurrentChange(currentPage) {
      this.currentPage = currentPage;
      this.getDeployments()
    },
    //处理抽屉的关闭,增加体验感
    handleClose(done) {
      this.$confirm('确认关闭?')
          .then(() => {
            done();
          })
          .catch(() => {});
    },
    //字符串截取、拼接并返回
    ellipsis(value) {
      return value.length>15?value.substring(0,15)+'...':value
    },
    //格林威治时间转为北京时间
    timeTrans(timestamp) {
      let date = new Date(new Date(timestamp).getTime() + 8 * 3600 * 1000)
      date = date.toJSON();
      date = date.substring(0, 19).replace('T', ' ')
      return date
    },
    //获取Namespace列表
    getNamespaces() {
      httpClient.get(this.namespaceListUrl)
          .then(res => {
            this.namespaceList = res.data.items
          })
          .catch(res => {
            this.$message.error({
              message: res.msg
            })
          })
    },
    //获取Deployment列表
    getDeployments() {
      //表格加载动画开启
      this.appLoading = true
      //getDeploymentsData是用于发起deployment列表请求的专用的对象,里面有url和params参数,以下是赋值
      this.getDeploymentsData.params.filter_name = this.searchInput
      this.getDeploymentsData.params.namespace = this.namespaceValue
      this.getDeploymentsData.params.page = this.currentPage
      this.getDeploymentsData.params.limit = this.pagesize
      httpClient.get(this.getDeploymentsData.url, {params: this.getDeploymentsData.params})
          .then(res => {
            //响应成功,获取deployment列表和total
            this.deploymentList = res.data.items
            this.deploymentTotal = res.data.total
          })
          .catch(res => {
            this.$message.error({
              message: res.msg
            })
          })
      //加载动画关闭
      this.appLoading = false
    },
    //获取deployment详情,e参数标识传入的scope插槽,.row是该行的数据
    getDeploymentDetail(e) {
      this.getDeploymentDetailData.params.deployment_name = e.row.metadata.name
      this.getDeploymentDetailData.params.namespace = this.namespaceValue
      httpClient.get(this.getDeploymentDetailData.url, {params: this.getDeploymentDetailData.params})
          .then(res => {
            this.contentYaml = this.transYaml(res.data)
            //打开弹出框
            this.yamlDialog = true
          })
          .catch(res => {
            this.$message.error({
              message: res.msg
            })
          })
    },
    //更新deployment
    updateDeployment() {
      //将yaml格式的deployment对象转为json
      let content = JSON.stringify(this.transObj(this.contentYaml))
      this.updateDeploymentData.params.namespace = this.namespaceValue
      this.updateDeploymentData.params.content = content
      httpClient.put(this.updateDeploymentData.url, this.updateDeploymentData.params)
          .then(res => {
            this.$message.success({
              message: res.msg
            })
            //更新后重新获取列表
            this.getDeployments()
          })
          .catch(res => {
            this.$message.error({
              message: res.msg
            })
          })
      //关闭弹出框
      this.yamlDialog = false
    },
    //扩缩容的中间方法,用于赋值及打开弹出框
    handleScale(e) {
      this.scaleDialog = true
      this.deploymentDetail = e.row
      this.scaleNum = e.row.spec.replicas
    },
    //扩缩容deployment
    scaleDeployment() {
      this.scaleDeploymentData.params.deployment_name = this.deploymentDetail.metadata.name
      this.scaleDeploymentData.params.namespace = this.namespaceValue
      this.scaleDeploymentData.params.scale_num = this.scaleNum
      httpClient.put(this.scaleDeploymentData.url, this.scaleDeploymentData.params)
          .then(res => {
            this.$message.success({
              message: res.msg
            })
            //更新后重新获取列表
            this.getDeployments()
          })
          .catch(res => {
            this.$message.error({
              message: res.msg
            })
          })
      //关闭弹出框
      this.scaleDialog = false
    },
    //重启deployment
    restartDeployment(e) {
      this.restartDeploymentData.params.deployment_name = e.row.metadata.name
      this.restartDeploymentData.params.namespace = this.namespaceValue
      httpClient.put(this.restartDeploymentData.url, this.restartDeploymentData.params)
          .then(res => {
            this.$message.success({
              message: res.msg
            })
            this.getDeployments()
          })
          .catch(res => {
            this.$message.error({
              message: res.msg
            })
          })
    },
    //删除deployment
    delDeployment(e) {
      this.delDeploymentData.params.deployment_name = e.row.metadata.name
      this.delDeploymentData.params.namespace = this.namespaceValue
      httpClient.delete(this.delDeploymentData.url, {data: this.delDeploymentData.params})
          .then(res => {
            this.$message.success({
              message: res.msg
            })
            this.getDeployments()
          })
          .catch(res => {
            this.$message.error({
              message: res.msg
            })
          })
    },
    //弹出确认框,用于危险操作的double check
    //obj是行数据,opeateName是操作名,fn是操作的方法
    handleConfirm(obj, operateName, fn) {
      this.confirmContent = '确认继续 ' + operateName + ' 操作吗?'
      //$confirm用于弹出确认框
      this.$confirm(this.confirmContent,'提示',{
        confirmButtonText: '确定',
        cancelButtonText: '取消',
      })
          .then(() => {
            fn(obj)
          })
          .catch(() => {
            this.$message.info({
              message: '已取消操作'
            })
          })
    },
    //创建deployment,加Func的原因是因为createDeploy用于属性了
    createDeployFunc() {
      //正则匹配,验证label的合法性
      let reg = new RegExp("(^[A-Za-z]+=[A-Za-z0-9]+).*")
      if (!reg.test(this.createDeployment.label_str)) {
        this.$message.warning({
          message: "标签填写异常,请确认后重新填写"
        })
        return
      }
      //加载loading动画
      this.fullscreenLoading = true
      //定义label、cpu和memory变量
      let label = new Map()
      let cpu, memory
      //将label字符串转成数组
      let a = (this.createDeployment.label_str).split(",")
      //将数组转成map
      a.forEach(item => {
        let b = item.split("=")
        label[b[0]] = b[1]
      })
      //将deployment的规格转成cpu和memory
      let resourceList = this.createDeployment.resource.split("/")
      cpu = resourceList[0]
      memory = resourceList[1] + "Gi"
      //赋值
      this.createDeploymentData.params = this.createDeployment
      this.createDeploymentData.params.container_port = parseInt(this.createDeployment.container_port)
      this.createDeploymentData.params.label = label
      this.createDeploymentData.params.cpu = cpu
      this.createDeploymentData.params.memory = memory
      httpClient.post(this.createDeploymentData.url, this.createDeploymentData.params)
          .then(res => {
            this.$message.success({
              message: res.msg
            })
            //创建后重新获取列表
            this.getDeployments()
          })
          .catch(res => {
            this.$message.error({
              message: res.msg
            })
          })
      //重置表单
      this.resetForm('createDeployment')
      //关闭加载动画
      this.fullscreenLoading = false
      //关闭抽屉
      this.createDeploymentDrawer = false
    },
    //重置表单方法,element plus课程讲过的
    resetForm(formName) {
      this.$refs[formName].resetFields()
    },
    //提交表单,校验参数合法性
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          this.createDeployFunc()
        } else {
          return false;
        }
      })
    }
  },
  watch: {
    //监听namespace的值,若发生变化,则执行handler方法中的内容
    namespaceValue: {
      handler() {
        //将namespace的值存入本地,用于path切换时依旧能获取得到
        localStorage.setItem('namespace', this.namespaceValue)
        //重置当前页为1
        this.currentPage = 1
        //获取deployment列表
        this.getDeployments()
      }
    },
  },
  beforeMount() {
    //加载页面时先获取localStorage中的namespace值,若获取不到则默认default
    if (localStorage.getItem('namespace') !== undefined && localStorage.getItem('namespace') !== null) {
      this.namespaceValue = localStorage.getItem('namespace')
    }
    this.getNamespaces()
    this.getDeployments()
  }
}
</script>


<style scoped>
/* 卡片属性 */
.deploy-head-card,.deploy-body-card {
  border-radius: 5px;
  margin-bottom: 5px;
}
.deploy-head-card-select {
  margin-left: 10px;
}
/* 搜索框 */
.deploy-head-search {
  width:160px;
  margin-right:10px;
}
/* 数据表格deployment名颜色 */
.deploy-body-deployname {
  color: #4795EE;
}
/* deployment名鼠标悬停 */
.deploy-body-deployname:hover {
  color: rgb(84, 138, 238);
  cursor: pointer;
  font-weight: bold;
}
</style>

3.2 main.js

src/main.js中引入codemirror

//codemirror编辑器
import { GlobalCmComponent } from "codemirror-editor-vue3";
// 引入主题
import 'codemirror/theme/idea.css'
// 引入yaml
import 'codemirror/mode/yaml/yaml.js'

4. 测试

4.1 显示命名空间下的deployment

请添加图片描述

4.2 创建Deployment

请添加图片描述

请添加图片描述

命令行下确认

请添加图片描述

4.3 显示yaml

通过修改yaml给deployment增加标签

请添加图片描述

请添加图片描述

请添加图片描述

4.4 删除deployment

请添加图片描述

命令行下确认

请添加图片描述

4.5 扩缩容

4.5.1 扩容

请添加图片描述

请添加图片描述

命令行确认

请添加图片描述

4.5.2 缩容

请添加图片描述

请添加图片描述

命令行

请添加图片描述

4.6 重启

请添加图片描述

请添加图片描述