k8s管理系统项目前端-loadbalance

一、ingress开发

<template>
  <!-- 新的 div 容器,使用flex布局对齐内容 -->
  <div class="deployment-header" style="flex: 1">
    <div class="left-section">
      <span>命名空间:</span>
      <el-select v-model="selectedNamespace" placeholder="请选择">
        <el-option
            v-for="namespace in namespaces"
            :key="namespace"
            :label="namespace"
            :value="namespace">
        </el-option>
      </el-select>
    </div>

    <!-- 移动的刷新按钮,保留在右侧 -->
    <div class="right-group">
      <el-button @click="refresh">
        <el-icon><Refresh /></el-icon>
        <span> 刷新 </span>
      </el-button>
    </div>
  </div>
  <div class="container">
    <!-- 第一部分: 头部 -->
    <div class="header shadow">
      <div class="left-group">
        <el-button  type="primary" @click="openCreateDrawer">
          <el-icon><EditPen /></el-icon>
          <span style="vertical-align: middle"> 创建 </span>
        </el-button>
        <el-input placeholder="请输入内容" v-model="searchText" class="search-input" @input="handleInput">
          <template #append>
            <el-button type="primary" @click="search()">
              <el-icon><Search /></el-icon>
            </el-button>
          </template>
        </el-input>
      </div>
    </div>

    <!-- 第二部分: 表格 -->
    <div class="table-wrapper shadow">
      <el-table :data="tableData" style="width: 100%" >
        <el-table-column prop="name" label="Ingress名"  align="center">
          <template #default="{ row }">
            <div>
              <span style="vertical-align: middle; color: #1395FF; cursor: pointer;" @click="handleRowClick(row)">
                {{ row.name }}
              </span>
            </div>
          </template>
        </el-table-column>
        <el-table-column prop="Labels" label="标签"  align="center">
          <template #default="{ row }">
            <div>
              <el-tooltip
                  v-for="(label, index) in row.Labels"
                  :key="index"
                  class="item"
                  effect="dark"
                  :content="label"
                  placement="top"
              >
                <el-tag class="ml-2" type="success">{{ label }}</el-tag>
              </el-tooltip>
            </div>
          </template>
        </el-table-column>
        <el-table-column prop="Host" label="Host" align="center">
          <template #default="{ row }">
            <div>
              <el-tag class="ml-2" type="success">{{ row.Host }}</el-tag>
            </div>
          </template>
        </el-table-column>
        <el-table-column prop="Path" label="Path" align="center">
          <template #default="{ row }">
            <div>
              <el-tag class="ml-2" type="success">{{ row.Path }}</el-tag>
            </div>
          </template>
        </el-table-column>
        <el-table-column prop="External_ip" label="EXTERNAL_IP" align="center" >
          <template #default="{ row }">
            <div style="display: flex; align-items: center;justify-content: center;height: 100%">
              {{ row.External_ip }}
            </div>
          </template>
        </el-table-column>
        <el-table-column prop="TLS" label="TLS" align="center">
          <template #default="{ row }">
            <div style="display: flex; align-items: center;justify-content: center;height: 100%">
              {{ row.TLS }}
            </div>
          </template>
        </el-table-column>
        <el-table-column prop="createTime" label="创建时间" align="center" >
          <template #default="{ row }">
            <div>
              <el-tag class="ml-2" type="warning">{{row.createTime}}</el-tag>
            </div>
          </template>
        </el-table-column>
        <el-table-column prop="Operation" label="操作" align="center">
          <template #default="{ row }">
            <div class="button-group">

              <el-button size="small" color="#5AABFF" :dark="isDark" plain @click="viewYAML(row)">
                <el-icon><EditPen /></el-icon>
                <span style="vertical-align: middle"> YAML </span>
              </el-button>
              <el-button size="small"  color="#F58D79" :dark="isDark" plain @click="confirmDelete(row)">
                <el-icon><Tickets /></el-icon>
                <span style="vertical-align: middle"> 删除 </span>
              </el-button>
            </div>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination
          v-model:current-page="currentPage"
          v-model:page-size="pageSize"
          :page-sizes="[5, 10, 20, 30]"
          :small="small"
          :disabled="disabled"
          :background="background"
          layout="total, sizes, prev, pager, next, jumper"
          :total=deploymentCount
          class="paginations"
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
      />
    </div>

    <el-dialog title="YAML信息" v-model="dialogVisible" width="45%" top="5%">

      <codemirror
          v-model="yamlContent"
          placeholder="请输入代码..."
          :style="{ height: '100%' }"
          v-bind="cmOptions"
          :extensions="extensions"
      />
      <template #footer>
                <span class="dialog-footer">
                    <el-button @click="dialogVisible = false">取 消</el-button>
                    <el-button  type="primary" @click="updateDeploy()">更 新</el-button>
                </span>
      </template>
    </el-dialog>
    <!-- 对话框 -->
    <el-dialog
        title="副本数调整"
        v-model="scaleDialogVisible"
        width="30%"
    >
      <div style="text-align: center; padding: 20px;">
        <label>实例数:</label>
        <el-input-number v-model="replicaCount" :min="1" label="副本数:" />
      </div>
      <span slot="footer" class="dialog-footer">
      <el-button @click="scaleDialogVisible = false">取消</el-button>
      <el-button type="primary" @click="updateReplicas">更新</el-button>
    </span>
    </el-dialog>
  </div>
  <el-drawer
      title="创建Service"
      v-model="createDrawer"
      direction="rtl"
  >

    <h3 style="margin-right: 10px;margin-bottom: 10px;">Service</h3>
    <div>
      <el-form ref="formRef" :model="formData" :rules="formRules">
        <div style="display: flex; align-items: center; margin-bottom: 20px;">
          <span style="width: 100px; display: inline-block; text-align: right; margin-right: 10px;">名称:</span>
          <el-form-item label="" prop="name">
            <el-input v-model="formData.name" placeholder="请输入内容" style="width: 250px"></el-input>
          </el-form-item>
        </div>
        <el-form-item label="" prop="namespace">
          <div style="display: flex; align-items: center;margin-bottom: 20px">
            <span style="width: 100px; display: inline-block; text-align: right; margin-right: 10px;">命名空间:</span>
            <el-select v-model="formData.namespace" placeholder="请选择" style="width: 150px;">
              <el-option
                  v-for="namespace in serviceNamespaces"
                  :key="namespace"
                  :label="namespace"
                  :value="namespace">
              </el-option>
            </el-select>
          </div>
        </el-form-item>
        <el-form-item label="" prop="type">
          <div style="display: flex; align-items: center;margin-bottom: 20px">
            <span style="width: 100px; display: inline-block; text-align: right; margin-right: 10px;">类型:</span>
            <el-select v-model="formData.type" placeholder="请选择" style="width: 150px;">
              <el-option
                  v-for="type in serviceType"
                  :key="type"
                  :label="type"
                  :value="type">
              </el-option>
            </el-select>
          </div>
        </el-form-item>
        <div style="display: flex; align-items: center; margin-bottom: 20px;">
          <span style="width: 100px; display: inline-block; text-align: right; margin-right: 10px;">域名:</span>
          <el-form-item label="" prop="domain">
            <el-input v-model="formData.domain" placeholder="请输入内容" style="width: 250px"></el-input>
          </el-form-item>
        </div>
        <div style="display: flex; align-items: center; margin-bottom: 20px;">
          <span style="width: 100px; display: inline-block; text-align: right; margin-right: 10px;">Path:</span>
          <el-form-item label="" prop="path">
            <el-input v-model="formData.path" placeholder="请输入内容" style="width: 250px"></el-input>
          </el-form-item>
        </div>
        <div style="display: flex; align-items: center; margin-bottom: 20px;">
          <span style="width: 100px; display: inline-block; text-align: right; margin-right: 10px;">Service端口:</span>
          <el-form-item label="" prop="port">
            <el-input v-model="formData.port" placeholder="请输入内容" style="width: 250px"></el-input>
          </el-form-item>
        </div>
        <div style="display: flex; align-items: center; margin-bottom: 20px;">
          <span style="width: 100px; display: inline-block; text-align: right; margin-right: 10px;">Service名:</span>
          <el-form-item label="" prop="serviceName">
            <el-input v-model="formData.serviceName" placeholder="请输入内容" style="width: 250px"></el-input>
          </el-form-item>
        </div>
        <div style="display: flex; align-items: center; margin-bottom: 20px;">
          <span style="width: 100px; display: inline-block; text-align: right; margin-right: 10px;">标签:</span>
          <el-form-item label="" prop="label">
            <el-input v-model="formData.label" placeholder="请输入内容" style="width: 250px"></el-input>
          </el-form-item>
        </div>

      </el-form>
      <!-- 更多输入项 -->
    </div>
    <template #footer>
      <el-button @click="closeDrawer">取消</el-button>
      <el-button type="primary"  @click="validateForm">创建</el-button>
    </template>
  </el-drawer>

</template>

<script setup>
import {nextTick, onBeforeMount, onBeforeUnmount, reactive, ref, watch} from 'vue';
import { Loading } from '@element-plus/icons-vue';
import 'element-plus/dist/index.css';
import { Refresh, EditPen, Search } from '@element-plus/icons-vue';
import {  onMounted } from 'vue';
import { useRouter } from 'vue-router';
import { ArrowLeft } from '@element-plus/icons-vue';


// 在模板中可以直接使用 Refresh, EditPen, 和 Search

import {
  CREATE_DEPLOYMENT, CREATE_INGRESS,
  CREATE_NAMESPACE,
  CREATE_SERVICE,
  DELETE_DEPLOYMENT, DELETE_INGRESS,
  DELETE_NAMESPACE,
  DELETE_SERVICE,
  DEPLOYMENT_DETAIL,
  DEPLOYMENT_LIST,
  INGRESS_DETAIL,
  INGRESS_LIST,
  NAMESPACE_DETAIL,
  NAMESPACE_LIST,
  RESTART_DEPLOYMENT,
  SERVICE_DETAIL,
  SERVICE_LIST,
  UPDATE_DEPLOYMENT,
  UPDATE_DEPLOYMENTSCALE,
  UPDATE_INGRESS,
  UPDATE_NAMESPACE,
  UPDATE_SERVICE
} from "../../../api/k8s.js";
import { Codemirror } from 'vue-codemirror'
import { javascript} from  '@codemirror/lang-javascript'
// import { javascript } from 'codemirror/lang-javascript'
import { oneDark } from '@codemirror/theme-one-dark'

import _, {parseInt} from 'lodash';
import json2yaml from 'json2yaml'
import yaml2obj from 'js-yaml';
import {ElMessage} from "element-plus";
import router from "@/router/index.js";
import { ElMessageBox } from 'element-plus';
import axios from "axios";
import {value} from "lodash/seq.js";
const extensions = [javascript(),oneDark]
const formRef = ref(null);

const formData = ref({
  name: '',
  namespace:'',
  type:'',
  port:'',
  label:'',
  path:'',
  domain:'',
  serviceName:'',
  // 初始化更多的表单数据
});
const validateForm = async () => {
  try {
    await formRef.value.validate();
    console.log(serviceType.value)
    console.log(formData.value)
    createService()
  } catch (error) {
    ElMessage.error('表单验证失败,请检查输入');
  }
};
const closeDrawer = () => {
  createDrawer.value = false

};
const formRules = {

  name: [
    { required: true, message: '请输入名称', trigger: 'blur' }
  ],
  serviceName: [
    { required: true, message: '请输入Service名称', trigger: 'blur' }
  ],
  port: [
    { required: true, message: '请输入service端口', trigger: 'change' }
  ],
  domain: [
    { required: true, message: '请输入域名', trigger: 'change' }
  ],
  path: [
    { required: true, message: '请输入PATH', trigger: 'change' }
  ],
  label: [
    { required: true, message: '请输入标签', trigger: 'blur' }
  ],
  // 其他校验规则
};
const dialogSelectedNamespace = ref(''); // 对话框的v-model
const scaleDialogVisible=  ref(false)
const replicaCount = ref(1)
const currentRow = ref(null)
const serviceNamespaces = ref([]); // 用于存储命名空间列表
const serviceType = ref(['Prefix','Exact','ImplementationSpecific']); // 用于存储命名空间列表

const openScaleDiglog = (row)=>{
  replicaCount.value = row.Replicas
  currentRow.value = row
  scaleDialogVisible.value = true
}
const createDrawer = ref(false)

const openCreateDrawer = ()=>{
  createDrawer.value = true
}
// 从localStorage加载保存的命名空间
const loadSelection = () => {
  selectedNamespace.value = localStorage.getItem('selectedNamespace') || '';
};
// 保存当前选中的命名空间到localStorage
const saveSelection = (value) => {
  localStorage.setItem('selectedNamespace', value);
};
const updateReplicas = async ()=> {
  const updateScale = reactive(
      {
        namespace: selectedNamespace,
        deploymentName: currentRow.value.deploymentName,
        scaleNum: replicaCount.value
      }
  )
  console.log("更新副本数至:", replicaCount.value);
  try {
    const resp = await UPDATE_DEPLOYMENTSCALE(updateScale);
    console.log(resp)
    getDeployData()
  } catch (e) {
    console.error(e);
    return []; // 出错时返回空数组
  }
  // 在这里编写更新逻辑
  scaleDialogVisible.value = false; // 关闭对话框
}
const handleRowClick = (row) => {
  router.push({
    name: 'Pod',
    params: { type:'deployment',deploymentName: row.deploymentName ,namespace: selectedNamespace.value}
  });
};

const createDialogVisible = ref(false);
const createForm = ref({
  name: '',
  description: '',
  labels: [{ key: 'apps', value: '' }],
  namespace: '',
  replicas: '',
});

const rules = {
  name: [
    { required: true, message: '请输入deployment名', trigger: 'blur' },
    // 此处添加其他验证规则
  ],
  description: [
    { required: true, message: '请输入描述', trigger: 'blur' },
    // 此处添加其他验证规则
  ],
  namespace: [
    { required: true, message: '请选择命名空间', trigger: 'change' },
  ],
};

const formItems = ref([
  { id: Date.now(), key: 'apps', value: '' } // 初始标签项,第一项是不可删除的
]);
const addFormItem = () => {
  const newItem = { id: Date.now(), key: '', value: '', editable: true };
  formItems.value.unshift(newItem);
  console.log(formItems.value)
}
const changeReplicas =  (value) => {
  console.log(value)
}
const removeFormItem = (index) => {
  const reversedIndex = formItems.value.length - 1 - index; // 反转后的索引
  console.log("reverse = ",reversedIndex)
  console.log(formItems.value[index])
  console.log("no ",index)
  if (reversedIndex !== 0) { // 确保不删除第一行标签项
    formItems.value.splice(index,1)
  }
  console.log(formItems.value)
};
const instanceItems = ref([]);

const addInstanceItem = () => {
  // 折叠所有现有的实例内容器
  instanceItems.value.forEach(item => {
    item.collapsed = true;
  });
  const id = generateUniqueId();
  const newItem = {
    id: id,
    name: '',
    image: '',
    image_tag: '',
    livenessCommand:'',
    dialogSelectedNamespace:'',
    livenessStartDelay:'',
    // 存活检查响应延时时间
    livenessResDelay:'',
    // 存活检查间隔时间
    livenessIntervalTime:'',
    // 存活检查健康阈值
    livenessHealththreshold:'',
    // 存活检查不健康阈值
    livenessUnHealththreshold:'',
    livenessselectedCheckMethod:'http',
    lives_selectedProtocol:'HTTP',
    // 就绪检查的检查方法
    ReadinessSelectedCheckMethod:'http',
    // 是否开启就绪检查
    isReadinessCheckActive: '',
    // 是否开启存活检查
    isLivenessCheckActive:'',
    // 就绪检查 检查的协议
    readnessSelectedProtocol:'',
    // 就绪检查 检查的端口号
    readnessHealthCheckPort:'80',
    // 就绪检查的路径
    readnessHealthCheckPath:'',
    // 就绪检查TCP方式的端口号
    readnessTcpCheckPort:'',
    // 就绪检查执行的命令
    readnessCommand:'',
    // 就绪检查启动延时时间
    readnessStartDelay:'',
    // 就绪检查响应时间
    readnessResDelay:'',
    // 就绪检查间隔时间
    readnessIntervalTime:'',
    // 就绪检查健康阈值
    readnessHealththreshold:'',
    // 就绪检查不健康阈值
    readnessUnHealththreshold:'',
    replicas:'',
    lives_tcpCheckPort: '',
    lives_healthCheckPath:'/',
    lives_healthCheckPort:'',
    workspace: '',
    args: '',
    cmd: '',
    cpu_request:'250',
    cpu_limit:'500',
    memory_request:'256',
    memory_limit:'1024',
    value: '',
    collapsed: false,
    editMode: true
  };
  instanceItems.value.push(newItem);
};
// 函数用来把健康检查类型转换为相应的数字
const mapHealthCheckType = (type) => {
  console.log(type,"aaaaaaaaaaaaaaaaaaaaaaaaaaaa")
  switch (type) {
    case 'http':
      return 0;
    case 'tcp':
      return 1;
    case 'exec':
      return 2;
    default:
      return -1; // 或者任何合适的默认值
  }
};
const createService = async ()=> {

  // 初始化labelMap
  const labelMap = {};
  if (formData.value.label) {
    formData.value.label.split(',').forEach(pair => {
      const [key, value] = pair.split('=').map(part => part.trim());
      labelMap[key] = value;
    });
  }

  const createParameters = ref({
    labels: labelMap,
    port: parseInt(formData.value.port,10),
    rules: [{
      host: formData.value.domain,
      paths: [{
        path: formData.value.path,
        pathType: formData.value.type,
        serviceName: formData.value.serviceName,
        servicePort: parseInt(formData.value.port,10)
      }]
    }],
    name: formData.value.name,
    namespace: formData.value.namespace
  });
  console.log(createParameters.value,'nmmmmm')
  // 发送 createParameters.value 到后端...
  try {
    const resps = await CREATE_INGRESS(createParameters.value);
    console.log(resps,'fuckyou')
    ElMessage.success("创建成功")
    createDrawer.value = false
    getDeployData()

  } catch (e) {
    console.error(e);
    return []; // 出错时返回空数组
  }

}
// 调用 goToCreateDeployment 函数以响应对话框的打开
watch(createDialogVisible, (newVal) => {
  if (newVal) {
    goToCreateDeployment();
  }
});
const generateUniqueId = () => {
  // 生成唯一标识符的逻辑
  const timestamp = new Date().getTime();
  const randomSuffix = Math.floor(Math.random() * 1000);
  return `${timestamp}-${randomSuffix}`;
};

const expandInstanceItem = (index) => {
  instanceItems.value[index].editMode = true;
  instanceItems.value[index].collapsed = false;
};

const saveInstanceItem = (index) => {
  instanceItems.value[index].editMode = false;
  instanceItems.value[index].collapsed = true;
};
const removeInstanceItem = (index) => {
  if (instanceItems.value.length > 1) {
    instanceItems.value.splice(index, 1);
  }};
const onSubmit = () => {
  const formEl = ref(null);
  formEl.value.validate((valid) => {
    if (valid) {
      // 提交表单
    } else {
      console.log('表单验证失败');
      return false;
    }
  });
};
const newNamespace = reactive({
  name: '',
  description: ''
});
let currentPage = ref(1)
let pageSize = ref(5)
const small = ref(false)
const background = ref(false)
const disabled = ref(false)
const dialogVisible = ref(false);
const currentDeployName = ref('');
let yamlContent = ref('');
// 新增命名空间列表和选中的命名空间
const namespaces = ref([]); // 用于存储命名空间列表
const selectedNamespace = ref(localStorage.getItem('selectedNamespace') || ''); // 用于存储用户选择的命名空间
// 方法来获取命名空间列表
// fetchNamespaces 函数使用 getNSData 的返回值来更新命名空间的下拉菜单
const fetchNamespaces = async () => {
  namespaces.value = await getNSData();
  serviceNamespaces.value = await getNSData()
};
// fetchNamespaces 函数使用 getNSData 的返回值来更新命名空间的下拉菜单
// getNSData 函数获取命名空间并返回名称数组
const getNSData = async () => {
  try {
    const resp = await NAMESPACE_LIST(namespaceAllParameters);
    if (resp && resp.code === 200 && resp.data && Array.isArray(resp.data.Items)) {
      // 只返回命名空间的名称数组
      return resp.data.Items.map(ns => ns.metadata.name);
    } else {
      throw new Error('无法获取数据或数据格式不正确');
    }
  } catch (e) {
    console.error(e);
    return []; // 出错时返回空数组
  }
};


const namespaceAllParameters = reactive({
  page_size: 100000,
  page_number: currentPage,
})

const formatImages = (images) => {
  return images.split('\n').map(image => `<div>${image}</div>`).join('');
};

const goToCreateDeployment = () => {

  // dialogSelectedNamespace.value = selectedNamespace.value;
  // createDialogVisible.value = true;
  // // 清空现有的实例内容器并添加一个新的实例内容器
  // instanceItems.value = [];
  // addInstanceItem();
};


//编辑器配置
const cmOptions = {
  // 语言及语法模式
  mode: 'text/yaml',
  // 主题
  theme: 'monokai',
  lint: true,
  // 显示行数
  lineNumbers: true,
  smartIndent: true, //智能缩进
  indentUnit: 4, // 智能缩进单元长度为 4 个空格
  styleActiveLine: true, // 显示选中行的样式
  matchBrackets: true, //每当光标位于匹配的方括号旁边时,都会使其高亮显示
  readOnly: false,
  lineWrapping: true //自动换行
}
const scaleDeployment = (row) => {
  console.log(row.deploymentName)
  console.log(selectedNamespace)

}
const restartDeployment = async (row) =>{

  ElMessageBox.confirm(
      `确定要重启Deployment "${row.deploymentName}" 吗?`,
      '警告',
      {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning',
      }
  ).then(async () => {
    const restarParameters = reactive({
      deploymentName: row.deploymentName,
      namespace: selectedNamespace
    })
    try {
      const resp = await RESTART_DEPLOYMENT(restarParameters)
      console.log("————————————————",resp)
      ElMessage({
        type: 'success',
        message: `Deployment "${row.deploymentName}" 已重启`
      });
      getDeployData()

    }catch (e){
      console.log(e)
      ElMessage.error(`重启失败: ${e}`);
    }
  }).catch(() => {

  });

}
const handleSizeChange = (val) => {
  console.log(`${val} items per page`)
  namespaceAllParameters.page_size = val
  localStorage.setItem('servicepageSize',val)
  getDeployData()
}

const handleInput = _.debounce(async () => {
  await search();
}, 500); // 使用 lodash 的 debounce 函数来防抖,防止搜索操作太频繁
const updateDeploy = async () =>{
  try {
    const updatedJson = yaml2obj.load(yamlContent.value)
    const jsonString = JSON.stringify(updatedJson);

    updateParameters.deploymentName = currentDeployName.value
    updateParameters.content = jsonString
    await updateDeployData()
    await getDeployData()
  }catch (e){
    ElMessage.error(`${e}`)
  }
}
const onChange = (val)=> {
  yamlContent.value = val
}

const handleCurrentChange = (val) => {
  console.log(`current page: ${val}`)
  currentPage.value = val
  namespaceAllParameters.page_number = val
  localStorage.setItem('servicecurrentPage', val); // 将当前页保存在 localStorage

  getDeployData()
}
const viewYAML = (row) => {
  console.log('显示YAML信息', row.name);
  // 这里可以编写显示YAML信息的逻辑
  // 假设提供了 `getYAMLContent` 方法来获取 YAML 内容
  // 直接使用传入的 row 作为 YAML 内容
  getDeployDetailData(row.name)
};
const confirmDelete =  (row) => {

  ElMessageBox.confirm(
      `确定要删除Ingress "${row.name}" 吗?`,
      '警告',
      {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning',
      }
  ).then(async () => {
    const deleteNSParameters = ref({
      name: row.name,
      namespace: selectedNamespace.value,
    })
    console.log(deleteNSParameters.value)
    try {
      const resp = await DELETE_INGRESS(deleteNSParameters.value)
      console.log("————————————————",resp)
      ElMessage({
        type: 'success',
        message: `Ingress "${row.name}" 已被删除`
      });
      getDeployData()

    }catch (e){
      console.log(e)
      ElMessage.error(`删除失败: ${e}`);
    }
  }).catch(() => {
    ElMessage({
      type: 'info',
      message: '已取消删除'
    });
  });
};


const formatDateTime = (dateTimeString) => {
  return dateTimeString.replace('T', ' ').replace('Z', '');
};
// 示例数据和方法
const searchText = ref('');
const tableData = ref([
  {
    name: "",
    Labels: '',
    Host:'',
    Path: '',
    External_ip: '',
    TLS:'',
    createTime:"",
    Operation:"",
  },
  // ...其他数据项
]);

const search = async () => {
  console.log('执行搜索:', searchText.value);
  const searchParameters = reactive({
    page_size: pageSize,
    page_number: currentPage,
    filterName: searchText.value,
    namespace: selectedNamespace
  })
  try {
    const resp = await INGRESS_LIST(searchParameters);
    if (resp && resp.data && Array.isArray(resp.data.items)) {
      tableData.value = resp.data.items.map((item) => {
        // 提取规则中的第一个规则和路径,这可能需要根据您的实际需要调整
        const firstRule = item.spec.rules && item.spec.rules[0];
        const firstPath = firstRule &&
            firstRule.http &&
            firstRule.http.paths &&
            firstRule.http.paths[0];
        const ip = item.status.loadBalancer.ingress && item.status.loadBalancer.ingress[0] && item.status.loadBalancer.ingress[0].ip;

        return {
          name: item.metadata.name,
          Labels: formatLabels(item.metadata.labels), // 假设您已定义formatLabels函数
          Host: firstRule ? firstRule.host : '', // 使用第一个规则的主机名
          External_ip: ip || '', // 使用负载均衡器的IP地址
          Path: firstPath ? firstPath.path : '', // 使用第一个路径的路径
          TLS: '', // TLS信息需要从其他部分提取,这里留空
          createTime: formatDateTime(item.metadata.creationTimestamp), // 假设您已定义formatDateTime函数
          // 其他属性...
        };
      });
    }
    // 更新部署计数
    deploymentCount.value = resp.data.count;
  } catch (e) {
    console.error(e);
    // 处理错误情况,可能要向用户显示错误信息或日志输出
  }
};

const refresh = () => {
  getDeployData()
  console.log('刷新表格数据');
};
const updateParameters = reactive({
  name: "",
  namespace: selectedNamespace,
  content: ""
})
const updateDeployData = async ()=>{
  try {
    console.log("你吗的",updateParameters.content)
    const resp = await UPDATE_INGRESS(updateParameters)
    if (resp.code !== 200){
      ElMessage.error(resp.message)
      return
    }
    ElMessage.success("更新成功")
    dialogVisible.value = false

  }catch (e){
    console.log(e)
    ElMessage.error(`${e}`)

  }
}
const deploymentParameters = reactive({
  page_size: pageSize,
  page_number: currentPage,
  namespace: selectedNamespace,
})

// 设置watcher来监听selectedNamespace的改变
watch(selectedNamespace, (newNamespace) => {
  // 更新deploymentParameters中的namespace
  deploymentParameters.namespace = newNamespace;

  // 重新调用getDeployData以获取新命名空间的部署数据
  getDeployData();
});
var deploymentCount = ref(0)
// 在这里创建一个方法来将 Labels 对象转换为一个字符串数组
// 格式化标签为字符串数组
const formatLabels = (labelsMap) => {
  return labelsMap ? Object.entries(labelsMap).map(([key, value]) => `${key}: ${value}`) : [];
};
const systemNamespaces = ['default', 'kube-system', 'kube-public', 'kube-node-lease'];

const getDeployData = async () => {
  try {
    const resp = await INGRESS_LIST(deploymentParameters);
    if (resp && resp.data && Array.isArray(resp.data.items)) {
      tableData.value = resp.data.items.map((item) => {
        // 提取规则中的第一个规则和路径,这可能需要根据您的实际需要调整
        const firstRule = item.spec.rules && item.spec.rules[0];
        const firstPath = firstRule &&
            firstRule.http &&
            firstRule.http.paths &&
            firstRule.http.paths[0];
        const ip = item.status.loadBalancer.ingress && item.status.loadBalancer.ingress[0] && item.status.loadBalancer.ingress[0].ip;

        return {
          name: item.metadata.name,
          Labels: formatLabels(item.metadata.labels), // 假设您已定义formatLabels函数
          Host: firstRule ? firstRule.host : '', // 使用第一个规则的主机名
          External_ip: ip || '', // 使用负载均衡器的IP地址
          Path: firstPath ? firstPath.path : '', // 使用第一个路径的路径
          TLS: '', // TLS信息需要从其他部分提取,这里留空
          createTime: formatDateTime(item.metadata.creationTimestamp), // 假设您已定义formatDateTime函数
          // 其他属性...
        };
      });
    }
    // 更新部署计数
    deploymentCount.value = resp.data.count;
  } catch (e) {
    console.error(e);
    // 处理错误情况,可能要向用户显示错误信息或日志输出
  }
};
const getDeployDetailData = async (serviceName)=>{
  try {
    const DeploymentDetailparams = reactive({
      name: serviceName,
      namespace: selectedNamespace.value
    })
    console.log("ddddddddd",DeploymentDetailparams)
    const resp = await INGRESS_DETAIL(DeploymentDetailparams)
    console.log("cccccccc",resp)
    console.log("yaml =======",json2yaml.stringify(resp.data))
    yamlContent.value = json2yaml.stringify(resp.data); // 确保将数据赋值给 yamlContent
    currentDeployName.value = resp.data.metadata.name
    updateParameters.content = yamlContent.value
    await  nextTick()
    dialogVisible.value = true;

  }catch (e){
    console.log(e)
    console.log("你吗")
  }
}
// 在setup函数中定义定时器
let refreshInterval = null;

onMounted(() => {
  loadSelection();
  refreshInterval = setInterval(() => {
    getDeployData();
  }, 30000); // 每30秒刷新一次
});
// 组件卸载前保存命名空间
onBeforeUnmount(() => {
  saveSelection(selectedNamespace.value);
});

onBeforeMount( async ()=> {
  clearInterval(refreshInterval);
  // 尝试从 localStorage 中读取状态
  const savedPageSize = localStorage.getItem('nspageSize');
  const savedCurrentPage = localStorage.getItem('nscurrentPage');

  // 如果存在则更新到响应式变量中
  if (savedPageSize) {
    pageSize.value = parseInt(savedPageSize, 10);
  }
  if (savedCurrentPage) {
    currentPage.value = parseInt(savedCurrentPage, 10);
  }
  getDeployData()
  await fetchNamespaces(); // 获取并更新命名空间列表
  // getNSAllData()

});
</script>

<style scoped>
.loading-icon {
  width: 20px; /* 或者您希望的任何尺寸 */
  height: 20px; /* 保持与宽度相同以保持图标的纵横比 */
  margin-left: 5px; /* 添加一点空间在状态文本和图标之间 */
  animation: loading-spin 2s linear infinite;
}

/* 如果需要,可以移除这个类,因为它可能会导致对齐问题 */
/* .loader {
  animation: loader-spin 1s linear infinite;
} */

@keyframes loading-spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}
.container {
  margin: 10px;
  background-color: #F2F2F2;
}
.deployment-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px;
  margin: 10px;
  margin-bottom: -10px;
  background: #FFF;
  border: 2px solid #ebeef5;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}

/* 新增左侧部分样式,放置“命名空间:”文本和下拉框 */
.left-section {
  display: flex;
  align-items: center;
}

/* 确保下拉框和文本在同一行 */
.el-select {
  margin-left: 10px; /* 为下拉框添加左侧间隔 */
}
.header {
  display: flex;
  align-items: center;
  justify-content: space-between; /* 添加此属性对子元素进行分散对齐 */
  margin-bottom: 0px;
  gap: 10px;
  padding: 10px;
  background: #FFF;
  border: 2px solid #ebeef5;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}

.search-input {
  /*flex-grow: 1;*/
  width: 200px;
}

.table-wrapper {
  background: #FFF;
  border: 2px solid #ebeef5; /* 浅色边框线 */
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
.paginations {
  margin-top: 10px;
  margin-left: 20px;
  margin-bottom: 10px;
}
/* 左侧组合样式,创建按钮和搜索框靠在一起 */
.left-group {
  display: flex;
  align-items: center;
  gap: 10px; /* You can adjust the gap as needed */
}

/* 右侧刷新按钮 */
.right-group {
  display: flex;
  align-items: center;
}
.yaml-content {
  background-color: #f5f5f5;
  border-left: 3px solid #4795EE;
  padding: 15px;
  white-space: pre-wrap;
  text-align: left;
  margin: 20px 0;
  overflow-x: auto;
}
.status-active {
  color: #67C23A;
}

.status-inactive {
  color: red;
}
.dialog-footer {
  /*text-align: right;*/
  display: flex;
  justify-content: flex-end;
  padding: 8px;
}




.deployment-header {
  display: flex;
  align-items: center;
  height: 30px;
  padding: 10px;
  margin: 10px;
  margin-bottom: -10px;
  background: #FFF;
  border: 2px solid #ebeef5;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}



.form-item-with-help {
  margin-top: 10px;
  margin-left: 20px;
}
.form-item-with-resource {
  margin-top: 10px;
  margin-left: 20px;
}
.form-item {
  flex-wrap: wrap; /* 确保换行 */
  /*align-items: center; !* 如果需要垂直居中 *!*/
  margin-bottom: 10px; /* 保持垂直间距 */
}

.input-item {
  width: 200px;
  margin-right: 10px;
}
.help-text {
  display: block; /* 保证帮助文本在新的行显示 */
  font-size: 12px;
  width: 1000px;
  color: #999999;
  margin-top: 5px;
}
.input-with-help {
  margin-top: 20px;
  display: flex;
  flex-direction: column;
}
.input-deployname {
  width: 300px; /* 限制这个div的宽度 */
  display: flex;
  flex-direction: column; /* 让子元素垂直排列 */
}
.input-containername {
  width: 250px; /* 限制这个div的宽度 */
  display: flex;
  margin-left: -50px;
  flex-direction: column; /* 让子元素垂直排列 */
}

.add-button {
  margin-top: -20px; /* 添加按钮与输入行之间的空间 */
  margin-left: 200px;
}

.input-container-cpu {
  display: flex;
  flex-direction: column;
  /*padding-left: -20px; !* 往右移动整个容器 *!*/

}

.cpu-label {
  margin-bottom: 5px; /* 调整为所需的间距 */
  margin-left: -50px;
}


.container {
  margin: 10px;
}
.item-container {
  margin-bottom: 10px;
}
.content-container {
  background-color: #F2F2F2;
  padding: 10px;
  display: flex;
  width: 700px;
  justify-content: space-between;
  align-items: center;
  transition: height 0.3s;
  overflow: hidden;
  position: relative;

}
.content-container.collapsed {
  height: 40px;
}
.info {
  display: flex;
  align-items: center;
}
.actions {
  position: absolute;
  right: 10px; /* 调整为需要的值 */
  top: 10px; /* 调整为需要的值 */
}



.input-row {
  display: flex;
  align-items: center;
  gap: 10px;
  /*margin-left: -50px;*/
}
.input-row .el-input {
  flex: 1;
}

.input-row label {
  margin-left: 10px; /* 或者需要的任何值 */
}

.input-row .el-input .el-input__inner {
  width: 100%; /* 让输入框充满其容器 */
}


.input-containername p {
  margin-bottom: 10px; /* 为“CPU:”下方添加一些间隔 */
}

.form-item-resource {
  margin-left: 20px; /* 整个表单项向右移动 20px */
  margin-top: 10px;
}
.custom-form-item {
  height: auto;
  overflow: auto;
}
.check-method-container,
.execution-command-container {
  display: flex;
  align-items: center;
  margin-bottom: 10px; /* 添加一些垂直间距 */
}

.method-label {
  width: 100px;
  margin: 10px;
  margin-right: 20px; /* 文本与选择框/输入框之间的间隔 */
}
.command-label {
  /*margin-right: 20px; !* 文本与输入框之间的间隔 *!*/
  width: 100px;
  margin: 10px;

}
.livenessdiv {
  background-color: white;
  width: 500px;
}
.port-range {
  margin-left: 10px;
}
.input-healthContainer {
  margin-left: -50px;
}
.el-select,
.el-input {
  /*flex-grow: 1; !* 输入框和选择框将占据剩余空间 *!*/
  max-width: calc(100% - 100px); /* 限制最大宽度,这里的100px是示例,可以根据实际情况调整 */
}
.button-group {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 10px; /* 调整按钮之间的间隔 */
}

</style>

二、service开发

<template>
  <!-- 新的 div 容器,使用flex布局对齐内容 -->
  <div class="deployment-header" style="flex: 1">
    <div class="left-section">
      <span>命名空间:</span>
      <el-select v-model="selectedNamespace" placeholder="请选择">
        <el-option
            v-for="namespace in namespaces"
            :key="namespace"
            :label="namespace"
            :value="namespace">
        </el-option>
      </el-select>
    </div>

    <!-- 移动的刷新按钮,保留在右侧 -->
    <div class="right-group">
      <el-button @click="refresh">
        <el-icon><Refresh /></el-icon>
        <span> 刷新 </span>
      </el-button>
    </div>
  </div>
  <div class="container">
    <!-- 第一部分: 头部 -->
    <div class="header shadow">
      <div class="left-group">
        <el-button  type="primary" @click="openCreateDrawer">
          <el-icon><EditPen /></el-icon>
          <span style="vertical-align: middle"> 创建 </span>
        </el-button>
        <el-input placeholder="请输入内容" v-model="searchText" class="search-input" @input="handleInput">
          <template #append>
            <el-button type="primary" @click="search()">
              <el-icon><Search /></el-icon>
            </el-button>
          </template>
        </el-input>
      </div>
    </div>

    <!-- 第二部分: 表格 -->
    <div class="table-wrapper shadow">
      <el-table :data="tableData" style="width: 100%" >
        <el-table-column prop="name" label="service名"  align="center">
          <template #default="{ row }">
            <div>
              <span style="vertical-align: middle; color: #1395FF; cursor: pointer;" @click="handleRowClick(row)">
                {{ row.name }}
              </span>
            </div>
          </template>
        </el-table-column>
        <el-table-column prop="Labels" label="标签"  align="center">
          <template #default="{ row }">
            <div>
              <el-tooltip
                  v-for="(label, index) in row.Labels"
                  :key="index"
                  class="item"
                  effect="dark"
                  :content="label"
                  placement="top"
              >
                <el-tag class="ml-2" type="success">{{ label }}</el-tag>
              </el-tooltip>
            </div>
          </template>
        </el-table-column>
        <el-table-column prop="Type" label="类型" align="center">
          <template #default="{ row }">
            <div>
                <el-tag class="ml-2" type="success">{{ row.Type }}</el-tag>
            </div>
          </template>
        </el-table-column>
        <el-table-column prop="Cluster_ip" label="CLUSTER_IP" align="center" >
          <template #default="{ row }">
            <div style="display: flex; align-items: center;justify-content: center;height: 100%">
              {{ row.Cluster_ip }}
            </div>
          </template>
        </el-table-column>
        <el-table-column prop="External_ip" label="EXTERNAL_IP" align="center" >
          <template #default="{ row }">
            <div style="display: flex; align-items: center;justify-content: center;height: 100%">
              {{ row.External_ip }}
            </div>
          </template>
        </el-table-column>
        <el-table-column prop="port" label="端口" align="center">
          <template #default="{ row }">
            <div style="display: flex; align-items: center;justify-content: center;height: 100%">
              {{ row.port }}
            </div>
          </template>
        </el-table-column>
        <el-table-column prop="createTime" label="创建时间" align="center" >
          <template #default="{ row }">
            <div>
              <el-tag class="ml-2" type="warning">{{row.createTime}}</el-tag>
            </div>
          </template>
        </el-table-column>
        <el-table-column prop="Operation" label="操作" align="center">
          <template #default="{ row }">
            <div class="button-group">

              <el-button size="small" color="#5AABFF" :dark="isDark" plain @click="viewYAML(row)">
                <el-icon><EditPen /></el-icon>
                <span style="vertical-align: middle"> YAML </span>
              </el-button>
              <el-button size="small"  color="#F58D79" :dark="isDark" plain @click="confirmDelete(row)">
                <el-icon><Tickets /></el-icon>
                <span style="vertical-align: middle"> 删除 </span>
              </el-button>
            </div>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination
          v-model:current-page="currentPage"
          v-model:page-size="pageSize"
          :page-sizes="[5, 10, 20, 30]"
          :small="small"
          :disabled="disabled"
          :background="background"
          layout="total, sizes, prev, pager, next, jumper"
          :total=deploymentCount
          class="paginations"
          @size-change="handleSizeChange"
          @current-change="handleCurrentChange"
      />
    </div>

    <el-dialog title="YAML信息" v-model="dialogVisible" width="45%" top="5%">

      <codemirror
          v-model="yamlContent"
          placeholder="请输入代码..."
          :style="{ height: '100%' }"
          v-bind="cmOptions"
          :extensions="extensions"
      />
      <template #footer>
                <span class="dialog-footer">
                    <el-button @click="dialogVisible = false">取 消</el-button>
                    <el-button  type="primary" @click="updateDeploy()">更 新</el-button>
                </span>
      </template>
    </el-dialog>
    <!-- 对话框 -->
    <el-dialog
        title="副本数调整"
        v-model="scaleDialogVisible"
        width="30%"
    >
      <div style="text-align: center; padding: 20px;">
        <label>实例数:</label>
        <el-input-number v-model="replicaCount" :min="1" label="副本数:" />
      </div>
      <span slot="footer" class="dialog-footer">
      <el-button @click="scaleDialogVisible = false">取消</el-button>
      <el-button type="primary" @click="updateReplicas">更新</el-button>
    </span>
    </el-dialog>
  </div>
  <el-drawer
      title="创建Service"
      v-model="createDrawer"
      direction="rtl"
  >

    <h3 style="margin-right: 10px;margin-bottom: 10px;">Service</h3>
    <div>
      <el-form ref="formRef" :model="formData" :rules="formRules">
        <div style="display: flex; align-items: center; margin-bottom: 20px;">
          <span style="width: 100px; display: inline-block; text-align: right; margin-right: 10px;">名称:</span>
          <el-form-item label="" prop="serviceName">
            <el-input v-model="formData.name" placeholder="请输入内容" style="width: 250px"></el-input>
          </el-form-item>
        </div>
        <el-form-item label="" prop="namespace">
          <div style="display: flex; align-items: center;margin-bottom: 20px">
            <span style="width: 100px; display: inline-block; text-align: right; margin-right: 10px;">命名空间:</span>
            <el-select v-model="formData.namespace" placeholder="请选择" style="width: 150px;">
              <el-option
                  v-for="namespace in serviceNamespaces"
                  :key="namespace"
                  :label="namespace"
                  :value="namespace">
              </el-option>
            </el-select>
          </div>
        </el-form-item>
        <el-form-item label="" prop="type">
          <div style="display: flex; align-items: center;margin-bottom: 20px">
            <span style="width: 100px; display: inline-block; text-align: right; margin-right: 10px;">类型:</span>
            <el-select v-model="formData.type" placeholder="请选择" style="width: 150px;">
              <el-option
                  v-for="type in serviceType"
                  :key="type"
                  :label="type"
                  :value="type">
              </el-option>
            </el-select>
          </div>
        </el-form-item>
        <div style="display: flex; align-items: center; margin-bottom: 20px;">
          <span style="width: 100px; display: inline-block; text-align: right; margin-right: 10px;">容器端口:</span>
          <el-form-item label="" prop="targetPort">
            <el-input v-model="formData.targetPort" placeholder="请输入内容" style="width: 250px"></el-input>
          </el-form-item>
        </div>
        <div style="display: flex; align-items: center; margin-bottom: 20px;">
          <span style="width: 100px; display: inline-block; text-align: right; margin-right: 10px;">Service端口:</span>
          <el-form-item label="" prop="port">
            <el-input v-model="formData.port" placeholder="请输入内容" style="width: 250px"></el-input>
          </el-form-item>
        </div>
        <div style="display: flex; align-items: center; margin-bottom: 20px;" v-if="formData.type === 'NodePort'">
          <span style="width: 100px; display: inline-block; text-align: right; margin-right: 10px;">NodePort:</span>
          <el-form-item label="" prop="nodePort">
            <el-input v-model="formData.nodePort" placeholder="请输入内容" style="width: 250px"></el-input>
          </el-form-item>
        </div>
        <div style="display: flex; align-items: center; margin-bottom: 20px;">
          <span style="width: 100px; display: inline-block; text-align: right; margin-right: 10px;">标签:</span>
          <el-form-item label="" prop="label">
            <el-input v-model="formData.label" placeholder="请输入内容" style="width: 250px"></el-input>
          </el-form-item>
        </div>

      </el-form>
      <!-- 更多输入项 -->
    </div>
    <template #footer>
      <el-button @click="closeDrawer">取消</el-button>
      <el-button type="primary"  @click="validateForm">创建</el-button>
    </template>
  </el-drawer>

</template>

<script setup>
import {nextTick, onBeforeMount, onBeforeUnmount, reactive, ref, watch} from 'vue';
import { Loading } from '@element-plus/icons-vue';
import 'element-plus/dist/index.css';
import { Refresh, EditPen, Search } from '@element-plus/icons-vue';
import {  onMounted } from 'vue';
import { useRouter } from 'vue-router';
import { ArrowLeft } from '@element-plus/icons-vue';


// 在模板中可以直接使用 Refresh, EditPen, 和 Search

import {
  CREATE_DEPLOYMENT,
  CREATE_NAMESPACE, CREATE_SERVICE, DELETE_DEPLOYMENT,
  DELETE_NAMESPACE, DELETE_SERVICE, DEPLOYMENT_DETAIL, DEPLOYMENT_LIST,
  NAMESPACE_DETAIL,
  NAMESPACE_LIST, RESTART_DEPLOYMENT, SERVICE_DETAIL, SERVICE_LIST, UPDATE_DEPLOYMENT, UPDATE_DEPLOYMENTSCALE,
  UPDATE_NAMESPACE, UPDATE_SERVICE
} from "../../../api/k8s.js";
import { Codemirror } from 'vue-codemirror'
import { javascript} from  '@codemirror/lang-javascript'
// import { javascript } from 'codemirror/lang-javascript'
import { oneDark } from '@codemirror/theme-one-dark'

import _, {parseInt} from 'lodash';
import json2yaml from 'json2yaml'
import yaml2obj from 'js-yaml';
import {ElMessage} from "element-plus";
import router from "@/router/index.js";
import { ElMessageBox } from 'element-plus';
import axios from "axios";
import {value} from "lodash/seq.js";
const extensions = [javascript(),oneDark]
const formRef = ref(null);

const formData = ref({
  name: '',
  namespace:'',
  type:'',
  port:'',
  label:'',
  targetPort:'',
  nodePort:'',
  // 初始化更多的表单数据
});
const validateForm = async () => {
  try {
    await formRef.value.validate();
    console.log(serviceType.value)
    console.log(formData.value)
    createService()
  } catch (error) {
    ElMessage.error('表单验证失败,请检查输入');
  }
};
const closeDrawer = () => {
  createDrawer.value = false

};
const formRules = {
  name: [
    { required: true, message: '请输入名称', trigger: 'blur' }
  ],
  port: [
    { required: true, message: '请输入service端口', trigger: 'change' }
  ],
  label: [
    { required: true, message: '请输入标签', trigger: 'blur' }
  ],
  targetPort: [
    { required: true, message: '请输入容器端口', trigger: 'blur' }
  ],
  nodePort: [
    { required: true, message: '请输入nodeport', trigger: 'blur' }
  ],
  // 其他校验规则
};
const dialogSelectedNamespace = ref(''); // 对话框的v-model
const scaleDialogVisible=  ref(false)
const replicaCount = ref(1)
const currentRow = ref(null)
const serviceNamespaces = ref([]); // 用于存储命名空间列表
const serviceType = ref(['NodePort','ClusterIP']); // 用于存储命名空间列表

const openScaleDiglog = (row)=>{
  replicaCount.value = row.Replicas
  currentRow.value = row
  scaleDialogVisible.value = true
}
const createDrawer = ref(false)

const openCreateDrawer = ()=>{
  createDrawer.value = true
}
// 从localStorage加载保存的命名空间
const loadSelection = () => {
  selectedNamespace.value = localStorage.getItem('selectedNamespace') || '';
};
// 保存当前选中的命名空间到localStorage
const saveSelection = (value) => {
  localStorage.setItem('selectedNamespace', value);
};
const updateReplicas = async ()=> {
  const updateScale = reactive(
      {
        namespace: selectedNamespace,
        deploymentName: currentRow.value.deploymentName,
        scaleNum: replicaCount.value
      }
  )
  console.log("更新副本数至:", replicaCount.value);
  try {
    const resp = await UPDATE_DEPLOYMENTSCALE(updateScale);
    console.log(resp)
    getDeployData()
  } catch (e) {
    console.error(e);
    return []; // 出错时返回空数组
  }
  // 在这里编写更新逻辑
  scaleDialogVisible.value = false; // 关闭对话框
}
const handleRowClick = (row) => {
  router.push({
    name: 'Pod',
    params: { type:'deployment',deploymentName: row.deploymentName ,namespace: selectedNamespace.value}
  });
};

const createDialogVisible = ref(false);
const createForm = ref({
  name: '',
  description: '',
  labels: [{ key: 'apps', value: '' }],
  namespace: '',
  replicas: '',
});

const rules = {
  name: [
    { required: true, message: '请输入deployment名', trigger: 'blur' },
    // 此处添加其他验证规则
  ],
  description: [
    { required: true, message: '请输入描述', trigger: 'blur' },
    // 此处添加其他验证规则
  ],
  namespace: [
    { required: true, message: '请选择命名空间', trigger: 'change' },
  ],
};

const formItems = ref([
  { id: Date.now(), key: 'apps', value: '' } // 初始标签项,第一项是不可删除的
]);
const addFormItem = () => {
  const newItem = { id: Date.now(), key: '', value: '', editable: true };
  formItems.value.unshift(newItem);
  console.log(formItems.value)
}
const changeReplicas =  (value) => {
  console.log(value)
}
const removeFormItem = (index) => {
  const reversedIndex = formItems.value.length - 1 - index; // 反转后的索引
  console.log("reverse = ",reversedIndex)
  console.log(formItems.value[index])
  console.log("no ",index)
  if (reversedIndex !== 0) { // 确保不删除第一行标签项
    formItems.value.splice(index,1)
  }
  console.log(formItems.value)
};
const instanceItems = ref([]);

const addInstanceItem = () => {
  // 折叠所有现有的实例内容器
  instanceItems.value.forEach(item => {
    item.collapsed = true;
  });
  const id = generateUniqueId();
  const newItem = {
    id: id,
    name: '',
    image: '',
    image_tag: '',
    livenessCommand:'',
    dialogSelectedNamespace:'',
    livenessStartDelay:'',
    // 存活检查响应延时时间
    livenessResDelay:'',
    // 存活检查间隔时间
    livenessIntervalTime:'',
    // 存活检查健康阈值
    livenessHealththreshold:'',
    // 存活检查不健康阈值
    livenessUnHealththreshold:'',
    livenessselectedCheckMethod:'http',
    lives_selectedProtocol:'HTTP',
    // 就绪检查的检查方法
    ReadinessSelectedCheckMethod:'http',
    // 是否开启就绪检查
    isReadinessCheckActive: '',
    // 是否开启存活检查
    isLivenessCheckActive:'',
    // 就绪检查 检查的协议
    readnessSelectedProtocol:'',
    // 就绪检查 检查的端口号
    readnessHealthCheckPort:'80',
    // 就绪检查的路径
    readnessHealthCheckPath:'',
    // 就绪检查TCP方式的端口号
    readnessTcpCheckPort:'',
    // 就绪检查执行的命令
    readnessCommand:'',
    // 就绪检查启动延时时间
    readnessStartDelay:'',
    // 就绪检查响应时间
    readnessResDelay:'',
    // 就绪检查间隔时间
    readnessIntervalTime:'',
    // 就绪检查健康阈值
    readnessHealththreshold:'',
    // 就绪检查不健康阈值
    readnessUnHealththreshold:'',
    replicas:'',
    lives_tcpCheckPort: '',
    lives_healthCheckPath:'/',
    lives_healthCheckPort:'',
    workspace: '',
    args: '',
    cmd: '',
    cpu_request:'250',
    cpu_limit:'500',
    memory_request:'256',
    memory_limit:'1024',
    value: '',
    collapsed: false,
    editMode: true
  };
  instanceItems.value.push(newItem);
};
// 函数用来把健康检查类型转换为相应的数字
const mapHealthCheckType = (type) => {
  console.log(type,"aaaaaaaaaaaaaaaaaaaaaaaaaaaa")
  switch (type) {
    case 'http':
      return 0;
    case 'tcp':
      return 1;
    case 'exec':
      return 2;
    default:
      return -1; // 或者任何合适的默认值
  }
};
const createService = async ()=> {
  let type
  if (formData.value.type == 'NodePort'){
      type = 1
  }else if (formData.value.type == 'ClusterIP'){
    type = 0
  }
  // 初始化labelMap
  const labelMap = {};
  if (formData.value.label) {
    formData.value.label.split(',').forEach(pair => {
      const [key, value] = pair.split('=').map(part => part.trim());
      labelMap[key] = value;
    });
  }
  const createParameters = ref({
    labels: labelMap,
    port: parseInt(formData.value.port,10),
    targetPort: parseInt(formData.value.targetPort,10),
    type: type,
    name: formData.value.name,
    namespace: formData.value.namespace
  });
  if (formData.value.type === 'NodePort') {
    createParameters.value.nodePort = parseInt(formData.value.nodePort,10);
  }
  // 发送 createParameters.value 到后端...
  try {
    const resps = await CREATE_SERVICE(createParameters.value);
    console.log(resps,'fuckyou')
    ElMessage.success("创建成功")
    createDrawer.value = false
    getDeployData()

  } catch (e) {
    console.error(e);
    return []; // 出错时返回空数组
  }

}
// 调用 goToCreateDeployment 函数以响应对话框的打开
watch(createDialogVisible, (newVal) => {
  if (newVal) {
    goToCreateDeployment();
  }
});
const generateUniqueId = () => {
  // 生成唯一标识符的逻辑
  const timestamp = new Date().getTime();
  const randomSuffix = Math.floor(Math.random() * 1000);
  return `${timestamp}-${randomSuffix}`;
};

const expandInstanceItem = (index) => {
  instanceItems.value[index].editMode = true;
  instanceItems.value[index].collapsed = false;
};

const saveInstanceItem = (index) => {
  instanceItems.value[index].editMode = false;
  instanceItems.value[index].collapsed = true;
};
const removeInstanceItem = (index) => {
  if (instanceItems.value.length > 1) {
    instanceItems.value.splice(index, 1);
  }};
const onSubmit = () => {
  const formEl = ref(null);
  formEl.value.validate((valid) => {
    if (valid) {
      // 提交表单
    } else {
      console.log('表单验证失败');
      return false;
    }
  });
};
const newNamespace = reactive({
  name: '',
  description: ''
});
let currentPage = ref(1)
let pageSize = ref(5)
const small = ref(false)
const background = ref(false)
const disabled = ref(false)
const dialogVisible = ref(false);
const currentDeployName = ref('');
let yamlContent = ref('');
// 新增命名空间列表和选中的命名空间
const namespaces = ref([]); // 用于存储命名空间列表
const selectedNamespace = ref(localStorage.getItem('selectedNamespace') || ''); // 用于存储用户选择的命名空间
// 方法来获取命名空间列表
// fetchNamespaces 函数使用 getNSData 的返回值来更新命名空间的下拉菜单
const fetchNamespaces = async () => {
  namespaces.value = await getNSData();
  serviceNamespaces.value = await getNSData()
};
// fetchNamespaces 函数使用 getNSData 的返回值来更新命名空间的下拉菜单
// getNSData 函数获取命名空间并返回名称数组
const getNSData = async () => {
  try {
    const resp = await NAMESPACE_LIST(namespaceAllParameters);
    if (resp && resp.code === 200 && resp.data && Array.isArray(resp.data.Items)) {
      // 只返回命名空间的名称数组
      return resp.data.Items.map(ns => ns.metadata.name);
    } else {
      throw new Error('无法获取数据或数据格式不正确');
    }
  } catch (e) {
    console.error(e);
    return []; // 出错时返回空数组
  }
};


const namespaceAllParameters = reactive({
  page_size: 100000,
  page_number: currentPage,
})

const formatImages = (images) => {
  return images.split('\n').map(image => `<div>${image}</div>`).join('');
};

const goToCreateDeployment = () => {

  // dialogSelectedNamespace.value = selectedNamespace.value;
  // createDialogVisible.value = true;
  // // 清空现有的实例内容器并添加一个新的实例内容器
  // instanceItems.value = [];
  // addInstanceItem();
};


//编辑器配置
const cmOptions = {
  // 语言及语法模式
  mode: 'text/yaml',
  // 主题
  theme: 'monokai',
  lint: true,
  // 显示行数
  lineNumbers: true,
  smartIndent: true, //智能缩进
  indentUnit: 4, // 智能缩进单元长度为 4 个空格
  styleActiveLine: true, // 显示选中行的样式
  matchBrackets: true, //每当光标位于匹配的方括号旁边时,都会使其高亮显示
  readOnly: false,
  lineWrapping: true //自动换行
}
const scaleDeployment = (row) => {
  console.log(row.deploymentName)
  console.log(selectedNamespace)

}
const restartDeployment = async (row) =>{

  ElMessageBox.confirm(
      `确定要重启Deployment "${row.deploymentName}" 吗?`,
      '警告',
      {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning',
      }
  ).then(async () => {
    const restarParameters = reactive({
      deploymentName: row.deploymentName,
      namespace: selectedNamespace
    })
    try {
      const resp = await RESTART_DEPLOYMENT(restarParameters)
      console.log("————————————————",resp)
      ElMessage({
        type: 'success',
        message: `Deployment "${row.deploymentName}" 已重启`
      });
      getDeployData()

    }catch (e){
      console.log(e)
      ElMessage.error(`重启失败: ${e}`);
    }
  }).catch(() => {

  });

}
const handleSizeChange = (val) => {
  console.log(`${val} items per page`)
  namespaceAllParameters.page_size = val
  localStorage.setItem('servicepageSize',val)
  getDeployData()
}

const handleInput = _.debounce(async () => {
  await search();
}, 500); // 使用 lodash 的 debounce 函数来防抖,防止搜索操作太频繁
const updateDeploy = async () =>{
  try {
    const updatedJson = yaml2obj.load(yamlContent.value)
    const jsonString = JSON.stringify(updatedJson);

    updateParameters.deploymentName = currentDeployName.value
    updateParameters.content = jsonString
    await updateDeployData()
    await getDeployData()
  }catch (e){
    ElMessage.error(`${e}`)
  }
}
const onChange = (val)=> {
  yamlContent.value = val
}

const handleCurrentChange = (val) => {
  console.log(`current page: ${val}`)
  currentPage.value = val
  namespaceAllParameters.page_number = val
  localStorage.setItem('servicecurrentPage', val); // 将当前页保存在 localStorage

  getDeployData()
}
const viewYAML = (row) => {
  console.log('显示YAML信息', row.name);
  // 这里可以编写显示YAML信息的逻辑
  // 假设提供了 `getYAMLContent` 方法来获取 YAML 内容
  // 直接使用传入的 row 作为 YAML 内容
  getDeployDetailData(row.name)
};
const confirmDelete =  (row) => {confirmDelete

  ElMessageBox.confirm(
      `确定要删除Service "${row.serviceName}" 吗?`,
      '警告',
      {
        confirmButtonText: '确认',
        cancelButtonText: '取消',
        type: 'warning',
      }
  ).then(async () => {
    const deleteNSParameters = ref({
      name: row.name,
      namespace: selectedNamespace.value,
    })
    console.log(deleteNSParameters.value)
    try {
      const resp = await DELETE_SERVICE(deleteNSParameters.value)
      console.log("————————————————",resp)
      ElMessage({
        type: 'success',
        message: `Service "${row.name}" 已被删除`
      });
      getDeployData()

    }catch (e){
      console.log(e)
      ElMessage.error(`删除失败: ${e}`);
    }
  }).catch(() => {
    ElMessage({
      type: 'info',
      message: '已取消删除'
    });
  });
};


const formatDateTime = (dateTimeString) => {
  return dateTimeString.replace('T', ' ').replace('Z', '');
};
// 示例数据和方法
const searchText = ref('');
const tableData = ref([
  {
    name: "",
    Labels: '',
    Type: '',
    Cluster_ip: '',
    External_ip: '',
    port:'',
    createTime:"",
    Operation:"",
  },
  // ...其他数据项
]);

const search = async () => {
  console.log('执行搜索:', searchText.value);
  const searchParameters = reactive({
    page_size: pageSize,
    page_number: currentPage,
    filterName: searchText.value,
    namespace: selectedNamespace
  })
  try {

    const resp = await SERVICE_LIST(searchParameters);
    if (resp && resp.data && Array.isArray(resp.data.items)) {
      tableData.value = resp.data.items.map((item) => {
        const ports = item.spec.ports
            .map(p => p.nodePort ? `${p.port}/${p.nodePort}` : p.port.toString()) // 如果nodePort存在,显示nodePort/port,否则只显示port
            .join(', '); // 用逗号和空格连接
        return {
          name: item.metadata.name,
          Labels: formatLabels(item.metadata.labels),
          // 更新状态显示为“运行副本数/期望副本数”格式
          Type: item.spec.type,
          Cluster_ip: item.spec.clusterIP,
          External_ip: "",
          port: ports,
          createTime: formatDateTime(item.metadata.creationTimestamp),
          // 其他属性...
        };
      });
    }
    // 更新部署计数
    deploymentCount.value = resp.data.count;
  } catch (e) {
    console.log(e);
  }
};

const refresh = () => {
  getDeployData()
  console.log('刷新表格数据');
};
const updateParameters = reactive({
  name: "",
  namespace: selectedNamespace,
  content: ""
})
const updateDeployData = async ()=>{
  try {
    console.log("你吗的",updateParameters.content)
    const resp = await UPDATE_SERVICE(updateParameters)
    if (resp.code !== 200){
      ElMessage.error(resp.message)
      return
    }
    ElMessage.success("更新成功")
    dialogVisible.value = false

  }catch (e){
    console.log(e)
    ElMessage.error(`${e}`)

  }
}
const deploymentParameters = reactive({
  page_size: pageSize,
  page_number: currentPage,
  namespace: selectedNamespace,
})

// 设置watcher来监听selectedNamespace的改变
watch(selectedNamespace, (newNamespace) => {
  // 更新deploymentParameters中的namespace
  deploymentParameters.namespace = newNamespace;

  // 重新调用getDeployData以获取新命名空间的部署数据
  getDeployData();
});
var deploymentCount = ref(0)
// 在这里创建一个方法来将 Labels 对象转换为一个字符串数组
// 格式化标签为字符串数组
const formatLabels = (labelsMap) => {
  return labelsMap ? Object.entries(labelsMap).map(([key, value]) => `${key}: ${value}`) : [];
};
const systemNamespaces = ['default', 'kube-system', 'kube-public', 'kube-node-lease'];

const getDeployData = async () => {
  try {

    const resp = await SERVICE_LIST(deploymentParameters);
    if (resp && resp.data && Array.isArray(resp.data.items)) {
      tableData.value = resp.data.items.map((item) => {
        const ports = item.spec.ports
            .map(p => p.nodePort ? `${p.port}/${p.nodePort}` : p.port.toString()) // 如果nodePort存在,显示nodePort/port,否则只显示port
            .join(', '); // 用逗号和空格连接
        return {
          name: item.metadata.name,
          Labels: formatLabels(item.metadata.labels),
          // 更新状态显示为“运行副本数/期望副本数”格式
          Type: item.spec.type,
          Cluster_ip: item.spec.clusterIP,
          External_ip: "",
          port: ports,
          createTime: formatDateTime(item.metadata.creationTimestamp),
          // 其他属性...
        };
      });
    }
    // 更新部署计数
    deploymentCount.value = resp.data.count;
  } catch (e) {
    console.log(e);
  }
};
const getDeployDetailData = async (serviceName)=>{
  try {
    const DeploymentDetailparams = reactive({
      name: serviceName,
      namespace: selectedNamespace.value
    })
    console.log("ddddddddd",DeploymentDetailparams)
    const resp = await SERVICE_DETAIL(DeploymentDetailparams)
    console.log("cccccccc",resp)
    console.log("yaml =======",json2yaml.stringify(resp.data))
    yamlContent.value = json2yaml.stringify(resp.data); // 确保将数据赋值给 yamlContent
    currentDeployName.value = resp.data.metadata.name
    updateParameters.content = yamlContent.value
    await  nextTick()
    dialogVisible.value = true;

  }catch (e){
    console.log(e)
    console.log("你吗")
  }
}
// 在setup函数中定义定时器
let refreshInterval = null;

onMounted(() => {
  loadSelection();
  refreshInterval = setInterval(() => {
    getDeployData();
  }, 30000); // 每30秒刷新一次
});
// 组件卸载前保存命名空间
onBeforeUnmount(() => {
  saveSelection(selectedNamespace.value);
});

onBeforeMount( async ()=> {
  clearInterval(refreshInterval);
  // 尝试从 localStorage 中读取状态
  const savedPageSize = localStorage.getItem('nspageSize');
  const savedCurrentPage = localStorage.getItem('nscurrentPage');

  // 如果存在则更新到响应式变量中
  if (savedPageSize) {
    pageSize.value = parseInt(savedPageSize, 10);
  }
  if (savedCurrentPage) {
    currentPage.value = parseInt(savedCurrentPage, 10);
  }
  getDeployData()
  await fetchNamespaces(); // 获取并更新命名空间列表
  // getNSAllData()

});
</script>

<style scoped>
.loading-icon {
  width: 20px; /* 或者您希望的任何尺寸 */
  height: 20px; /* 保持与宽度相同以保持图标的纵横比 */
  margin-left: 5px; /* 添加一点空间在状态文本和图标之间 */
  animation: loading-spin 2s linear infinite;
}

/* 如果需要,可以移除这个类,因为它可能会导致对齐问题 */
/* .loader {
  animation: loader-spin 1s linear infinite;
} */

@keyframes loading-spin {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}
.container {
  margin: 10px;
  background-color: #F2F2F2;
}
.deployment-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 10px;
  margin: 10px;
  margin-bottom: -10px;
  background: #FFF;
  border: 2px solid #ebeef5;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}

/* 新增左侧部分样式,放置“命名空间:”文本和下拉框 */
.left-section {
  display: flex;
  align-items: center;
}

/* 确保下拉框和文本在同一行 */
.el-select {
  margin-left: 10px; /* 为下拉框添加左侧间隔 */
}
.header {
  display: flex;
  align-items: center;
  justify-content: space-between; /* 添加此属性对子元素进行分散对齐 */
  margin-bottom: 0px;
  gap: 10px;
  padding: 10px;
  background: #FFF;
  border: 2px solid #ebeef5;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}

.search-input {
  /*flex-grow: 1;*/
  width: 200px;
}

.table-wrapper {
  background: #FFF;
  border: 2px solid #ebeef5; /* 浅色边框线 */
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
.paginations {
  margin-top: 10px;
  margin-left: 20px;
  margin-bottom: 10px;
}
/* 左侧组合样式,创建按钮和搜索框靠在一起 */
.left-group {
  display: flex;
  align-items: center;
  gap: 10px; /* You can adjust the gap as needed */
}

/* 右侧刷新按钮 */
.right-group {
  display: flex;
  align-items: center;
}
.yaml-content {
  background-color: #f5f5f5;
  border-left: 3px solid #4795EE;
  padding: 15px;
  white-space: pre-wrap;
  text-align: left;
  margin: 20px 0;
  overflow-x: auto;
}
.status-active {
  color: #67C23A;
}

.status-inactive {
  color: red;
}
.dialog-footer {
  /*text-align: right;*/
  display: flex;
  justify-content: flex-end;
  padding: 8px;
}




.deployment-header {
  display: flex;
  align-items: center;
  height: 30px;
  padding: 10px;
  margin: 10px;
  margin-bottom: -10px;
  background: #FFF;
  border: 2px solid #ebeef5;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}



.form-item-with-help {
  margin-top: 10px;
  margin-left: 20px;
}
.form-item-with-resource {
  margin-top: 10px;
  margin-left: 20px;
}
.form-item {
  flex-wrap: wrap; /* 确保换行 */
  /*align-items: center; !* 如果需要垂直居中 *!*/
  margin-bottom: 10px; /* 保持垂直间距 */
}

.input-item {
  width: 200px;
  margin-right: 10px;
}
.help-text {
  display: block; /* 保证帮助文本在新的行显示 */
  font-size: 12px;
  width: 1000px;
  color: #999999;
  margin-top: 5px;
}
.input-with-help {
  margin-top: 20px;
  display: flex;
  flex-direction: column;
}
.input-deployname {
  width: 300px; /* 限制这个div的宽度 */
  display: flex;
  flex-direction: column; /* 让子元素垂直排列 */
}
.input-containername {
  width: 250px; /* 限制这个div的宽度 */
  display: flex;
  margin-left: -50px;
  flex-direction: column; /* 让子元素垂直排列 */
}

.add-button {
  margin-top: -20px; /* 添加按钮与输入行之间的空间 */
  margin-left: 200px;
}

.input-container-cpu {
  display: flex;
  flex-direction: column;
  /*padding-left: -20px; !* 往右移动整个容器 *!*/

}

.cpu-label {
  margin-bottom: 5px; /* 调整为所需的间距 */
  margin-left: -50px;
}


.container {
  margin: 10px;
}
.item-container {
  margin-bottom: 10px;
}
.content-container {
  background-color: #F2F2F2;
  padding: 10px;
  display: flex;
  width: 700px;
  justify-content: space-between;
  align-items: center;
  transition: height 0.3s;
  overflow: hidden;
  position: relative;

}
.content-container.collapsed {
  height: 40px;
}
.info {
  display: flex;
  align-items: center;
}
.actions {
  position: absolute;
  right: 10px; /* 调整为需要的值 */
  top: 10px; /* 调整为需要的值 */
}



.input-row {
  display: flex;
  align-items: center;
  gap: 10px;
  /*margin-left: -50px;*/
}
.input-row .el-input {
  flex: 1;
}

.input-row label {
  margin-left: 10px; /* 或者需要的任何值 */
}

.input-row .el-input .el-input__inner {
  width: 100%; /* 让输入框充满其容器 */
}


.input-containername p {
  margin-bottom: 10px; /* 为“CPU:”下方添加一些间隔 */
}

.form-item-resource {
  margin-left: 20px; /* 整个表单项向右移动 20px */
  margin-top: 10px;
}
.custom-form-item {
  height: auto;
  overflow: auto;
}
.check-method-container,
.execution-command-container {
  display: flex;
  align-items: center;
  margin-bottom: 10px; /* 添加一些垂直间距 */
}

.method-label {
  width: 100px;
  margin: 10px;
  margin-right: 20px; /* 文本与选择框/输入框之间的间隔 */
}
.command-label {
  /*margin-right: 20px; !* 文本与输入框之间的间隔 *!*/
  width: 100px;
  margin: 10px;

}
.livenessdiv {
  background-color: white;
  width: 500px;
}
.port-range {
  margin-left: 10px;
}
.input-healthContainer {
  margin-left: -50px;
}
.el-select,
.el-input {
  /*flex-grow: 1; !* 输入框和选择框将占据剩余空间 *!*/
  max-width: calc(100% - 100px); /* 限制最大宽度,这里的100px是示例,可以根据实际情况调整 */
}
.button-group {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 10px; /* 调整按钮之间的间隔 */
}

</style>