DKube v1.0.0
							
								
								
									
										23
									
								
								dkube-web/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,23 @@
 | 
				
			|||||||
 | 
					.DS_Store
 | 
				
			||||||
 | 
					node_modules
 | 
				
			||||||
 | 
					/dist
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# local env files
 | 
				
			||||||
 | 
					.env.local
 | 
				
			||||||
 | 
					.env.*.local
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Log files
 | 
				
			||||||
 | 
					npm-debug.log*
 | 
				
			||||||
 | 
					yarn-debug.log*
 | 
				
			||||||
 | 
					yarn-error.log*
 | 
				
			||||||
 | 
					pnpm-debug.log*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Editor directories and files
 | 
				
			||||||
 | 
					.idea
 | 
				
			||||||
 | 
					.vscode
 | 
				
			||||||
 | 
					*.suo
 | 
				
			||||||
 | 
					*.ntvs*
 | 
				
			||||||
 | 
					*.njsproj
 | 
				
			||||||
 | 
					*.sln
 | 
				
			||||||
 | 
					*.sw?
 | 
				
			||||||
							
								
								
									
										66
									
								
								dkube-web/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,66 @@
 | 
				
			|||||||
 | 
					<div style="text-align: center"></div>
 | 
				
			||||||
 | 
					  <p align="center">
 | 
				
			||||||
 | 
					  <img src="https://user-images.githubusercontent.com/42825450/193592031-49863a65-3f0e-4f94-bf98-82dac27b9d58.jpg" width="250px" height="220px">
 | 
				
			||||||
 | 
					      <br>
 | 
				
			||||||
 | 
					      <i>Make the project development and release simpler, easier and more efficient.</i>
 | 
				
			||||||
 | 
					  </p>
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## What is DKube
 | 
				
			||||||
 | 
					This is a K8s cluster management platform;DKube Provides a wizard-style operation interface for K8s cluster management to help your team manage your cluster environment quickly and easily
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 功能
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<details>
 | 
				
			||||||
 | 
					  <summary><b> K8s集群管理</b></summary>
 | 
				
			||||||
 | 
					</details>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<details>
 | 
				
			||||||
 | 
					  <summary><b> 平台化界面</b></summary>
 | 
				
			||||||
 | 
					</details>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<details>
 | 
				
			||||||
 | 
					  <summary><b> 更加便捷的管理K8s</b></summary>
 | 
				
			||||||
 | 
					</details>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<details>
 | 
				
			||||||
 | 
					  <summary><b> 支持YAML信息查看\变更</b></summary>
 | 
				
			||||||
 | 
					</details>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<details>
 | 
				
			||||||
 | 
					  <summary><b> 平台化管理控制器</b></summary>
 | 
				
			||||||
 | 
					</details>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<details>
 | 
				
			||||||
 | 
					  <summary><b> 实时查看容器日志</b></summary>
 | 
				
			||||||
 | 
					</details>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 截图
 | 
				
			||||||
 | 
					<br/>
 | 
				
			||||||
 | 
					<table>
 | 
				
			||||||
 | 
					    <tr>
 | 
				
			||||||
 | 
					      <td width="50%" align="center"><b>登入认证管理</b></td>
 | 
				
			||||||
 | 
					      <td width="50%" align="center"><b>集群信息状态</b></td>
 | 
				
			||||||
 | 
					    </tr>
 | 
				
			||||||
 | 
					    <tr>
 | 
				
			||||||
 | 
					        <td width="50%" align="center"><img src="https://user-images.githubusercontent.com/42825450/193593148-4d258b30-b972-4583-b359-32978a8a8637.jpg?raw=true"></td>
 | 
				
			||||||
 | 
					        <td width="50%" align="center"><img src="https://user-images.githubusercontent.com/42825450/193593170-3373dabd-8d5d-4a01-a59f-49851f11f433.jpg?raw=true"></td>
 | 
				
			||||||
 | 
					    </tr>
 | 
				
			||||||
 | 
					    <tr>
 | 
				
			||||||
 | 
					      <td width="50%" align="center"><b>节点资源管理</b></td>
 | 
				
			||||||
 | 
					      <td width="50%" align="center"><b>名称空间管理</b></td>
 | 
				
			||||||
 | 
					    </tr>
 | 
				
			||||||
 | 
					        <td width="50%" align="center"><img src="https://user-images.githubusercontent.com/42825450/193593569-daebc649-f6c4-45a2-88f6-2aa4860c3dea.jpg?raw=true"></td>
 | 
				
			||||||
 | 
					        <td width="50%" align="center"><img src="https://user-images.githubusercontent.com/42825450/193593579-e0539ab0-6b22-4060-b254-c6495fb87cbd.jpg?raw=true"></td>
 | 
				
			||||||
 | 
					    <tr>
 | 
				
			||||||
 | 
					    </tr>
 | 
				
			||||||
 | 
					    <tr>
 | 
				
			||||||
 | 
					      <td width="50%" align="center"><b>YAML信息管理</b></td>
 | 
				
			||||||
 | 
					      <td width="50%" align="center"><b>Pod副本管理</b></td>
 | 
				
			||||||
 | 
					    </tr>
 | 
				
			||||||
 | 
					        <td width="50%" align="center"><img src="https://user-images.githubusercontent.com/42825450/193593867-4a98bd0f-a910-4b90-92e3-6a3164d0c241.jpg?raw=true"></td>
 | 
				
			||||||
 | 
					        <td width="50%" align="center"><img src="https://user-images.githubusercontent.com/42825450/193593871-ee004cb8-42cb-427a-a0cc-fa1e15e7d466.jpg?raw=true"></td>
 | 
				
			||||||
 | 
					    <tr>
 | 
				
			||||||
 | 
					    </tr>
 | 
				
			||||||
 | 
					</table>
 | 
				
			||||||
							
								
								
									
										5
									
								
								dkube-web/babel.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,5 @@
 | 
				
			|||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					  presets: [
 | 
				
			||||||
 | 
					    '@vue/cli-plugin-babel/preset'
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										19
									
								
								dkube-web/jsconfig.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,19 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "compilerOptions": {
 | 
				
			||||||
 | 
					    "target": "es5",
 | 
				
			||||||
 | 
					    "module": "esnext",
 | 
				
			||||||
 | 
					    "baseUrl": "./",
 | 
				
			||||||
 | 
					    "moduleResolution": "node",
 | 
				
			||||||
 | 
					    "paths": {
 | 
				
			||||||
 | 
					      "@/*": [
 | 
				
			||||||
 | 
					        "src/*"
 | 
				
			||||||
 | 
					      ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "lib": [
 | 
				
			||||||
 | 
					      "esnext",
 | 
				
			||||||
 | 
					      "dom",
 | 
				
			||||||
 | 
					      "dom.iterable",
 | 
				
			||||||
 | 
					      "scripthost"
 | 
				
			||||||
 | 
					    ]
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										29239
									
								
								dkube-web/package-lock.json
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										55
									
								
								dkube-web/package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,55 @@
 | 
				
			|||||||
 | 
					{
 | 
				
			||||||
 | 
					  "name": "k8s-demo-fe",
 | 
				
			||||||
 | 
					  "version": "0.1.0",
 | 
				
			||||||
 | 
					  "private": true,
 | 
				
			||||||
 | 
					  "scripts": {
 | 
				
			||||||
 | 
					    "serve": "vue-cli-service serve",
 | 
				
			||||||
 | 
					    "build": "vue-cli-service build",
 | 
				
			||||||
 | 
					    "lint": "vue-cli-service lint"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "dependencies": {
 | 
				
			||||||
 | 
					    "@element-plus/icons-vue": "^1.1.4",
 | 
				
			||||||
 | 
					    "axios": "^0.26.1",
 | 
				
			||||||
 | 
					    "codemirror-editor-vue3": "^2.1.3",
 | 
				
			||||||
 | 
					    "core-js": "^3.6.5",
 | 
				
			||||||
 | 
					    "echarts": "^5.3.2",
 | 
				
			||||||
 | 
					    "element-plus": "^2.1.5",
 | 
				
			||||||
 | 
					    "json-editor-vue3": "^1.0.5",
 | 
				
			||||||
 | 
					    "json2yaml": "^1.1.0",
 | 
				
			||||||
 | 
					    "jsonwebtoken": "^8.5.1",
 | 
				
			||||||
 | 
					    "moment": "^2.29.2",
 | 
				
			||||||
 | 
					    "nprogress": "^0.2.0",
 | 
				
			||||||
 | 
					    "vue": "^3.0.0",
 | 
				
			||||||
 | 
					    "vue-router": "^4.0.14",
 | 
				
			||||||
 | 
					    "xterm": "^4.18.0",
 | 
				
			||||||
 | 
					    "xterm-addon-fit": "^0.5.0"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "devDependencies": {
 | 
				
			||||||
 | 
					    "@vue/cli-plugin-babel": "~4.5.15",
 | 
				
			||||||
 | 
					    "@vue/cli-plugin-eslint": "~4.5.15",
 | 
				
			||||||
 | 
					    "@vue/cli-service": "~4.5.15",
 | 
				
			||||||
 | 
					    "@vue/compiler-sfc": "^3.0.0",
 | 
				
			||||||
 | 
					    "babel-eslint": "^10.1.0",
 | 
				
			||||||
 | 
					    "eslint": "^6.7.2",
 | 
				
			||||||
 | 
					    "eslint-plugin-vue": "^7.0.0"
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "eslintConfig": {
 | 
				
			||||||
 | 
					    "root": true,
 | 
				
			||||||
 | 
					    "env": {
 | 
				
			||||||
 | 
					      "node": true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "extends": [
 | 
				
			||||||
 | 
					      "plugin:vue/vue3-essential",
 | 
				
			||||||
 | 
					      "eslint:recommended"
 | 
				
			||||||
 | 
					    ],
 | 
				
			||||||
 | 
					    "parserOptions": {
 | 
				
			||||||
 | 
					      "parser": "babel-eslint"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    "rules": {}
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  "browserslist": [
 | 
				
			||||||
 | 
					    "> 1%",
 | 
				
			||||||
 | 
					    "last 2 versions",
 | 
				
			||||||
 | 
					    "not dead"
 | 
				
			||||||
 | 
					  ]
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								dkube-web/public/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 9.3 KiB  | 
							
								
								
									
										17
									
								
								dkube-web/public/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					<!DOCTYPE html>
 | 
				
			||||||
 | 
					<html lang="">
 | 
				
			||||||
 | 
					  <head>
 | 
				
			||||||
 | 
					    <meta charset="utf-8">
 | 
				
			||||||
 | 
					    <meta http-equiv="X-UA-Compatible" content="IE=edge">
 | 
				
			||||||
 | 
					    <meta name="viewport" content="width=device-width,initial-scale=1.0">
 | 
				
			||||||
 | 
					    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
 | 
				
			||||||
 | 
					    <title><%= htmlWebpackPlugin.options.title %></title>
 | 
				
			||||||
 | 
					  </head>
 | 
				
			||||||
 | 
					  <body>
 | 
				
			||||||
 | 
					    <noscript>
 | 
				
			||||||
 | 
					      <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
 | 
				
			||||||
 | 
					    </noscript>
 | 
				
			||||||
 | 
					    <div id="app"></div>
 | 
				
			||||||
 | 
					    <!-- built files will be auto injected -->
 | 
				
			||||||
 | 
					  </body>
 | 
				
			||||||
 | 
					</html>
 | 
				
			||||||
							
								
								
									
										15
									
								
								dkube-web/src/App.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,15 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <router-view></router-view>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style>
 | 
				
			||||||
 | 
					html,body {
 | 
				
			||||||
 | 
					  width: 100%;
 | 
				
			||||||
 | 
					  height: 100%;
 | 
				
			||||||
 | 
					  padding: 0;
 | 
				
			||||||
 | 
					  margin: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#nprogress .bar {
 | 
				
			||||||
 | 
					  background: #2186c0 !important;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								dkube-web/src/assets/avator/avator.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 3.5 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dkube-web/src/assets/img/1.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 21 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dkube-web/src/assets/img/403.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 16 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dkube-web/src/assets/img/404.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 17 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dkube-web/src/assets/img/login3.webp
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 8.0 MiB  | 
							
								
								
									
										
											BIN
										
									
								
								dkube-web/src/assets/k8s/k8s-metrics.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 9.3 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								dkube-web/src/assets/logo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 9.3 KiB  | 
							
								
								
									
										58
									
								
								dkube-web/src/components/HelloWorld.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,58 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="hello">
 | 
				
			||||||
 | 
					    <h1>{{ msg }}</h1>
 | 
				
			||||||
 | 
					    <p>
 | 
				
			||||||
 | 
					      For a guide and recipes on how to configure / customize this project,<br>
 | 
				
			||||||
 | 
					      check out the
 | 
				
			||||||
 | 
					      <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
 | 
				
			||||||
 | 
					    </p>
 | 
				
			||||||
 | 
					    <h3>Installed CLI Plugins</h3>
 | 
				
			||||||
 | 
					    <ul>
 | 
				
			||||||
 | 
					      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-babel" target="_blank" rel="noopener">babel</a></li>
 | 
				
			||||||
 | 
					      <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
 | 
				
			||||||
 | 
					    </ul>
 | 
				
			||||||
 | 
					    <h3>Essential Links</h3>
 | 
				
			||||||
 | 
					    <ul>
 | 
				
			||||||
 | 
					      <li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
 | 
				
			||||||
 | 
					      <li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
 | 
				
			||||||
 | 
					      <li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
 | 
				
			||||||
 | 
					      <li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
 | 
				
			||||||
 | 
					      <li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
 | 
				
			||||||
 | 
					    </ul>
 | 
				
			||||||
 | 
					    <h3>Ecosystem</h3>
 | 
				
			||||||
 | 
					    <ul>
 | 
				
			||||||
 | 
					      <li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
 | 
				
			||||||
 | 
					      <li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
 | 
				
			||||||
 | 
					      <li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
 | 
				
			||||||
 | 
					      <li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
 | 
				
			||||||
 | 
					      <li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
 | 
				
			||||||
 | 
					    </ul>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					  name: 'HelloWorld',
 | 
				
			||||||
 | 
					  props: {
 | 
				
			||||||
 | 
					    msg: String
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<!-- Add "scoped" attribute to limit CSS to this component only -->
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					h3 {
 | 
				
			||||||
 | 
					  margin: 40px 0 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					ul {
 | 
				
			||||||
 | 
					  list-style-type: none;
 | 
				
			||||||
 | 
					  padding: 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					li {
 | 
				
			||||||
 | 
					  display: inline-block;
 | 
				
			||||||
 | 
					  margin: 0 10px;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					a {
 | 
				
			||||||
 | 
					  color: #42b983;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										219
									
								
								dkube-web/src/layout/Layout.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,219 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div class="common-layout">
 | 
				
			||||||
 | 
					        <el-container style="height: 100vh;">
 | 
				
			||||||
 | 
					            <el-aside class="aside" :width="asideWidth">
 | 
				
			||||||
 | 
					                <el-affix class="aside-affix" :z-index="1200">
 | 
				
			||||||
 | 
					                    <div class="aside-logo" >
 | 
				
			||||||
 | 
					                        <el-image class="logo-image" :src="logo" />
 | 
				
			||||||
 | 
					                        <span :class="[isCollapse ? 'is-collapse' : '']">
 | 
				
			||||||
 | 
					                            <span class="logo-name" >DKube</span>
 | 
				
			||||||
 | 
					                        </span>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                </el-affix>
 | 
				
			||||||
 | 
					                <el-menu class="aside-menu"
 | 
				
			||||||
 | 
					                    router
 | 
				
			||||||
 | 
					                    :default-active="$route.path"
 | 
				
			||||||
 | 
					                    :collapse="isCollapse"
 | 
				
			||||||
 | 
					                    background-color="#131b27"
 | 
				
			||||||
 | 
					                    text-color="#bfcbd9"
 | 
				
			||||||
 | 
					                    active-text-color="#20a0ff">
 | 
				
			||||||
 | 
					                    <div v-for="menu in routers" :key="menu">
 | 
				
			||||||
 | 
					                        <el-menu-item class="aside-menu-item" v-if="menu.children && menu.children.length == 1" :index="menu.children[0].path">
 | 
				
			||||||
 | 
					                        <el-icon><component :is="menu.children[0].icon" /></el-icon>
 | 
				
			||||||
 | 
					                        <template #title>
 | 
				
			||||||
 | 
					                            {{menu.children[0].name}}
 | 
				
			||||||
 | 
					                        </template>
 | 
				
			||||||
 | 
					                        </el-menu-item>
 | 
				
			||||||
 | 
					                        <el-sub-menu class="aside-submenu" v-else-if="menu.children" :index="menu.path">
 | 
				
			||||||
 | 
					                            <template #title>
 | 
				
			||||||
 | 
					                                <el-icon><component :is="menu.icon" /></el-icon>
 | 
				
			||||||
 | 
					                                <span :class="[isCollapse ? 'is-collapse' : '']">{{menu.name}}</span>
 | 
				
			||||||
 | 
					                            </template>
 | 
				
			||||||
 | 
					                            <el-menu-item class="aside-menu-childitem" v-for="child in menu.children" :key="child" :index="child.path">
 | 
				
			||||||
 | 
					                                <el-icon><component :is="child.icon" /></el-icon>
 | 
				
			||||||
 | 
					                                <template #title>
 | 
				
			||||||
 | 
					                                    {{child.name}}
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-menu-item>
 | 
				
			||||||
 | 
					                        </el-sub-menu>
 | 
				
			||||||
 | 
					                    </div>
 | 
				
			||||||
 | 
					                </el-menu>
 | 
				
			||||||
 | 
					            </el-aside>
 | 
				
			||||||
 | 
					            <el-container>
 | 
				
			||||||
 | 
					                <el-header class="header" >
 | 
				
			||||||
 | 
					                    <el-row :gutter="20">
 | 
				
			||||||
 | 
					                        <el-col :span="1">
 | 
				
			||||||
 | 
					                            <div class="header-collapse" @click="onCollapse">
 | 
				
			||||||
 | 
					                                <el-icon><component :is="isCollapse ? 'expand':'fold'" /></el-icon>
 | 
				
			||||||
 | 
					                            </div>
 | 
				
			||||||
 | 
					                        </el-col>
 | 
				
			||||||
 | 
					                        <el-col :span="10" >
 | 
				
			||||||
 | 
					                            <div class="header-breadcrumb">
 | 
				
			||||||
 | 
					                                <el-breadcrumb separator="/" v-if="this.$route.matched[0].path != '/main'">
 | 
				
			||||||
 | 
					                                    <el-breadcrumb-item :to="{ path: '/' }">工作台</el-breadcrumb-item>
 | 
				
			||||||
 | 
					                                    <template v-for="(matched,m) in this.$route.matched" :key="m">
 | 
				
			||||||
 | 
					                                        <el-breadcrumb-item v-if="matched.name != undefined" >
 | 
				
			||||||
 | 
					                                        {{ matched.name }}
 | 
				
			||||||
 | 
					                                        </el-breadcrumb-item>
 | 
				
			||||||
 | 
					                                    </template>
 | 
				
			||||||
 | 
					                                </el-breadcrumb>
 | 
				
			||||||
 | 
					                                <el-breadcrumb separator="/" v-else>
 | 
				
			||||||
 | 
					                                    <el-breadcrumb-item>工作台</el-breadcrumb-item>
 | 
				
			||||||
 | 
					                                </el-breadcrumb> 
 | 
				
			||||||
 | 
					                            </div>
 | 
				
			||||||
 | 
					                        </el-col>
 | 
				
			||||||
 | 
					                        <el-col class="header-menu" :span="13">
 | 
				
			||||||
 | 
					                            <el-dropdown>
 | 
				
			||||||
 | 
					                                <div class="header-dropdown">
 | 
				
			||||||
 | 
					                                    <el-image class="avator-image" :src="avator" />
 | 
				
			||||||
 | 
					                                    <span>{{ username }}</span>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                                <template #dropdown>
 | 
				
			||||||
 | 
					                                    <el-dropdown-menu>
 | 
				
			||||||
 | 
					                                        <el-dropdown-item icon="el-icon-switch-button" @click="logout()">退出</el-dropdown-item>
 | 
				
			||||||
 | 
					                                        <el-dropdown-item icon="el-icon-unlock">修改密码</el-dropdown-item>
 | 
				
			||||||
 | 
					                                    </el-dropdown-menu>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-dropdown>
 | 
				
			||||||
 | 
					                        </el-col>
 | 
				
			||||||
 | 
					                    </el-row>
 | 
				
			||||||
 | 
					                </el-header>
 | 
				
			||||||
 | 
					                <el-main class="main">
 | 
				
			||||||
 | 
					                    <router-view></router-view>
 | 
				
			||||||
 | 
					                </el-main>
 | 
				
			||||||
 | 
					                <el-footer class="footer">
 | 
				
			||||||
 | 
					                    <el-icon style="width:2em;top:3px;font-size:18px"><place/></el-icon>
 | 
				
			||||||
 | 
					                    <a class="footer el-icon-place">2022 DevOps </a>
 | 
				
			||||||
 | 
					                </el-footer>
 | 
				
			||||||
 | 
					                <el-backtop target=".el-main"></el-backtop>
 | 
				
			||||||
 | 
					            </el-container>
 | 
				
			||||||
 | 
					        </el-container>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					import {useRouter} from 'vue-router'
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					    data() {
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            avator: require('@/assets/avator/avator.png'),
 | 
				
			||||||
 | 
					            logo: require('@/assets/k8s/k8s-metrics.png'),
 | 
				
			||||||
 | 
					            isCollapse: false,
 | 
				
			||||||
 | 
					            asideWidth: '220px',
 | 
				
			||||||
 | 
					            routers: [],
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    computed: {
 | 
				
			||||||
 | 
					        username() {
 | 
				
			||||||
 | 
					            let username = localStorage.getItem('username');
 | 
				
			||||||
 | 
					            return username ? username : '未知';
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    methods: {
 | 
				
			||||||
 | 
					        onCollapse() {
 | 
				
			||||||
 | 
					            if (this.isCollapse) {
 | 
				
			||||||
 | 
					                this.asideWidth = '220px'
 | 
				
			||||||
 | 
					                this.isCollapse = false
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                this.isCollapse = true
 | 
				
			||||||
 | 
					                this.asideWidth = '64px'
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        logout() {
 | 
				
			||||||
 | 
					            localStorage.removeItem('username');
 | 
				
			||||||
 | 
					            localStorage.removeItem('token');
 | 
				
			||||||
 | 
					            this.$router.push('/login');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    beforeMount() {
 | 
				
			||||||
 | 
					        this.routers = useRouter().options.routes
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					    .aside {
 | 
				
			||||||
 | 
					        transition: all .5s;
 | 
				
			||||||
 | 
					        background-color: #131b27;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .aside-logo {
 | 
				
			||||||
 | 
					        background-color: #131b27;
 | 
				
			||||||
 | 
					        height: 60px;
 | 
				
			||||||
 | 
					        color: white;
 | 
				
			||||||
 | 
					        cursor: pointer;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .logo-image {
 | 
				
			||||||
 | 
					        width: 40px;
 | 
				
			||||||
 | 
					        height: 40px;
 | 
				
			||||||
 | 
					        top: 12px;
 | 
				
			||||||
 | 
					        padding-left: 12px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .logo-name {
 | 
				
			||||||
 | 
					        font-size: 20px;
 | 
				
			||||||
 | 
					        font-weight: bold;
 | 
				
			||||||
 | 
					        padding: 10px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .aside::-webkit-scrollbar {
 | 
				
			||||||
 | 
					        display: none;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .aside-affix {
 | 
				
			||||||
 | 
					        border-bottom-width: 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .aside-menu {
 | 
				
			||||||
 | 
					        border-right-width: 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .aside-menu-item.is-active {
 | 
				
			||||||
 | 
					        background-color: #1f2a3a;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .aside-menu-item {
 | 
				
			||||||
 | 
					        padding-left: 20px !important;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .aside-menu-childitem {
 | 
				
			||||||
 | 
					        padding-left: 20px !important;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .aside-menu-childitem.is-active {
 | 
				
			||||||
 | 
					        background-color: #1f2a3a;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .aside-menu-childitem:hover {
 | 
				
			||||||
 | 
					        background-color: #142c4e;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .header {
 | 
				
			||||||
 | 
					        z-index:1200;
 | 
				
			||||||
 | 
					        line-height: 60px;
 | 
				
			||||||
 | 
					        font-size: 24px;
 | 
				
			||||||
 | 
					        box-shadow: 0 2px 4px rgba(0, 0, 0, .12),0 0 6px rgba(0, 0, 0, .04)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .header-collapse {
 | 
				
			||||||
 | 
					        cursor: pointer;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .header-breadcrumb {
 | 
				
			||||||
 | 
					        padding-top: 0.9em;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .header-menu {
 | 
				
			||||||
 | 
					        text-align: right;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .is-collapse {
 | 
				
			||||||
 | 
					        display: none;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .header-dropdown {
 | 
				
			||||||
 | 
					        line-height: 60px;
 | 
				
			||||||
 | 
					        cursor: pointer;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .avator-image {
 | 
				
			||||||
 | 
					        top: 12px;
 | 
				
			||||||
 | 
					        width: 40px;
 | 
				
			||||||
 | 
					        height: 40px;
 | 
				
			||||||
 | 
					        border-radius: 50%;
 | 
				
			||||||
 | 
					        margin-right: 8px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .main {
 | 
				
			||||||
 | 
					        padding: 10px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .footer {
 | 
				
			||||||
 | 
					        z-index: 1200;
 | 
				
			||||||
 | 
					        color: rgb(187, 184, 184);
 | 
				
			||||||
 | 
					        font-size: 14px;
 | 
				
			||||||
 | 
					        text-align: center;
 | 
				
			||||||
 | 
					        line-height: 60px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										18
									
								
								dkube-web/src/main.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,18 @@
 | 
				
			|||||||
 | 
					import { createApp } from 'vue'
 | 
				
			||||||
 | 
					import ElementPlus from 'element-plus'
 | 
				
			||||||
 | 
					import 'element-plus/dist/index.css'
 | 
				
			||||||
 | 
					import * as ELIcons from '@element-plus/icons-vue'
 | 
				
			||||||
 | 
					import App from './App.vue'
 | 
				
			||||||
 | 
					import router from './router'
 | 
				
			||||||
 | 
					import { GlobalCmComponent } from "codemirror-editor-vue3";
 | 
				
			||||||
 | 
					import 'codemirror/theme/idea.css'
 | 
				
			||||||
 | 
					import 'codemirror/mode/yaml/yaml.js'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const app = createApp(App)
 | 
				
			||||||
 | 
					for (let iconName in ELIcons) {
 | 
				
			||||||
 | 
					    app.component(iconName, ELIcons[iconName])
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					app.use(ElementPlus)
 | 
				
			||||||
 | 
					app.use(GlobalCmComponent, { componentName: "codemirror" });
 | 
				
			||||||
 | 
					app.use(router)
 | 
				
			||||||
 | 
					app.mount('#app')
 | 
				
			||||||
							
								
								
									
										221
									
								
								dkube-web/src/router/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,221 @@
 | 
				
			|||||||
 | 
					import {createRouter,createWebHistory} from 'vue-router'
 | 
				
			||||||
 | 
					import NProgress from 'nprogress'
 | 
				
			||||||
 | 
					import 'nprogress/nprogress.css'
 | 
				
			||||||
 | 
					import Layout from "@/layout/Layout"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import jwt from 'jsonwebtoken'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const routes =[
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        path: '/login',
 | 
				
			||||||
 | 
					        component: () => import('@/views/login/Login.vue'),
 | 
				
			||||||
 | 
					        icon: "odometer",
 | 
				
			||||||
 | 
					        meta: {title: "登录", requireAuth: false},
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        path: '/',
 | 
				
			||||||
 | 
					        redirect: '/home'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        path: '/home',
 | 
				
			||||||
 | 
					        component: Layout,
 | 
				
			||||||
 | 
					        icon: "odometer",
 | 
				
			||||||
 | 
					        children: [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                path: "/home",
 | 
				
			||||||
 | 
					                name: "K8s概览",
 | 
				
			||||||
 | 
					                icon: "odometer",
 | 
				
			||||||
 | 
					                meta: {title: "K8s概览", requireAuth: true},
 | 
				
			||||||
 | 
					                component: () => import('@/views/home/Home.vue'),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        path: '/workflow',
 | 
				
			||||||
 | 
					        component: Layout,
 | 
				
			||||||
 | 
					        icon: "VideoPlay",
 | 
				
			||||||
 | 
					        children: [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                path: "/workflow",
 | 
				
			||||||
 | 
					                name: "工作流",
 | 
				
			||||||
 | 
					                icon: "VideoPlay",
 | 
				
			||||||
 | 
					                meta: {title: "工作流", requireAuth: true},
 | 
				
			||||||
 | 
					                component: () => import('@/views/workflow/Workflow.vue')
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        path: "/cluster",
 | 
				
			||||||
 | 
					        name: "集群信息",
 | 
				
			||||||
 | 
					        component: Layout,
 | 
				
			||||||
 | 
					        icon: "home-filled",
 | 
				
			||||||
 | 
					        meta: {title: "集群信息", requireAuth: true},
 | 
				
			||||||
 | 
					        children: [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                path: "/cluster/node",
 | 
				
			||||||
 | 
					                name: "Node",
 | 
				
			||||||
 | 
					                icon: "el-icon-s-data",
 | 
				
			||||||
 | 
					                meta: {title: "Node", requireAuth: true},
 | 
				
			||||||
 | 
					                component: () => import("@/views/node/Node.vue")
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                path: "/cluster/namespace",
 | 
				
			||||||
 | 
					                name: "Namespace",
 | 
				
			||||||
 | 
					                icon: "el-icon-document-add",
 | 
				
			||||||
 | 
					                meta: {title: "Namespace", requireAuth: true},
 | 
				
			||||||
 | 
					                component: () => import("@/views/namespace/Namespace.vue")
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                path: "/cluster/persistentvolume",
 | 
				
			||||||
 | 
					                name: "PersistentVolume",
 | 
				
			||||||
 | 
					                icon: "el-icon-document-add",
 | 
				
			||||||
 | 
					                meta: {title: "PersistemtVolume", requireAuth: true},
 | 
				
			||||||
 | 
					                component: () => import("@/views/persistentvolume/PersistentVolume.vue")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        path: '/workload',
 | 
				
			||||||
 | 
					        name: '工作负载',
 | 
				
			||||||
 | 
					        component: Layout,
 | 
				
			||||||
 | 
					        icon: "menu",
 | 
				
			||||||
 | 
					        meta: {title: "工作负载", requireAuth: true},
 | 
				
			||||||
 | 
					        children: [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                path: '/workload/deployment',
 | 
				
			||||||
 | 
					                name: 'Deployment',
 | 
				
			||||||
 | 
					                icon: 'el-icon-s-data',
 | 
				
			||||||
 | 
					                meta: {title: "Deployment", requireAuth: true},
 | 
				
			||||||
 | 
					                component: () => import("@/views/deployment/Deployment.vue")
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                path: '/workload/pod',
 | 
				
			||||||
 | 
					                name: 'Pod',
 | 
				
			||||||
 | 
					                icon: 'el-icon-document-add', 
 | 
				
			||||||
 | 
					                meta: {title: "Pod", requireAuth: true},
 | 
				
			||||||
 | 
					                component: () => import("@/views/pod/Pod.vue")
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                path: '/workload/daemonset',
 | 
				
			||||||
 | 
					                name: 'DaemonSet',
 | 
				
			||||||
 | 
					                icon: 'el-icon-document-add',
 | 
				
			||||||
 | 
					                meta: {title: "DaemonSet", requireAuth: true},
 | 
				
			||||||
 | 
					                component: () => import("@/views/daemonset/DaemonSet.vue")
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                path: '/workload/statefulset',
 | 
				
			||||||
 | 
					                name: 'StatefulSet',
 | 
				
			||||||
 | 
					                icon: 'el-icon-document-add', 
 | 
				
			||||||
 | 
					                meta: {title: "StatefulSet", requireAuth: true},
 | 
				
			||||||
 | 
					                component: () => import("@/views/statefulset/StatefulSet.vue")
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        path: "/loadbalance",
 | 
				
			||||||
 | 
					        name: "负载均衡",
 | 
				
			||||||
 | 
					        component: Layout,
 | 
				
			||||||
 | 
					        icon: "files",
 | 
				
			||||||
 | 
					        meta: {title: "负载均衡", requireAuth: true},
 | 
				
			||||||
 | 
					        children: [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                path: "/loadbalance/service",
 | 
				
			||||||
 | 
					                name: "Service",
 | 
				
			||||||
 | 
					                icon: "el-icon-s-data",
 | 
				
			||||||
 | 
					                meta: {title: "Service", requireAuth: true},
 | 
				
			||||||
 | 
					                component: () => import("@/views/service/Service.vue")
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                path: "/loadbalance/ingress",
 | 
				
			||||||
 | 
					                name: "Ingress",
 | 
				
			||||||
 | 
					                icon: "el-icon-document-add",
 | 
				
			||||||
 | 
					                meta: {title: "Ingress", requireAuth: true},
 | 
				
			||||||
 | 
					                component: () => import("@/views/ingress/Ingress.vue")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        path: "/storage",
 | 
				
			||||||
 | 
					        name: "存储与配置",
 | 
				
			||||||
 | 
					        component: Layout,
 | 
				
			||||||
 | 
					        icon: "tickets",
 | 
				
			||||||
 | 
					        meta: {title: "存储与配置", requireAuth: true},
 | 
				
			||||||
 | 
					        children: [
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                path: "/storage/configmap",
 | 
				
			||||||
 | 
					                name: "Configmap",
 | 
				
			||||||
 | 
					                icon: "el-icon-document-add",
 | 
				
			||||||
 | 
					                meta: {title: "Configmap", requireAuth: true},
 | 
				
			||||||
 | 
					                component: () => import("@/views/configmap/ConfigMap.vue")
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                path: "/storage/secret",
 | 
				
			||||||
 | 
					                name: "Secret",
 | 
				
			||||||
 | 
					                icon: "el-icon-document-add",
 | 
				
			||||||
 | 
					                meta: {title: "Secret", requireAuth: true},
 | 
				
			||||||
 | 
					                component: () => import("@/views/secret/Secret.vue")
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                path: "/storage/persistentvolumeclaim",
 | 
				
			||||||
 | 
					                name: "PersistentVolumeClaim",
 | 
				
			||||||
 | 
					                icon: "el-icon-s-data",
 | 
				
			||||||
 | 
					                meta: {title: "PersistentVolumeClaim", requireAuth: true},
 | 
				
			||||||
 | 
					                component: () => import("@/views/persistentvolumeclaim/PersistentVolumeClaim.vue")
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        ]
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        path: '/404',
 | 
				
			||||||
 | 
					        component: () => import('@/views/common/404.vue'),
 | 
				
			||||||
 | 
					        meta: {
 | 
				
			||||||
 | 
					            title: '404'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        path: '/403',
 | 
				
			||||||
 | 
					        component: () => import('@/views/common/403.vue'),
 | 
				
			||||||
 | 
					        meta: {
 | 
				
			||||||
 | 
					            title: '403'
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        path: '/:pathMatch(.*)',
 | 
				
			||||||
 | 
					        redirect: '/404'
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const router = createRouter ({
 | 
				
			||||||
 | 
					    history: createWebHistory(),
 | 
				
			||||||
 | 
					    routes
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					NProgress.inc(100)
 | 
				
			||||||
 | 
					NProgress.configure({ easing: 'ease', speed: 600,showSpinner: false})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.beforeEach((to,from,next) => {
 | 
				
			||||||
 | 
					    NProgress.start()
 | 
				
			||||||
 | 
					    if (to.meta.title) {
 | 
				
			||||||
 | 
					        document.title = to.meta.title
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        document.title = "DKube"
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    next()
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.beforeEach((to, from, next) => {
 | 
				
			||||||
 | 
					    jwt.verify(localStorage.getItem('token'), 'devops', function (err) {
 | 
				
			||||||
 | 
					        if (to.path === '/login') {
 | 
				
			||||||
 | 
					            next()
 | 
				
			||||||
 | 
					        } else if (err) {
 | 
				
			||||||
 | 
					            next('/login');
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            next();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					router.afterEach (() => {
 | 
				
			||||||
 | 
					    NProgress.done()
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default router
 | 
				
			||||||
							
								
								
									
										44
									
								
								dkube-web/src/utils/request.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					import axios from 'axios';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const httpClient = axios.create({
 | 
				
			||||||
 | 
					    validateStatus(status) {
 | 
				
			||||||
 | 
					        return status >= 200 && status < 504
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    timeout: 10000
 | 
				
			||||||
 | 
					});
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					httpClient.defaults.retry = 3 
 | 
				
			||||||
 | 
					httpClient.defaults.retryDelay = 1000
 | 
				
			||||||
 | 
					httpClient.defaults.shouldRetry = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					httpClient.interceptors.request.use (
 | 
				
			||||||
 | 
					    config => {
 | 
				
			||||||
 | 
					        config.headers['Content-Type'] = 'application/json'
 | 
				
			||||||
 | 
					        config.headers['Accept-Language'] = 'zh-CN'
 | 
				
			||||||
 | 
					        config.headers['Authorization'] = localStorage.getItem('token') 
 | 
				
			||||||
 | 
					        if (config.method === 'post') {
 | 
				
			||||||
 | 
					            if (!config.data) {
 | 
				
			||||||
 | 
					                config.data = {}
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return config
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    err => {
 | 
				
			||||||
 | 
					        Promise.reject(err)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					httpClient.interceptors.response.use (
 | 
				
			||||||
 | 
					    response => {
 | 
				
			||||||
 | 
					        if (response.status !== 200) {
 | 
				
			||||||
 | 
					            return Promise.reject(response.data)
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return response.data
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    err => {
 | 
				
			||||||
 | 
					        return Promise.reject(err)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export default httpClient;
 | 
				
			||||||
							
								
								
									
										44
									
								
								dkube-web/src/views/common/403.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,44 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div class="main-body-div">
 | 
				
			||||||
 | 
					        <el-row>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <img class="main-body-img" src="../../assets/img/403.png" />
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <p class="status-code">403</p>
 | 
				
			||||||
 | 
					                    <p class="status-describe">你暂时无权限访问该页面······</p>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					        </el-row>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					  .main-body-img {
 | 
				
			||||||
 | 
					    margin-top: 150px
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .main-body-div {
 | 
				
			||||||
 | 
					    text-align: center;
 | 
				
			||||||
 | 
					    height: 100vh;
 | 
				
			||||||
 | 
					    width: 100vw;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .status-code {
 | 
				
			||||||
 | 
					    margin-top: 20px;
 | 
				
			||||||
 | 
					    margin-bottom: 10px;
 | 
				
			||||||
 | 
					    font-size: 95px;
 | 
				
			||||||
 | 
					    font-weight: bold;
 | 
				
			||||||
 | 
					    color: rgb(54, 95, 230);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .status-describe {
 | 
				
			||||||
 | 
					    color: rgb(145, 143, 143);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										43
									
								
								dkube-web/src/views/common/404.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,43 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div class="main-body-div">
 | 
				
			||||||
 | 
					        <el-row>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <img class="main-body-img" src="../../assets/img/404.png" />
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					                </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <p class="status-code">404</p>
 | 
				
			||||||
 | 
					                    <p class="status-describe">你所访问的页面不存在······</p>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					        </el-row>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					  .main-body-img {
 | 
				
			||||||
 | 
					    margin-top: 15%;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .main-body-div {
 | 
				
			||||||
 | 
					    text-align: center;
 | 
				
			||||||
 | 
					    height: 100vh;
 | 
				
			||||||
 | 
					    width: 100vw;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .status-code {
 | 
				
			||||||
 | 
					    margin: 20px 0 20px 0;
 | 
				
			||||||
 | 
					    font-size: 95px;
 | 
				
			||||||
 | 
					    font-weight: bold;
 | 
				
			||||||
 | 
					    color: rgb(54, 95, 230);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .status-describe {
 | 
				
			||||||
 | 
					    color: rgb(145, 143, 143);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										72
									
								
								dkube-web/src/views/common/Config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,72 @@
 | 
				
			|||||||
 | 
					export default {
 | 
				
			||||||
 | 
					    loginAuth: 'http://localhost:9090/api/login',
 | 
				
			||||||
 | 
					    k8sWorkflowCreate: 'http://localhost:9090/api/k8s/workflow/create',
 | 
				
			||||||
 | 
					    k8sWorkflowDetail: 'http://localhost:9090/api/k8s/workflow/detail',
 | 
				
			||||||
 | 
					    k8sWorkflowList: 'http://localhost:9090/api/k8s/workflows',
 | 
				
			||||||
 | 
					    k8sWorkflowDel: 'http://localhost:9090/api/k8s/workflow/del',
 | 
				
			||||||
 | 
					    k8sDeploymentList: 'http://localhost:9090/api/k8s/deployments',
 | 
				
			||||||
 | 
					    k8sDeploymentDetail: 'http://localhost:9090/api/k8s/deployment/detail',
 | 
				
			||||||
 | 
					    k8sDeploymentUpdate: 'http://localhost:9090/api/k8s/deployment/update',
 | 
				
			||||||
 | 
					    k8sDeploymentScale: 'http://localhost:9090/api/k8s/deployment/scale',
 | 
				
			||||||
 | 
					    k8sDeploymentRestart: 'http://localhost:9090/api/k8s/deployment/restart',
 | 
				
			||||||
 | 
					    k8sDeploymentDel: 'http://localhost:9090/api/k8s/deployment/del',
 | 
				
			||||||
 | 
					    k8sDeploymentCreate: 'http://localhost:9090/api/k8s/deployment/create',
 | 
				
			||||||
 | 
					    k8sDeploymentNumNp: 'http://localhost:9090/api/k8s/deployment/numnp',
 | 
				
			||||||
 | 
					    k8sPodList: 'http://localhost:9090/api/k8s/pods',
 | 
				
			||||||
 | 
					    k8sPodDetail: 'http://localhost:9090/api/k8s/pod/detail',
 | 
				
			||||||
 | 
					    k8sPodUpdate: 'http://localhost:9090/api/k8s/pod/update',
 | 
				
			||||||
 | 
					    k8sPodDel: 'http://localhost:9090/api/k8s/pod/del',
 | 
				
			||||||
 | 
					    k8sPodContainer: 'http://localhost:9090/api/k8s/pod/container',
 | 
				
			||||||
 | 
					    k8sPodLog: 'http://localhost:9090/api/k8s/pod/log',
 | 
				
			||||||
 | 
					    k8sPodNumNp: 'http://localhost:9090/api/k8s/pod/numnp',
 | 
				
			||||||
 | 
					    k8sDaemonSetList: 'http://localhost:9090/api/k8s/daemonsets',
 | 
				
			||||||
 | 
					    k8sDaemonSetDetail: 'http://localhost:9090/api/k8s/daemonset/detail',
 | 
				
			||||||
 | 
					    k8sDaemonSetUpdate: 'http://localhost:9090/api/k8s/daemonset/update',
 | 
				
			||||||
 | 
					    k8sDaemonSetDel: 'http://localhost:9090/api/k8s/daemonset/del',
 | 
				
			||||||
 | 
					    k8sStatefulSetList: 'http://localhost:9090/api/k8s/statefulsets',
 | 
				
			||||||
 | 
					    k8sStatefulSetDetail: 'http://localhost:9090/api/k8s/daemonset/detail',
 | 
				
			||||||
 | 
					    k8sStatefulSetUpdate: 'http://localhost:9090/api/k8s/daemonset/update',
 | 
				
			||||||
 | 
					    k8sStatefulSetDel: 'http://localhost:9090/api/k8s/daemonset/del',
 | 
				
			||||||
 | 
					    k8sServiceList: 'http://localhost:9090/api/k8s/services',
 | 
				
			||||||
 | 
					    k8sServiceDetail: 'http://localhost:9090/api/k8s/service/detail',
 | 
				
			||||||
 | 
					    k8sServiceUpdate: 'http://localhost:9090/api/k8s/service/update',
 | 
				
			||||||
 | 
					    k8sServiceDel: 'http://localhost:9090/api/k8s/service/del',
 | 
				
			||||||
 | 
					    k8sServiceCreate: 'http://localhost:9090/api/k8s/service/create',
 | 
				
			||||||
 | 
					    k8sIngressList: 'http://localhost:9090/api/k8s/ingresses',
 | 
				
			||||||
 | 
					    k8sIngressDetail: 'http://localhost:9090/api/k8s/ingress/detail',
 | 
				
			||||||
 | 
					    k8sIngressUpdate: 'http://localhost:9090/api/k8s/ingress/update',
 | 
				
			||||||
 | 
					    k8sIngressDel: 'http://localhost:9090/api/k8s/ingress/del',
 | 
				
			||||||
 | 
					    k8sIngressCreate: 'http://localhost:9090/api/k8s/ingress/create',
 | 
				
			||||||
 | 
					    k8sConfigMapList: 'http://localhost:9090/api/k8s/configmaps',
 | 
				
			||||||
 | 
					    k8sConfigMapDetail: 'http://localhost:9090/api/k8s/configmap/detail',
 | 
				
			||||||
 | 
					    k8sConfigMapUpdate: 'http://localhost:9090/api/k8s/configmap/update',
 | 
				
			||||||
 | 
					    k8sConfigMapDel: 'http://localhost:9090/api/k8s/configmap/del',
 | 
				
			||||||
 | 
					    k8sSecretList: 'http://localhost:9090/api/k8s/secrets',
 | 
				
			||||||
 | 
					    k8sSecretDetail: 'http://localhost:9090/api/k8s/secret/detail',
 | 
				
			||||||
 | 
					    k8sSecretUpdate: 'http://localhost:9090/api/k8s/secret/update',
 | 
				
			||||||
 | 
					    k8sSecretDel: 'http://localhost:9090/api/k8s/secret/del',
 | 
				
			||||||
 | 
					    k8sPvcList: 'http://localhost:9090/api/k8s/pvcs',
 | 
				
			||||||
 | 
					    k8sPvcDetail: 'http://localhost:9090/api/k8s/pvc/detail',
 | 
				
			||||||
 | 
					    k8sPvcUpdate: 'http://localhost:9090/api/k8s/pvc/update',
 | 
				
			||||||
 | 
					    k8sPvcDel: 'http://localhost:9090/api/k8s/pvc/del',
 | 
				
			||||||
 | 
					    k8sNodeList: 'http://localhost:9090/api/k8s/nodes',
 | 
				
			||||||
 | 
					    k8sNodeDetail: 'http://localhost:9090/api/k8s/node/detail',
 | 
				
			||||||
 | 
					    k8sNamespaceList: 'http://localhost:9090/api/k8s/namespaces',
 | 
				
			||||||
 | 
					    k8sNamespaceDetail: 'http://localhost:9090/api/k8s/namespace/detail',
 | 
				
			||||||
 | 
					    k8sNamespaceDel: 'http://localhost:9090/api/k8s/namespace/del',
 | 
				
			||||||
 | 
					    k8sPvList: 'http://localhost:9090/api/k8s/pvs',
 | 
				
			||||||
 | 
					    k8sPvDetail: 'http://localhost:9090/api/k8s/pv/detail',
 | 
				
			||||||
 | 
					    k8sTerminalWs: 'ws://localhost:8081/ws',
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    cmOptions: {
 | 
				
			||||||
 | 
					        mode: 'text/yaml',
 | 
				
			||||||
 | 
					        theme: 'idea',
 | 
				
			||||||
 | 
					        lineNumbers: true,
 | 
				
			||||||
 | 
					        smartIndent: true,
 | 
				
			||||||
 | 
					        indentUnit: 4,
 | 
				
			||||||
 | 
					        styleActiveLine: true,
 | 
				
			||||||
 | 
					        matchBrackets: true,
 | 
				
			||||||
 | 
					        readOnly: false,
 | 
				
			||||||
 | 
					        lineWrapping: true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										365
									
								
								dkube-web/src/views/configmap/ConfigMap.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,365 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div class="configmap">
 | 
				
			||||||
 | 
					        <el-row>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="configmap-head-card" shadow="never" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                        <el-row>
 | 
				
			||||||
 | 
					                            <el-col :span="6">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <span>命名空间: </span>
 | 
				
			||||||
 | 
					                                    <el-select v-model="namespaceValue" filterable placeholder="请选择">
 | 
				
			||||||
 | 
					                                        <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>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Refresh" plain @click="getConfigMaps()">刷新</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                        </el-row>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="configmap-head-card" shadow="never" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                        <el-row>
 | 
				
			||||||
 | 
					                            <el-col :span="2">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-button disabled style="border-radius:2px;" icon="Edit" type="primary">创建</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                            <el-col :span="6">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-input class="configmap-head-search" clearable placeholder="请输入" v-model="searchInput"></el-input>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Search" type="primary" plain @click="getConfigMaps()">搜索</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                        </el-row>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="configmap-body-card" shadow="never" :body-style="{padding:'5px'}">
 | 
				
			||||||
 | 
					                        <el-table
 | 
				
			||||||
 | 
					                        style="width:100%;font-size:12px;margin-bottom:10px;"
 | 
				
			||||||
 | 
					                        :data="configMapList"
 | 
				
			||||||
 | 
					                        v-loading="appLoading">
 | 
				
			||||||
 | 
					                            <el-table-column width="20"></el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=left label="ConfigMap名">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <a class="configmap-body-configmapname">{{ scope.row.metadata.name }}</a>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center label="标签">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <div v-for="(val, key) in scope.row.metadata.labels" :key="key">
 | 
				
			||||||
 | 
					                                        <el-popover
 | 
				
			||||||
 | 
					                                            placement="right"
 | 
				
			||||||
 | 
					                                            :width="200"
 | 
				
			||||||
 | 
					                                            trigger="hover"
 | 
				
			||||||
 | 
					                                            :content="key + ':' + val">
 | 
				
			||||||
 | 
					                                            <template #reference>
 | 
				
			||||||
 | 
					                                                <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="DATA">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                        <el-popover
 | 
				
			||||||
 | 
					                                            style="overflow:auto"
 | 
				
			||||||
 | 
					                                            placement="right"
 | 
				
			||||||
 | 
					                                            :width="400"
 | 
				
			||||||
 | 
					                                            trigger="click">
 | 
				
			||||||
 | 
					                                            <div style="overflow-y:auto;max-height:500px;">
 | 
				
			||||||
 | 
					                                                <span>{{ scope.row.data }}</span>
 | 
				
			||||||
 | 
					                                            </div>
 | 
				
			||||||
 | 
					                                            <template #reference>
 | 
				
			||||||
 | 
					                                                <el-icon style="font-size:18px;cursor:pointer;"><reading/></el-icon>
 | 
				
			||||||
 | 
					                                            </template>
 | 
				
			||||||
 | 
					                                        </el-popover>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center min-width="100" label="创建时间">
 | 
				
			||||||
 | 
					                                <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="操作" width="200">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <el-button size="small" style="border-radius:2px;" icon="Edit" type="primary" plain @click="getConfigMapDetail(scope)">YAML</el-button>
 | 
				
			||||||
 | 
					                                    <el-button size="small" style="border-radius:2px;" icon="Delete" type="danger" @click="handleConfirm(scope, '删除', delConfigMap)">删除</el-button>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                        </el-table>
 | 
				
			||||||
 | 
					                        <el-pagination
 | 
				
			||||||
 | 
					                        class="configmap-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="configMapTotal">
 | 
				
			||||||
 | 
					                        </el-pagination>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					        </el-row>
 | 
				
			||||||
 | 
					        <el-dialog title="YAML信息" v-model="yamlDialog" width="45%" top="5%">
 | 
				
			||||||
 | 
					        <codemirror
 | 
				
			||||||
 | 
					            :value="contentYaml"
 | 
				
			||||||
 | 
					            border
 | 
				
			||||||
 | 
					            :options="cmOptions"
 | 
				
			||||||
 | 
					            height="500"
 | 
				
			||||||
 | 
					            style="font-size:14px;"
 | 
				
			||||||
 | 
					            @change="onChange"
 | 
				
			||||||
 | 
					        ></codemirror>
 | 
				
			||||||
 | 
					            <template #footer>
 | 
				
			||||||
 | 
					                <span class="dialog-footer">
 | 
				
			||||||
 | 
					                    <el-button @click="yamlDialog = false">取 消</el-button>
 | 
				
			||||||
 | 
					                    <el-button type="primary" @click="updateConfigMap()">更 新</el-button>
 | 
				
			||||||
 | 
					                </span>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					        </el-dialog>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					import common from "../common/Config";
 | 
				
			||||||
 | 
					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,
 | 
				
			||||||
 | 
					            configMapList: [],
 | 
				
			||||||
 | 
					            configMapTotal: 0,
 | 
				
			||||||
 | 
					            getConfigMapsData: {
 | 
				
			||||||
 | 
					                url: common.k8sConfigMapList,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    filter_name: '',
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    page: '',
 | 
				
			||||||
 | 
					                    limit: '',
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            configMapDetail: {},
 | 
				
			||||||
 | 
					            getConfigMapDetailData: {
 | 
				
			||||||
 | 
					                url: common.k8sConfigMapDetail,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    configmap_name: '',
 | 
				
			||||||
 | 
					                    namespace: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            yamlDialog: false,
 | 
				
			||||||
 | 
					            updateConfigMapData: {
 | 
				
			||||||
 | 
					                url: common.k8sConfigMapUpdate,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    content: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            delConfigMapData: {
 | 
				
			||||||
 | 
					                url: common.k8sconfigmapDel,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    configmap_name: '',
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    methods: {
 | 
				
			||||||
 | 
					        transYaml(content) {
 | 
				
			||||||
 | 
					            return json2yaml.stringify(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        transObj(content) {
 | 
				
			||||||
 | 
					            return yaml2obj.load(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        onChange(val) {
 | 
				
			||||||
 | 
					            this.contentYaml = val
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleSizeChange(size) {
 | 
				
			||||||
 | 
					            this.pagesize = size;
 | 
				
			||||||
 | 
					            this.getConfigMaps()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleCurrentChange(currentPage) {
 | 
				
			||||||
 | 
					            this.currentPage = currentPage;
 | 
				
			||||||
 | 
					            this.getConfigMaps()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        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 
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        restartTotal(e) {
 | 
				
			||||||
 | 
					            let index, sum = 0
 | 
				
			||||||
 | 
					            let containerStatuses = e.row.status.containerStatuses
 | 
				
			||||||
 | 
					            for ( index in containerStatuses) {
 | 
				
			||||||
 | 
					                sum = sum + containerStatuses[index].restartCount 
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return sum
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getNamespaces() {
 | 
				
			||||||
 | 
					            httpClient.get(this.namespaceListUrl)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.namespaceList = res.data.items
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getConfigMaps() {
 | 
				
			||||||
 | 
					            this.appLoading = true
 | 
				
			||||||
 | 
					            this.getConfigMapsData.params.filter_name = this.searchInput
 | 
				
			||||||
 | 
					            this.getConfigMapsData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            this.getConfigMapsData.params.page = this.currentPage
 | 
				
			||||||
 | 
					            this.getConfigMapsData.params.limit = this.pagesize
 | 
				
			||||||
 | 
					            httpClient.get(this.getConfigMapsData.url, {params: this.getConfigMapsData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.configMapList = res.data.items
 | 
				
			||||||
 | 
					                this.configMapTotal = res.data.total
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.appLoading = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getConfigMapDetail(e) {
 | 
				
			||||||
 | 
					            this.getConfigMapDetailData.params.configmap_name = e.row.metadata.name
 | 
				
			||||||
 | 
					            this.getConfigMapDetailData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.get(this.getConfigMapDetailData.url, {params: this.getConfigMapDetailData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.configMapDetail = res.data
 | 
				
			||||||
 | 
					                this.contentYaml = this.transYaml(this.configMapDetail)
 | 
				
			||||||
 | 
					                this.yamlDialog = true
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        updateConfigMap() {
 | 
				
			||||||
 | 
					            let content = JSON.stringify(this.transObj(this.contentYaml))
 | 
				
			||||||
 | 
					            this.updateConfigMapData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            this.updateConfigMapData.params.content = content
 | 
				
			||||||
 | 
					            httpClient.put(this.updateConfigMapData.url, this.updateConfigMapData.params)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.yamlDialog = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        delConfigMap(e) {
 | 
				
			||||||
 | 
					            this.delConfigMapData.params.configmap_name = e.row.metadata.name
 | 
				
			||||||
 | 
					            this.delConfigMapData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.delete(this.delConfigMapData.url, {data: this.delConfigMapData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.getConfigMaps()
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleConfirm(obj, operateName, fn) {
 | 
				
			||||||
 | 
					            this.confirmContent = '确认继续 ' + operateName + ' 操作吗?'
 | 
				
			||||||
 | 
					            this.$confirm(this.confirmContent,'提示',{
 | 
				
			||||||
 | 
					                confirmButtonText: '确定',
 | 
				
			||||||
 | 
					                cancelButtonText: '取消',
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .then(() => {
 | 
				
			||||||
 | 
					                fn(obj)
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            .catch(() => {
 | 
				
			||||||
 | 
					                this.$message.info({
 | 
				
			||||||
 | 
					                    message: '已取消操作'
 | 
				
			||||||
 | 
					                })          
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    watch: {
 | 
				
			||||||
 | 
					        namespaceValue: {
 | 
				
			||||||
 | 
					            handler() {
 | 
				
			||||||
 | 
					                localStorage.setItem('namespace', this.namespaceValue)
 | 
				
			||||||
 | 
					                this.currentPage = 1
 | 
				
			||||||
 | 
					                this.getConfigMaps()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    beforeMount() {
 | 
				
			||||||
 | 
					        if (localStorage.getItem('namespace') !== undefined && localStorage.getItem('namespace') !== null) {
 | 
				
			||||||
 | 
					            this.namespaceValue = localStorage.getItem('namespace')
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.getNamespaces()
 | 
				
			||||||
 | 
					        this.getConfigMaps()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					    .configmap-head-card,.configmap-body-card {
 | 
				
			||||||
 | 
					        border-radius: 1px;
 | 
				
			||||||
 | 
					        margin-bottom: 5px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .configmap-head-search {
 | 
				
			||||||
 | 
					        width:160px;
 | 
				
			||||||
 | 
					        margin-right:10px; 
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .configmap-body-configmapname {
 | 
				
			||||||
 | 
					        color: #4795EE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .configmap-body-configmapname:hover {
 | 
				
			||||||
 | 
					        color: rgb(84, 138, 238);
 | 
				
			||||||
 | 
					        cursor: pointer;
 | 
				
			||||||
 | 
					        font-weight: bold;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										369
									
								
								dkube-web/src/views/daemonset/DaemonSet.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,369 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div class="daemonset">
 | 
				
			||||||
 | 
					        <el-row>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="daemonset-head-card" shadow="never" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                        <el-row>
 | 
				
			||||||
 | 
					                            <el-col :span="6">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <span>命名空间: </span>
 | 
				
			||||||
 | 
					                                    <el-select v-model="namespaceValue" filterable placeholder="请选择">
 | 
				
			||||||
 | 
					                                        <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>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Refresh" plain @click="getDaemonSets()">刷新</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                        </el-row>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="daemonset-head-card" shadow="never" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                        <el-row>
 | 
				
			||||||
 | 
					                            <el-col :span="2">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-button disabled style="border-radius:2px;" icon="Edit" type="primary">创建</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                            <el-col :span="6">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-input class="daemonset-head-search" clearable placeholder="请输入" v-model="searchInput"></el-input>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Search" type="primary" plain @click="getDaemonSets()">搜索</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                        </el-row>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="daemonset-body-card" shadow="never" :body-style="{padding:'5px'}">
 | 
				
			||||||
 | 
					                        <el-table
 | 
				
			||||||
 | 
					                        style="width:100%;font-size:12px;margin-bottom:10px;"
 | 
				
			||||||
 | 
					                        :data="daemonSetList"
 | 
				
			||||||
 | 
					                        v-loading="appLoading">
 | 
				
			||||||
 | 
					                            <el-table-column width="20"></el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=left label="DaemonSet名">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <a class="daemonset-body-daemonsetname">{{ scope.row.metadata.name }}</a>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center label="标签">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <div v-for="(val, key) in scope.row.metadata.labels" :key="key">
 | 
				
			||||||
 | 
					                                        <el-popover
 | 
				
			||||||
 | 
					                                            placement="right"
 | 
				
			||||||
 | 
					                                            :width="200"
 | 
				
			||||||
 | 
					                                            trigger="hover"
 | 
				
			||||||
 | 
					                                            :content="key + ':' + val">
 | 
				
			||||||
 | 
					                                            <template #reference>
 | 
				
			||||||
 | 
					                                                <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="容器组">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <span>{{ scope.row.status.numberAvailable>0?scope.row.status.numberAvailable:0  }} / {{ scope.row.status.desiredNumberScheduled>0?scope.row.status.desiredNumberScheduled:0 }} </span>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center min-width="100" label="创建时间">
 | 
				
			||||||
 | 
					                                <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="镜像">
 | 
				
			||||||
 | 
					                                <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="200">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <el-button size="small" style="border-radius:2px;" icon="Edit" type="primary" plain @click="getDaemonSetDetail(scope)">YAML</el-button>
 | 
				
			||||||
 | 
					                                    <el-button size="small" style="border-radius:2px;" icon="Delete" type="danger" @click="handleConfirm(scope, '删除', delDaemonSet)">删除</el-button>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                        </el-table>
 | 
				
			||||||
 | 
					                        <el-pagination
 | 
				
			||||||
 | 
					                        class="daemonset-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="daemonSetTotal">
 | 
				
			||||||
 | 
					                        </el-pagination>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					        </el-row>
 | 
				
			||||||
 | 
					        <el-dialog title="YAML信息" v-model="yamlDialog" width="45%" top="5%">
 | 
				
			||||||
 | 
					            <codemirror
 | 
				
			||||||
 | 
					                :value="contentYaml"
 | 
				
			||||||
 | 
					                border
 | 
				
			||||||
 | 
					                :options="cmOptions"
 | 
				
			||||||
 | 
					                height="500"
 | 
				
			||||||
 | 
					                style="font-size:14px;"
 | 
				
			||||||
 | 
					                @change="onChange"
 | 
				
			||||||
 | 
					            ></codemirror>
 | 
				
			||||||
 | 
					            <template #footer>
 | 
				
			||||||
 | 
					                <span class="dialog-footer">
 | 
				
			||||||
 | 
					                    <el-button @click="yamlDialog = false">取 消</el-button>
 | 
				
			||||||
 | 
					                    <el-button type="primary" @click="updateDaemonSet()">更 新</el-button>
 | 
				
			||||||
 | 
					                </span>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					        </el-dialog>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					import common from "../common/Config";
 | 
				
			||||||
 | 
					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,
 | 
				
			||||||
 | 
					            daemonSetList: [],
 | 
				
			||||||
 | 
					            daemonSetTotal: 0,
 | 
				
			||||||
 | 
					            getDaemonSetsData: {
 | 
				
			||||||
 | 
					                url: common.k8sDaemonSetList,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    filter_name: '',
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    page: '',
 | 
				
			||||||
 | 
					                    limit: '',
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            daemonSetDetail: {},
 | 
				
			||||||
 | 
					            getDaemonSetDetailData: {
 | 
				
			||||||
 | 
					                url: common.k8sDaemonSetDetail,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    daemonset_name: '',
 | 
				
			||||||
 | 
					                    namespace: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            yamlDialog: false,
 | 
				
			||||||
 | 
					            updateDaemonSetData: {
 | 
				
			||||||
 | 
					                url: common.k8sDaemonSetUpdate,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    content: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            delDaemonSetData: {
 | 
				
			||||||
 | 
					                url: common.k8sdaemonsetDel,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    daemonset_name: '',
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    methods: {
 | 
				
			||||||
 | 
					        transYaml(content) {
 | 
				
			||||||
 | 
					            return json2yaml.stringify(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        transObj(content) {
 | 
				
			||||||
 | 
					            return yaml2obj.load(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        onChange(val) {
 | 
				
			||||||
 | 
					            this.contentYaml = val
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleSizeChange(size) {
 | 
				
			||||||
 | 
					            this.pagesize = size;
 | 
				
			||||||
 | 
					            this.getDaemonSets()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleCurrentChange(currentPage) {
 | 
				
			||||||
 | 
					            this.currentPage = currentPage;
 | 
				
			||||||
 | 
					            this.getDaemonSets()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        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 
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        restartTotal(e) {
 | 
				
			||||||
 | 
					            let index, sum = 0
 | 
				
			||||||
 | 
					            let containerStatuses = e.row.status.containerStatuses
 | 
				
			||||||
 | 
					            for ( index in containerStatuses) {
 | 
				
			||||||
 | 
					                sum = sum + containerStatuses[index].restartCount 
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return sum
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getNamespaces() {
 | 
				
			||||||
 | 
					            httpClient.get(this.namespaceListUrl)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.namespaceList = res.data.items
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getDaemonSets() {
 | 
				
			||||||
 | 
					            this.appLoading = true
 | 
				
			||||||
 | 
					            this.getDaemonSetsData.params.filter_name = this.searchInput
 | 
				
			||||||
 | 
					            this.getDaemonSetsData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            this.getDaemonSetsData.params.page = this.currentPage
 | 
				
			||||||
 | 
					            this.getDaemonSetsData.params.limit = this.pagesize
 | 
				
			||||||
 | 
					            httpClient.get(this.getDaemonSetsData.url, {params: this.getDaemonSetsData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.daemonSetList = res.data.items
 | 
				
			||||||
 | 
					                this.daemonSetTotal = res.data.total
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.appLoading = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getDaemonSetDetail(e) {
 | 
				
			||||||
 | 
					            this.getDaemonSetDetailData.params.daemonset_name = e.row.metadata.name
 | 
				
			||||||
 | 
					            this.getDaemonSetDetailData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.get(this.getDaemonSetDetailData.url, {params: this.getDaemonSetDetailData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.daemonSetDetail = res.data
 | 
				
			||||||
 | 
					                this.contentYaml = this.transYaml(this.daemonSetDetail)
 | 
				
			||||||
 | 
					                this.yamlDialog = true
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        updateDaemonSet() {
 | 
				
			||||||
 | 
					            let content = JSON.stringify(this.transObj(this.contentYaml))
 | 
				
			||||||
 | 
					            this.updateDaemonSetData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            this.updateDaemonSetData.params.content = content
 | 
				
			||||||
 | 
					            httpClient.put(this.updateDaemonSetData.url, this.updateDaemonSetData.params)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.yamlDialog = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        delDaemonSet(e) {
 | 
				
			||||||
 | 
					            this.delDaemonSetData.params.daemonset_name = e.row.metadata.name
 | 
				
			||||||
 | 
					            this.delDaemonSetData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.delete(this.delDaemonSetData.url, {data: this.delDaemonSetData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.getDaemonSets()
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleConfirm(obj, operateName, fn) {
 | 
				
			||||||
 | 
					            this.confirmContent = '确认继续 ' + operateName + ' 操作吗?'
 | 
				
			||||||
 | 
					            this.$confirm(this.confirmContent,'提示',{
 | 
				
			||||||
 | 
					                confirmButtonText: '确定',
 | 
				
			||||||
 | 
					                cancelButtonText: '取消',
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .then(() => {
 | 
				
			||||||
 | 
					                fn(obj)
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            .catch(() => {
 | 
				
			||||||
 | 
					                this.$message.info({
 | 
				
			||||||
 | 
					                    message: '已取消操作'
 | 
				
			||||||
 | 
					                })          
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    watch: {
 | 
				
			||||||
 | 
					        namespaceValue: {
 | 
				
			||||||
 | 
					            handler() {
 | 
				
			||||||
 | 
					                localStorage.setItem('namespace', this.namespaceValue)
 | 
				
			||||||
 | 
					                this.currentPage = 1
 | 
				
			||||||
 | 
					                this.getDaemonSets()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    beforeMount() {
 | 
				
			||||||
 | 
					        if (localStorage.getItem('namespace') !== undefined && localStorage.getItem('namespace') !== null) {
 | 
				
			||||||
 | 
					            this.namespaceValue = localStorage.getItem('namespace')
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.getNamespaces()
 | 
				
			||||||
 | 
					        this.getDaemonSets()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					    .daemonset-head-card,.daemonset-body-card {
 | 
				
			||||||
 | 
					        border-radius: 1px;
 | 
				
			||||||
 | 
					        margin-bottom: 5px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .daemonset-head-search {
 | 
				
			||||||
 | 
					        width:160px;
 | 
				
			||||||
 | 
					        margin-right:10px; 
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .daemonset-body-daemonsetname {
 | 
				
			||||||
 | 
					        color: #4795EE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .daemonset-body-daemonsetname:hover {
 | 
				
			||||||
 | 
					        color: rgb(84, 138, 238);
 | 
				
			||||||
 | 
					        cursor: pointer;
 | 
				
			||||||
 | 
					        font-weight: bold;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										611
									
								
								dkube-web/src/views/deployment/Deployment.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,611 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div class="deploy">
 | 
				
			||||||
 | 
					        <el-row>
 | 
				
			||||||
 | 
					            <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>
 | 
				
			||||||
 | 
					                                    <el-select v-model="namespaceValue" filterable placeholder="请选择">
 | 
				
			||||||
 | 
					                                        <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>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Refresh" plain @click="getDeployments()">刷新</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                        </el-row>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="deploy-head-card" shadow="never" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                        <el-row>
 | 
				
			||||||
 | 
					                            <el-col :span="2">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <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'}">
 | 
				
			||||||
 | 
					                        <el-table
 | 
				
			||||||
 | 
					                        style="width:100%;font-size:12px;margin-bottom:10px;"
 | 
				
			||||||
 | 
					                        :data="deploymentList"
 | 
				
			||||||
 | 
					                        v-loading="appLoading">
 | 
				
			||||||
 | 
					                            <el-table-column width="20"></el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=left label="Deployment名">
 | 
				
			||||||
 | 
					                                <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">
 | 
				
			||||||
 | 
					                                    <div v-for="(val, key) in scope.row.metadata.labels" :key="key">
 | 
				
			||||||
 | 
					                                        <el-popover
 | 
				
			||||||
 | 
					                                            placement="right"
 | 
				
			||||||
 | 
					                                            :width="200"
 | 
				
			||||||
 | 
					                                            trigger="hover"
 | 
				
			||||||
 | 
					                                            :content="key + ':' + val">
 | 
				
			||||||
 | 
					                                            <template #reference>
 | 
				
			||||||
 | 
					                                                <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="容器组">
 | 
				
			||||||
 | 
					                                <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="创建时间">
 | 
				
			||||||
 | 
					                                <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="镜像">
 | 
				
			||||||
 | 
					                                <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>
 | 
				
			||||||
 | 
					                        <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>
 | 
				
			||||||
 | 
					        <el-drawer
 | 
				
			||||||
 | 
					            v-model="createDeploymentDrawer"
 | 
				
			||||||
 | 
					            :direction="direction"
 | 
				
			||||||
 | 
					            :before-close="handleClose">
 | 
				
			||||||
 | 
					            <template #title>
 | 
				
			||||||
 | 
					                <h4>创建Deployment</h4>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					            <template #default>
 | 
				
			||||||
 | 
					                <el-row type="flex" justify="center">
 | 
				
			||||||
 | 
					                    <el-col :span="20">
 | 
				
			||||||
 | 
					                        <el-form ref="createDeployment" :rules="createDeploymentRules" :model="createDeployment" label-width="80px">
 | 
				
			||||||
 | 
					                            <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>
 | 
				
			||||||
 | 
					                            <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>
 | 
				
			||||||
 | 
					                            <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>
 | 
				
			||||||
 | 
					            <template #footer>
 | 
				
			||||||
 | 
					                <el-button @click="createDeploymentDrawer = false">取消</el-button>
 | 
				
			||||||
 | 
					                <el-button type="primary" @click="submitForm('createDeployment')">立即创建</el-button>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					        </el-drawer>
 | 
				
			||||||
 | 
					        <el-dialog title="YAML信息" v-model="yamlDialog" width="45%" top="2%">
 | 
				
			||||||
 | 
					            <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";
 | 
				
			||||||
 | 
					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: {}
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            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: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            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: {
 | 
				
			||||||
 | 
					        transYaml(content) {
 | 
				
			||||||
 | 
					            return json2yaml.stringify(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        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 
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getNamespaces() {
 | 
				
			||||||
 | 
					            httpClient.get(this.namespaceListUrl)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.namespaceList = res.data.items
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getDeployments() {
 | 
				
			||||||
 | 
					            this.appLoading = true
 | 
				
			||||||
 | 
					            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 => {
 | 
				
			||||||
 | 
					                this.deploymentList = res.data.items
 | 
				
			||||||
 | 
					                this.deploymentTotal = res.data.total
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.appLoading = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        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.deploymentDetail = res.data
 | 
				
			||||||
 | 
					                this.contentYaml = this.transYaml(this.deploymentDetail)
 | 
				
			||||||
 | 
					                this.yamlDialog = true
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        updateDeployment() {
 | 
				
			||||||
 | 
					            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
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        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
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        handleConfirm(obj, operateName, fn) {
 | 
				
			||||||
 | 
					            this.confirmContent = '确认继续 ' + operateName + ' 操作吗?'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.$confirm(this.confirmContent,'提示',{
 | 
				
			||||||
 | 
					                confirmButtonText: '确定',
 | 
				
			||||||
 | 
					                cancelButtonText: '取消',
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .then(() => {
 | 
				
			||||||
 | 
					                fn(obj)
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(() => {
 | 
				
			||||||
 | 
					                this.$message.info({
 | 
				
			||||||
 | 
					                    message: '已取消操作'
 | 
				
			||||||
 | 
					                })          
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        createDeployFunc() {
 | 
				
			||||||
 | 
					            let reg = new RegExp("(^[A-Za-z]+=[A-Za-z0-9]+).*")
 | 
				
			||||||
 | 
					            if (!reg.test(this.createDeployment.label_str)) {
 | 
				
			||||||
 | 
					                this.$message.warning({
 | 
				
			||||||
 | 
					                    message: "标签填写异常,请确认后重新填写"
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.fullscreenLoading = true
 | 
				
			||||||
 | 
					            let label = new Map()
 | 
				
			||||||
 | 
					            let cpu, memory
 | 
				
			||||||
 | 
					            let a = (this.createDeployment.label_str).split(",")
 | 
				
			||||||
 | 
					            a.forEach(item => {
 | 
				
			||||||
 | 
					                let b = item.split("=")
 | 
				
			||||||
 | 
					                label[b[0]] = b[1]
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            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
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        resetForm(formName) {
 | 
				
			||||||
 | 
					            this.$refs[formName].resetFields()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        submitForm(formName) {
 | 
				
			||||||
 | 
					            this.$refs[formName].validate((valid) => {
 | 
				
			||||||
 | 
					                if (valid) {
 | 
				
			||||||
 | 
					                    this.createDeployFunc()
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    watch: {
 | 
				
			||||||
 | 
					        namespaceValue: {
 | 
				
			||||||
 | 
					            handler() {
 | 
				
			||||||
 | 
					                localStorage.setItem('namespace', this.namespaceValue)
 | 
				
			||||||
 | 
					                this.currentPage = 1
 | 
				
			||||||
 | 
					                this.getDeployments()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    beforeMount() {
 | 
				
			||||||
 | 
					        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: 1px;
 | 
				
			||||||
 | 
					        margin-bottom: 5px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .deploy-head-search {
 | 
				
			||||||
 | 
					        width:160px;
 | 
				
			||||||
 | 
					        margin-right:10px; 
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .deploy-body-deployname {
 | 
				
			||||||
 | 
					        color: #4795EE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .deploy-body-deployname:hover {
 | 
				
			||||||
 | 
					        color: rgb(84, 138, 238);
 | 
				
			||||||
 | 
					        cursor: pointer;
 | 
				
			||||||
 | 
					        font-weight: bold;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										365
									
								
								dkube-web/src/views/home/Home.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,365 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					  <div class="home">
 | 
				
			||||||
 | 
					      <el-collapse v-model="activeNames">
 | 
				
			||||||
 | 
					          <el-collapse-item title="集群资源" name="1">
 | 
				
			||||||
 | 
					              <el-row :gutter="10" style="margin-bottom: 10px;">
 | 
				
			||||||
 | 
					                  <el-col :span="5">
 | 
				
			||||||
 | 
					                      <el-card class="home-node-card" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                          <div style="float:left;padding-top:20%">
 | 
				
			||||||
 | 
					                              <el-progress  :stroke-width="20" :show-text="false" type="circle" :percentage="namespaceActive/namespaceTotal * 100"></el-progress>
 | 
				
			||||||
 | 
					                          </div>
 | 
				
			||||||
 | 
					                          <div>
 | 
				
			||||||
 | 
					                              <p class="home-node-card-title">命名空间: Active/总量</p>
 | 
				
			||||||
 | 
					                              <p class="home-node-card-num">{{ namespaceActive }}/{{ namespaceTotal }}</p>
 | 
				
			||||||
 | 
					                          </div>
 | 
				
			||||||
 | 
					                      </el-card>
 | 
				
			||||||
 | 
					                  </el-col>
 | 
				
			||||||
 | 
					                  <el-col :span="5">
 | 
				
			||||||
 | 
					                      <el-card class="home-node-card" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                          <div>
 | 
				
			||||||
 | 
					                              <p class="home-node-card-title">服务数</p>
 | 
				
			||||||
 | 
					                              <p class="home-node-card-num">{{ deploymentTotal }}</p>
 | 
				
			||||||
 | 
					                          </div>
 | 
				
			||||||
 | 
					                      </el-card>
 | 
				
			||||||
 | 
					                  </el-col>
 | 
				
			||||||
 | 
					                  <el-col :span="5">
 | 
				
			||||||
 | 
					                      <el-card class="home-node-card" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                          <div>
 | 
				
			||||||
 | 
					                              <p class="home-node-card-title">实例数</p>
 | 
				
			||||||
 | 
					                              <p class="home-node-card-num">{{ podTotal }}</p>
 | 
				
			||||||
 | 
					                          </div>
 | 
				
			||||||
 | 
					                      </el-card>
 | 
				
			||||||
 | 
					                  </el-col>
 | 
				
			||||||
 | 
					              </el-row>
 | 
				
			||||||
 | 
					          </el-collapse-item>
 | 
				
			||||||
 | 
					          <el-collapse-item title="节点资源" name="2">
 | 
				
			||||||
 | 
					              <el-row :gutter="10" style="margin-bottom: 10px;">
 | 
				
			||||||
 | 
					                  <el-col :span="5">
 | 
				
			||||||
 | 
					                      <el-card class="home-node-card" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                          <div style="float:left;padding-top:20%">
 | 
				
			||||||
 | 
					                              <el-progress :stroke-width="20" :show-text="false" type="circle" :percentage="nodeTotal/nodeTotal * 100"></el-progress>
 | 
				
			||||||
 | 
					                          </div>
 | 
				
			||||||
 | 
					                          <div>
 | 
				
			||||||
 | 
					                              <p class="home-node-card-title">节点: Ready/总数量</p>
 | 
				
			||||||
 | 
					                              <p class="home-node-card-num">{{ nodeTotal }}/{{ nodeTotal }}</p>
 | 
				
			||||||
 | 
					                          </div>
 | 
				
			||||||
 | 
					                      </el-card>
 | 
				
			||||||
 | 
					                  </el-col>
 | 
				
			||||||
 | 
					                  <el-col :span="5">
 | 
				
			||||||
 | 
					                      <el-card class="home-node-card" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                          <div style="float:left;padding-top:20%">
 | 
				
			||||||
 | 
					                              <el-progress :stroke-width="20" :show-text="false" type="circle" :percentage="nodeCpuAllocatable/nodeCpuCapacity * 100"></el-progress>
 | 
				
			||||||
 | 
					                          </div>
 | 
				
			||||||
 | 
					                          <div>
 | 
				
			||||||
 | 
					                              <p class="home-node-card-title">CPU: 可分配/容量</p>
 | 
				
			||||||
 | 
					                              <p class="home-node-card-num">{{ nodeCpuAllocatable }}/{{ nodeCpuCapacity }}</p>
 | 
				
			||||||
 | 
					                          </div>
 | 
				
			||||||
 | 
					                      </el-card>
 | 
				
			||||||
 | 
					                  </el-col>
 | 
				
			||||||
 | 
					                  <el-col :span="5">
 | 
				
			||||||
 | 
					                      <el-card class="home-node-card" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                          <div style="float:left;padding-top:20%">
 | 
				
			||||||
 | 
					                              <el-progress :stroke-width="20" :show-text="false" type="circle" :percentage="nodeMemAllocatable/nodeMemCapacity * 100"></el-progress>
 | 
				
			||||||
 | 
					                          </div>
 | 
				
			||||||
 | 
					                          <div>
 | 
				
			||||||
 | 
					                              <p class="home-node-card-title">内存: 可分配/容量</p>
 | 
				
			||||||
 | 
					                              <p class="home-node-card-num">{{ specTrans(nodeMemAllocatable) }}Gi/{{ specTrans(nodeMemCapacity) }}Gi</p>
 | 
				
			||||||
 | 
					                          </div>
 | 
				
			||||||
 | 
					                      </el-card>
 | 
				
			||||||
 | 
					                  </el-col>
 | 
				
			||||||
 | 
					                  <el-col :span="5">
 | 
				
			||||||
 | 
					                      <el-card class="home-node-card" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                          <div style="float:left;padding-top:20%">
 | 
				
			||||||
 | 
					                              <el-progress :stroke-width="20" :show-text="false" type="circle" :percentage="nodePodAllocatable/nodePodAllocatable * 100"></el-progress>
 | 
				
			||||||
 | 
					                          </div>
 | 
				
			||||||
 | 
					                          <div>
 | 
				
			||||||
 | 
					                              <p class="home-node-card-title">POD: 可分配/容量</p>
 | 
				
			||||||
 | 
					                              <p class="home-node-card-num">{{ nodePodAllocatable }}/{{ nodePodAllocatable }}</p>
 | 
				
			||||||
 | 
					                          </div>
 | 
				
			||||||
 | 
					                      </el-card>
 | 
				
			||||||
 | 
					                  </el-col>
 | 
				
			||||||
 | 
					              </el-row>
 | 
				
			||||||
 | 
					          </el-collapse-item>
 | 
				
			||||||
 | 
					          <el-collapse-item title="资源统计" name="3">
 | 
				
			||||||
 | 
					              <el-row :gutter="10">
 | 
				
			||||||
 | 
					                  <el-col :span="24" style="margin-bottom: 10px;">
 | 
				
			||||||
 | 
					                      <el-card class="home-dash-card" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                          <div id="podNumDash" style="height: 300px;">
 | 
				
			||||||
 | 
					                          </div>
 | 
				
			||||||
 | 
					                      </el-card>
 | 
				
			||||||
 | 
					                  </el-col>
 | 
				
			||||||
 | 
					                  <el-col :span="24">
 | 
				
			||||||
 | 
					                      <el-card class="home-dash-card" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                          <div id="deployNumDash" style="height: 300px;">
 | 
				
			||||||
 | 
					                          </div>
 | 
				
			||||||
 | 
					                      </el-card>
 | 
				
			||||||
 | 
					                  </el-col>
 | 
				
			||||||
 | 
					              </el-row>
 | 
				
			||||||
 | 
					          </el-collapse-item>
 | 
				
			||||||
 | 
					      </el-collapse>
 | 
				
			||||||
 | 
					  </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					import * as echarts from 'echarts'
 | 
				
			||||||
 | 
					import common from "../common/Config";
 | 
				
			||||||
 | 
					import httpClient from '../../utils/request';
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					  data() {
 | 
				
			||||||
 | 
					      return {
 | 
				
			||||||
 | 
					          activeNames: ["1", "2", "3"],
 | 
				
			||||||
 | 
					          namespaceActive: 0,
 | 
				
			||||||
 | 
					          namespaceValue: 'default',
 | 
				
			||||||
 | 
					          namespaceTotal: 0,
 | 
				
			||||||
 | 
					          namespaceListUrl: common.k8sNamespaceList,
 | 
				
			||||||
 | 
					          nodeTotal: 0,
 | 
				
			||||||
 | 
					          nodeCpuAllocatable: 0,
 | 
				
			||||||
 | 
					          nodeCpuCapacity: 0,
 | 
				
			||||||
 | 
					          nodeMemAllocatable: 0,
 | 
				
			||||||
 | 
					          nodeMemCapacity: 0,
 | 
				
			||||||
 | 
					          nodePodAllocatable: 0,
 | 
				
			||||||
 | 
					          nodePodCapacity: 0,
 | 
				
			||||||
 | 
					          getNodesData: {
 | 
				
			||||||
 | 
					              url: common.k8sNodeList,
 | 
				
			||||||
 | 
					              params: {}
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          deploymentTotal: 0,
 | 
				
			||||||
 | 
					          getDeploymentsData: {
 | 
				
			||||||
 | 
					              url: common.k8sDeploymentList,
 | 
				
			||||||
 | 
					              params: {
 | 
				
			||||||
 | 
					                  namespace: '',
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          podTotal: 0,
 | 
				
			||||||
 | 
					          getPodsData: {
 | 
				
			||||||
 | 
					              url: common.k8sPodList,
 | 
				
			||||||
 | 
					              params: {
 | 
				
			||||||
 | 
					                  namespace: '',
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					          },
 | 
				
			||||||
 | 
					          podNumNp: [],
 | 
				
			||||||
 | 
					          podNumNpUrl: common.k8sPodNumNp,
 | 
				
			||||||
 | 
					          deploymentNumNp: [],
 | 
				
			||||||
 | 
					          deploymentNumNpUrl: common.k8sDeploymentNumNp
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  methods: {
 | 
				
			||||||
 | 
					      getNamespaces() {
 | 
				
			||||||
 | 
					          httpClient.get(this.namespaceListUrl)
 | 
				
			||||||
 | 
					          .then(res => {
 | 
				
			||||||
 | 
					              this.namespaceTotal = res.data.total
 | 
				
			||||||
 | 
					              let namespaceList = res.data.items
 | 
				
			||||||
 | 
					              let index
 | 
				
			||||||
 | 
					              for (index in namespaceList) {
 | 
				
			||||||
 | 
					                  if (namespaceList[index].status.phase === "Active" ) {
 | 
				
			||||||
 | 
					                      this.namespaceActive = this.namespaceActive + 1
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					          .catch(res => {
 | 
				
			||||||
 | 
					              this.$message.error({
 | 
				
			||||||
 | 
					              message: res.msg
 | 
				
			||||||
 | 
					              })
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      specTrans(num) {
 | 
				
			||||||
 | 
					          let a = num / 1024 / 1024
 | 
				
			||||||
 | 
					          return a.toFixed(0)
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      getNodes() {
 | 
				
			||||||
 | 
					          httpClient.get(this.getNodesData.url, {params: this.getNodesData.params})
 | 
				
			||||||
 | 
					          .then(res => {
 | 
				
			||||||
 | 
					              this.nodeTotal = res.data.total
 | 
				
			||||||
 | 
					              let nodeList = res.data.items
 | 
				
			||||||
 | 
					              let index
 | 
				
			||||||
 | 
					              for (index in nodeList) {
 | 
				
			||||||
 | 
					                  let isnum = /^\d+$/.test(nodeList[index].status.allocatable.cpu);
 | 
				
			||||||
 | 
					                  if (!isnum) {
 | 
				
			||||||
 | 
					                      continue
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					                  this.nodeCpuAllocatable = parseInt(nodeList[index].status.allocatable.cpu) + this.nodeCpuAllocatable
 | 
				
			||||||
 | 
					                  this.nodeCpuCapacity = parseInt(nodeList[index].status.capacity.cpu) + this.nodeCpuCapacity
 | 
				
			||||||
 | 
					                  this.nodeMemAllocatable = parseInt(nodeList[index].status.allocatable.memory) + this.nodeMemAllocatable
 | 
				
			||||||
 | 
					                  this.nodeMemCapacity = parseInt(nodeList[index].status.capacity.memory) + this.nodeMemCapacity
 | 
				
			||||||
 | 
					                  this.nodePodAllocatable = parseInt(nodeList[index].status.allocatable.pods) + this.nodePodAllocatable
 | 
				
			||||||
 | 
					                  this.nodePodCapacity = parseInt(nodeList[index].status.capacity.pods) + this.nodePodCapacity
 | 
				
			||||||
 | 
					              }
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					          .catch(res => {
 | 
				
			||||||
 | 
					              this.$message.error({
 | 
				
			||||||
 | 
					              message: res.msg
 | 
				
			||||||
 | 
					              })
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      getDeployments() {
 | 
				
			||||||
 | 
					          this.getDeploymentsData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					          httpClient.get(this.getDeploymentsData.url, {params: this.getDeploymentsData.params})
 | 
				
			||||||
 | 
					          .then(res => {
 | 
				
			||||||
 | 
					              this.deploymentTotal = res.data.total
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					          .catch(res => {
 | 
				
			||||||
 | 
					              this.$message.error({
 | 
				
			||||||
 | 
					              message: res.msg
 | 
				
			||||||
 | 
					              })
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      getPods() {
 | 
				
			||||||
 | 
					          this.getPodsData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					          httpClient.get(this.getPodsData.url, {params: this.getPodsData.params})
 | 
				
			||||||
 | 
					          .then(res => {
 | 
				
			||||||
 | 
					              this.podTotal = res.data.total
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					          .catch(res => {
 | 
				
			||||||
 | 
					              this.$message.error({
 | 
				
			||||||
 | 
					              message: res.msg
 | 
				
			||||||
 | 
					              })
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      getDeploymentNumNp() {
 | 
				
			||||||
 | 
					          httpClient.get(this.deploymentNumNpUrl)
 | 
				
			||||||
 | 
					          .then(res => {
 | 
				
			||||||
 | 
					              this.deploymentNumNp = res.data
 | 
				
			||||||
 | 
					              this.getDeployNumDash()
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					          .catch(res => {
 | 
				
			||||||
 | 
					              this.$message.error({
 | 
				
			||||||
 | 
					              message: res.msg
 | 
				
			||||||
 | 
					              })
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      getPodNumNp() {
 | 
				
			||||||
 | 
					          httpClient.get(this.podNumNpUrl)
 | 
				
			||||||
 | 
					          .then(res => {
 | 
				
			||||||
 | 
					              this.podNumNp = res.data
 | 
				
			||||||
 | 
					              this.getPodNumDash()
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					          .catch(res => {
 | 
				
			||||||
 | 
					              this.$message.error({
 | 
				
			||||||
 | 
					              message: res.msg
 | 
				
			||||||
 | 
					              })
 | 
				
			||||||
 | 
					          })
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      getPodNumDash(){
 | 
				
			||||||
 | 
					          if (this.podNumDash != null && this.podNumDash != "" && this.podNumDash != undefined) {
 | 
				
			||||||
 | 
					              this.podNumDash.dispose()
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          this.podNumDash = echarts.init(document.getElementById('podNumDash'));
 | 
				
			||||||
 | 
					          this.podNumDash.setOption({
 | 
				
			||||||
 | 
					              title: { text: 'Pods per Namespace', textStyle: {color:'rgb(134, 135, 136)'}},
 | 
				
			||||||
 | 
					              color: ['#67E0E3', '#9FE6B8', '#FFDB5C','#ff9f7f', '#fb7293', '#E062AE', '#E690D1', '#e7bcf3', '#9d96f5', '#8378EA', '#96BFFF'],
 | 
				
			||||||
 | 
					              tooltip: { 
 | 
				
			||||||
 | 
					                  trigger: "axis", 
 | 
				
			||||||
 | 
					                  axisPointer: { 
 | 
				
			||||||
 | 
					                      type: "cross", 
 | 
				
			||||||
 | 
					                      label: { 
 | 
				
			||||||
 | 
					                          backgroundColor: "#76baf1" 
 | 
				
			||||||
 | 
					                      } 
 | 
				
			||||||
 | 
					                  } 
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              legend: {
 | 
				
			||||||
 | 
					                  data: ['Pods']
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              dataset: {
 | 
				
			||||||
 | 
					                  dimensions: ['namespace','pod_num'],
 | 
				
			||||||
 | 
					                  source: this.podNumNp
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              xAxis: {
 | 
				
			||||||
 | 
					                  type: 'category',
 | 
				
			||||||
 | 
					                  axisLabel:{
 | 
				
			||||||
 | 
					                      interval: 0,
 | 
				
			||||||
 | 
					                      formatter: function (value) {
 | 
				
			||||||
 | 
					                          return value.length>5?value.substring(0,5)+'...':value
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              yAxis: [
 | 
				
			||||||
 | 
					                  {type: 'value'}
 | 
				
			||||||
 | 
					              ],
 | 
				
			||||||
 | 
					              series: [{
 | 
				
			||||||
 | 
					                  name: 'Pods',
 | 
				
			||||||
 | 
					                  type: 'bar',
 | 
				
			||||||
 | 
					                  label: {
 | 
				
			||||||
 | 
					                      show: true,
 | 
				
			||||||
 | 
					                      position: 'top'
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					              ]
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					      getDeployNumDash(){
 | 
				
			||||||
 | 
					          if (this.deployNumDash != null && this.deployNumDash != "" && this.deployNumDash != undefined) {
 | 
				
			||||||
 | 
					              this.deployNumDash.dispose()
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          this.deployNumDash = echarts.init(document.getElementById('deployNumDash'));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          this.deployNumDash.setOption({
 | 
				
			||||||
 | 
					              title: { text: 'Deployments per Namespace', textStyle: {color:'rgb(134, 135, 136)'}},
 | 
				
			||||||
 | 
					              color: ['#9FE6B8', '#FFDB5C','#ff9f7f', '#fb7293', '#E062AE', '#E690D1', '#e7bcf3', '#9d96f5', '#8378EA', '#96BFFF'],
 | 
				
			||||||
 | 
					              tooltip: { trigger: "axis", axisPointer: { type: "cross", label: { backgroundColor: "#76baf1" } } },
 | 
				
			||||||
 | 
					              legend: {
 | 
				
			||||||
 | 
					                  data: ['Deployments']
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              dataset: {
 | 
				
			||||||
 | 
					                  dimensions: ['namespace','deployment_num'],
 | 
				
			||||||
 | 
					                  source: this.deploymentNumNp
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              xAxis: {
 | 
				
			||||||
 | 
					                  type: 'category',
 | 
				
			||||||
 | 
					                  axisLabel:{
 | 
				
			||||||
 | 
					                      interval: 0,
 | 
				
			||||||
 | 
					                      formatter: function (value) {
 | 
				
			||||||
 | 
					                          return value.length>5?value.substring(0,5)+'...':value
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					                  },
 | 
				
			||||||
 | 
					              },
 | 
				
			||||||
 | 
					              yAxis: [
 | 
				
			||||||
 | 
					                  {type: 'value'}
 | 
				
			||||||
 | 
					              ],
 | 
				
			||||||
 | 
					              series: [{
 | 
				
			||||||
 | 
					                  name: 'Deployments',
 | 
				
			||||||
 | 
					                  type: 'bar',
 | 
				
			||||||
 | 
					                  label: {
 | 
				
			||||||
 | 
					                      show: true,
 | 
				
			||||||
 | 
					                      position: 'top'
 | 
				
			||||||
 | 
					                      }
 | 
				
			||||||
 | 
					                  }
 | 
				
			||||||
 | 
					              ]
 | 
				
			||||||
 | 
					          });
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  beforeMount() {
 | 
				
			||||||
 | 
					      this.getNamespaces()
 | 
				
			||||||
 | 
					      this.getNodes()
 | 
				
			||||||
 | 
					      this.getDeployments()
 | 
				
			||||||
 | 
					      this.getPods()
 | 
				
			||||||
 | 
					      this.getDeploymentNumNp()
 | 
				
			||||||
 | 
					      this.getPodNumNp()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					  :v-deep .el-collapse-item__header {
 | 
				
			||||||
 | 
					      font-size: 16px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .home-node-card {
 | 
				
			||||||
 | 
					      border-radius:1px;
 | 
				
			||||||
 | 
					      text-align: center;
 | 
				
			||||||
 | 
					      background-color: rgb(250, 253, 255);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .home-dash-card {
 | 
				
			||||||
 | 
					      border-radius:1px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .home-node-card-title {
 | 
				
			||||||
 | 
					      font-size: 12px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .home-node-card-num {
 | 
				
			||||||
 | 
					      font-size: 22px;
 | 
				
			||||||
 | 
					      font-weight: bold;
 | 
				
			||||||
 | 
					      color: rgb(63, 92, 135);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  :v-deep .el-progress-circle {
 | 
				
			||||||
 | 
					      height: 50px !important;
 | 
				
			||||||
 | 
					      width: 50px !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										556
									
								
								dkube-web/src/views/ingress/Ingress.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,556 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div class="ingress">
 | 
				
			||||||
 | 
					        <el-row>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="ingress-head-card" shadow="never" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                        <el-row>
 | 
				
			||||||
 | 
					                            <el-col :span="6">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <span>命名空间: </span>
 | 
				
			||||||
 | 
					                                    <el-select v-model="namespaceValue" filterable placeholder="请选择">
 | 
				
			||||||
 | 
					                                        <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>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Refresh" plain @click="getIngresss()">刷新</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                        </el-row>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="ingress-head-card" shadow="never" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                        <el-row>
 | 
				
			||||||
 | 
					                            <el-col :span="2">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Edit" type="primary" @click="createIngressDrawer = true" v-loading.fullscreen.lock="fullscreenLoading">创建</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                            <el-col :span="6">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-input class="ingress-head-search" clearable placeholder="请输入" v-model="searchInput"></el-input>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Search" type="primary" plain @click="getIngresss()">搜索</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                        </el-row>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="ingress-body-card" shadow="never" :body-style="{padding:'5px'}">
 | 
				
			||||||
 | 
					                        <el-table
 | 
				
			||||||
 | 
					                        style="width:100%;font-size:12px;margin-bottom:10px;"
 | 
				
			||||||
 | 
					                        :data="ingressList"
 | 
				
			||||||
 | 
					                        v-loading="appLoading">
 | 
				
			||||||
 | 
					                            <el-table-column width="10"></el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=left label="Ingress名">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <a class="ingress-body-ingressname">{{ scope.row.metadata.name }}</a>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center label="标签" min-width='120'>
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <div v-for="(val, key) in scope.row.metadata.labels" :key="key">
 | 
				
			||||||
 | 
					                                        <el-popover
 | 
				
			||||||
 | 
					                                            placement="right"
 | 
				
			||||||
 | 
					                                            :width="200"
 | 
				
			||||||
 | 
					                                            trigger="hover"
 | 
				
			||||||
 | 
					                                            :content="key + ':' + val">
 | 
				
			||||||
 | 
					                                            <template #reference>
 | 
				
			||||||
 | 
					                                                <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="Host" min-width='120'>
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <div v-for="(item, index) in scope.row.spec.rules" :key="index">
 | 
				
			||||||
 | 
					                                        <el-popover
 | 
				
			||||||
 | 
					                                            placement="right"
 | 
				
			||||||
 | 
					                                            :width="200"
 | 
				
			||||||
 | 
					                                            trigger="hover"
 | 
				
			||||||
 | 
					                                            :content="item.host">
 | 
				
			||||||
 | 
					                                            <template #reference>
 | 
				
			||||||
 | 
					                                                <el-tag style="margin-bottom: 5px" type="danger">{{ ellipsis(item.host) }}</el-tag>
 | 
				
			||||||
 | 
					                                            </template>
 | 
				
			||||||
 | 
					                                        </el-popover>
 | 
				
			||||||
 | 
					                                    </div>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center label="Path">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <div v-for="(item, index) in scope.row.spec.rules" :key="index">
 | 
				
			||||||
 | 
					                                        <el-popover
 | 
				
			||||||
 | 
					                                            placement="right"
 | 
				
			||||||
 | 
					                                            :width="100"
 | 
				
			||||||
 | 
					                                            trigger="hover"
 | 
				
			||||||
 | 
					                                            :content="item.http.paths[0].path">
 | 
				
			||||||
 | 
					                                            <template #reference>
 | 
				
			||||||
 | 
					                                                <el-tag style="margin-bottom: 5px" type="danger">{{ item.http.paths[0].path }}</el-tag>
 | 
				
			||||||
 | 
					                                            </template>
 | 
				
			||||||
 | 
					                                        </el-popover>
 | 
				
			||||||
 | 
					                                    </div>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center label="EXTERNAL-IP">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <span>{{ scope.row.status.loadBalancer.ingress ? scope.row.status.loadBalancer.ingress[0].ip : '' }} </span>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center label="TLS">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <span>{{ scope.row.spec.tls ? 'YES' : '' }} </span>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center min-width="100" label="创建时间">
 | 
				
			||||||
 | 
					                                <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="操作" width="200">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <el-button size="small" style="border-radius:2px;" icon="Edit" type="primary" plain @click="getIngressDetail(scope)">YAML</el-button>
 | 
				
			||||||
 | 
					                                    <el-button size="small" style="border-radius:2px;" icon="Delete" type="danger" @click="handleConfirm(scope, '删除', delIngress)">删除</el-button>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                        </el-table>
 | 
				
			||||||
 | 
					                        <el-pagination
 | 
				
			||||||
 | 
					                        class="ingress-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="ingressTotal">
 | 
				
			||||||
 | 
					                        </el-pagination>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					        </el-row>
 | 
				
			||||||
 | 
					        <el-dialog title="YAML信息" v-model="yamlDialog" width="45%" top="5%">
 | 
				
			||||||
 | 
					            <codemirror
 | 
				
			||||||
 | 
					                :value="contentYaml"
 | 
				
			||||||
 | 
					                border
 | 
				
			||||||
 | 
					                :options="cmOptions"
 | 
				
			||||||
 | 
					                height="500"
 | 
				
			||||||
 | 
					                style="font-size:14px;"
 | 
				
			||||||
 | 
					                @change="onChange"
 | 
				
			||||||
 | 
					            ></codemirror>
 | 
				
			||||||
 | 
					            <template #footer>
 | 
				
			||||||
 | 
					                <span class="dialog-footer">
 | 
				
			||||||
 | 
					                    <el-button @click="yamlDialog = false">取 消</el-button>
 | 
				
			||||||
 | 
					                    <el-button type="primary" @click="updateIngress()">更 新</el-button>
 | 
				
			||||||
 | 
					                </span>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					        </el-dialog>
 | 
				
			||||||
 | 
					        <el-drawer
 | 
				
			||||||
 | 
					            v-model="createIngressDrawer"
 | 
				
			||||||
 | 
					            :direction="direction"
 | 
				
			||||||
 | 
					            :before-close="handleClose">
 | 
				
			||||||
 | 
					            <template #title>
 | 
				
			||||||
 | 
					                <h4>创建Ingress</h4>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					            <template #default>
 | 
				
			||||||
 | 
					                <el-row type="flex" justify="center">
 | 
				
			||||||
 | 
					                    <el-col :span="20">
 | 
				
			||||||
 | 
					                        <el-form ref="createIngress" :rules="createIngressRules" :model="createIngress" label-width="80px">
 | 
				
			||||||
 | 
					                            <el-form-item class="ingress-create-form" label="名称" prop="name">
 | 
				
			||||||
 | 
					                                <el-input v-model="createIngress.name"></el-input>
 | 
				
			||||||
 | 
					                            </el-form-item>
 | 
				
			||||||
 | 
					                            <el-form-item class="ingress-create-form" label="命名空间" prop="namespace">
 | 
				
			||||||
 | 
					                                <el-select v-model="createIngress.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>
 | 
				
			||||||
 | 
					                            <el-form-item class="SERVICE-create-form" label="标签" prop="label_str">
 | 
				
			||||||
 | 
					                                <el-input v-model="createIngress.label_str" placeholder="示例: project=ms,app=gateway"></el-input>
 | 
				
			||||||
 | 
					                            </el-form-item>
 | 
				
			||||||
 | 
					                            <el-form-item class="deploy-create-form" label="域名" prop="host">
 | 
				
			||||||
 | 
					                                <el-input v-model="createIngress.host" placeholder="示例: www.example.com"></el-input>
 | 
				
			||||||
 | 
					                            </el-form-item>
 | 
				
			||||||
 | 
					                            <el-form-item class="ingress-create-form" label="Path" prop="path">
 | 
				
			||||||
 | 
					                                <el-input v-model="createIngress.path" placeholder="示例: /abc"></el-input>
 | 
				
			||||||
 | 
					                            </el-form-item>
 | 
				
			||||||
 | 
					                            <el-form-item class="deploy-create-form" label="匹配类型" prop="path_type">
 | 
				
			||||||
 | 
					                                <el-select v-model="createIngress.path_type" placeholder="请选择">
 | 
				
			||||||
 | 
					                                    <el-option value="Prefix" label="Prefix"></el-option>
 | 
				
			||||||
 | 
					                                    <el-option value="Exact" label="Exact"></el-option>
 | 
				
			||||||
 | 
					                                    <el-option value="ImplementationSpecific" label="ImplementationSpecific"></el-option>
 | 
				
			||||||
 | 
					                                </el-select>
 | 
				
			||||||
 | 
					                            </el-form-item>
 | 
				
			||||||
 | 
					                            <el-form-item class="ingress-create-form" label="Service名" prop="service_name">
 | 
				
			||||||
 | 
					                                <el-input disabled v-model="createIngress.name"></el-input>
 | 
				
			||||||
 | 
					                            </el-form-item>
 | 
				
			||||||
 | 
					                            <el-form-item class="ingress-create-form" label="Service端口" prop="service_port">
 | 
				
			||||||
 | 
					                                <el-input v-model="createIngress.service_port" placeholder="示例: 80"></el-input>
 | 
				
			||||||
 | 
					                            </el-form-item>
 | 
				
			||||||
 | 
					                        </el-form>
 | 
				
			||||||
 | 
					                    </el-col>
 | 
				
			||||||
 | 
					                </el-row>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					            <template #footer>
 | 
				
			||||||
 | 
					                <el-button @click="createIngressDrawer = false">取消</el-button>
 | 
				
			||||||
 | 
					                <el-button type="primary" @click="submitForm('createIngress')">立即创建</el-button>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					        </el-drawer>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					import common from "../common/Config";
 | 
				
			||||||
 | 
					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,
 | 
				
			||||||
 | 
					            ingressList: [],
 | 
				
			||||||
 | 
					            ingressTotal: 0,
 | 
				
			||||||
 | 
					            getIngresssData: {
 | 
				
			||||||
 | 
					                url: common.k8sIngressList,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    filter_name: '',
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    page: '',
 | 
				
			||||||
 | 
					                    limit: '',
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            ingressDetail: {},
 | 
				
			||||||
 | 
					            getIngressDetailData: {
 | 
				
			||||||
 | 
					                url: common.k8sIngressDetail,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    ingress_name: '',
 | 
				
			||||||
 | 
					                    namespace: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            yamlDialog: false,
 | 
				
			||||||
 | 
					            updateIngressData: {
 | 
				
			||||||
 | 
					                url: common.k8sIngressUpdate,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    content: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            delIngressData: {
 | 
				
			||||||
 | 
					                url: common.k8sIngressDel,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    ingress_name: '',
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            fullscreenLoading: false,
 | 
				
			||||||
 | 
					            direction: 'rtl',
 | 
				
			||||||
 | 
					            createIngressDrawer: false,
 | 
				
			||||||
 | 
					            createIngress: {
 | 
				
			||||||
 | 
					                name: '',
 | 
				
			||||||
 | 
					                namespace: '',
 | 
				
			||||||
 | 
					                label_str: '',
 | 
				
			||||||
 | 
					                host: '',
 | 
				
			||||||
 | 
					                path: '',
 | 
				
			||||||
 | 
					                path_type: '',
 | 
				
			||||||
 | 
					                service_name: '',
 | 
				
			||||||
 | 
					                service_port: '',
 | 
				
			||||||
 | 
					                hosts: {}
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            createIngressData: {
 | 
				
			||||||
 | 
					                url: common.k8sIngressCreate,
 | 
				
			||||||
 | 
					                params: {}
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            createIngressRules: {
 | 
				
			||||||
 | 
					                name: [{
 | 
				
			||||||
 | 
					                    required: true,
 | 
				
			||||||
 | 
					                    message: '请填写名称',
 | 
				
			||||||
 | 
					                    trigger: 'change'
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					                namespace: [{
 | 
				
			||||||
 | 
					                    required: true,
 | 
				
			||||||
 | 
					                    message: '请选择命名空间',
 | 
				
			||||||
 | 
					                    trigger: 'change'
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					                host: [{
 | 
				
			||||||
 | 
					                    required: true,
 | 
				
			||||||
 | 
					                    message: '请填写域名',
 | 
				
			||||||
 | 
					                    trigger: 'change'
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					                path: [{
 | 
				
			||||||
 | 
					                    required: true,
 | 
				
			||||||
 | 
					                    message: '请填写路径',
 | 
				
			||||||
 | 
					                    trigger: 'change'
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					                service_port: [{
 | 
				
			||||||
 | 
					                    required: true,
 | 
				
			||||||
 | 
					                    message: '请填写Service端口',
 | 
				
			||||||
 | 
					                    trigger: 'change'
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					                label_str: [{
 | 
				
			||||||
 | 
					                    required: true,
 | 
				
			||||||
 | 
					                    message: '请填写标签',
 | 
				
			||||||
 | 
					                    trigger: 'change'
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					                path_type: [{
 | 
				
			||||||
 | 
					                    required: true,
 | 
				
			||||||
 | 
					                    message: '请选择匹配类型',
 | 
				
			||||||
 | 
					                    trigger: 'change'
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    methods: {
 | 
				
			||||||
 | 
					        transYaml(content) {
 | 
				
			||||||
 | 
					            return json2yaml.stringify(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        transObj(content) {
 | 
				
			||||||
 | 
					            return yaml2obj.load(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        onChange(val) {
 | 
				
			||||||
 | 
					            this.contentYaml = val
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleSizeChange(size) {
 | 
				
			||||||
 | 
					            this.pagesize = size;
 | 
				
			||||||
 | 
					            this.getIngresss()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleCurrentChange(currentPage) {
 | 
				
			||||||
 | 
					            this.currentPage = currentPage;
 | 
				
			||||||
 | 
					            this.getIngresss()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        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 
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        restartTotal(e) {
 | 
				
			||||||
 | 
					            let index, sum = 0
 | 
				
			||||||
 | 
					            let containerStatuses = e.row.status.containerStatuses
 | 
				
			||||||
 | 
					            for ( index in containerStatuses) {
 | 
				
			||||||
 | 
					                sum = sum + containerStatuses[index].restartCount 
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return sum
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getNamespaces() {
 | 
				
			||||||
 | 
					            httpClient.get(this.namespaceListUrl)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.namespaceList = res.data.items
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getIngresss() {
 | 
				
			||||||
 | 
					            this.appLoading = true
 | 
				
			||||||
 | 
					            this.getIngresssData.params.filter_name = this.searchInput
 | 
				
			||||||
 | 
					            this.getIngresssData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            this.getIngresssData.params.page = this.currentPage
 | 
				
			||||||
 | 
					            this.getIngresssData.params.limit = this.pagesize
 | 
				
			||||||
 | 
					            httpClient.get(this.getIngresssData.url, {params: this.getIngresssData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.ingressList = res.data.items
 | 
				
			||||||
 | 
					                this.ingressTotal = res.data.total
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.appLoading = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getIngressDetail(e) {
 | 
				
			||||||
 | 
					            this.getIngressDetailData.params.ingress_name = e.row.metadata.name
 | 
				
			||||||
 | 
					            this.getIngressDetailData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.get(this.getIngressDetailData.url, {params: this.getIngressDetailData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.ingressDetail = res.data
 | 
				
			||||||
 | 
					                this.contentYaml = this.transYaml(this.ingressDetail)
 | 
				
			||||||
 | 
					                this.yamlDialog = true
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        updateIngress() {
 | 
				
			||||||
 | 
					            let content = JSON.stringify(this.transObj(this.contentYaml))
 | 
				
			||||||
 | 
					            this.updateIngressData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            this.updateIngressData.params.content = content
 | 
				
			||||||
 | 
					            httpClient.put(this.updateIngressData.url, this.updateIngressData.params)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.yamlDialog = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        delIngress(e) {
 | 
				
			||||||
 | 
					            this.delIngressData.params.ingress_name = e.row.metadata.name
 | 
				
			||||||
 | 
					            this.delIngressData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.delete(this.delIngressData.url, {data: this.delIngressData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.getIngresss()
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleConfirm(obj, operateName, fn) {
 | 
				
			||||||
 | 
					            this.confirmContent = '确认继续 ' + operateName + ' 操作吗?'
 | 
				
			||||||
 | 
					            this.$confirm(this.confirmContent,'提示',{
 | 
				
			||||||
 | 
					                confirmButtonText: '确定',
 | 
				
			||||||
 | 
					                cancelButtonText: '取消',
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .then(() => {
 | 
				
			||||||
 | 
					                fn(obj)
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            .catch(() => {
 | 
				
			||||||
 | 
					                this.$message.info({
 | 
				
			||||||
 | 
					                    message: '已取消操作'
 | 
				
			||||||
 | 
					                })          
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        createIngressFunc() {
 | 
				
			||||||
 | 
					            let reg = new RegExp("(^[A-Za-z]+=[A-Za-z0-9]+).*")
 | 
				
			||||||
 | 
					            if (!reg.test(this.createIngress.label_str)) {
 | 
				
			||||||
 | 
					                this.$message.warning({
 | 
				
			||||||
 | 
					                    message: "标签填写异常,请确认后重新填写"
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            this.fullscreenLoading = true
 | 
				
			||||||
 | 
					            let label = new Map()
 | 
				
			||||||
 | 
					            let a = (this.createIngress.label_str).split(",")
 | 
				
			||||||
 | 
					            a.forEach(item => {
 | 
				
			||||||
 | 
					                let b = item.split("=")
 | 
				
			||||||
 | 
					                label[b[0]] = b[1]
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            let hosts = new Map()
 | 
				
			||||||
 | 
					            let httpPaths = []
 | 
				
			||||||
 | 
					            let httpPath = {
 | 
				
			||||||
 | 
					                path: this.createIngress.path,
 | 
				
			||||||
 | 
					                path_type: this.createIngress.path_type,
 | 
				
			||||||
 | 
					                service_name: this.createIngress.name,
 | 
				
			||||||
 | 
					                service_port: parseInt(this.createIngress.service_port)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            httpPaths.push(httpPath)
 | 
				
			||||||
 | 
					            hosts[this.createIngress.host] = httpPaths
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.createIngressData.params = this.createIngress
 | 
				
			||||||
 | 
					            this.createIngressData.params.label = label
 | 
				
			||||||
 | 
					            this.createIngressData.params.hosts = hosts
 | 
				
			||||||
 | 
					            httpClient.post(this.createIngressData.url, this.createIngressData.params)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                this.getIngresss()
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.resetForm('createIngress')
 | 
				
			||||||
 | 
					            this.fullscreenLoading = false
 | 
				
			||||||
 | 
					            this.createIngressDrawer = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        resetForm(formName) {
 | 
				
			||||||
 | 
					            this.$refs[formName].resetFields()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        submitForm(formName) {
 | 
				
			||||||
 | 
					            this.$refs[formName].validate((valid) => {
 | 
				
			||||||
 | 
					                if (valid) {
 | 
				
			||||||
 | 
					                    this.createIngressFunc()
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    watch: {
 | 
				
			||||||
 | 
					        namespaceValue: {
 | 
				
			||||||
 | 
					            handler() {
 | 
				
			||||||
 | 
					                localStorage.setItem('namespace', this.namespaceValue)
 | 
				
			||||||
 | 
					                this.currentPage = 1
 | 
				
			||||||
 | 
					                this.getIngresss()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    beforeMount() {
 | 
				
			||||||
 | 
					        if (localStorage.getItem('namespace') !== undefined && localStorage.getItem('namespace') !== null) {
 | 
				
			||||||
 | 
					            this.namespaceValue = localStorage.getItem('namespace')
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.getNamespaces()
 | 
				
			||||||
 | 
					        this.getIngresss()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					    .ingress-head-card,.ingress-body-card {
 | 
				
			||||||
 | 
					        border-radius: 1px;
 | 
				
			||||||
 | 
					        margin-bottom: 5px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .ingress-head-search {
 | 
				
			||||||
 | 
					        width:160px;
 | 
				
			||||||
 | 
					        margin-right:10px; 
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .ingress-body-ingressname {
 | 
				
			||||||
 | 
					        color: #4795EE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .ingress-body-ingressname:hover {
 | 
				
			||||||
 | 
					        color: rgb(84, 138, 238);
 | 
				
			||||||
 | 
					        cursor: pointer;
 | 
				
			||||||
 | 
					        font-weight: bold;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										96
									
								
								dkube-web/src/views/login/Login.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,96 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div class="login">
 | 
				
			||||||
 | 
					        <el-card class="login-card">
 | 
				
			||||||
 | 
					            <template #header>
 | 
				
			||||||
 | 
					                <div class="login-card-header">
 | 
				
			||||||
 | 
					                    <span>用户登录</span>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					            <el-form :model="loginData" :rules="loginDataRules" ref="loginData">
 | 
				
			||||||
 | 
					                <el-form-item prop="username">
 | 
				
			||||||
 | 
					                    <el-input prefix-icon="UserFilled" v-model.trim="loginData.username" maxlength="32" placeholder="请输入账号" clearable></el-input>
 | 
				
			||||||
 | 
					                </el-form-item>
 | 
				
			||||||
 | 
					                <el-form-item prop="password">
 | 
				
			||||||
 | 
					                    <el-input prefix-icon="Lock" v-model.trim="loginData.password" maxlength="16" show-password placeholder="请输入密码" clearable></el-input>
 | 
				
			||||||
 | 
					                </el-form-item>
 | 
				
			||||||
 | 
					                <el-form-item>
 | 
				
			||||||
 | 
					                    <el-button type="primary" style="width: 100%;border-radius: 2px" :loading="loginLoading" @click="handleLogin">登 录</el-button>
 | 
				
			||||||
 | 
					                </el-form-item>
 | 
				
			||||||
 | 
					            </el-form>
 | 
				
			||||||
 | 
					        </el-card>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					import common from "../common/Config";
 | 
				
			||||||
 | 
					import httpClient from '../../utils/request';
 | 
				
			||||||
 | 
					import moment from 'moment';
 | 
				
			||||||
 | 
					import jwt from 'jsonwebtoken';
 | 
				
			||||||
 | 
					export default{
 | 
				
			||||||
 | 
					    data() {
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            loginLoading: false,
 | 
				
			||||||
 | 
					            loginUrl: common.loginAuth,
 | 
				
			||||||
 | 
					            loginData: {
 | 
				
			||||||
 | 
					                username: '',
 | 
				
			||||||
 | 
					                password: ''
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            loginDataRules: {
 | 
				
			||||||
 | 
					                username: [{
 | 
				
			||||||
 | 
					                    required: true,
 | 
				
			||||||
 | 
					                    message: '请填写用户名',
 | 
				
			||||||
 | 
					                    trigger: 'change'
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					                password: [{
 | 
				
			||||||
 | 
					                    required: true,
 | 
				
			||||||
 | 
					                    message: '请填写密码',
 | 
				
			||||||
 | 
					                    trigger: 'change'
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    methods: {
 | 
				
			||||||
 | 
					        handleLogin() {
 | 
				
			||||||
 | 
					            httpClient.post(this.loginUrl, this.loginData)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                localStorage.setItem('username', this.loginData.username);
 | 
				
			||||||
 | 
					                localStorage.setItem('loginDate', moment().format('YYYY-MM-DD HH:mm:ss'));
 | 
				
			||||||
 | 
					                let token = jwt.sign(this.loginData, 'devops', { expiresIn: '10h' });
 | 
				
			||||||
 | 
					                localStorage.setItem('token', token);
 | 
				
			||||||
 | 
					                this.$router.push('/');
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                    message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					    .login {
 | 
				
			||||||
 | 
					        position: absolute;
 | 
				
			||||||
 | 
					        width: 100%;
 | 
				
			||||||
 | 
					        height: 100%;
 | 
				
			||||||
 | 
					        background: aquamarine;
 | 
				
			||||||
 | 
					        background-image: url(../../assets/img/login3.webp);
 | 
				
			||||||
 | 
					        background-size: 100%;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .login-card {
 | 
				
			||||||
 | 
					        position: absolute;
 | 
				
			||||||
 | 
					        left: 40%;
 | 
				
			||||||
 | 
					        top: 30%;
 | 
				
			||||||
 | 
					        width: 350px;
 | 
				
			||||||
 | 
					        border-radius: 5px;
 | 
				
			||||||
 | 
					        background: rgb(255, 255, 255);
 | 
				
			||||||
 | 
					        overflow: hidden;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .login-card-header {
 | 
				
			||||||
 | 
					        text-align: center;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										313
									
								
								dkube-web/src/views/namespace/Namespace.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,313 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div class="namespace">
 | 
				
			||||||
 | 
					        <el-row>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="namespace-head-card" shadow="never" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                        <el-row>
 | 
				
			||||||
 | 
					                            <el-col :span="2">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-button disabled style="border-radius:2px;" icon="Edit" type="primary">创建</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                            <el-col :span="6">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-input class="namespace-head-search" clearable placeholder="请输入" v-model="searchInput"></el-input>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Search" type="primary" plain @click="getNamespaces()">搜索</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                            <el-col :span="2" :offset="14">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Refresh" plain @click="getNamespaces()">刷新</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                        </el-row>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="namespace-body-card" shadow="never" :body-style="{padding:'5px'}">
 | 
				
			||||||
 | 
					                        <el-table
 | 
				
			||||||
 | 
					                        style="width:100%;font-size:12px;margin-bottom:10px;"
 | 
				
			||||||
 | 
					                        :data="namespaceList"
 | 
				
			||||||
 | 
					                        v-loading="appLoading">
 | 
				
			||||||
 | 
					                            <el-table-column width="20"></el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=left label="Namespace名">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <a class="namespace-body-namespacename">{{ scope.row.metadata.name }}</a>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center label="标签" min-width='120'>
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <div v-for="(val, key) in scope.row.metadata.labels" :key="key">
 | 
				
			||||||
 | 
					                                        <el-popover
 | 
				
			||||||
 | 
					                                            placement="right"
 | 
				
			||||||
 | 
					                                            :width="200"
 | 
				
			||||||
 | 
					                                            trigger="hover"
 | 
				
			||||||
 | 
					                                            :content="key + ':' + val">
 | 
				
			||||||
 | 
					                                            <template #reference>
 | 
				
			||||||
 | 
					                                                <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 prop="status.phase" label="状态">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <span :class="[scope.row.status.phase === 'Active' ? 'success-status' : 'error-status']">{{ scope.row.status.phase }}</span>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center min-width="100" label="创建时间">
 | 
				
			||||||
 | 
					                                <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="操作" min-width="120">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <el-button size="small" style="border-radius:2px;" icon="Edit" type="primary" plain @click="getNamespaceDetail(scope)">YAML</el-button>
 | 
				
			||||||
 | 
					                                    <el-button size="small" style="border-radius:2px;" icon="Delete" type="danger" @click="handleConfirm(scope, '删除', delNamespace)">删除</el-button>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                        </el-table>
 | 
				
			||||||
 | 
					                        <el-pagination
 | 
				
			||||||
 | 
					                        class="namespace-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="namespaceTotal">
 | 
				
			||||||
 | 
					                        </el-pagination>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					        </el-row>
 | 
				
			||||||
 | 
					        <el-dialog title="YAML信息" v-model="yamlDialog" width="45%" top="5%">
 | 
				
			||||||
 | 
					            <codemirror
 | 
				
			||||||
 | 
					                :value="contentYaml"
 | 
				
			||||||
 | 
					                border
 | 
				
			||||||
 | 
					                :options="cmOptions"
 | 
				
			||||||
 | 
					                height="500"
 | 
				
			||||||
 | 
					                style="font-size:14px;"
 | 
				
			||||||
 | 
					                @change="onChange"
 | 
				
			||||||
 | 
					            ></codemirror>
 | 
				
			||||||
 | 
					            <template #footer>
 | 
				
			||||||
 | 
					                <span class="dialog-footer">
 | 
				
			||||||
 | 
					                    <el-button @click="yamlDialog = false">取 消</el-button>
 | 
				
			||||||
 | 
					                    <el-button disabled type="primary" @click="updateNamespace()">更 新</el-button>
 | 
				
			||||||
 | 
					                </span>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					        </el-dialog>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					import common from "../common/Config";
 | 
				
			||||||
 | 
					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,
 | 
				
			||||||
 | 
					            namespaceTotal: 0,
 | 
				
			||||||
 | 
					            getNamespacesData: {
 | 
				
			||||||
 | 
					                url: common.k8sNamespaceList,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    filter_name: '',
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    page: 1,
 | 
				
			||||||
 | 
					                    limit: 10,
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            namespaceDetail: {},
 | 
				
			||||||
 | 
					            getNamespaceDetailData: {
 | 
				
			||||||
 | 
					                url: common.k8sNamespaceDetail,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    namespace_name: '',
 | 
				
			||||||
 | 
					                    namespace: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            yamlDialog: false,
 | 
				
			||||||
 | 
					            updateNamespaceData: {
 | 
				
			||||||
 | 
					                url: common.k8sNamespaceUpdate,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    content: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            delNamespaceData: {
 | 
				
			||||||
 | 
					                url: common.k8snamespaceDel,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    namespace_name: '',
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    methods: {
 | 
				
			||||||
 | 
					        transYaml(content) {
 | 
				
			||||||
 | 
					            return json2yaml.stringify(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        transObj(content) {
 | 
				
			||||||
 | 
					            return yaml2obj.load(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        onChange(val) {
 | 
				
			||||||
 | 
					            this.contentYaml = val
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleSizeChange(size) {
 | 
				
			||||||
 | 
					            this.pagesize = size;
 | 
				
			||||||
 | 
					            this.getNamespaces()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleCurrentChange(currentPage) {
 | 
				
			||||||
 | 
					            this.currentPage = currentPage;
 | 
				
			||||||
 | 
					            this.getNamespaces()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        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 
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        specTrans(str) {
 | 
				
			||||||
 | 
					            if ( str.indexOf('Ki') == -1 ) {
 | 
				
			||||||
 | 
					                return str
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            let num = str.slice(0,-2) / 1024 / 1024
 | 
				
			||||||
 | 
					            return num.toFixed(0)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getNamespaces() {
 | 
				
			||||||
 | 
					            this.getNamespacesData.params.filter_name = this.searchInput
 | 
				
			||||||
 | 
					            this.getNamespacesData.params.limit = this.pagesize
 | 
				
			||||||
 | 
					            this.getNamespacesData.params.page = this.currentPage
 | 
				
			||||||
 | 
					            httpClient.get(this.getNamespacesData.url, {params: this.getNamespacesData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.namespaceList = res.data.items
 | 
				
			||||||
 | 
					                this.namespaceTotal = res.data.total
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getNamespaceDetail(e) {
 | 
				
			||||||
 | 
					            this.getNamespaceDetailData.params.namespace_name = e.row.metadata.name
 | 
				
			||||||
 | 
					            this.getNamespaceDetailData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.get(this.getNamespaceDetailData.url, {params: this.getNamespaceDetailData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.namespaceDetail = res.data
 | 
				
			||||||
 | 
					                this.contentYaml = this.transYaml(this.namespaceDetail)
 | 
				
			||||||
 | 
					                this.yamlDialog = true
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        updateNamespace() {
 | 
				
			||||||
 | 
					            let content = JSON.stringify(this.transObj(this.contentYaml))
 | 
				
			||||||
 | 
					            this.updateNamespaceData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            this.updateNamespaceData.params.content = content
 | 
				
			||||||
 | 
					            httpClient.put(this.updateNamespaceData.url, this.updateNamespaceData.params)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.yamlDialog = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        delNamespace(e) {
 | 
				
			||||||
 | 
					            this.delNamespaceData.params.namespace_name = e.row.metadata.name
 | 
				
			||||||
 | 
					            this.delNamespaceData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.delete(this.delNamespaceData.url, {data: this.delNamespaceData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.getNamespaces()
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleConfirm(obj, operateName, fn) {
 | 
				
			||||||
 | 
					            this.confirmContent = '确认继续 ' + operateName + ' 操作吗?'
 | 
				
			||||||
 | 
					            this.$confirm(this.confirmContent,'提示',{
 | 
				
			||||||
 | 
					                confirmButtonText: '确定',
 | 
				
			||||||
 | 
					                cancelButtonText: '取消',
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .then(() => {
 | 
				
			||||||
 | 
					                fn(obj)
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            .catch(() => {
 | 
				
			||||||
 | 
					                this.$message.info({
 | 
				
			||||||
 | 
					                    message: '已取消操作'
 | 
				
			||||||
 | 
					                })          
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    beforeMount() {
 | 
				
			||||||
 | 
					        this.getNamespaces()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					    .namespace-head-card,.namespace-body-card {
 | 
				
			||||||
 | 
					        border-radius: 1px;
 | 
				
			||||||
 | 
					        margin-bottom: 5px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .namespace-head-search {
 | 
				
			||||||
 | 
					        width:160px;
 | 
				
			||||||
 | 
					        margin-right:10px; 
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .namespace-body-namespacename {
 | 
				
			||||||
 | 
					        color: #4795EE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .namespace-body-namespacename:hover {
 | 
				
			||||||
 | 
					        color: rgb(84, 138, 238);
 | 
				
			||||||
 | 
					        cursor: pointer;
 | 
				
			||||||
 | 
					        font-weight: bold;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .success-status {
 | 
				
			||||||
 | 
					        color: rgb(27, 202, 21);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .warning-status {
 | 
				
			||||||
 | 
					        color: rgb(233, 200, 16);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .error-status {
 | 
				
			||||||
 | 
					        color: rgb(226, 23, 23);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										319
									
								
								dkube-web/src/views/node/Node.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,319 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div class="node">
 | 
				
			||||||
 | 
					        <el-row>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="node-head-card" shadow="never" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                        <el-row>
 | 
				
			||||||
 | 
					                            <el-col :span="2">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-button disabled style="border-radius:2px;" icon="Edit" type="primary">创建</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                            <el-col :span="6">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-input class="node-head-search" clearable placeholder="请输入" v-model="searchInput"></el-input>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Search" type="primary" plain @click="getNodes()">搜索</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                            <el-col :span="2" :offset="14">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Refresh" plain @click="getNodes()">刷新</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                        </el-row>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="node-body-card" shadow="never" :body-style="{padding:'5px'}">
 | 
				
			||||||
 | 
					                        <el-table
 | 
				
			||||||
 | 
					                        style="width:100%;font-size:12px;margin-bottom:10px;"
 | 
				
			||||||
 | 
					                        :data="nodeList"
 | 
				
			||||||
 | 
					                        v-loading="appLoading">
 | 
				
			||||||
 | 
					                            <el-table-column width="20"></el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=left label="Node名">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <p class="node-body-nodename">{{ scope.row.metadata.name }}</p>
 | 
				
			||||||
 | 
					                                    <p class="node-body-ip">{{ scope.row.status.addresses[0].address }}</p>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center label="规格">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <el-tag type="warning">{{ scope.row.status.capacity.cpu }}核{{ specTrans(scope.row.status.capacity.memory) }}G</el-tag>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center label="POD-CIDR">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <span>{{ scope.row.spec.podCIDR }} </span>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center label="版本">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <span>{{ scope.row.status.nodeInfo.kubeletVersion }} </span>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center min-width="100" label="创建时间">
 | 
				
			||||||
 | 
					                                <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="操作" min-width="120">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <el-button size="small" style="border-radius:2px;" icon="Edit" type="primary" plain @click="getNodeDetail(scope)">YAML</el-button>
 | 
				
			||||||
 | 
					                                    <el-button disabled size="small" style="border-radius:2px;" icon="Document" type="warning" plain @click="handleConfirm(scope, '删除', delIngress)">详情</el-button>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                        </el-table>
 | 
				
			||||||
 | 
					                        <el-pagination
 | 
				
			||||||
 | 
					                        class="node-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="nodeTotal">
 | 
				
			||||||
 | 
					                        </el-pagination>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					        </el-row>
 | 
				
			||||||
 | 
					        <el-dialog title="YAML信息" v-model="yamlDialog" width="45%" top="5%">
 | 
				
			||||||
 | 
					            <codemirror
 | 
				
			||||||
 | 
					                :value="contentYaml"
 | 
				
			||||||
 | 
					                border
 | 
				
			||||||
 | 
					                :options="cmOptions"
 | 
				
			||||||
 | 
					                height="500"
 | 
				
			||||||
 | 
					                style="font-size:14px;"
 | 
				
			||||||
 | 
					                @change="onChange"
 | 
				
			||||||
 | 
					            ></codemirror>
 | 
				
			||||||
 | 
					            <template #footer>
 | 
				
			||||||
 | 
					                <span class="dialog-footer">
 | 
				
			||||||
 | 
					                    <el-button @click="yamlDialog = false">取 消</el-button>
 | 
				
			||||||
 | 
					                    <el-button disabled type="primary" @click="updateNode()">更 新</el-button>
 | 
				
			||||||
 | 
					                </span>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					        </el-dialog>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					import common from "../common/Config";
 | 
				
			||||||
 | 
					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,
 | 
				
			||||||
 | 
					            nodeList: [],
 | 
				
			||||||
 | 
					            nodeTotal: 0,
 | 
				
			||||||
 | 
					            getNodesData: {
 | 
				
			||||||
 | 
					                url: common.k8sNodeList,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    filter_name: '',
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    page: '',
 | 
				
			||||||
 | 
					                    limit: '',
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            nodeDetail: {},
 | 
				
			||||||
 | 
					            getNodeDetailData: {
 | 
				
			||||||
 | 
					                url: common.k8sNodeDetail,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    node_name: '',
 | 
				
			||||||
 | 
					                    namespace: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            yamlDialog: false,
 | 
				
			||||||
 | 
					            updateNodeData: {
 | 
				
			||||||
 | 
					                url: common.k8sNodeUpdate,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    content: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            delNodeData: {
 | 
				
			||||||
 | 
					                url: common.k8snodeDel,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    node_name: '',
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    methods: {
 | 
				
			||||||
 | 
					        transYaml(content) {
 | 
				
			||||||
 | 
					            return json2yaml.stringify(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        transObj(content) {
 | 
				
			||||||
 | 
					            return yaml2obj.load(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        onChange(val) {
 | 
				
			||||||
 | 
					            this.contentYaml = val
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleSizeChange(size) {
 | 
				
			||||||
 | 
					            this.pagesize = size;
 | 
				
			||||||
 | 
					            this.getNodes()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleCurrentChange(currentPage) {
 | 
				
			||||||
 | 
					            this.currentPage = currentPage;
 | 
				
			||||||
 | 
					            this.getNodes()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        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 
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        specTrans(str) {
 | 
				
			||||||
 | 
					            if ( str.indexOf('Ki') == -1 ) {
 | 
				
			||||||
 | 
					                return str
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            let num = str.slice(0,-2) / 1024 / 1024
 | 
				
			||||||
 | 
					            return num.toFixed(0)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getNamespaces() {
 | 
				
			||||||
 | 
					            httpClient.get(this.namespaceListUrl)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.namespaceList = res.data.items
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getNodes() {
 | 
				
			||||||
 | 
					            this.appLoading = true
 | 
				
			||||||
 | 
					            this.getNodesData.params.filter_name = this.searchInput
 | 
				
			||||||
 | 
					            this.getNodesData.params.page = this.currentPage
 | 
				
			||||||
 | 
					            this.getNodesData.params.limit = this.pagesize
 | 
				
			||||||
 | 
					            httpClient.get(this.getNodesData.url, {params: this.getNodesData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.nodeList = res.data.items
 | 
				
			||||||
 | 
					                this.nodeTotal = res.data.total
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.appLoading = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getNodeDetail(e) {
 | 
				
			||||||
 | 
					            this.getNodeDetailData.params.node_name = e.row.metadata.name
 | 
				
			||||||
 | 
					            this.getNodeDetailData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.get(this.getNodeDetailData.url, {params: this.getNodeDetailData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.nodeDetail = res.data
 | 
				
			||||||
 | 
					                this.contentYaml = this.transYaml(this.nodeDetail)
 | 
				
			||||||
 | 
					                this.yamlDialog = true
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        updateNode() {
 | 
				
			||||||
 | 
					            let content = JSON.stringify(this.transObj(this.contentYaml))
 | 
				
			||||||
 | 
					            this.updateNodeData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            this.updateNodeData.params.content = content
 | 
				
			||||||
 | 
					            httpClient.put(this.updateNodeData.url, this.updateNodeData.params)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.yamlDialog = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        delNode(e) {
 | 
				
			||||||
 | 
					            this.delNodeData.params.node_name = e.row.metadata.name
 | 
				
			||||||
 | 
					            this.delNodeData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.delete(this.delNodeData.url, {data: this.delNodeData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.getNodes()
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleConfirm(obj, operateName, fn) {
 | 
				
			||||||
 | 
					            this.confirmContent = '确认继续 ' + operateName + ' 操作吗?'
 | 
				
			||||||
 | 
					            this.$confirm(this.confirmContent,'提示',{
 | 
				
			||||||
 | 
					                confirmButtonText: '确定',
 | 
				
			||||||
 | 
					                cancelButtonText: '取消',
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .then(() => {
 | 
				
			||||||
 | 
					                fn(obj)
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            .catch(() => {
 | 
				
			||||||
 | 
					                this.$message.info({
 | 
				
			||||||
 | 
					                    message: '已取消操作'
 | 
				
			||||||
 | 
					                })          
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    beforeMount() {
 | 
				
			||||||
 | 
					        this.getNodes()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					    .node-head-card,.node-body-card {
 | 
				
			||||||
 | 
					        border-radius: 1px;
 | 
				
			||||||
 | 
					        margin-bottom: 5px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .node-head-search {
 | 
				
			||||||
 | 
					        width:160px;
 | 
				
			||||||
 | 
					        margin-right:10px; 
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .node-body-nodename {
 | 
				
			||||||
 | 
					        margin: 0px;
 | 
				
			||||||
 | 
					        color: #4795EE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .node-body-ip {
 | 
				
			||||||
 | 
					        margin: 0px;
 | 
				
			||||||
 | 
					        color: rgb(145, 145, 145);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .node-body-nodename:hover {
 | 
				
			||||||
 | 
					        color: rgb(84, 138, 238);
 | 
				
			||||||
 | 
					        cursor: pointer;
 | 
				
			||||||
 | 
					        font-weight: bold;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										316
									
								
								dkube-web/src/views/persistentvolume/PersistentVolume.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,316 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div class="pv">
 | 
				
			||||||
 | 
					        <el-row>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="pv-head-card" shadow="never" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                        <el-row>
 | 
				
			||||||
 | 
					                            <el-col :span="2">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-button disabled style="border-radius:2px;" icon="Edit" type="primary">创建</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                            <el-col :span="6">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-input class="pv-head-search" clearable placeholder="请输入" v-model="searchInput"></el-input>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Search" type="primary" plain @click="getPvs()">搜索</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                            <el-col :span="2" :offset="14">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Refresh" plain @click="getPvs()">刷新</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                        </el-row>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="pv-body-card" shadow="never" :body-style="{padding:'5px'}">
 | 
				
			||||||
 | 
					                        <el-table
 | 
				
			||||||
 | 
					                        style="width:100%;font-size:12px;margin-bottom:10px;"
 | 
				
			||||||
 | 
					                        :data="pvList"
 | 
				
			||||||
 | 
					                        v-loading="appLoading">
 | 
				
			||||||
 | 
					                            <el-table-column width="20"></el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=left label="PV名">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <a class="pv-body-pvname">{{ scope.row.metadata.name }}</a>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center label="状态">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <span :class="[scope.row.status.phase === 'Bound' ? 'success-status' : 'error-status']">{{ scope.row.status.phase }}</span>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center prop="spec.accessModes[0]" label="访问模式"></el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center prop="spec.capacity.storage" label="容量"></el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center prop="spec.claimRef.name" label="PVC"></el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center min-width="100" label="创建时间">
 | 
				
			||||||
 | 
					                                <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="操作" min-width="120">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <el-button size="small" style="border-radius:2px;" icon="Edit" type="primary" plain @click="getPvDetail(scope)">YAML</el-button>
 | 
				
			||||||
 | 
					                                    <el-button size="small" style="border-radius:2px;" icon="Delete" type="danger" @click="handleConfirm(scope, '删除', delPv)">删除</el-button>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                        </el-table>
 | 
				
			||||||
 | 
					                        <el-pagination
 | 
				
			||||||
 | 
					                        class="pv-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="pvTotal">
 | 
				
			||||||
 | 
					                        </el-pagination>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					        </el-row>
 | 
				
			||||||
 | 
					        <el-dialog title="YAML信息" v-model="yamlDialog" width="45%" top="5%">
 | 
				
			||||||
 | 
					            <codemirror
 | 
				
			||||||
 | 
					                :value="contentYaml"
 | 
				
			||||||
 | 
					                border
 | 
				
			||||||
 | 
					                :options="cmOptions"
 | 
				
			||||||
 | 
					                height="500"
 | 
				
			||||||
 | 
					                style="font-size:14px;"
 | 
				
			||||||
 | 
					                @change="onChange"
 | 
				
			||||||
 | 
					            ></codemirror>
 | 
				
			||||||
 | 
					            <template #footer>
 | 
				
			||||||
 | 
					                <span class="dialog-footer">
 | 
				
			||||||
 | 
					                    <el-button @click="yamlDialog = false">取 消</el-button>
 | 
				
			||||||
 | 
					                    <el-button disabled type="primary" @click="updatePv()">更 新</el-button>
 | 
				
			||||||
 | 
					                </span>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					        </el-dialog>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					import common from "../common/Config";
 | 
				
			||||||
 | 
					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,
 | 
				
			||||||
 | 
					            pvList: [],
 | 
				
			||||||
 | 
					            pvTotal: 0,
 | 
				
			||||||
 | 
					            getPvsData: {
 | 
				
			||||||
 | 
					                url: common.k8sPvList,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    filter_name: '',
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    page: '',
 | 
				
			||||||
 | 
					                    limit: '',
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            pvDetail: {},
 | 
				
			||||||
 | 
					            getPvDetailData: {
 | 
				
			||||||
 | 
					                url: common.k8sPvDetail,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    pv_name: '',
 | 
				
			||||||
 | 
					                    namespace: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            yamlDialog: false,
 | 
				
			||||||
 | 
					            updatePvData: {
 | 
				
			||||||
 | 
					                url: common.k8sPvUpdate,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    content: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            delPvData: {
 | 
				
			||||||
 | 
					                url: common.k8spvDel,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    pv_name: '',
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    methods: {
 | 
				
			||||||
 | 
					        transYaml(content) {
 | 
				
			||||||
 | 
					            return json2yaml.stringify(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        transObj(content) {
 | 
				
			||||||
 | 
					            return yaml2obj.load(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        onChange(val) {
 | 
				
			||||||
 | 
					            this.contentYaml = val
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleSizeChange(size) {
 | 
				
			||||||
 | 
					            this.pagesize = size;
 | 
				
			||||||
 | 
					            this.getPvs()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleCurrentChange(currentPage) {
 | 
				
			||||||
 | 
					            this.currentPage = currentPage;
 | 
				
			||||||
 | 
					            this.getPvs()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        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 
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        specTrans(str) {
 | 
				
			||||||
 | 
					            if ( str.indexOf('Ki') == -1 ) {
 | 
				
			||||||
 | 
					                return str
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            let num = str.slice(0,-2) / 1024 / 1024
 | 
				
			||||||
 | 
					            return num.toFixed(0)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getNamespaces() {
 | 
				
			||||||
 | 
					            httpClient.get(this.namespaceListUrl)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.namespaceList = res.data.items
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getPvs() {
 | 
				
			||||||
 | 
					            this.appLoading = true
 | 
				
			||||||
 | 
					            this.getPvsData.params.filter_name = this.searchInput
 | 
				
			||||||
 | 
					            this.getPvsData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            this.getPvsData.params.page = this.currentPage
 | 
				
			||||||
 | 
					            this.getPvsData.params.limit = this.pagesize
 | 
				
			||||||
 | 
					            httpClient.get(this.getPvsData.url, {params: this.getPvsData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.pvList = res.data.items
 | 
				
			||||||
 | 
					                this.pvTotal = res.data.total
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.appLoading = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getPvDetail(e) {
 | 
				
			||||||
 | 
					            this.getPvDetailData.params.pv_name = e.row.metadata.name
 | 
				
			||||||
 | 
					            this.getPvDetailData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.get(this.getPvDetailData.url, {params: this.getPvDetailData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.pvDetail = res.data
 | 
				
			||||||
 | 
					                this.contentYaml = this.transYaml(this.pvDetail)
 | 
				
			||||||
 | 
					                this.yamlDialog = true
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        updatePv() {
 | 
				
			||||||
 | 
					            let content = JSON.stringify(this.transObj(this.contentYaml))
 | 
				
			||||||
 | 
					            this.updatePvData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            this.updatePvData.params.content = content
 | 
				
			||||||
 | 
					            httpClient.put(this.updatePvData.url, this.updatePvData.params)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.yamlDialog = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        delPv(e) {
 | 
				
			||||||
 | 
					            this.delPvData.params.pv_name = e.row.metadata.name
 | 
				
			||||||
 | 
					            this.delPvData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.delete(this.delPvData.url, {data: this.delPvData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.getPvs()
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleConfirm(obj, operateName, fn) {
 | 
				
			||||||
 | 
					            this.confirmContent = '确认继续 ' + operateName + ' 操作吗?'
 | 
				
			||||||
 | 
					            this.$confirm(this.confirmContent,'提示',{
 | 
				
			||||||
 | 
					                confirmButtonText: '确定',
 | 
				
			||||||
 | 
					                cancelButtonText: '取消',
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .then(() => {
 | 
				
			||||||
 | 
					                fn(obj)
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            .catch(() => {
 | 
				
			||||||
 | 
					                this.$message.info({
 | 
				
			||||||
 | 
					                    message: '已取消操作'
 | 
				
			||||||
 | 
					                })          
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    beforeMount() {
 | 
				
			||||||
 | 
					        this.getPvs()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					    .pv-head-card,.pv-body-card {
 | 
				
			||||||
 | 
					        border-radius: 1px;
 | 
				
			||||||
 | 
					        margin-bottom: 5px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .pv-head-search {
 | 
				
			||||||
 | 
					        width:160px;
 | 
				
			||||||
 | 
					        margin-right:10px; 
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .pv-body-pvname {
 | 
				
			||||||
 | 
					        color: #4795EE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .pv-body-pvname:hover {
 | 
				
			||||||
 | 
					        color: rgb(84, 138, 238);
 | 
				
			||||||
 | 
					        cursor: pointer;
 | 
				
			||||||
 | 
					        font-weight: bold;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .success-status {
 | 
				
			||||||
 | 
					        color: rgb(27, 202, 21);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .warning-status {
 | 
				
			||||||
 | 
					        color: rgb(233, 200, 16);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .error-status {
 | 
				
			||||||
 | 
					        color: rgb(226, 23, 23);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
@ -0,0 +1,369 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div class="pvc">
 | 
				
			||||||
 | 
					        <el-row>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="pvc-head-card" shadow="never" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                        <el-row>
 | 
				
			||||||
 | 
					                            <el-col :span="6">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <span>命名空间: </span>
 | 
				
			||||||
 | 
					                                    <el-select v-model="namespaceValue" filterable placeholder="请选择">
 | 
				
			||||||
 | 
					                                        <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>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Refresh" plain @click="getPvcs()">刷新</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                        </el-row>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="pvc-head-card" shadow="never" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                        <el-row>
 | 
				
			||||||
 | 
					                            <el-col :span="2">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-button disabled style="border-radius:2px;" icon="Edit" type="primary">创建</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                            <el-col :span="6">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-input class="pvc-head-search" clearable placeholder="请输入" v-model="searchInput"></el-input>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Search" type="primary" plain @click="getPvcs()">搜索</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                        </el-row>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="pvc-body-card" shadow="never" :body-style="{padding:'5px'}">
 | 
				
			||||||
 | 
					                        <el-table
 | 
				
			||||||
 | 
					                        style="width:100%;font-size:12px;margin-bottom:10px;"
 | 
				
			||||||
 | 
					                        :data="pvcList"
 | 
				
			||||||
 | 
					                        v-loading="appLoading">
 | 
				
			||||||
 | 
					                            <el-table-column width="20"></el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=left label="PVC名">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <a class="pvc-body-pvcname">{{ scope.row.metadata.name }}</a>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center label="标签">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <div v-for="(val, key) in scope.row.metadata.labels" :key="key">
 | 
				
			||||||
 | 
					                                        <el-popover
 | 
				
			||||||
 | 
					                                            placement="right"
 | 
				
			||||||
 | 
					                                            :width="200"
 | 
				
			||||||
 | 
					                                            trigger="hover"
 | 
				
			||||||
 | 
					                                            :content="key + ':' + val">
 | 
				
			||||||
 | 
					                                            <template #reference>
 | 
				
			||||||
 | 
					                                                <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="状态">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <span :class="[scope.row.status.phase === 'Bound' ? 'success-status' : 'error-status']">{{ scope.row.status.phase }}</span>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center prop="status.capacity.storage" label="容量">
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center prop="status.accessModes[0]" label="访问模式">
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center prop="spec.storageClassName" label="StorageClass">
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center min-width="100" label="创建时间">
 | 
				
			||||||
 | 
					                                <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="操作" width="200">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <el-button size="small" style="border-radius:2px;" icon="Edit" type="primary" plain @click="getPvcDetail(scope)">YAML</el-button>
 | 
				
			||||||
 | 
					                                    <el-button size="small" style="border-radius:2px;" icon="Delete" type="danger" @click="handleConfirm(scope, '删除', delPvc)">删除</el-button>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                        </el-table>
 | 
				
			||||||
 | 
					                        <el-pagination
 | 
				
			||||||
 | 
					                        class="pvc-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="pvcTotal">
 | 
				
			||||||
 | 
					                        </el-pagination>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					        </el-row>
 | 
				
			||||||
 | 
					        <el-dialog title="YAML信息" v-model="yamlDialog" width="45%" top="5%">
 | 
				
			||||||
 | 
					            <codemirror
 | 
				
			||||||
 | 
					                :value="contentYaml"
 | 
				
			||||||
 | 
					                border
 | 
				
			||||||
 | 
					                :options="cmOptions"
 | 
				
			||||||
 | 
					                height="500"
 | 
				
			||||||
 | 
					                style="font-size:14px;"
 | 
				
			||||||
 | 
					                @change="onChange"
 | 
				
			||||||
 | 
					            ></codemirror>
 | 
				
			||||||
 | 
					            <template #footer>
 | 
				
			||||||
 | 
					                <span class="dialog-footer">
 | 
				
			||||||
 | 
					                    <el-button @click="yamlDialog = false">取 消</el-button>
 | 
				
			||||||
 | 
					                    <el-button type="primary" @click="updatePvc()">更 新</el-button>
 | 
				
			||||||
 | 
					                </span>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					        </el-dialog>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					import common from "../common/Config";
 | 
				
			||||||
 | 
					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,
 | 
				
			||||||
 | 
					            pvcList: [],
 | 
				
			||||||
 | 
					            pvcTotal: 0,
 | 
				
			||||||
 | 
					            getPvcsData: {
 | 
				
			||||||
 | 
					                url: common.k8sPvcList,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    filter_name: '',
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    page: '',
 | 
				
			||||||
 | 
					                    limit: '',
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            pvcDetail: {},
 | 
				
			||||||
 | 
					            getPvcDetailData: {
 | 
				
			||||||
 | 
					                url: common.k8sPvcDetail,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    pvc_name: '',
 | 
				
			||||||
 | 
					                    namespace: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            yamlDialog: false,
 | 
				
			||||||
 | 
					            updatePvcData: {
 | 
				
			||||||
 | 
					                url: common.k8sPvcUpdate,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    content: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            delPvcData: {
 | 
				
			||||||
 | 
					                url: common.k8spvcDel,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    pvc_name: '',
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    methods: {
 | 
				
			||||||
 | 
					        transYaml(content) {
 | 
				
			||||||
 | 
					            return json2yaml.stringify(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        transObj(content) {
 | 
				
			||||||
 | 
					            return yaml2obj.load(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        onChange(val) {
 | 
				
			||||||
 | 
					            this.contentYaml = val
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleSizeChange(size) {
 | 
				
			||||||
 | 
					            this.pagesize = size;
 | 
				
			||||||
 | 
					            this.getPvcs()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleCurrentChange(currentPage) {
 | 
				
			||||||
 | 
					            this.currentPage = currentPage;
 | 
				
			||||||
 | 
					            this.getPvcs()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        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 
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        restartTotal(e) {
 | 
				
			||||||
 | 
					            let index, sum = 0
 | 
				
			||||||
 | 
					            let containerStatuses = e.row.status.containerStatuses
 | 
				
			||||||
 | 
					            for ( index in containerStatuses) {
 | 
				
			||||||
 | 
					                sum = sum + containerStatuses[index].restartCount 
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return sum
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getNamespaces() {
 | 
				
			||||||
 | 
					            httpClient.get(this.namespaceListUrl)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.namespaceList = res.data.items
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getPvcs() {
 | 
				
			||||||
 | 
					            this.appLoading = true
 | 
				
			||||||
 | 
					            this.getPvcsData.params.filter_name = this.searchInput
 | 
				
			||||||
 | 
					            this.getPvcsData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            this.getPvcsData.params.page = this.currentPage
 | 
				
			||||||
 | 
					            this.getPvcsData.params.limit = this.pagesize
 | 
				
			||||||
 | 
					            httpClient.get(this.getPvcsData.url, {params: this.getPvcsData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.pvcList = res.data.items
 | 
				
			||||||
 | 
					                this.pvcTotal = res.data.total
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.appLoading = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getPvcDetail(e) {
 | 
				
			||||||
 | 
					            this.getPvcDetailData.params.pvc_name = e.row.metadata.name
 | 
				
			||||||
 | 
					            this.getPvcDetailData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.get(this.getPvcDetailData.url, {params: this.getPvcDetailData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.pvcDetail = res.data
 | 
				
			||||||
 | 
					                this.contentYaml = this.transYaml(this.pvcDetail)
 | 
				
			||||||
 | 
					                this.yamlDialog = true
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        updatePvc() {
 | 
				
			||||||
 | 
					            let content = JSON.stringify(this.transObj(this.contentYaml))
 | 
				
			||||||
 | 
					            this.updatePvcData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            this.updatePvcData.params.content = content
 | 
				
			||||||
 | 
					            httpClient.put(this.updatePvcData.url, this.updatePvcData.params)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.yamlDialog = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        delPvc(e) {
 | 
				
			||||||
 | 
					            this.delPvcData.params.pvc_name = e.row.metadata.name
 | 
				
			||||||
 | 
					            this.delPvcData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.delete(this.delPvcData.url, {data: this.delPvcData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.getPvcs()
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleConfirm(obj, operateName, fn) {
 | 
				
			||||||
 | 
					            this.confirmContent = '确认继续 ' + operateName + ' 操作吗?'
 | 
				
			||||||
 | 
					            this.$confirm(this.confirmContent,'提示',{
 | 
				
			||||||
 | 
					                confirmButtonText: '确定',
 | 
				
			||||||
 | 
					                cancelButtonText: '取消',
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .then(() => {
 | 
				
			||||||
 | 
					                fn(obj)
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            .catch(() => {
 | 
				
			||||||
 | 
					                this.$message.info({
 | 
				
			||||||
 | 
					                    message: '已取消操作'
 | 
				
			||||||
 | 
					                })          
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    watch: {
 | 
				
			||||||
 | 
					        namespaceValue: {
 | 
				
			||||||
 | 
					            handler() {
 | 
				
			||||||
 | 
					                localStorage.setItem('namespace', this.namespaceValue)
 | 
				
			||||||
 | 
					                this.currentPage = 1
 | 
				
			||||||
 | 
					                this.getPvcs()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    beforeMount() {
 | 
				
			||||||
 | 
					        if (localStorage.getItem('namespace') !== undefined && localStorage.getItem('namespace') !== null) {
 | 
				
			||||||
 | 
					            this.namespaceValue = localStorage.getItem('namespace')
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.getNamespaces()
 | 
				
			||||||
 | 
					        this.getPvcs()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					    .pvc-head-card,.pvc-body-card {
 | 
				
			||||||
 | 
					        border-radius: 1px;
 | 
				
			||||||
 | 
					        margin-bottom: 5px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .pvc-head-search {
 | 
				
			||||||
 | 
					        width:160px;
 | 
				
			||||||
 | 
					        margin-right:10px; 
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .pvc-body-pvcname {
 | 
				
			||||||
 | 
					        color: #4795EE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .pvc-body-pvcname:hover {
 | 
				
			||||||
 | 
					        color: rgb(84, 138, 238);
 | 
				
			||||||
 | 
					        cursor: pointer;
 | 
				
			||||||
 | 
					        font-weight: bold;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .success-status {
 | 
				
			||||||
 | 
					        color: rgb(27, 202, 21);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .warning-status {
 | 
				
			||||||
 | 
					        color: rgb(233, 200, 16);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .error-status {
 | 
				
			||||||
 | 
					        color: rgb(226, 23, 23);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										644
									
								
								dkube-web/src/views/pod/Pod.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,644 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div class="pod">
 | 
				
			||||||
 | 
					        <el-row>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="pod-head-card" shadow="never" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                        <el-row>
 | 
				
			||||||
 | 
					                            <el-col :span="6">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <span>命名空间: </span>
 | 
				
			||||||
 | 
					                                    <el-select v-model="namespaceValue" filterable placeholder="请选择">
 | 
				
			||||||
 | 
					                                        <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>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Refresh" plain @click="getPods()">刷新</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                        </el-row>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="pod-head-card" shadow="never" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                        <el-row>
 | 
				
			||||||
 | 
					                            <el-col :span="2">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-button disabled style="border-radius:2px;" icon="Edit" type="primary">创建</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                            <el-col :span="6">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-input class="pod-head-search" clearable placeholder="请输入" v-model="searchInput"></el-input>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Search" type="primary" plain @click="getPods()">搜索</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                        </el-row>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="pod-body-card" shadow="never" :body-style="{padding:'5px'}">
 | 
				
			||||||
 | 
					                        <el-table
 | 
				
			||||||
 | 
					                        style="width:100%;font-size:12px;margin-bottom:10px;"
 | 
				
			||||||
 | 
					                        :data="podList"
 | 
				
			||||||
 | 
					                        v-loading="appLoading"
 | 
				
			||||||
 | 
					                        :row-key="getRowKeys"
 | 
				
			||||||
 | 
					                        :expand-row-keys="expandKeys"
 | 
				
			||||||
 | 
					                        @expand-change="expandChange">
 | 
				
			||||||
 | 
					                            <el-table-column width="10"></el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column type="expand">
 | 
				
			||||||
 | 
					                                <template #default="props">
 | 
				
			||||||
 | 
					                                    <el-tabs v-model="activeName" type="card">
 | 
				
			||||||
 | 
					                                        <el-tab-pane label="容器" name="container">
 | 
				
			||||||
 | 
					                                            <el-card shadow="never" style="border-radius:1px;" :body-style="{padding:'5px'}">
 | 
				
			||||||
 | 
					                                                <el-table
 | 
				
			||||||
 | 
					                                                style="width:100%;font-size:12px;"
 | 
				
			||||||
 | 
					                                                :data="props.row.spec.containers">
 | 
				
			||||||
 | 
					                                                    <el-table-column align=left prop="name" label="容器名"></el-table-column>
 | 
				
			||||||
 | 
					                                                    <el-table-column align=left prop="image" label="镜像"></el-table-column>
 | 
				
			||||||
 | 
					                                                    <el-table-column align=center label="Pod IP">
 | 
				
			||||||
 | 
					                                                        <span>{{ props.row.status.podIP }}</span>
 | 
				
			||||||
 | 
					                                                    </el-table-column>
 | 
				
			||||||
 | 
					                                                    <el-table-column align=center prop="args" label="启动命令"></el-table-column>
 | 
				
			||||||
 | 
					                                                    <el-table-column align=center label="环境变量">
 | 
				
			||||||
 | 
					                                                        <template v-slot="scope">
 | 
				
			||||||
 | 
					                                                            <el-popover :width="500" placement="left" trigger="hover">
 | 
				
			||||||
 | 
					                                                                <el-table style="width:100%;font-size:12px;" size="mini" :show-header="false" :data="scope.row.env">
 | 
				
			||||||
 | 
					                                                                    <el-table-column property="name" label="名称"></el-table-column>
 | 
				
			||||||
 | 
					                                                                    <el-table-column property="value" label="值"></el-table-column>
 | 
				
			||||||
 | 
					                                                                </el-table>
 | 
				
			||||||
 | 
					                                                                <template #reference>
 | 
				
			||||||
 | 
					                                                                <el-button size="small">此处查看</el-button>
 | 
				
			||||||
 | 
					                                                                </template>
 | 
				
			||||||
 | 
					                                                            </el-popover>
 | 
				
			||||||
 | 
					                                                        </template>
 | 
				
			||||||
 | 
					                                                    </el-table-column>
 | 
				
			||||||
 | 
					                                                </el-table>
 | 
				
			||||||
 | 
					                                            </el-card>
 | 
				
			||||||
 | 
					                                        </el-tab-pane>
 | 
				
			||||||
 | 
					                                        <el-tab-pane label="日志" name="log">
 | 
				
			||||||
 | 
					                                            <el-card shadow="never" style="border-radius:1px;" :body-style="{padding:'5px'}">
 | 
				
			||||||
 | 
					                                                <el-row :gutter="10">
 | 
				
			||||||
 | 
					                                                    <el-col :span="3">
 | 
				
			||||||
 | 
					                                                        <el-select size="small" v-model="containerValue" placeholder="请选择">
 | 
				
			||||||
 | 
					                                                            <el-option v-for="item in containerList" :key="item" :value="item">
 | 
				
			||||||
 | 
					                                                            </el-option>
 | 
				
			||||||
 | 
					                                                        </el-select>
 | 
				
			||||||
 | 
					                                                    </el-col>
 | 
				
			||||||
 | 
					                                                    <el-col :span="2">
 | 
				
			||||||
 | 
					                                                        <el-button style="border-radius:2px;" size="small" type="primary" @click="getPodLog(props.row.metadata.name)">查看</el-button>
 | 
				
			||||||
 | 
					                                                    </el-col>
 | 
				
			||||||
 | 
					                                                    <el-col :span="24" style="margin-top: 5px">
 | 
				
			||||||
 | 
					                                                        <el-card shadow="never" class="pod-body-log-card" :body-style="{padding:'5px'}">
 | 
				
			||||||
 | 
					                                                            <span class="pod-body-log-span">{{ logContent }}</span>
 | 
				
			||||||
 | 
					                                                        </el-card>
 | 
				
			||||||
 | 
					                                                    </el-col>
 | 
				
			||||||
 | 
					                                                 </el-row>
 | 
				
			||||||
 | 
					                                            </el-card>
 | 
				
			||||||
 | 
					                                        </el-tab-pane>
 | 
				
			||||||
 | 
					                                        <el-tab-pane label="终端" name="shell">
 | 
				
			||||||
 | 
					                                            <el-card shadow="never" style="border-radius:1px;" :body-style="{padding:'5px'}">
 | 
				
			||||||
 | 
					                                                <el-row :gutter="10">
 | 
				
			||||||
 | 
					                                                    <el-col :span="3">
 | 
				
			||||||
 | 
					                                                        <el-select size="small" v-model="containerValue" placeholder="请选择">
 | 
				
			||||||
 | 
					                                                            <el-option v-for="item in containerList" :key="item" :value="item">
 | 
				
			||||||
 | 
					                                                            </el-option>
 | 
				
			||||||
 | 
					                                                        </el-select>
 | 
				
			||||||
 | 
					                                                    </el-col>
 | 
				
			||||||
 | 
					                                                    <el-col :span="1">
 | 
				
			||||||
 | 
					                                                        <el-button style="border-radius:2px;" size="small" type="primary" @click="initSocket(props.row)">连接</el-button>
 | 
				
			||||||
 | 
					                                                    </el-col>
 | 
				
			||||||
 | 
					                                                    <el-col :span="1">
 | 
				
			||||||
 | 
					                                                        <el-button style="border-radius:2px;" size="small" type="danger" @click="closeSocket()">关闭</el-button>
 | 
				
			||||||
 | 
					                                                    </el-col>
 | 
				
			||||||
 | 
					                                                    <el-col :span="24" style="margin-top: 5px">
 | 
				
			||||||
 | 
					                                                        <el-card shadow="never" class="pod-body-shell-card" :body-style="{padding:'5px'}">
 | 
				
			||||||
 | 
					                                                            <div id="xterm"></div>
 | 
				
			||||||
 | 
					                                                        </el-card>
 | 
				
			||||||
 | 
					                                                    </el-col>
 | 
				
			||||||
 | 
					                                                 </el-row>
 | 
				
			||||||
 | 
					                                            </el-card>
 | 
				
			||||||
 | 
					                                        </el-tab-pane>
 | 
				
			||||||
 | 
					                                    </el-tabs>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=left label="Pod名">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <a class="pod-body-podname" @click="expandMap[scope.row.metadata.name] ? expandChange(scope.row, []) : expandChange(scope.row, [scope.row])">{{ scope.row.metadata.name }}</a>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center min-width="150" label="节点">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <el-tag v-if="scope.row.spec.nodeName !== undefined" type="warning">{{ scope.row.spec.nodeName }}</el-tag>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center label="状态">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <div :class="{'success-dot':scope.row.status.phase == 'Running', 'warning-dot':scope.row.status.phase == 'Pending', 'error-dot':scope.row.status.phase != 'Running' && scope.row.status.phase != 'Pending'}"></div>
 | 
				
			||||||
 | 
					                                    <span :class="{'success-status':scope.row.status.phase == 'Running', 'warning-status':scope.row.status.phase == 'Pending', 'error-status':scope.row.status.phase != 'Running' && scope.row.status.phase != 'Pending'}">{{ scope.row.status.phase }} </span>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center label="重启数">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <span>{{ restartTotal(scope) }} </span>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center min-width="100" label="创建时间">
 | 
				
			||||||
 | 
					                                <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="操作" width="200">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <el-button size="small" style="border-radius:2px;" icon="Edit" type="primary" plain @click="getPodDetail(scope)">YAML</el-button>
 | 
				
			||||||
 | 
					                                    <el-button size="small" style="border-radius:2px;" icon="Delete" type="danger" @click="handleConfirm(scope, '删除', delPod)">删除</el-button>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                        </el-table>
 | 
				
			||||||
 | 
					                        <el-pagination
 | 
				
			||||||
 | 
					                        class="pod-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="podTotal">
 | 
				
			||||||
 | 
					                        </el-pagination>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					        </el-row>
 | 
				
			||||||
 | 
					        <el-dialog title="YAML信息" v-model="yamlDialog" width="45%" top="5%">
 | 
				
			||||||
 | 
					            <codemirror
 | 
				
			||||||
 | 
					                :value="contentYaml"
 | 
				
			||||||
 | 
					                border
 | 
				
			||||||
 | 
					                :options="cmOptions"
 | 
				
			||||||
 | 
					                height="500"
 | 
				
			||||||
 | 
					                style="font-size:14px;"
 | 
				
			||||||
 | 
					                @change="onChange"
 | 
				
			||||||
 | 
					            ></codemirror>
 | 
				
			||||||
 | 
					            <template #footer>
 | 
				
			||||||
 | 
					                <span class="dialog-footer">
 | 
				
			||||||
 | 
					                    <el-button @click="yamlDialog = false">取 消</el-button>
 | 
				
			||||||
 | 
					                    <el-button type="primary" @click="updatePod()">更 新</el-button>
 | 
				
			||||||
 | 
					                </span>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					        </el-dialog>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					import common from "../common/Config";
 | 
				
			||||||
 | 
					import httpClient from '../../utils/request';
 | 
				
			||||||
 | 
					import { Terminal } from 'xterm';
 | 
				
			||||||
 | 
					import { FitAddon } from 'xterm-addon-fit';
 | 
				
			||||||
 | 
					import 'xterm/css/xterm.css';
 | 
				
			||||||
 | 
					import 'xterm/lib/xterm.js';
 | 
				
			||||||
 | 
					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,
 | 
				
			||||||
 | 
					            podList: [],
 | 
				
			||||||
 | 
					            podTotal: 0,
 | 
				
			||||||
 | 
					            getPodsData: {
 | 
				
			||||||
 | 
					                url: common.k8sPodList,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    filter_name: '',
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    page: '',
 | 
				
			||||||
 | 
					                    limit: '',
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            podDetail: {},
 | 
				
			||||||
 | 
					            getPodDetailData: {
 | 
				
			||||||
 | 
					                url: common.k8sPodDetail,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    pod_name: '',
 | 
				
			||||||
 | 
					                    namespace: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            yamlDialog: false,
 | 
				
			||||||
 | 
					            updatePodData: {
 | 
				
			||||||
 | 
					                url: common.k8sPodUpdate,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    content: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            delPodData: {
 | 
				
			||||||
 | 
					                url: common.k8sPodDel,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    pod_name: '',
 | 
				
			||||||
 | 
					                    namespace: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            activeName: 'container',
 | 
				
			||||||
 | 
					            expandKeys: [],
 | 
				
			||||||
 | 
					            expandMap: {},
 | 
				
			||||||
 | 
					            containerList: {},
 | 
				
			||||||
 | 
					            containerValue: '',
 | 
				
			||||||
 | 
					            getPodContainerData: {
 | 
				
			||||||
 | 
					                url: common.k8sPodContainer,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    pod_name: '',
 | 
				
			||||||
 | 
					                    namespace: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            logContent: '',
 | 
				
			||||||
 | 
					            getPodLogData: {
 | 
				
			||||||
 | 
					                url: common.k8sPodLog,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    container_name: '',
 | 
				
			||||||
 | 
					                    pod_name: '',
 | 
				
			||||||
 | 
					                    namespace: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            term: null,
 | 
				
			||||||
 | 
					            socket: null
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    methods: {
 | 
				
			||||||
 | 
					        transYaml(content) {
 | 
				
			||||||
 | 
					            return json2yaml.stringify(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        transObj(content) {
 | 
				
			||||||
 | 
					            return yaml2obj.load(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        onChange(val) {
 | 
				
			||||||
 | 
					            this.contentYaml = val
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleSizeChange(size) {
 | 
				
			||||||
 | 
					            this.pagesize = size;
 | 
				
			||||||
 | 
					            this.getPods()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleCurrentChange(currentPage) {
 | 
				
			||||||
 | 
					            this.currentPage = currentPage;
 | 
				
			||||||
 | 
					            this.getPods()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        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 
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        restartTotal(e) {
 | 
				
			||||||
 | 
					            let index, sum = 0
 | 
				
			||||||
 | 
					            let containerStatuses = e.row.status.containerStatuses
 | 
				
			||||||
 | 
					            for ( index in containerStatuses) {
 | 
				
			||||||
 | 
					                sum = sum + containerStatuses[index].restartCount 
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return sum
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getNamespaces() {
 | 
				
			||||||
 | 
					            httpClient.get(this.namespaceListUrl)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.namespaceList = res.data.items
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getPods() {
 | 
				
			||||||
 | 
					            this.appLoading = true
 | 
				
			||||||
 | 
					            this.getPodsData.params.filter_name = this.searchInput
 | 
				
			||||||
 | 
					            this.getPodsData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            this.getPodsData.params.page = this.currentPage
 | 
				
			||||||
 | 
					            this.getPodsData.params.limit = this.pagesize
 | 
				
			||||||
 | 
					            httpClient.get(this.getPodsData.url, {params: this.getPodsData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.podList = res.data.items
 | 
				
			||||||
 | 
					                this.podTotal = res.data.total
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.appLoading = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getPodDetail(e) {
 | 
				
			||||||
 | 
					            this.getPodDetailData.params.pod_name = e.row.metadata.name
 | 
				
			||||||
 | 
					            this.getPodDetailData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.get(this.getPodDetailData.url, {params: this.getPodDetailData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.podDetail = res.data
 | 
				
			||||||
 | 
					                this.contentYaml = this.transYaml(this.podDetail)
 | 
				
			||||||
 | 
					                this.yamlDialog = true
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        updatePod() {
 | 
				
			||||||
 | 
					            let content = JSON.stringify(this.transObj(this.contentYaml))
 | 
				
			||||||
 | 
					            this.updatePodData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            this.updatePodData.params.content = content
 | 
				
			||||||
 | 
					            httpClient.put(this.updatePodData.url, this.updatePodData.params)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.yamlDialog = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        delPod(e) {
 | 
				
			||||||
 | 
					            this.delPodData.params.pod_name = e.row.metadata.name
 | 
				
			||||||
 | 
					            this.delPodData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.delete(this.delPodData.url, {data: this.delPodData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.getPods()
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleConfirm(obj, operateName, fn) {
 | 
				
			||||||
 | 
					            this.confirmContent = '确认继续 ' + operateName + ' 操作吗?'
 | 
				
			||||||
 | 
					            this.$confirm(this.confirmContent,'提示',{
 | 
				
			||||||
 | 
					                confirmButtonText: '确定',
 | 
				
			||||||
 | 
					                cancelButtonText: '取消',
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .then(() => {
 | 
				
			||||||
 | 
					                fn(obj)
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            .catch(() => {
 | 
				
			||||||
 | 
					                this.$message.info({
 | 
				
			||||||
 | 
					                    message: '已取消操作'
 | 
				
			||||||
 | 
					                })          
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getRowKeys(row) {
 | 
				
			||||||
 | 
					            return row.metadata.name
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        expandChange(row, expandedRows) {
 | 
				
			||||||
 | 
					            this.expandKeys = []
 | 
				
			||||||
 | 
					            this.logContent= ''
 | 
				
			||||||
 | 
					            this.containerValue = ''
 | 
				
			||||||
 | 
					            this.activeName = 'container'
 | 
				
			||||||
 | 
					            if (expandedRows.length > 0) {
 | 
				
			||||||
 | 
					                this.expandMap[row.metadata.name] = 1
 | 
				
			||||||
 | 
					                this.setExpandMap(row.metadata.name)
 | 
				
			||||||
 | 
					                row ? (this.expandKeys.push(row.metadata.name), this. getPodContainer(row)) : ''
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                this.expandMap[row.metadata.name] = 0
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        setExpandMap(podName) {
 | 
				
			||||||
 | 
					            let key
 | 
				
			||||||
 | 
					            for ( key in this.expandMap ) {
 | 
				
			||||||
 | 
					                key !== podName ? this.expandMap[key] = 0 : ''
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getPodContainer(row) {
 | 
				
			||||||
 | 
					            this.getPodContainerData.params.pod_name = row.metadata.name
 | 
				
			||||||
 | 
					            this.getPodContainerData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.get(this.getPodContainerData.url, {params: this.getPodContainerData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.containerList = res.data
 | 
				
			||||||
 | 
					                this.containerValue = this.containerList[0]
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getPodLog(podName) {
 | 
				
			||||||
 | 
					            this.getPodLogData.params.pod_name = podName
 | 
				
			||||||
 | 
					            this.getPodLogData.params.container_name = this.containerValue
 | 
				
			||||||
 | 
					            this.getPodLogData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.get(this.getPodLogData.url, {params: this.getPodLogData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.logContent = res.data
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        initTerm() {
 | 
				
			||||||
 | 
					            this.term = new Terminal({
 | 
				
			||||||
 | 
					                rendererType: 'canvas',
 | 
				
			||||||
 | 
					                rows: 30,
 | 
				
			||||||
 | 
					                cols: 110,
 | 
				
			||||||
 | 
					                convertEol: false, 
 | 
				
			||||||
 | 
					                scrollback: 10,
 | 
				
			||||||
 | 
					                disableStdin: false,
 | 
				
			||||||
 | 
					                cursorStyle: 'underline', 
 | 
				
			||||||
 | 
					                cursorBlink: true,
 | 
				
			||||||
 | 
					                theme: {
 | 
				
			||||||
 | 
					                foreground: 'white',
 | 
				
			||||||
 | 
					                background: '#060101',
 | 
				
			||||||
 | 
					                cursor: 'help'
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            this.term.open(document.getElementById('xterm'))
 | 
				
			||||||
 | 
					            const fitAddon = new FitAddon()
 | 
				
			||||||
 | 
					            this.term.loadAddon(fitAddon)
 | 
				
			||||||
 | 
					            fitAddon.fit();
 | 
				
			||||||
 | 
					            this.term.focus();
 | 
				
			||||||
 | 
					            let _this = this;
 | 
				
			||||||
 | 
					            this.term.onData(function (key) {
 | 
				
			||||||
 | 
					                let msgOrder = {
 | 
				
			||||||
 | 
					                operation: 'stdin',
 | 
				
			||||||
 | 
					                data: key,
 | 
				
			||||||
 | 
					                };
 | 
				
			||||||
 | 
					                _this.socket.send(JSON.stringify(msgOrder));
 | 
				
			||||||
 | 
					            });
 | 
				
			||||||
 | 
					            let msgOrder2 = {
 | 
				
			||||||
 | 
					                operation: 'resize',
 | 
				
			||||||
 | 
					                cols: this.term.cols,
 | 
				
			||||||
 | 
					                rows: this.term.rows,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					            this.socket.send(JSON.stringify(msgOrder2))
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        initSocket(row) {
 | 
				
			||||||
 | 
					            let terminalWsUrl = common.k8sTerminalWs + "?pod_name=" + row.metadata.name + "&container_name=" + this.containerValue + "&namespace=" + this.namespaceValue
 | 
				
			||||||
 | 
					            this.socket = new WebSocket(terminalWsUrl);
 | 
				
			||||||
 | 
					            this.socketOnClose();
 | 
				
			||||||
 | 
					            this.socketOnOpen();
 | 
				
			||||||
 | 
					            this.socketOnMessage();
 | 
				
			||||||
 | 
					            this.socketOnError();
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        socketOnOpen() {
 | 
				
			||||||
 | 
					            this.socket.onopen = () => {
 | 
				
			||||||
 | 
					                this.initTerm()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        socketOnMessage() {
 | 
				
			||||||
 | 
					            this.socket.onmessage = (msg) => {
 | 
				
			||||||
 | 
					                let content = JSON.parse(msg.data)
 | 
				
			||||||
 | 
					                this.term.write(content.data)
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        socketOnClose() {
 | 
				
			||||||
 | 
					            this.socket.onclose = () => {
 | 
				
			||||||
 | 
					                this.term.write("链接已关闭")
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        socketOnError() {
 | 
				
			||||||
 | 
					            this.socket.onerror = () => {
 | 
				
			||||||
 | 
					                console.log('socket 链接失败')
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        closeSocket() {
 | 
				
			||||||
 | 
					            if (this.socket === null) {
 | 
				
			||||||
 | 
					                    return 
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            this.term.write("链接关闭中。。。")
 | 
				
			||||||
 | 
					            this.socket.close()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    watch: {
 | 
				
			||||||
 | 
					        namespaceValue: {
 | 
				
			||||||
 | 
					            handler() {
 | 
				
			||||||
 | 
					                localStorage.setItem('namespace', this.namespaceValue)
 | 
				
			||||||
 | 
					                this.currentPage = 1
 | 
				
			||||||
 | 
					                this.getPods()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        activeName: {
 | 
				
			||||||
 | 
					            handler() {
 | 
				
			||||||
 | 
					                if ( this.activeName == 'log' ) {
 | 
				
			||||||
 | 
					                    this.expandKeys.length == 1 ? this.getPodLog(this.expandKeys[0]) : ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    beforeMount() {
 | 
				
			||||||
 | 
					        if (localStorage.getItem('namespace') !== undefined && localStorage.getItem('namespace') !== null) {
 | 
				
			||||||
 | 
					            this.namespaceValue = localStorage.getItem('namespace')
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.getNamespaces()
 | 
				
			||||||
 | 
					        this.getPods()
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    beforeUnmount() {
 | 
				
			||||||
 | 
					        if ( this.socket !== null ) {
 | 
				
			||||||
 | 
					            this.socket.close()
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					    .pod-head-card,.pod-body-card {
 | 
				
			||||||
 | 
					        border-radius: 1px;
 | 
				
			||||||
 | 
					        margin-bottom: 5px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .pod-head-search {
 | 
				
			||||||
 | 
					        width:160px;
 | 
				
			||||||
 | 
					        margin-right:10px; 
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .pod-body-podname {
 | 
				
			||||||
 | 
					        color: #4795EE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .pod-body-podname:hover {
 | 
				
			||||||
 | 
					        color: rgb(84, 138, 238);
 | 
				
			||||||
 | 
					        cursor: pointer;
 | 
				
			||||||
 | 
					        font-weight: bold;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .success-dot{
 | 
				
			||||||
 | 
					        display:inline-block;
 | 
				
			||||||
 | 
					        width: 7px;
 | 
				
			||||||
 | 
					        height:7px;
 | 
				
			||||||
 | 
					        background: rgb(27, 202, 21);
 | 
				
			||||||
 | 
					        border-radius:50%;
 | 
				
			||||||
 | 
					        border:1px solid rgb(27, 202, 21);
 | 
				
			||||||
 | 
					        margin-right: 10px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .warning-dot{
 | 
				
			||||||
 | 
					        display:inline-block;
 | 
				
			||||||
 | 
					        width: 7px;
 | 
				
			||||||
 | 
					        height:7px;
 | 
				
			||||||
 | 
					        background: rgb(233, 200, 16);
 | 
				
			||||||
 | 
					        border-radius:50%;
 | 
				
			||||||
 | 
					        border:1px solid rgb(233, 200, 16);
 | 
				
			||||||
 | 
					        margin-right: 10px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .error-dot{
 | 
				
			||||||
 | 
					        display:inline-block;
 | 
				
			||||||
 | 
					        width: 7px;
 | 
				
			||||||
 | 
					        height:7px;
 | 
				
			||||||
 | 
					        background: rgb(226, 23, 23);
 | 
				
			||||||
 | 
					        border-radius:50%;
 | 
				
			||||||
 | 
					        border:1px solid rgb(226, 23, 23);
 | 
				
			||||||
 | 
					        margin-right: 10px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .success-status {
 | 
				
			||||||
 | 
					        color: rgb(27, 202, 21);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .warning-status {
 | 
				
			||||||
 | 
					        color: rgb(233, 200, 16);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .error-status {
 | 
				
			||||||
 | 
					        color: rgb(226, 23, 23);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    :v-deep .el-tabs__item {
 | 
				
			||||||
 | 
					        font-size: 12px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    :v-deep .el-tabs__header {
 | 
				
			||||||
 | 
					        margin-bottom: 8px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .pod-body-log-card, .pod-body-shell-card {
 | 
				
			||||||
 | 
					        border-radius:1px;
 | 
				
			||||||
 | 
					        height:600px;
 | 
				
			||||||
 | 
					        overflow:auto;
 | 
				
			||||||
 | 
					        background-color: #060101;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .pod-body-log-card {
 | 
				
			||||||
 | 
					        color: aliceblue;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .pod-body-log-span {
 | 
				
			||||||
 | 
					        white-space:pre;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										367
									
								
								dkube-web/src/views/secret/Secret.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,367 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div class="secret">
 | 
				
			||||||
 | 
					        <el-row>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="secret-head-card" shadow="never" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                        <el-row>
 | 
				
			||||||
 | 
					                            <el-col :span="6">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <span>命名空间: </span>
 | 
				
			||||||
 | 
					                                    <el-select v-model="namespaceValue" filterable placeholder="请选择">
 | 
				
			||||||
 | 
					                                        <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>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Refresh" plain @click="getSecrets()">刷新</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                        </el-row>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="secret-head-card" shadow="never" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                        <el-row>
 | 
				
			||||||
 | 
					                            <el-col :span="2">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-button disabled style="border-radius:2px;" icon="Edit" type="primary">创建</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                            <el-col :span="6">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-input class="secret-head-search" clearable placeholder="请输入" v-model="searchInput"></el-input>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Search" type="primary" plain @click="getSecrets()">搜索</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                        </el-row>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="secret-body-card" shadow="never" :body-style="{padding:'5px'}">
 | 
				
			||||||
 | 
					                        <el-table
 | 
				
			||||||
 | 
					                        style="width:100%;font-size:12px;margin-bottom:10px;"
 | 
				
			||||||
 | 
					                        :data="secretList"
 | 
				
			||||||
 | 
					                        v-loading="appLoading">
 | 
				
			||||||
 | 
					                            <el-table-column width="20"></el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=left label="Secret名">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <a class="secret-body-secretname">{{ scope.row.metadata.name }}</a>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center label="标签">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <div v-for="(val, key) in scope.row.metadata.labels" :key="key">
 | 
				
			||||||
 | 
					                                        <el-popover
 | 
				
			||||||
 | 
					                                            placement="right"
 | 
				
			||||||
 | 
					                                            :width="200"
 | 
				
			||||||
 | 
					                                            trigger="hover"
 | 
				
			||||||
 | 
					                                            :content="key + ':' + val">
 | 
				
			||||||
 | 
					                                            <template #reference>
 | 
				
			||||||
 | 
					                                                <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="DATA">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                        <el-popover
 | 
				
			||||||
 | 
					                                            style="overflow:auto"
 | 
				
			||||||
 | 
					                                            placement="right"
 | 
				
			||||||
 | 
					                                            :width="400"
 | 
				
			||||||
 | 
					                                            trigger="click">
 | 
				
			||||||
 | 
					                                            <div style="overflow-y:auto;max-height:500px;">
 | 
				
			||||||
 | 
					                                                <span>{{ scope.row.data }}</span>
 | 
				
			||||||
 | 
					                                            </div>
 | 
				
			||||||
 | 
					                                            <template #reference>
 | 
				
			||||||
 | 
					                                                <el-icon style="font-size:18px;cursor:pointer;"><reading/></el-icon>
 | 
				
			||||||
 | 
					                                            </template>
 | 
				
			||||||
 | 
					                                        </el-popover>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center prop="type" min-width="100" label="类型">
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center min-width="100" label="创建时间">
 | 
				
			||||||
 | 
					                                <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="操作" width="200">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <el-button size="small" style="border-radius:2px;" icon="Edit" type="primary" plain @click="getSecretDetail(scope)">YAML</el-button>
 | 
				
			||||||
 | 
					                                    <el-button size="small" style="border-radius:2px;" icon="Delete" type="danger" @click="handleConfirm(scope, '删除', delSecret)">删除</el-button>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                        </el-table>
 | 
				
			||||||
 | 
					                        <el-pagination
 | 
				
			||||||
 | 
					                        class="secret-body-pagination"
 | 
				
			||||||
 | 
					                        background
 | 
				
			||||||
 | 
					                        @size-change="handleSizeChange"
 | 
				
			||||||
 | 
					                        @current-change="handleCurrentChange"
 | 
				
			||||||
 | 
					                        :current-page="currentPage"
 | 
				
			||||||
 | 
					                        :page-sizes="pagesizeList"
 | 
				
			||||||
 | 
					                        layout="total, sizes, prev, pager, next, jumper"
 | 
				
			||||||
 | 
					                        :prev-click="getSecrets"
 | 
				
			||||||
 | 
					                        :total="secretTotal">
 | 
				
			||||||
 | 
					                        </el-pagination>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					        </el-row>
 | 
				
			||||||
 | 
					        <el-dialog title="YAML信息" v-model="yamlDialog" width="45%" top="5%">
 | 
				
			||||||
 | 
					            <codemirror
 | 
				
			||||||
 | 
					                :value="contentYaml"
 | 
				
			||||||
 | 
					                border
 | 
				
			||||||
 | 
					                :options="cmOptions"
 | 
				
			||||||
 | 
					                height="500"
 | 
				
			||||||
 | 
					                style="font-size:14px;"
 | 
				
			||||||
 | 
					                @change="onChange"
 | 
				
			||||||
 | 
					            ></codemirror>
 | 
				
			||||||
 | 
					            <template #footer>
 | 
				
			||||||
 | 
					                <span class="dialog-footer">
 | 
				
			||||||
 | 
					                    <el-button @click="yamlDialog = false">取 消</el-button>
 | 
				
			||||||
 | 
					                    <el-button type="primary" @click="updateSecret()">更 新</el-button>
 | 
				
			||||||
 | 
					                </span>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					        </el-dialog>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					import common from "../common/Config";
 | 
				
			||||||
 | 
					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,
 | 
				
			||||||
 | 
					            secretList: [],
 | 
				
			||||||
 | 
					            secretTotal: 0,
 | 
				
			||||||
 | 
					            getSecretsData: {
 | 
				
			||||||
 | 
					                url: common.k8sSecretList,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    filter_name: '',
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    page: '',
 | 
				
			||||||
 | 
					                    limit: '',
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            secretDetail: {},
 | 
				
			||||||
 | 
					            getSecretDetailData: {
 | 
				
			||||||
 | 
					                url: common.k8sSecretDetail,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    secret_name: '',
 | 
				
			||||||
 | 
					                    namespace: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            yamlDialog: false,
 | 
				
			||||||
 | 
					            updateSecretData: {
 | 
				
			||||||
 | 
					                url: common.k8sSecretUpdate,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    content: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            delSecretData: {
 | 
				
			||||||
 | 
					                url: common.k8ssecretDel,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    secret_name: '',
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    methods: {
 | 
				
			||||||
 | 
					        transYaml(content) {
 | 
				
			||||||
 | 
					            return json2yaml.stringify(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        transObj(content) {
 | 
				
			||||||
 | 
					            return yaml2obj.load(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        onChange(val) {
 | 
				
			||||||
 | 
					            this.contentYaml = val
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleSizeChange(size) {
 | 
				
			||||||
 | 
					            this.pagesize = size;
 | 
				
			||||||
 | 
					            this.getSecrets()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleCurrentChange(currentPage) {
 | 
				
			||||||
 | 
					            this.currentPage = currentPage;
 | 
				
			||||||
 | 
					            this.getSecrets()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        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 
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        restartTotal(e) {
 | 
				
			||||||
 | 
					            let index, sum = 0
 | 
				
			||||||
 | 
					            let containerStatuses = e.row.status.containerStatuses
 | 
				
			||||||
 | 
					            for ( index in containerStatuses) {
 | 
				
			||||||
 | 
					                sum = sum + containerStatuses[index].restartCount 
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return sum
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getNamespaces() {
 | 
				
			||||||
 | 
					            httpClient.get(this.namespaceListUrl)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.namespaceList = res.data.items
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getSecrets() {
 | 
				
			||||||
 | 
					            this.appLoading = true
 | 
				
			||||||
 | 
					            this.getSecretsData.params.filter_name = this.searchInput
 | 
				
			||||||
 | 
					            this.getSecretsData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            this.getSecretsData.params.page = this.currentPage
 | 
				
			||||||
 | 
					            this.getSecretsData.params.limit = this.pagesize
 | 
				
			||||||
 | 
					            httpClient.get(this.getSecretsData.url, {params: this.getSecretsData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.secretList = res.data.items
 | 
				
			||||||
 | 
					                this.secretTotal = res.data.total
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.appLoading = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getSecretDetail(e) {
 | 
				
			||||||
 | 
					            this.getSecretDetailData.params.secret_name = e.row.metadata.name
 | 
				
			||||||
 | 
					            this.getSecretDetailData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.get(this.getSecretDetailData.url, {params: this.getSecretDetailData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.secretDetail = res.data
 | 
				
			||||||
 | 
					                this.contentYaml = this.transYaml(this.secretDetail)
 | 
				
			||||||
 | 
					                this.yamlDialog = true
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        updateSecret() {
 | 
				
			||||||
 | 
					            let content = JSON.stringify(this.transObj(this.contentYaml))
 | 
				
			||||||
 | 
					            this.updateSecretData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            this.updateSecretData.params.content = content
 | 
				
			||||||
 | 
					            httpClient.put(this.updateSecretData.url, this.updateSecretData.params)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.yamlDialog = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        delSecret(e) {
 | 
				
			||||||
 | 
					            this.delSecretData.params.secret_name = e.row.metadata.name
 | 
				
			||||||
 | 
					            this.delSecretData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.delete(this.delSecretData.url, {data: this.delSecretData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.getSecrets()
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleConfirm(obj, operateName, fn) {
 | 
				
			||||||
 | 
					            this.confirmContent = '确认继续 ' + operateName + ' 操作吗?'
 | 
				
			||||||
 | 
					            this.$confirm(this.confirmContent,'提示',{
 | 
				
			||||||
 | 
					                confirmButtonText: '确定',
 | 
				
			||||||
 | 
					                cancelButtonText: '取消',
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .then(() => {
 | 
				
			||||||
 | 
					                fn(obj)
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            .catch(() => {
 | 
				
			||||||
 | 
					                this.$message.info({
 | 
				
			||||||
 | 
					                    message: '已取消操作'
 | 
				
			||||||
 | 
					                })          
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    watch: {
 | 
				
			||||||
 | 
					        namespaceValue: {
 | 
				
			||||||
 | 
					            handler() {
 | 
				
			||||||
 | 
					                localStorage.setItem('namespace', this.namespaceValue)
 | 
				
			||||||
 | 
					                this.currentPage = 1
 | 
				
			||||||
 | 
					                this.getSecrets()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    beforeMount() {
 | 
				
			||||||
 | 
					        if (localStorage.getItem('namespace') !== undefined && localStorage.getItem('namespace') !== null) {
 | 
				
			||||||
 | 
					            this.namespaceValue = localStorage.getItem('namespace')
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.getNamespaces()
 | 
				
			||||||
 | 
					        this.getSecrets()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					    .secret-head-card,.secret-body-card {
 | 
				
			||||||
 | 
					        border-radius: 1px;
 | 
				
			||||||
 | 
					        margin-bottom: 5px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .secret-head-search {
 | 
				
			||||||
 | 
					        width:160px;
 | 
				
			||||||
 | 
					        margin-right:10px; 
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .secret-body-secretname {
 | 
				
			||||||
 | 
					        color: #4795EE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .secret-body-secretname:hover {
 | 
				
			||||||
 | 
					        color: rgb(84, 138, 238);
 | 
				
			||||||
 | 
					        cursor: pointer;
 | 
				
			||||||
 | 
					        font-weight: bold;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										518
									
								
								dkube-web/src/views/service/Service.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,518 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div class="service">
 | 
				
			||||||
 | 
					        <el-row>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="service-head-card" shadow="never" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                        <el-row>
 | 
				
			||||||
 | 
					                            <el-col :span="6">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <span>命名空间: </span>
 | 
				
			||||||
 | 
					                                    <el-select v-model="namespaceValue" filterable placeholder="请选择">
 | 
				
			||||||
 | 
					                                        <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>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Refresh" plain @click="getServices()">刷新</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                        </el-row>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="service-head-card" shadow="never" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                        <el-row>
 | 
				
			||||||
 | 
					                            <el-col :span="2">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Edit" type="primary" @click="createServiceDrawer = true" v-loading.fullscreen.lock="fullscreenLoading">创建</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                            <el-col :span="6">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-input class="service-head-search" clearable placeholder="请输入" v-model="searchInput"></el-input>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Search" type="primary" plain @click="getServices()">搜索</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                        </el-row>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="service-body-card" shadow="never" :body-style="{padding:'5px'}">
 | 
				
			||||||
 | 
					                        <el-table
 | 
				
			||||||
 | 
					                        style="width:100%;font-size:12px;margin-bottom:10px;"
 | 
				
			||||||
 | 
					                        :data="serviceList"
 | 
				
			||||||
 | 
					                        v-loading="appLoading">
 | 
				
			||||||
 | 
					                            <el-table-column width="20"></el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=left label="Service名">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <a class="service-body-servicename">{{ scope.row.metadata.name }}</a>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center label="标签" min-width='120'>
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <div v-for="(val, key) in scope.row.metadata.labels" :key="key">
 | 
				
			||||||
 | 
					                                        <el-popover
 | 
				
			||||||
 | 
					                                            placement="right"
 | 
				
			||||||
 | 
					                                            :width="200"
 | 
				
			||||||
 | 
					                                            trigger="hover"
 | 
				
			||||||
 | 
					                                            :content="key + ':' + val">
 | 
				
			||||||
 | 
					                                            <template #reference>
 | 
				
			||||||
 | 
					                                                <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="类型">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <span style="font-weight:bold;">{{ scope.row.spec.type }} </span>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center label="CLUSTER-IP">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <span>{{ scope.row.spec.clusterIP }} </span>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center label="EXTERNAL-IP">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <span>{{ scope.row.status.loadBalancer.ingress ? scope.row.status.loadBalancer.ingress[0].ip : '' }} </span>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center label="端口">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <span v-if="!scope.row.spec.ports[0].nodePort">{{ scope.row.spec.ports[0].port }}/{{ scope.row.spec.ports[0].protocol }}</span>
 | 
				
			||||||
 | 
					                                    <span v-if="scope.row.spec.ports[0].nodePort">{{ scope.row.spec.ports[0].port }}:{{ scope.row.spec.ports[0].nodePort }}/{{ scope.row.spec.ports[0].protocol }}</span>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center min-width="100" label="创建时间">
 | 
				
			||||||
 | 
					                                <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="操作" width="200">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <el-button size="small" style="border-radius:2px;" icon="Edit" type="primary" plain @click="getServiceDetail(scope)">YAML</el-button>
 | 
				
			||||||
 | 
					                                    <el-button size="small" style="border-radius:2px;" icon="Delete" type="danger" @click="handleConfirm(scope, '删除', delService)">删除</el-button>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                        </el-table>
 | 
				
			||||||
 | 
					                        <el-pagination
 | 
				
			||||||
 | 
					                        class="service-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="serviceTotal">
 | 
				
			||||||
 | 
					                        </el-pagination>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					        </el-row>
 | 
				
			||||||
 | 
					        <el-dialog title="YAML信息" v-model="yamlDialog" width="45%" top="5%">
 | 
				
			||||||
 | 
					            <codemirror
 | 
				
			||||||
 | 
					                :value="contentYaml"
 | 
				
			||||||
 | 
					                border
 | 
				
			||||||
 | 
					                :options="cmOptions"
 | 
				
			||||||
 | 
					                height="500"
 | 
				
			||||||
 | 
					                style="font-size:14px;"
 | 
				
			||||||
 | 
					                @change="onChange"
 | 
				
			||||||
 | 
					            ></codemirror>
 | 
				
			||||||
 | 
					            <template #footer>
 | 
				
			||||||
 | 
					                <span class="dialog-footer">
 | 
				
			||||||
 | 
					                    <el-button @click="yamlDialog = false">取 消</el-button>
 | 
				
			||||||
 | 
					                    <el-button type="primary" @click="updateService()">更 新</el-button>
 | 
				
			||||||
 | 
					                </span>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					        </el-dialog>
 | 
				
			||||||
 | 
					        <el-drawer
 | 
				
			||||||
 | 
					            v-model="createServiceDrawer"
 | 
				
			||||||
 | 
					            :direction="direction"
 | 
				
			||||||
 | 
					            :before-close="handleClose">
 | 
				
			||||||
 | 
					            <template #title>
 | 
				
			||||||
 | 
					                <h4>创建Service</h4>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					            <template #default>
 | 
				
			||||||
 | 
					                <el-row type="flex" justify="center">
 | 
				
			||||||
 | 
					                    <el-col :span="20">
 | 
				
			||||||
 | 
					                        <el-form ref="createService" :rules="createServiceRules" :model="createService" label-width="80px">
 | 
				
			||||||
 | 
					                            <el-form-item class="service-create-form" label="名称" prop="name">
 | 
				
			||||||
 | 
					                                <el-input v-model="createService.name"></el-input>
 | 
				
			||||||
 | 
					                            </el-form-item>
 | 
				
			||||||
 | 
					                            <el-form-item class="service-create-form" label="命名空间" prop="namespace">
 | 
				
			||||||
 | 
					                                <el-select v-model="createService.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>
 | 
				
			||||||
 | 
					                            <el-form-item class="service-create-form" label="类型" prop="type">
 | 
				
			||||||
 | 
					                                <el-select v-model="createService.type" placeholder="请选择">
 | 
				
			||||||
 | 
					                                    <el-option value="ClusterIP" label="ClusterIP"></el-option>
 | 
				
			||||||
 | 
					                                    <el-option value="NodePort" label="NodePort"></el-option>
 | 
				
			||||||
 | 
					                                </el-select>
 | 
				
			||||||
 | 
					                            </el-form-item>
 | 
				
			||||||
 | 
					                            <el-form-item class="deploy-create-form" label="容器端口" prop="container_port">
 | 
				
			||||||
 | 
					                                <el-input v-model="createService.container_port" placeholder="示例: 80"></el-input>
 | 
				
			||||||
 | 
					                            </el-form-item>
 | 
				
			||||||
 | 
					                            <el-form-item class="service-create-form" label="Service端口" prop="port">
 | 
				
			||||||
 | 
					                                <el-input v-model="createService.port" placeholder="示例: 80"></el-input>
 | 
				
			||||||
 | 
					                            </el-form-item>
 | 
				
			||||||
 | 
					                            <el-form-item v-if="createService.type == 'NodePort'" class="service-create-form" label="NodePort" prop="node_port">
 | 
				
			||||||
 | 
					                                <el-input v-model="createService.node_port" placeholder="示例: 30001"></el-input>
 | 
				
			||||||
 | 
					                            </el-form-item>
 | 
				
			||||||
 | 
					                            <el-form-item class="SERVICE-create-form" label="标签" prop="label_str">
 | 
				
			||||||
 | 
					                                <el-input v-model="createService.label_str" placeholder="示例: project=ms,app=gateway"></el-input>
 | 
				
			||||||
 | 
					                            </el-form-item>
 | 
				
			||||||
 | 
					                        </el-form>
 | 
				
			||||||
 | 
					                    </el-col>
 | 
				
			||||||
 | 
					                </el-row>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					            <template #footer>
 | 
				
			||||||
 | 
					                <el-button @click="createServiceDrawer = false">取消</el-button>
 | 
				
			||||||
 | 
					                <el-button type="primary" @click="submitForm('createService')">立即创建</el-button>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					        </el-drawer>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					import common from "../common/Config";
 | 
				
			||||||
 | 
					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,
 | 
				
			||||||
 | 
					            serviceList: [],
 | 
				
			||||||
 | 
					            serviceTotal: 0,
 | 
				
			||||||
 | 
					            getServicesData: {
 | 
				
			||||||
 | 
					                url: common.k8sServiceList,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    filter_name: '',
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    page: '',
 | 
				
			||||||
 | 
					                    limit: '',
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            serviceDetail: {},
 | 
				
			||||||
 | 
					            getServiceDetailData: {
 | 
				
			||||||
 | 
					                url: common.k8sServiceDetail,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    service_name: '',
 | 
				
			||||||
 | 
					                    namespace: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            yamlDialog: false,
 | 
				
			||||||
 | 
					            updateServiceData: {
 | 
				
			||||||
 | 
					                url: common.k8sServiceUpdate,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    content: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            delServiceData: {
 | 
				
			||||||
 | 
					                url: common.k8sServiceDel,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    service_name: '',
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            fullscreenLoading: false,
 | 
				
			||||||
 | 
					            direction: 'rtl',
 | 
				
			||||||
 | 
					            createServiceDrawer: false,
 | 
				
			||||||
 | 
					            createService: {
 | 
				
			||||||
 | 
					                name: '',
 | 
				
			||||||
 | 
					                namespace: '',
 | 
				
			||||||
 | 
					                type: 'ClusterIP',
 | 
				
			||||||
 | 
					                container_port: '',
 | 
				
			||||||
 | 
					                port: '',
 | 
				
			||||||
 | 
					                node_port: '',
 | 
				
			||||||
 | 
					                label: {},
 | 
				
			||||||
 | 
					                label_str: ''
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            createServiceData: {
 | 
				
			||||||
 | 
					                url: common.k8sServiceCreate,
 | 
				
			||||||
 | 
					                params: {}
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            createServiceRules: {
 | 
				
			||||||
 | 
					                name: [{
 | 
				
			||||||
 | 
					                    required: true,
 | 
				
			||||||
 | 
					                    message: '请填写名称',
 | 
				
			||||||
 | 
					                    trigger: 'change'
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					                namespace: [{
 | 
				
			||||||
 | 
					                    required: true,
 | 
				
			||||||
 | 
					                    message: '请选择命名空间',
 | 
				
			||||||
 | 
					                    trigger: 'change'
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					                port: [{
 | 
				
			||||||
 | 
					                    required: true,
 | 
				
			||||||
 | 
					                    message: '请填写Service端口',
 | 
				
			||||||
 | 
					                    trigger: 'change'
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					                node_port: [{
 | 
				
			||||||
 | 
					                    required: true,
 | 
				
			||||||
 | 
					                    message: '请填写NodePort',
 | 
				
			||||||
 | 
					                    trigger: 'change'
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					                label_str: [{
 | 
				
			||||||
 | 
					                    required: true,
 | 
				
			||||||
 | 
					                    message: '请填写标签',
 | 
				
			||||||
 | 
					                    trigger: 'change'
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					                container_port: [{
 | 
				
			||||||
 | 
					                    required: true,
 | 
				
			||||||
 | 
					                    message: '请填写容器端口',
 | 
				
			||||||
 | 
					                    trigger: 'change'
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    methods: {
 | 
				
			||||||
 | 
					        transYaml(content) {
 | 
				
			||||||
 | 
					            return json2yaml.stringify(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        transObj(content) {
 | 
				
			||||||
 | 
					            return yaml2obj.load(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        onChange(val) {
 | 
				
			||||||
 | 
					            this.contentYaml = val
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleSizeChange(size) {
 | 
				
			||||||
 | 
					            this.pagesize = size;
 | 
				
			||||||
 | 
					            this.getServices()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleCurrentChange(currentPage) {
 | 
				
			||||||
 | 
					            this.currentPage = currentPage;
 | 
				
			||||||
 | 
					            this.getServices()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        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 
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        restartTotal(e) {
 | 
				
			||||||
 | 
					            let index, sum = 0
 | 
				
			||||||
 | 
					            let containerStatuses = e.row.status.containerStatuses
 | 
				
			||||||
 | 
					            for ( index in containerStatuses) {
 | 
				
			||||||
 | 
					                sum = sum + containerStatuses[index].restartCount 
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return sum
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getNamespaces() {
 | 
				
			||||||
 | 
					            httpClient.get(this.namespaceListUrl)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.namespaceList = res.data.items
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getServices() {
 | 
				
			||||||
 | 
					            this.appLoading = true
 | 
				
			||||||
 | 
					            this.getServicesData.params.filter_name = this.searchInput
 | 
				
			||||||
 | 
					            this.getServicesData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            this.getServicesData.params.page = this.currentPage
 | 
				
			||||||
 | 
					            this.getServicesData.params.limit = this.pagesize
 | 
				
			||||||
 | 
					            httpClient.get(this.getServicesData.url, {params: this.getServicesData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.serviceList = res.data.items
 | 
				
			||||||
 | 
					                this.serviceTotal = res.data.total
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.appLoading = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getServiceDetail(e) {
 | 
				
			||||||
 | 
					            this.getServiceDetailData.params.service_name = e.row.metadata.name
 | 
				
			||||||
 | 
					            this.getServiceDetailData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.get(this.getServiceDetailData.url, {params: this.getServiceDetailData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.serviceDetail = res.data
 | 
				
			||||||
 | 
					                this.contentYaml = this.transYaml(this.serviceDetail)
 | 
				
			||||||
 | 
					                this.yamlDialog = true
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        updateService() {
 | 
				
			||||||
 | 
					            let content = JSON.stringify(this.transObj(this.contentYaml))
 | 
				
			||||||
 | 
					            this.updateServiceData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            this.updateServiceData.params.content = content
 | 
				
			||||||
 | 
					            httpClient.put(this.updateServiceData.url, this.updateServiceData.params)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.yamlDialog = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        delService(e) {
 | 
				
			||||||
 | 
					            this.delServiceData.params.service_name = e.row.metadata.name
 | 
				
			||||||
 | 
					            this.delServiceData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.delete(this.delServiceData.url, {data: this.delServiceData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.getServices()
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleConfirm(obj, operateName, fn) {
 | 
				
			||||||
 | 
					            this.confirmContent = '确认继续 ' + operateName + ' 操作吗?'
 | 
				
			||||||
 | 
					            this.$confirm(this.confirmContent,'提示',{
 | 
				
			||||||
 | 
					                confirmButtonText: '确定',
 | 
				
			||||||
 | 
					                cancelButtonText: '取消',
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .then(() => {
 | 
				
			||||||
 | 
					                fn(obj)
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            .catch(() => {
 | 
				
			||||||
 | 
					                this.$message.info({
 | 
				
			||||||
 | 
					                    message: '已取消操作'
 | 
				
			||||||
 | 
					                })          
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        createServiceFunc() {
 | 
				
			||||||
 | 
					            let reg = new RegExp("(^[A-Za-z]+=[A-Za-z0-9]+).*")
 | 
				
			||||||
 | 
					            if (!reg.test(this.createService.label_str)) {
 | 
				
			||||||
 | 
					                this.$message.warning({
 | 
				
			||||||
 | 
					                    message: "标签填写异常,请确认后重新填写"
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            this.fullscreenLoading = true
 | 
				
			||||||
 | 
					            let label = new Map()
 | 
				
			||||||
 | 
					            let a = (this.createService.label_str).split(",")
 | 
				
			||||||
 | 
					            a.forEach(item => {
 | 
				
			||||||
 | 
					                let b = item.split("=")
 | 
				
			||||||
 | 
					                label[b[0]] = b[1]
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.createServiceData.params = this.createService
 | 
				
			||||||
 | 
					            this.createServiceData.params.label = label
 | 
				
			||||||
 | 
					            this.createServiceData.params.container_port = parseInt(this.createService.container_port)
 | 
				
			||||||
 | 
					            this.createServiceData.params.port = parseInt(this.createService.port)
 | 
				
			||||||
 | 
					            this.createServiceData.params.node_port = parseInt(this.createService.node_port)
 | 
				
			||||||
 | 
					            httpClient.post(this.createServiceData.url, this.createServiceData.params)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                this.getServices()
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.resetForm('createService')
 | 
				
			||||||
 | 
					            this.fullscreenLoading = false
 | 
				
			||||||
 | 
					            this.createServiceDrawer = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        resetForm(formName) {
 | 
				
			||||||
 | 
					            this.$refs[formName].resetFields()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        submitForm(formName) {
 | 
				
			||||||
 | 
					            this.$refs[formName].validate((valid) => {
 | 
				
			||||||
 | 
					                if (valid) {
 | 
				
			||||||
 | 
					                    this.createServiceFunc()
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    watch: {
 | 
				
			||||||
 | 
					        namespaceValue: {
 | 
				
			||||||
 | 
					            handler() {
 | 
				
			||||||
 | 
					                localStorage.setItem('namespace', this.namespaceValue)
 | 
				
			||||||
 | 
					                this.currentPage = 1
 | 
				
			||||||
 | 
					                this.getServices()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    beforeMount() {
 | 
				
			||||||
 | 
					        if (localStorage.getItem('namespace') !== undefined && localStorage.getItem('namespace') !== null) {
 | 
				
			||||||
 | 
					            this.namespaceValue = localStorage.getItem('namespace')
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.getNamespaces()
 | 
				
			||||||
 | 
					        this.getServices()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					    .service-head-card,.service-body-card {
 | 
				
			||||||
 | 
					        border-radius: 1px;
 | 
				
			||||||
 | 
					        margin-bottom: 5px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .service-head-search {
 | 
				
			||||||
 | 
					        width:160px;
 | 
				
			||||||
 | 
					        margin-right:10px; 
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .service-body-servicename {
 | 
				
			||||||
 | 
					        color: #4795EE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .service-body-servicename:hover {
 | 
				
			||||||
 | 
					        color: rgb(84, 138, 238);
 | 
				
			||||||
 | 
					        cursor: pointer;
 | 
				
			||||||
 | 
					        font-weight: bold;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										370
									
								
								dkube-web/src/views/statefulset/StatefulSet.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,370 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div class="statefulset">
 | 
				
			||||||
 | 
					        <el-row>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="statefulset-head-card" shadow="never" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                        <el-row>
 | 
				
			||||||
 | 
					                            <el-col :span="6">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <span>命名空间: </span>
 | 
				
			||||||
 | 
					                                    <el-select v-model="namespaceValue" filterable placeholder="请选择">
 | 
				
			||||||
 | 
					                                        <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>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Refresh" plain @click="getStatefulSets()">刷新</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                        </el-row>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="statefulset-head-card" shadow="never" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                        <el-row>
 | 
				
			||||||
 | 
					                            <el-col :span="2">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-button disabled style="border-radius:2px;" icon="Edit" type="primary">创建</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                            <el-col :span="6">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-input class="statefulset-head-search" clearable placeholder="请输入" v-model="searchInput"></el-input>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Search" type="primary" plain @click="getStatefulSets()">搜索</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                        </el-row>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="statefulset-body-card" shadow="never" :body-style="{padding:'5px'}">
 | 
				
			||||||
 | 
					                        <el-table
 | 
				
			||||||
 | 
					                        style="width:100%;font-size:12px;margin-bottom:10px;"
 | 
				
			||||||
 | 
					                        :data="statefulSetList"
 | 
				
			||||||
 | 
					                        v-loading="appLoading">
 | 
				
			||||||
 | 
					                            <el-table-column width="20"></el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=left label="StatefulSet名">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <a class="statefulset-body-statefulsetname">{{ scope.row.metadata.name }}</a>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center label="标签">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <div v-for="(val, key) in scope.row.metadata.labels" :key="key">
 | 
				
			||||||
 | 
					                                        <el-popover
 | 
				
			||||||
 | 
					                                            placement="right"
 | 
				
			||||||
 | 
					                                            :width="200"
 | 
				
			||||||
 | 
					                                            trigger="hover"
 | 
				
			||||||
 | 
					                                            :content="key + ':' + val">
 | 
				
			||||||
 | 
					                                            <template #reference>
 | 
				
			||||||
 | 
					                                                <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="容器组">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <span>{{ scope.row.status.currentReplicas>0?scope.row.status.currentReplicas: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="创建时间">
 | 
				
			||||||
 | 
					                                <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="镜像">
 | 
				
			||||||
 | 
					                                <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="200">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <el-button size="small" style="border-radius:2px;" icon="Edit" type="primary" plain @click="getStatefulSetDetail(scope)">YAML</el-button>
 | 
				
			||||||
 | 
					                                    <el-button size="small" style="border-radius:2px;" icon="Delete" type="danger" @click="handleConfirm(scope, '删除', delStatefulSet)">删除</el-button>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                        </el-table>
 | 
				
			||||||
 | 
					                        <el-pagination
 | 
				
			||||||
 | 
					                        class="statefulset-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="statefulSetTotal">
 | 
				
			||||||
 | 
					                        </el-pagination>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					        </el-row>
 | 
				
			||||||
 | 
					        <el-dialog title="YAML信息" v-model="yamlDialog" width="45%" top="5%">
 | 
				
			||||||
 | 
					            <codemirror
 | 
				
			||||||
 | 
					                :value="contentYaml"
 | 
				
			||||||
 | 
					                border
 | 
				
			||||||
 | 
					                :options="cmOptions"
 | 
				
			||||||
 | 
					                height="500"
 | 
				
			||||||
 | 
					                style="font-size:14px;"
 | 
				
			||||||
 | 
					                @change="onChange"
 | 
				
			||||||
 | 
					            ></codemirror>
 | 
				
			||||||
 | 
					            <template #footer>
 | 
				
			||||||
 | 
					                <span class="dialog-footer">
 | 
				
			||||||
 | 
					                    <el-button @click="yamlDialog = false">取 消</el-button>
 | 
				
			||||||
 | 
					                    <el-button type="primary" @click="updateStatefulSet()">更 新</el-button>
 | 
				
			||||||
 | 
					                </span>
 | 
				
			||||||
 | 
					            </template>
 | 
				
			||||||
 | 
					        </el-dialog>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					import common from "../common/Config";
 | 
				
			||||||
 | 
					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,
 | 
				
			||||||
 | 
					            statefulSetList: [],
 | 
				
			||||||
 | 
					            statefulSetTotal: 0,
 | 
				
			||||||
 | 
					            getStatefulSetsData: {
 | 
				
			||||||
 | 
					                url: common.k8sStatefulSetList,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    filter_name: '',
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    page: '',
 | 
				
			||||||
 | 
					                    limit: '',
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            statefulSetDetail: {},
 | 
				
			||||||
 | 
					            getStatefulSetDetailData: {
 | 
				
			||||||
 | 
					                url: common.k8sStatefulSetDetail,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    statefulset_name: '',
 | 
				
			||||||
 | 
					                    namespace: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            yamlDialog: false,
 | 
				
			||||||
 | 
					            updateStatefulSetData: {
 | 
				
			||||||
 | 
					                url: common.k8sStatefulSetUpdate,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    content: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            delStatefulSetData: {
 | 
				
			||||||
 | 
					                url: common.k8sstatefulsetDel,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    statefulset_name: '',
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    methods: {
 | 
				
			||||||
 | 
					        transYaml(content) {
 | 
				
			||||||
 | 
					            return json2yaml.stringify(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        transObj(content) {
 | 
				
			||||||
 | 
					            return yaml2obj.load(content)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        onChange(val) {
 | 
				
			||||||
 | 
					            this.contentYaml = val
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleSizeChange(size) {
 | 
				
			||||||
 | 
					            this.pagesize = size;
 | 
				
			||||||
 | 
					            this.getStatefulSets()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleCurrentChange(currentPage) {
 | 
				
			||||||
 | 
					            this.currentPage = currentPage;
 | 
				
			||||||
 | 
					            this.getStatefulSets()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        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 
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        restartTotal(e) {
 | 
				
			||||||
 | 
					            let index, sum = 0
 | 
				
			||||||
 | 
					            let containerStatuses = e.row.status.containerStatuses
 | 
				
			||||||
 | 
					            for ( index in containerStatuses) {
 | 
				
			||||||
 | 
					                sum = sum + containerStatuses[index].restartCount 
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return sum
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getNamespaces() {
 | 
				
			||||||
 | 
					            httpClient.get(this.namespaceListUrl)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.namespaceList = res.data.items
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getStatefulSets() {
 | 
				
			||||||
 | 
					            this.appLoading = true
 | 
				
			||||||
 | 
					            this.getStatefulSetsData.params.filter_name = this.searchInput
 | 
				
			||||||
 | 
					            this.getStatefulSetsData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            this.getStatefulSetsData.params.page = this.currentPage
 | 
				
			||||||
 | 
					            this.getStatefulSetsData.params.limit = this.pagesize
 | 
				
			||||||
 | 
					            httpClient.get(this.getStatefulSetsData.url, {params: this.getStatefulSetsData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.statefulSetList = res.data.items
 | 
				
			||||||
 | 
					                this.statefulSetTotal = res.data.total
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.appLoading = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getStatefulSetDetail(e) {
 | 
				
			||||||
 | 
					            this.getStatefulSetDetailData.params.statefulset_name = e.row.metadata.name
 | 
				
			||||||
 | 
					            this.getStatefulSetDetailData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.get(this.getStatefulSetDetailData.url, {params: this.getStatefulSetDetailData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.statefulSetDetail = res.data
 | 
				
			||||||
 | 
					                this.contentYaml = this.transYaml(this.statefulSetDetail)
 | 
				
			||||||
 | 
					                this.yamlDialog = true
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        updateStatefulSet() {
 | 
				
			||||||
 | 
					            let content = JSON.stringify(this.transObj(this.contentYaml))
 | 
				
			||||||
 | 
					            this.updateStatefulSetData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            this.updateStatefulSetData.params.content = content
 | 
				
			||||||
 | 
					            httpClient.put(this.updateStatefulSetData.url, this.updateStatefulSetData.params)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.yamlDialog = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        delStatefulSet(e) {
 | 
				
			||||||
 | 
					            this.delStatefulSetData.params.statefulset_name = e.row.metadata.name
 | 
				
			||||||
 | 
					            this.delStatefulSetData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            httpClient.delete(this.delStatefulSetData.url, {data: this.delStatefulSetData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.getStatefulSets()
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleConfirm(obj, operateName, fn) {
 | 
				
			||||||
 | 
					            this.confirmContent = '确认继续 ' + operateName + ' 操作吗?'
 | 
				
			||||||
 | 
					            this.$confirm(this.confirmContent,'提示',{
 | 
				
			||||||
 | 
					                confirmButtonText: '确定',
 | 
				
			||||||
 | 
					                cancelButtonText: '取消',
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .then(() => {
 | 
				
			||||||
 | 
					                fn(obj)
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            .catch(() => {
 | 
				
			||||||
 | 
					                this.$message.info({
 | 
				
			||||||
 | 
					                    message: '已取消操作'
 | 
				
			||||||
 | 
					                })          
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    watch: {
 | 
				
			||||||
 | 
					        namespaceValue: {
 | 
				
			||||||
 | 
					            handler() {
 | 
				
			||||||
 | 
					                localStorage.setItem('namespace', this.namespaceValue)
 | 
				
			||||||
 | 
					                this.currentPage = 1
 | 
				
			||||||
 | 
					                this.getStatefulSets()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    beforeMount() {
 | 
				
			||||||
 | 
					        if (localStorage.getItem('namespace') !== undefined && localStorage.getItem('namespace') !== null) {
 | 
				
			||||||
 | 
					            this.namespaceValue = localStorage.getItem('namespace')
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.getNamespaces()
 | 
				
			||||||
 | 
					        this.getStatefulSets()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					    .statefulset-head-card,.statefulset-body-card {
 | 
				
			||||||
 | 
					        border-radius: 1px;
 | 
				
			||||||
 | 
					        margin-bottom: 5px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .statefulset-head-search {
 | 
				
			||||||
 | 
					        width:160px;
 | 
				
			||||||
 | 
					        margin-right:10px; 
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .statefulset-body-statefulsetname {
 | 
				
			||||||
 | 
					        color: #4795EE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .statefulset-body-statefulsetname:hover {
 | 
				
			||||||
 | 
					        color: rgb(84, 138, 238);
 | 
				
			||||||
 | 
					        cursor: pointer;
 | 
				
			||||||
 | 
					        font-weight: bold;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										608
									
								
								dkube-web/src/views/workflow/Workflow.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,608 @@
 | 
				
			|||||||
 | 
					<template>
 | 
				
			||||||
 | 
					    <div class="workflow">
 | 
				
			||||||
 | 
					        <el-row>
 | 
				
			||||||
 | 
					            <!-- header1 -->
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="workflow-head-card" shadow="never" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                        <el-row>
 | 
				
			||||||
 | 
					                            <el-col :span="6">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <span>命名空间: </span>
 | 
				
			||||||
 | 
					                                    <el-select v-model="namespaceValue" filterable placeholder="请选择">
 | 
				
			||||||
 | 
					                                        <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>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Refresh" plain @click="getWorkflows()">刷新</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                        </el-row>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <!-- header2 -->
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="workflow-head-card" shadow="never" :body-style="{padding:'30px 10px 20px 10px'}">
 | 
				
			||||||
 | 
					                        <el-steps :active="active" align-center finish-status="success">
 | 
				
			||||||
 | 
					                            <el-step title="步骤1" description="选择工作流类型, ClusterIP NodePort Workflow"></el-step>
 | 
				
			||||||
 | 
					                            <el-step title="步骤2" description="填写Deployment Workflow Workflow表单"></el-step>
 | 
				
			||||||
 | 
					                            <el-step title="步骤3" description="创建Deployment Workflow Workflow"></el-step>
 | 
				
			||||||
 | 
					                        </el-steps>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <!-- header3 -->
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="workflow-head-card" shadow="never" :body-style="{padding:'10px'}">
 | 
				
			||||||
 | 
					                        <el-row>
 | 
				
			||||||
 | 
					                            <el-col :span="3">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Edit" type="primary" @click="createWorkflowDrawerIndex1 = true" v-loading.fullscreen.lock="fullscreenLoading">创建工作流</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                            <el-col :span="6">
 | 
				
			||||||
 | 
					                                <div>
 | 
				
			||||||
 | 
					                                    <el-input class="workflow-head-search" clearable placeholder="请输入" v-model="searchInput"></el-input>
 | 
				
			||||||
 | 
					                                    <el-button style="border-radius:2px;" icon="Search" type="primary" plain @click="getWorkflows()">搜索</el-button>
 | 
				
			||||||
 | 
					                                </div>
 | 
				
			||||||
 | 
					                            </el-col>
 | 
				
			||||||
 | 
					                        </el-row>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					            <el-col :span="24">
 | 
				
			||||||
 | 
					                <div>
 | 
				
			||||||
 | 
					                    <el-card class="workflow-body-card" shadow="never" :body-style="{padding:'5px'}">
 | 
				
			||||||
 | 
					                        <el-table
 | 
				
			||||||
 | 
					                        style="width:100%;font-size:12px;margin-bottom:10px;"
 | 
				
			||||||
 | 
					                        :data="workflowList"
 | 
				
			||||||
 | 
					                        v-loading="appLoading">
 | 
				
			||||||
 | 
					                            <el-table-column width="20"></el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column min-width="50" align=left label="ID" prop="id"></el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column min-width="100" label="Workflow名">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <a class="workflow-body-workflowname">{{ scope.row.name }}</a>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column label="类型" prop="type">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <el-tag type="warning">{{ scope.row.type }}</el-tag>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column label="实例数" prop="replicas"></el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column min-width="100" label="deployment" prop="deployment"></el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column min-width="150" label="service" prop="service"></el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column min-width="150" label="ingress" prop="ingress"></el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center min-width="150" label="创建时间">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <el-tag type="info">{{ timeTransNot8(scope.row.created_at) }} </el-tag>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                            <el-table-column align=center label="操作" width="200">
 | 
				
			||||||
 | 
					                                <template v-slot="scope">
 | 
				
			||||||
 | 
					                                    <el-button size="small" disabled style="border-radius:2px;" icon="Edit" type="primary" plain @click="getWorkflowDetail(scope)">详情</el-button>
 | 
				
			||||||
 | 
					                                    <el-button size="small" style="border-radius:2px;" icon="Delete" type="danger" @click="handleConfirm(scope, '删除', delWorkflow)">删除</el-button>
 | 
				
			||||||
 | 
					                                </template>
 | 
				
			||||||
 | 
					                            </el-table-column>
 | 
				
			||||||
 | 
					                        </el-table>
 | 
				
			||||||
 | 
					                        <el-pagination
 | 
				
			||||||
 | 
					                        class="workflow-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="workflowTotal">
 | 
				
			||||||
 | 
					                        </el-pagination>
 | 
				
			||||||
 | 
					                    </el-card>
 | 
				
			||||||
 | 
					                </div>
 | 
				
			||||||
 | 
					            </el-col>
 | 
				
			||||||
 | 
					        </el-row>
 | 
				
			||||||
 | 
					    <el-drawer
 | 
				
			||||||
 | 
					        v-model="createWorkflowDrawerIndex1"
 | 
				
			||||||
 | 
					        :direction="direction"
 | 
				
			||||||
 | 
					        :before-close="handleClose">
 | 
				
			||||||
 | 
					        <template #title>
 | 
				
			||||||
 | 
					            <h4>创建Workflow-步骤1</h4>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					        <template #default>
 | 
				
			||||||
 | 
					            <el-row type="flex" justify="center">
 | 
				
			||||||
 | 
					                <el-col :span="20">
 | 
				
			||||||
 | 
					                    <el-form label-width="80px">
 | 
				
			||||||
 | 
					                        <el-form-item class="workflow-create-form" label="类型" prop="name">
 | 
				
			||||||
 | 
					                            <el-radio v-model="createWorkflow.type" label="ClusterIP">ClusterIP</el-radio>
 | 
				
			||||||
 | 
					                            <el-radio v-model="createWorkflow.type" label="NodePort">NodePort</el-radio>
 | 
				
			||||||
 | 
					                            <el-radio v-model="createWorkflow.type" label="Ingress">Ingress</el-radio>
 | 
				
			||||||
 | 
					                        </el-form-item>
 | 
				
			||||||
 | 
					                    </el-form>
 | 
				
			||||||
 | 
					                </el-col>
 | 
				
			||||||
 | 
					            </el-row>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					        <template #footer>
 | 
				
			||||||
 | 
					            <el-button @click="drawerCancel('createWorkflowDrawerIndex1')">取消</el-button>
 | 
				
			||||||
 | 
					            <el-button type="primary" @click="workflowIndex1Next()">下一步</el-button>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					    </el-drawer>
 | 
				
			||||||
 | 
					    <el-drawer
 | 
				
			||||||
 | 
					        v-model="createWorkflowDrawerIndex2_1"
 | 
				
			||||||
 | 
					        :direction="direction"
 | 
				
			||||||
 | 
					        :before-close="handleClose">
 | 
				
			||||||
 | 
					        <template #title>
 | 
				
			||||||
 | 
					            <h4>创建Workflow-步骤2</h4>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					        <template #default>
 | 
				
			||||||
 | 
					            <el-row type="flex" justify="center">
 | 
				
			||||||
 | 
					                <el-col :span="20">
 | 
				
			||||||
 | 
					                    <el-form ref="createWorkflow" :rules="createWorkflowRules" :model="createWorkflow" label-width="80px">
 | 
				
			||||||
 | 
					                        <h4 style="margin-bottom:10px">Deployment</h4>
 | 
				
			||||||
 | 
					                        <el-form-item class="workflow-create-form" label="名称" prop="name">
 | 
				
			||||||
 | 
					                            <el-input v-model="createWorkflow.name"></el-input>
 | 
				
			||||||
 | 
					                        </el-form-item>
 | 
				
			||||||
 | 
					                        <el-form-item class="workflow-create-form" label="命名空间" prop="namespace">
 | 
				
			||||||
 | 
					                            <el-select v-model="createWorkflow.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>
 | 
				
			||||||
 | 
					                        <el-form-item class="workflow-create-form" label="副本数" prop="replicas">
 | 
				
			||||||
 | 
					                            <el-input-number v-model="createWorkflow.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="workflow-create-form" label="镜像" prop="image">
 | 
				
			||||||
 | 
					                            <el-input v-model="createWorkflow.image"></el-input>
 | 
				
			||||||
 | 
					                        </el-form-item>
 | 
				
			||||||
 | 
					                        <el-form-item class="workflow-create-form" label="标签" prop="label_str">
 | 
				
			||||||
 | 
					                            <el-input v-model="createWorkflow.label_str" placeholder="示例: project=ms,app=gateway"></el-input>
 | 
				
			||||||
 | 
					                        </el-form-item>
 | 
				
			||||||
 | 
					                        <el-form-item class="workflow-create-form" label="资源配额" prop="resource">
 | 
				
			||||||
 | 
					                            <el-select v-model="createWorkflow.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="workflow-create-form" label="容器端口" prop="container_port">
 | 
				
			||||||
 | 
					                            <el-input v-model="createWorkflow.container_port" placeholder="示例: 80"></el-input>
 | 
				
			||||||
 | 
					                        </el-form-item>
 | 
				
			||||||
 | 
					                        <el-form-item class="workflow-create-form" label="健康检查" prop="health">
 | 
				
			||||||
 | 
					                            <el-switch v-model="createWorkflow.health_check" />
 | 
				
			||||||
 | 
					                        </el-form-item>
 | 
				
			||||||
 | 
					                        <el-form-item class="workflow-create-form" label="检查路径" prop="healthPath">
 | 
				
			||||||
 | 
					                            <el-input v-model="createWorkflow.health_path" placeholder="示例: /health"></el-input>
 | 
				
			||||||
 | 
					                        </el-form-item>
 | 
				
			||||||
 | 
					                    </el-form>
 | 
				
			||||||
 | 
					                </el-col>
 | 
				
			||||||
 | 
					            </el-row>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					        <template #footer>
 | 
				
			||||||
 | 
					            <el-button @click="drawerCancel('createWorkflowDrawerIndex2_1')">取消</el-button>
 | 
				
			||||||
 | 
					            <el-button type="primary" @click="submitForm('createWorkflow', workflowIndex2_1Next)">下一步</el-button>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					    </el-drawer>
 | 
				
			||||||
 | 
					    <el-drawer
 | 
				
			||||||
 | 
					        v-model="createWorkflowDrawerIndex2_2"
 | 
				
			||||||
 | 
					        :direction="direction"
 | 
				
			||||||
 | 
					        :before-close="handleClose">
 | 
				
			||||||
 | 
					        <template #title>
 | 
				
			||||||
 | 
					            <h4>创建Workflow-步骤2</h4>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					        <template #default>
 | 
				
			||||||
 | 
					            <el-row type="flex" justify="center">
 | 
				
			||||||
 | 
					                <el-col :span="20">
 | 
				
			||||||
 | 
					                    <el-form ref="createWorkflow" :rules="createWorkflowRules" :model="createWorkflow" label-width="80px">
 | 
				
			||||||
 | 
					                        <h4 style="margin-bottom:10px">Service</h4>
 | 
				
			||||||
 | 
					                        <el-form-item class="service-create-form" label="Service端口" prop="port">
 | 
				
			||||||
 | 
					                            <el-input v-model="createWorkflow.port" placeholder="示例: 80"></el-input>
 | 
				
			||||||
 | 
					                        </el-form-item>
 | 
				
			||||||
 | 
					                        <el-form-item v-if="createWorkflow.type == 'NodePort'" class="service-create-form" label="NodePort" prop="node_port">
 | 
				
			||||||
 | 
					                            <el-input v-model="createWorkflow.node_port" placeholder="示例: 30001"></el-input>
 | 
				
			||||||
 | 
					                        </el-form-item>
 | 
				
			||||||
 | 
					                        <el-divider v-if="createWorkflow.type == 'Ingress'"></el-divider>
 | 
				
			||||||
 | 
					                        <h4 v-if="createWorkflow.type == 'Ingress'" style="margin-bottom:10px">Ingress</h4>
 | 
				
			||||||
 | 
					                        <el-form-item v-if="createWorkflow.type == 'Ingress'" class="deploy-create-form" label="域名" prop="host">
 | 
				
			||||||
 | 
					                            <el-input v-model="createWorkflow.host" placeholder="示例: www.example.com"></el-input>
 | 
				
			||||||
 | 
					                        </el-form-item>
 | 
				
			||||||
 | 
					                        <el-form-item v-if="createWorkflow.type == 'Ingress'" class="ingress-create-form" label="Path" prop="path">
 | 
				
			||||||
 | 
					                            <el-input v-model="createWorkflow.path" placeholder="示例: /abc"></el-input>
 | 
				
			||||||
 | 
					                        </el-form-item>
 | 
				
			||||||
 | 
					                        <el-form-item v-if="createWorkflow.type == 'Ingress'" class="deploy-create-form" label="匹配类型" prop="path_type">
 | 
				
			||||||
 | 
					                            <el-select v-model="createWorkflow.path_type" placeholder="请选择">
 | 
				
			||||||
 | 
					                                <el-option value="Prefix" label="Prefix"></el-option>
 | 
				
			||||||
 | 
					                                <el-option value="Exact" label="Exact"></el-option>
 | 
				
			||||||
 | 
					                                <el-option value="ImplementationSpecific" label="ImplementationSpecific"></el-option>
 | 
				
			||||||
 | 
					                            </el-select>
 | 
				
			||||||
 | 
					                        </el-form-item>
 | 
				
			||||||
 | 
					                    </el-form>
 | 
				
			||||||
 | 
					                </el-col>
 | 
				
			||||||
 | 
					            </el-row>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					        <template #footer>
 | 
				
			||||||
 | 
					            <el-button @click="drawerCancel('createWorkflowDrawerIndex2_2')">取消</el-button>
 | 
				
			||||||
 | 
					            <el-button type="primary" @click="submitForm('createWorkflow', createWorkflowFunc)">立即创建</el-button>
 | 
				
			||||||
 | 
					        </template>
 | 
				
			||||||
 | 
					    </el-drawer>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					</template>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<script>
 | 
				
			||||||
 | 
					import common from "../common/Config";
 | 
				
			||||||
 | 
					import httpClient from '../../utils/request';
 | 
				
			||||||
 | 
					export default {
 | 
				
			||||||
 | 
					    data() {
 | 
				
			||||||
 | 
					        return {
 | 
				
			||||||
 | 
					            active: 0,
 | 
				
			||||||
 | 
					            createWorkflowDrawerIndex1: false,
 | 
				
			||||||
 | 
					            createWorkflowDrawerIndex2_1: false,
 | 
				
			||||||
 | 
					            createWorkflowDrawerIndex2_2: false,
 | 
				
			||||||
 | 
					            currentPage: 1,
 | 
				
			||||||
 | 
					            pagesize: 10,
 | 
				
			||||||
 | 
					            pagesizeList: [10, 20, 30],
 | 
				
			||||||
 | 
					            searchInput: '',
 | 
				
			||||||
 | 
					            namespaceValue: 'default',
 | 
				
			||||||
 | 
					            namespaceList: [],
 | 
				
			||||||
 | 
					            namespaceListUrl: common.k8sNamespaceList,
 | 
				
			||||||
 | 
					            appLoading: false,
 | 
				
			||||||
 | 
					            workflowList: [],
 | 
				
			||||||
 | 
					            workflowTotal: 0,
 | 
				
			||||||
 | 
					            getWorkflowsData: {
 | 
				
			||||||
 | 
					                url: common.k8sWorkflowList,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    name: '',
 | 
				
			||||||
 | 
					                    namespace: '',
 | 
				
			||||||
 | 
					                    page: '',
 | 
				
			||||||
 | 
					                    limit: '',
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            fullscreenLoading: false,
 | 
				
			||||||
 | 
					            direction: 'rtl',
 | 
				
			||||||
 | 
					            createWorkflowDrawer: false,
 | 
				
			||||||
 | 
					            createWorkflow: {
 | 
				
			||||||
 | 
					                name: '',
 | 
				
			||||||
 | 
					                namespace: '',
 | 
				
			||||||
 | 
					                replicas: 1,
 | 
				
			||||||
 | 
					                image: '',
 | 
				
			||||||
 | 
					                resource: '',
 | 
				
			||||||
 | 
					                health_check: false,
 | 
				
			||||||
 | 
					                health_path: '',
 | 
				
			||||||
 | 
					                label_str: '',
 | 
				
			||||||
 | 
					                label: {},
 | 
				
			||||||
 | 
					                container_port: '',
 | 
				
			||||||
 | 
					                type: '',
 | 
				
			||||||
 | 
					                port: '',
 | 
				
			||||||
 | 
					                node_port: '',
 | 
				
			||||||
 | 
					                host: '',
 | 
				
			||||||
 | 
					                path: '',
 | 
				
			||||||
 | 
					                path_type: ''
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            createWorkflowData: {
 | 
				
			||||||
 | 
					                url: common.k8sWorkflowCreate,
 | 
				
			||||||
 | 
					                params: {}
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            createWorkflowRules: {
 | 
				
			||||||
 | 
					                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'
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					                type: [{
 | 
				
			||||||
 | 
					                    required: true,
 | 
				
			||||||
 | 
					                    message: '请填写工作流类型',
 | 
				
			||||||
 | 
					                    trigger: 'change'
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					                port: [{
 | 
				
			||||||
 | 
					                    required: true,
 | 
				
			||||||
 | 
					                    message: '请填写Workflow端口',
 | 
				
			||||||
 | 
					                    trigger: 'change'
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					                node_port: [{
 | 
				
			||||||
 | 
					                    required: true,
 | 
				
			||||||
 | 
					                    message: '请填写NodePort',
 | 
				
			||||||
 | 
					                    trigger: 'change'
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					                host: [{
 | 
				
			||||||
 | 
					                    required: true,
 | 
				
			||||||
 | 
					                    message: '请填写域名',
 | 
				
			||||||
 | 
					                    trigger: 'change'
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					                path: [{
 | 
				
			||||||
 | 
					                    required: true,
 | 
				
			||||||
 | 
					                    message: '请填写路径',
 | 
				
			||||||
 | 
					                    trigger: 'change'
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					                path_type: [{
 | 
				
			||||||
 | 
					                    required: true,
 | 
				
			||||||
 | 
					                    message: '你选择匹配类型',
 | 
				
			||||||
 | 
					                    trigger: 'change'
 | 
				
			||||||
 | 
					                }],
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            delWorkflowData: {
 | 
				
			||||||
 | 
					                url: common.k8sWorkflowDel,
 | 
				
			||||||
 | 
					                params: {
 | 
				
			||||||
 | 
					                    id: ''
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    methods: {
 | 
				
			||||||
 | 
					        handleSizeChange(size) {
 | 
				
			||||||
 | 
					            this.pagesize = size;
 | 
				
			||||||
 | 
					            this.getWorkflows()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleCurrentChange(currentPage) {
 | 
				
			||||||
 | 
					            this.currentPage = currentPage;
 | 
				
			||||||
 | 
					            this.getWorkflows()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleClose(done) {
 | 
				
			||||||
 | 
					            this.$confirm('确认关闭?')
 | 
				
			||||||
 | 
					            .then(() => {
 | 
				
			||||||
 | 
					                done();
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(() => {});
 | 
				
			||||||
 | 
					            this.active = 0
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        drawerCancel(drawerName) {
 | 
				
			||||||
 | 
					            switch (drawerName) {
 | 
				
			||||||
 | 
					                case 'createWorkflowDrawerIndex1':
 | 
				
			||||||
 | 
					                    this.createWorkflowDrawerIndex1 = false
 | 
				
			||||||
 | 
					                    break
 | 
				
			||||||
 | 
					                case 'createWorkflowDrawerIndex2_1':
 | 
				
			||||||
 | 
					                    this.createWorkflowDrawerIndex2_1 = false
 | 
				
			||||||
 | 
					                    break
 | 
				
			||||||
 | 
					                case 'createWorkflowDrawerIndex2_2':
 | 
				
			||||||
 | 
					                    this.createWorkflowDrawerIndex2_2 = false
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            this.active = 0
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        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 
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        timeTransNot8(timestamp) {
 | 
				
			||||||
 | 
					            let date = new Date(new Date(timestamp).getTime() + 8 * 3600 * 1000)
 | 
				
			||||||
 | 
					            date = date.toJSON();
 | 
				
			||||||
 | 
					            date = date.substring(0, 19).replace('T', ' ')
 | 
				
			||||||
 | 
					            return date 
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getNamespaces() {
 | 
				
			||||||
 | 
					            httpClient.get(this.namespaceListUrl)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.namespaceList = res.data.items
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        getWorkflows() {
 | 
				
			||||||
 | 
					            this.appLoading = true
 | 
				
			||||||
 | 
					            this.getWorkflowsData.params.name = this.searchInput
 | 
				
			||||||
 | 
					            this.getWorkflowsData.params.namespace = this.namespaceValue
 | 
				
			||||||
 | 
					            this.getWorkflowsData.params.page = this.currentPage
 | 
				
			||||||
 | 
					            this.getWorkflowsData.params.limit = this.pagesize
 | 
				
			||||||
 | 
					            httpClient.get(this.getWorkflowsData.url, {params: this.getWorkflowsData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.workflowList = res.data.items
 | 
				
			||||||
 | 
					                this.workflowTotal = res.data.total
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.appLoading = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        delWorkflow(e) {
 | 
				
			||||||
 | 
					            this.delWorkflowData.params.id = e.row.id
 | 
				
			||||||
 | 
					            httpClient.delete(this.delWorkflowData.url, {data: this.delWorkflowData.params})
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.getWorkflows()
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            console.log(123)
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        handleConfirm(obj, operateName, fn) {
 | 
				
			||||||
 | 
					            this.confirmContent = '确认继续 ' + operateName + ' 操作吗?'
 | 
				
			||||||
 | 
					            this.$confirm(this.confirmContent,'提示',{
 | 
				
			||||||
 | 
					                confirmButtonText: '确定',
 | 
				
			||||||
 | 
					                cancelButtonText: '取消',
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .then(() => {
 | 
				
			||||||
 | 
					                fn(obj)
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(() => {
 | 
				
			||||||
 | 
					                this.$message.info({
 | 
				
			||||||
 | 
					                    message: '已取消操作'
 | 
				
			||||||
 | 
					                })          
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        createWorkflowFunc() {
 | 
				
			||||||
 | 
					            let reg = new RegExp("(^[A-Za-z]+=[A-Za-z0-9]+).*")
 | 
				
			||||||
 | 
					            if (!reg.test(this.createWorkflow.label_str)) {
 | 
				
			||||||
 | 
					                this.$message.warning({
 | 
				
			||||||
 | 
					                    message: "标签填写异常,请确认后重新填写"
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            this.fullscreenLoading = true
 | 
				
			||||||
 | 
					            let label = new Map()
 | 
				
			||||||
 | 
					            let cpu, memory
 | 
				
			||||||
 | 
					            let a = (this.createWorkflow.label_str).split(",")
 | 
				
			||||||
 | 
					            a.forEach(item => {
 | 
				
			||||||
 | 
					                let b = item.split("=")
 | 
				
			||||||
 | 
					                label[b[0]] = b[1]
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            let resourceList = this.createWorkflow.resource.split("/")
 | 
				
			||||||
 | 
					            cpu = resourceList[0]
 | 
				
			||||||
 | 
					            memory = resourceList[1] + "Gi"
 | 
				
			||||||
 | 
					            this.createWorkflowData.params = this.createWorkflow
 | 
				
			||||||
 | 
					            this.createWorkflowData.params.label = label
 | 
				
			||||||
 | 
					            this.createWorkflowData.params.cpu = cpu
 | 
				
			||||||
 | 
					            this.createWorkflowData.params.memory = memory
 | 
				
			||||||
 | 
					            this.createWorkflowData.params.container_port = parseInt(this.createWorkflow.container_port)
 | 
				
			||||||
 | 
					            this.createWorkflowData.params.port = parseInt(this.createWorkflow.port)
 | 
				
			||||||
 | 
					            this.createWorkflowData.params.node_port = parseInt(this.createWorkflow.node_port)
 | 
				
			||||||
 | 
					            if (this.createWorkflow.type == 'Ingress') {
 | 
				
			||||||
 | 
					                let hosts = new Map()
 | 
				
			||||||
 | 
					                let httpPaths = []
 | 
				
			||||||
 | 
					                let httpPath = {
 | 
				
			||||||
 | 
					                    path: this.createWorkflow.path,
 | 
				
			||||||
 | 
					                    path_type: this.createWorkflow.path_type,
 | 
				
			||||||
 | 
					                    service_name: this.createWorkflow.name,
 | 
				
			||||||
 | 
					                    service_port: parseInt(this.createWorkflow.port)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                httpPaths.push(httpPath)
 | 
				
			||||||
 | 
					                hosts[this.createWorkflow.host] = httpPaths
 | 
				
			||||||
 | 
					                this.createWorkflowData.params.hosts = hosts
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            httpClient.post(this.createWorkflowData.url, this.createWorkflowData.params)
 | 
				
			||||||
 | 
					            .then(res => {
 | 
				
			||||||
 | 
					                this.$message.success({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                this.getWorkflows()
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            .catch(res => {
 | 
				
			||||||
 | 
					                this.$message.error({
 | 
				
			||||||
 | 
					                message: res.msg
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					            this.resetForm('createWorkflow')
 | 
				
			||||||
 | 
					            this.createWorkflowDrawerIndex2_2 = false
 | 
				
			||||||
 | 
					            this.active = 3
 | 
				
			||||||
 | 
					            this.fullscreenLoading = false
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        resetForm(formName) {
 | 
				
			||||||
 | 
					            this.$refs[formName].resetFields()
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        submitForm(formName, fn) {
 | 
				
			||||||
 | 
					            this.$refs[formName].validate((valid) => {
 | 
				
			||||||
 | 
					                if (valid) {
 | 
				
			||||||
 | 
					                    fn()
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    return false;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            })
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        workflowIndex1Next() {
 | 
				
			||||||
 | 
					            if (!this.createWorkflow.type) {
 | 
				
			||||||
 | 
					                this.$message.warning({
 | 
				
			||||||
 | 
					                    message: "请选择工作流类型"
 | 
				
			||||||
 | 
					                })
 | 
				
			||||||
 | 
					                return
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            this.createWorkflowDrawerIndex1 = false
 | 
				
			||||||
 | 
					            this.createWorkflowDrawerIndex2_1 = true
 | 
				
			||||||
 | 
					            this.active = 1
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        workflowIndex2_1Next() {
 | 
				
			||||||
 | 
					            this.createWorkflowDrawerIndex2_1 = false
 | 
				
			||||||
 | 
					            this.createWorkflowDrawerIndex2_2 = true
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    watch: {
 | 
				
			||||||
 | 
					        namespaceValue: {
 | 
				
			||||||
 | 
					            handler() {
 | 
				
			||||||
 | 
					                localStorage.setItem('namespace', this.namespaceValue)
 | 
				
			||||||
 | 
					                this.currentPage = 1
 | 
				
			||||||
 | 
					                this.getWorkflows()
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    beforeMount() {
 | 
				
			||||||
 | 
					        if (localStorage.getItem('namespace') !== undefined && localStorage.getItem('namespace') !== null) {
 | 
				
			||||||
 | 
					            this.namespaceValue = localStorage.getItem('namespace')
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        this.getNamespaces()
 | 
				
			||||||
 | 
					        this.getWorkflows()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					</script>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<style scoped>
 | 
				
			||||||
 | 
					    .workflow-head-card,.workflow-body-card {
 | 
				
			||||||
 | 
					        border-radius: 1px;
 | 
				
			||||||
 | 
					        margin-bottom: 5px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .workflow-head-search {
 | 
				
			||||||
 | 
					        width:160px;
 | 
				
			||||||
 | 
					        margin-right:10px; 
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .workflow-body-workflowname {
 | 
				
			||||||
 | 
					        color: #4795EE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    .workflow-body-workflowname:hover {
 | 
				
			||||||
 | 
					        color: rgb(84, 138, 238);
 | 
				
			||||||
 | 
					        cursor: pointer;
 | 
				
			||||||
 | 
					        font-weight: bold;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    :v-deep .el-drawer__header {
 | 
				
			||||||
 | 
					        margin-bottom: 0px !important;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    v-deep .el-drawer__body {
 | 
				
			||||||
 | 
					        padding: 0px 0px 0px 0px;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					</style>
 | 
				
			||||||
							
								
								
									
										8
									
								
								dkube-web/vue.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,8 @@
 | 
				
			|||||||
 | 
					module.exports = {
 | 
				
			||||||
 | 
					    devServer:{
 | 
				
			||||||
 | 
					        host: '0.0.0.0',
 | 
				
			||||||
 | 
					        port: 8080,
 | 
				
			||||||
 | 
					        open: true
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    lintOnSave: false
 | 
				
			||||||
 | 
					}
 | 
				
			||||||