Переглянути джерело

feat: 更新了各种功能,NGINX代理问题待解决

刘一也 4 роки тому
батько
коміт
e7eee59f29

+ 7 - 0
src/api/limitRequest.js

@@ -0,0 +1,7 @@
+import axios from "@/util/request.js"
+
+export const getRequestsByCurrentAndSize = config => axios.get('/api/limitrequest/page', config);
+export const searchRequestsByCurrentAndSize = config => axios.get('/api/limitrequest/search', config);
+export const permitRequest = config => axios.post('/api/limitrequest/permit', null, config);
+export const denyRequest = config => axios.post('/api/limitrequest/deny', null, config);
+export const getTotalRequests = config => axios.get('/api/limitrequest/pages', config);

+ 5 - 0
src/api/locallog.js

@@ -0,0 +1,5 @@
+import axios from "@/util/request.js"
+
+export const getLocallogsByCurrentAndSize = config => axios.get('/api/locallog/page', config);
+export const searchLocallogsByCurrentAndSize = config => axios.get('/api/locallog/search', config);
+export const getTotalLocallogs = config => axios.get('/api/locallog/pages', config);

+ 76 - 0
src/components/ContainerInfoCard.vue

@@ -0,0 +1,76 @@
+<template>
+  <div class="body">
+    <el-row class="item">
+      <el-col :span="5">
+        <span class="item-title">name:</span>
+      </el-col>
+      <el-col :span="30">{{info.name}}</el-col>
+      <!-- <el-col :span="21">
+        <el-tag size="small">{{ownerInfo.id}}</el-tag>
+      </el-col> -->
+    </el-row>
+    <el-row class="item">
+      <el-col :span="6">
+        <span class="item-title">image:</span>
+      </el-col>
+      <el-col :span="30">{{info.image}}</el-col>
+    </el-row>
+    <el-row class="item">
+      <el-col :span="4">
+        <span class="item-title">args:</span>
+      </el-col>
+      <el-col :span="30">{{info.args ? info.args : 'null'}}</el-col>
+    </el-row>
+    <el-row class="item">
+      <el-col :span="8">
+        <span class="item-title">command:</span>
+      </el-col>
+      <el-col :span="30">{{info.command ? info.command : 'null'}}</el-col>
+    </el-row>
+    <el-row class="item">
+      <el-col :span="5">
+        <span class="item-title">port:</span>
+      </el-col>
+      <el-col :span="30">{{info.ports[0].port}}/{{info.ports[0].protocol}}</el-col>
+    </el-row>
+    <!-- <el-row class="item">
+      <el-col :span="5">
+        <span class="item-title">role:</span>
+      </el-col>
+      <el-col :span="19">
+        <el-tag type="success" size="small">{{ownerInfo.role}}</el-tag>
+      </el-col>
+    </el-row> -->
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'ContainerInfoCard',
+  props: {
+    info: Object
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.body {
+  width: 80%;
+  margin: 0 auto;
+  .item {
+    margin-bottom: 15px;
+    &-title {
+      font-weight: bold;
+    }
+    .ellipsis{
+      overflow: hidden;    
+      text-overflow: ellipsis;    
+      white-space: nowrap;
+      display: inline-block;
+    }
+  }
+  .item:nth-child(1) {
+    margin-top: 10px;
+  }
+}
+</style>

+ 54 - 43
src/components/DeploymentDetail.vue

@@ -1,7 +1,13 @@
 <template>
   <div>
-    <div class="title">部署实例详情
-      <el-button type="text" @click="$router.push({path: '/'})" style="vertical-align: middle">←返回上一页</el-button>
+    <div class="title">
+      部署实例详情
+      <el-button
+        type="text"
+        @click="$router.push({ path: '/' })"
+        style="vertical-align: middle"
+        >←返回上一页</el-button
+      >
     </div>
     <div class="wrapper">
       <div class="common">
@@ -10,26 +16,26 @@
       </div>
       <div class="common" style="height: 100%">
         <div class="inner-title">容器信息</div>
-        <div style="height: 90%; overflow-y: auto;">
-          <info-card :info="containerInfo" :depth="depth"></info-card>
+        <div style="height: 90%; overflow-y: auto">
+          <container-info-card :info="containerInfo"></container-info-card>
         </div>
       </div>
-      <div class="common" style="height: 100%">
+      <!-- <div class="common" style="height: 100%">
         <div class="inner-title">容器状态</div>
         <div style="height: 90%; overflow-y: auto;">
           <info-card :info="containerStatus" :depth="depth"></info-card>
         </div>
-      </div>
+      </div> -->
       <div class="common" style="height: 100%">
         <div class="inner-title">pod状态</div>
-        <div style="height: 90%; overflow-y: auto;">
+        <div style="height: 90%; overflow-y: auto">
           <info-card :info="podStatus" :depth="depth"></info-card>
         </div>
       </div>
       <div class="common" style="height: 100%">
         <div class="inner-title">限额配置</div>
-        <div style="height: 70%; overflow-y: auto;">
-          <limit-range-card :namespace="namespace"></limit-range-card>
+        <div style="height: 90%; overflow-y: auto">
+          <limit-card :namespace="namespace" :name="deployName"></limit-card>
         </div>
       </div>
     </div>
@@ -39,8 +45,10 @@
 <script>
 import { getPodInfo } from '@/api/deployment'
 import OwnerCard from '@/components/OwnerCard.vue'
+import ContainerInfoCard from '@/components/ContainerInfoCard.vue'
+import LimitCard from '@/components/LimitCard.vue'
 import InfoCard from '@/components/InfoCard.vue'
-import LimitRangeCard from '@/components/LimitRangeCard.vue'
+// import LimitRangeCard from '@/components/LimitRangeCard.vue'
 export default {
   name: 'DeploymentDetail',
   data() {
@@ -54,53 +62,56 @@ export default {
   components: {
     OwnerCard,
     InfoCard,
-    LimitRangeCard
+    // LimitRangeCard,
+    ContainerInfoCard,
+    LimitCard,
   },
   computed: {
     namespace() {
-      return this.$route.query.namespace;
+      return this.$route.query.namespace
     },
     deployName() {
-      return this.$route.query.deployName;
-    }
+      return this.$route.query.deployName
+    },
   },
   async mounted() {
     const config = {
       params: {
-        namespace: this.namespace
-      }
-    };
-    await getPodInfo(config).then(res => {
-      const data = res.data.data[0];
-      this.containerInfo = {
-        apiVersion: data.apiVersion,
-        kind: data.kind,
-        name: data.name,
-        namespace: data.namespace,
-        labels: data.labels,
-        annotations: data.annotations,
-        containers: data.containers
-      };
-      this.podStatus = data.podStatus.conditions;
-      this.containerStatus = data.podStatus;
-      delete this.containerStatus.conditions;
-      console.log(this.containerStatus);
-    }).catch(err => {
-      console.log(err);
-    })
-  }
+        namespace: this.namespace,
+      },
+    }
+    await getPodInfo(config)
+      .then((res) => {
+        const datas = res.data.data
+        for (let i = 0; i < datas.length; ++i) {
+          const data = datas[i]
+          if (data.containers[0].name.startsWith(this.deployName)) {
+            this.containerInfo = data.containers[0]
+            this.podStatus = data.podStatus.conditions
+            this.containerStatus = data.podStatus
+            delete this.containerStatus.conditions
+            console.log(this.containerStatus)
+            break
+          }
+        }
+      })
+      .catch((err) => {
+        console.log(err)
+      })
+  },
 }
 </script>
 
 <style lang="scss" scoped>
 .wrapper {
   display: grid;
-  grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
-  grid-template-rows: 1fr 1fr 1fr 1fr;
-  grid-template-areas: 'a b b c c c'
-                       'a b b c c c'
-                       'd d d e e e'
-                       'd d d e e e';
+  grid-template-columns: 2fr 1fr 1fr 1fr 1fr 1fr;
+  grid-template-rows: 2fr 1fr 1fr 1fr;
+  grid-template-areas:
+    'a b b e e e'
+    'd d d e e e'
+    'd d d e e e'
+    'd d d e e e';
   height: 85vh;
   grid-gap: 12px;
   width: 95%;
@@ -121,7 +132,7 @@ export default {
   grid-area: b;
 }
 .wrapper div:nth-child(3) {
-  grid-area: c;
+  grid-area: e;
 }
 .wrapper div:nth-child(4) {
   grid-area: d;

+ 123 - 0
src/components/LimitCard.vue

@@ -0,0 +1,123 @@
+<template>
+  <div class="body">
+    <el-row class="item">
+      <el-col :span="12">
+        <span class="item-title">name:</span>
+      </el-col>
+      <el-col :span="12">{{info.name}}</el-col>
+      <!-- <el-col :span="12">
+        <el-tag size="small">{{ownerInfo.id}}</el-tag>
+      </el-col> -->
+    </el-row>
+    <el-row class="item">
+      <el-col :span="12">
+        <span class="item-title">namespace:</span>
+      </el-col>
+      <el-col :span="12">{{info.namespace}}</el-col>
+    </el-row>
+    <el-row class="item">
+      <el-col :span="12">
+        <span class="item-title">default cpu:</span>
+      </el-col>
+      <el-col :span="12">{{info.defaultCpu}}</el-col>
+    </el-row>
+    <el-row class="item">
+      <el-col :span="12">
+        <span class="item-title">default memory:</span>
+      </el-col>
+      <el-col :span="12">{{info.defaultMemory}}</el-col>
+    </el-row>
+    <el-row class="item">
+      <el-col :span="12">
+        <span class="item-title">default request cpu:</span>
+      </el-col>
+      <el-col :span="12">{{info.defaultRequestCpu}}</el-col>
+    </el-row>
+    <el-row class="item">
+      <el-col :span="12">
+        <span class="item-title">default request memory:</span>
+      </el-col>
+      <el-col :span="12">{{info.defaultRequestMemory}}</el-col>
+    </el-row>
+    <el-row class="item">
+      <el-col :span="12">
+        <span class="item-title">min cpu:</span>
+      </el-col>
+      <el-col :span="12">{{info.minCpu}}</el-col>
+    </el-row>
+    <el-row class="item">
+      <el-col :span="12">
+        <span class="item-title">min memory:</span>
+      </el-col>
+      <el-col :span="12">{{info.minMemory}}</el-col>
+    </el-row>
+    <el-row class="item">
+      <el-col :span="12">
+        <span class="item-title">max cpu:</span>
+      </el-col>
+      <el-col :span="12">{{info.maxCpu}}</el-col>
+    </el-row>
+    <el-row class="item">
+      <el-col :span="12">
+        <span class="item-title">max memory:</span>
+      </el-col>
+      <el-col :span="12">{{info.maxMemory}}</el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { getLimitRange } from '@/api/limitRange'
+export default {
+  name: 'LimitCard',
+  props: {
+    name: String,
+    namespace: String
+  },
+  data() {
+    return {
+      info: {}
+    }
+  },
+  mounted() {
+    const config = {
+      params: {
+        namespace: this.namespace
+      }
+    };
+    getLimitRange(config).then(res => {
+      const theData = res.data.data
+      for (var i = 0; i < theData.length; ++i) {
+        if (theData[i].name === `${this.name}-limit-range`) {
+          this.info = theData[i]
+          break
+        }
+      }
+    }).catch(err => {
+      console.log(err)
+    })
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.body {
+  width: 80%;
+  margin: 0 auto;
+  .item {
+    margin-bottom: 15px;
+    &-title {
+      font-weight: bold;
+    }
+    .ellipsis{
+      overflow: hidden;    
+      text-overflow: ellipsis;    
+      white-space: nowrap;
+      display: inline-block;
+    }
+  }
+  .item:nth-child(1) {
+    margin-top: 10px;
+  }
+}
+</style>

+ 4 - 4
src/components/OwnerCard.vue

@@ -9,19 +9,19 @@
       </el-col>
     </el-row>
     <el-row class="item">
-      <el-col :span="11">
+      <el-col :span="9">
         <span class="item-title">username:</span>
       </el-col>
       <el-col :span="13">{{ownerInfo.username}}</el-col>
     </el-row>
     <el-row class="item">
-      <el-col :span="7">
+      <el-col :span="6">
         <span class="item-title">phone:</span>
       </el-col>
       <el-col :span="17">{{ownerInfo.phone}}</el-col>
     </el-row>
     <el-row class="item">
-      <el-col :span="6">
+      <el-col :span="5">
         <span class="item-title">email:</span>
       </el-col>
       <el-col :span="18" class="ellipsis">
@@ -35,7 +35,7 @@
       </el-col>
     </el-row>
     <el-row class="item">
-      <el-col :span="5">
+      <el-col :span="4">
         <span class="item-title">role:</span>
       </el-col>
       <el-col :span="19">

+ 2 - 2
src/components/SideBar.vue

@@ -18,10 +18,10 @@
         <i class="el-icon-service"></i>
         <span slot="title">限额请求</span>
       </el-menu-item>
-      <el-menu-item index="/containerPolicy">
+      <!-- <el-menu-item index="/containerPolicy">
         <i class="el-icon-cpu"></i>
         <span slot="title">容器策略</span>
-      </el-menu-item>
+      </el-menu-item> -->
       <el-menu-item index="/operationLog">
         <i class="el-icon-document"></i>
         <span slot="title">操作日志</span>

+ 3 - 1
src/router/index.js

@@ -46,7 +46,9 @@ router.beforeEach((to, from, next) => {
   // console.log(token);
   if (token) {
     const user = jwt_decode(token);
-    if (user.auth === 'SEEC' || user.auth === 'ADMIN') {
+    const exp = user.exp * 1000;
+    const currentTimestamp = + new Date();
+    if ((user.auth === 'SEEC' || user.auth === 'ADMIN') && currentTimestamp < exp) {
       store.commit('setToken', token);
       store.commit('setUser', user);
       Message.success('Welcome, ' + user.user_info.name + '!');

+ 63 - 59
src/views/DeploymentManage.vue

@@ -3,32 +3,26 @@
     <div class="title">部署管理</div>
     <div class="body">
       <el-table
-        :data="deployments.filter(data => !search || data.namespace.includes(search))"
+        :data="
+          deployments.filter(
+            (data) => !search || data.namespace.includes(search),
+          )
+        "
         :height="'70vh'"
-        :header-cell-style="{'text-align':'center'}"
-        :cell-style="{'text-align':'center', 'cursor': 'pointer'}"
-        :default-sort = "{prop: 'deployedTime', order: 'descending'}"
-        @row-click="viewDetails">
-        <el-table-column
-          prop="id"
-          label="ID"
-          width="120">
-        </el-table-column>
-        <el-table-column
-          prop="pipelineId"
-          label="流水线ID"
-          width="120">
+        :header-cell-style="{ 'text-align': 'center' }"
+        :cell-style="{ 'text-align': 'center', cursor: 'pointer' }"
+        :default-sort="{ prop: 'deployedTime', order: 'descending' }"
+        @row-click="viewDetails"
+      >
+        <el-table-column prop="id" label="ID" width="120"> </el-table-column>
+        <el-table-column prop="pipelineId" label="流水线ID" width="120">
         </el-table-column>
-        <el-table-column
-          label="namespace"
-          width="auto">
+        <el-table-column label="namespace" width="auto">
           <template slot-scope="scope">
             <el-tag>{{ scope.row.namespace }}</el-tag>
           </template>
         </el-table-column>
-        <el-table-column
-          label="deployName"
-          width="auto">
+        <el-table-column label="deployName" width="auto">
           <template slot-scope="scope">
             <el-tag type="success">{{ scope.row.deployName }}</el-tag>
           </template>
@@ -37,21 +31,24 @@
           prop="deployedTime"
           label="部署时间"
           width="250"
-          sortable>
+          sortable
+        >
         </el-table-column>
-        <el-table-column
-          align="right">
+        <el-table-column align="right">
           <template slot="header">
             <el-input
               v-model="search"
               size="mini"
-              placeholder="输入关键字搜索"/>
+              placeholder="输入关键字搜索"
+            />
           </template>
           <template slot-scope="scope">
             <el-button
               size="mini"
               type="primary"
-              @click="viewDetails(scope.row)">查看详情</el-button>
+              @click="viewDetails(scope.row)"
+              >查看详情</el-button
+            >
           </template>
         </el-table-column>
       </el-table>
@@ -65,15 +62,18 @@
         :page-sizes="[5, 10, 20]"
         :page-size="pageSize"
         layout="sizes, prev, pager, next"
-        :total="totalItems">
+        :total="totalItems"
+      >
       </el-pagination>
     </div>
   </div>
 </template>
 
 <script>
-import { getTotalDeployments,
-         getDeploymentsByCurrentAndSize} from '@/api/deployment'
+import {
+  getTotalDeployments,
+  getDeploymentsByCurrentAndSize,
+} from '@/api/deployment'
 export default {
   name: 'DeploymentManage',
   data() {
@@ -82,68 +82,72 @@ export default {
       pageSize: 10,
       currentPage: 1,
       deployments: [],
-      search: ''
+      search: '',
     }
   },
   computed: {
     totalItems() {
       return this.pageSize * this.pageTotal
-    }
+    },
   },
   async mounted() {
-    await this.getTotalPages(this.pageSize);
-    await this.getDataByCurrentAndPageSize(this.currentPage, this.pageSize);
+    await this.getTotalPages(this.pageSize)
+    await this.getDataByCurrentAndPageSize(this.currentPage, this.pageSize)
   },
   methods: {
     getTotalPages(pageSize) {
       const config = {
         params: {
-          pageSize: pageSize
-        }
-      };
-      getTotalDeployments(config).then(res => {
-        this.pageTotal = res.data.data;
-      }).catch(err => {
-        console.log(err);
-      })
+          pageSize: pageSize,
+        },
+      }
+      getTotalDeployments(config)
+        .then((res) => {
+          this.pageTotal = res.data.data
+        })
+        .catch((err) => {
+          console.log(err)
+        })
     },
     getDataByCurrentAndPageSize(current, pageSize) {
       const config = {
         params: {
           pageNo: current - 1,
-          pageSize: pageSize
-        }
-      };
-      getDeploymentsByCurrentAndSize(config).then(res => {
-        this.deployments = res.data.data;
-      }).catch(err => {
-        console.log(err);
-      })
+          pageSize: pageSize,
+        },
+      }
+      getDeploymentsByCurrentAndSize(config)
+        .then((res) => {
+          this.deployments = res.data.data
+        })
+        .catch((err) => {
+          console.log(err)
+        })
     },
     // 切换每页大小
     async handleSizeChange(val) {
-      this.pageSize = val;
-      this.currentPage = 1;
-      await this.getTotalPages(this.pageSize);
-      await this.getDataByCurrentAndPageSize(this.currentPage, this.pageSize);
+      this.pageSize = val
+      this.currentPage = 1
+      await this.getTotalPages(this.pageSize)
+      await this.getDataByCurrentAndPageSize(this.currentPage, this.pageSize)
     },
     // 切换页数
     async handleCurrentChange(val) {
-      this.currentPage = val;
-      await this.getDataByCurrentAndPageSize(this.currentPage, this.pageSize);
+      this.currentPage = val
+      await this.getDataByCurrentAndPageSize(this.currentPage, this.pageSize)
     },
     // 查看详情
     viewDetails(row) {
-      console.log(row, row.deployName, row.namespace);
+      console.log(row, row.deployName, row.namespace)
       this.$router.push({
         path: '/deploymentDetail',
         query: {
           namespace: row.namespace,
-          deployName: row.deployName
-        }
+          deployName: row.deployName,
+        },
       })
-    }
-  }
+    },
+  },
 }
 </script>
 

+ 222 - 2
src/views/LimitRequest.vue

@@ -1,14 +1,234 @@
 <template>
   <div>
     <div class="title">请求管理</div>
+    <div class="body">
+      <el-table
+        :data="
+          requests.filter((data) => !search || data.namespace.includes(search))
+        "
+        :height="'70vh'"
+        :header-cell-style="{ 'text-align': 'center' }"
+        :cell-style="{ 'text-align': 'center', cursor: 'pointer' }"
+        :default-sort="{ prop: 'time', order: 'descending' }"
+      >
+        <el-table-column prop="id" label="ID" width="120"> </el-table-column>
+        <el-table-column prop="requester" label="请求者" width="120">
+        </el-table-column>
+        <el-table-column prop="maxMem" label="内存限额 (Mi)" width="120">
+        </el-table-column>
+        <el-table-column prop="maxCpu" label="CPU 限额 (m)" width="120">
+        </el-table-column>
+        <el-table-column prop="handled" label="是否处理" width="120">
+        </el-table-column>
+        <el-table-column prop="permitted" label="处理结果" width="120">
+        </el-table-column>
+        <el-table-column prop="time" label="请求时间" width="200" sortable>
+        </el-table-column>
+        <el-table-column align="right">
+          <template slot="header">
+            <el-input
+              v-model="search"
+              size="mini"
+              placeholder="输入关键字搜索"
+            />
+          </template>
+          <template slot-scope="scope">
+            <el-button
+              :disabled="scope.row.handled === '已处理'"
+              size="mini"
+              type="primary"
+              @click="openModal(scope.row)"
+              >审核</el-button
+            >
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+    <div class="footer">
+      <el-pagination
+        background
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+        :current-page="currentPage"
+        :page-sizes="[5, 10, 20]"
+        :page-size="pageSize"
+        layout="sizes, prev, pager, next"
+        :total="pageTotal"
+      >
+      </el-pagination>
+    </div>
   </div>
 </template>
 
 <script>
+import {
+  getRequestsByCurrentAndSize,
+  getTotalRequests,
+  permitRequest,
+  denyRequest,
+} from '@/api/limitRequest'
 export default {
-  name: 'LimitRequest'
+  name: 'LimitRequest',
+  data() {
+    return {
+      pageTotal: 0,
+      pageSize: 10,
+      currentPage: 1,
+      requests: [],
+      search: '',
+    }
+  },
+  computed: {
+    totalItems() {
+      return this.pageSize * this.pageTotal
+    },
+  },
+  async mounted() {
+    await this.getTotalPages(this.pageSize)
+    await this.getDataByCurrentAndPageSize(this.currentPage, this.pageSize)
+  },
+  methods: {
+    openModal(row) {
+      console.log(row)
+      this.$confirm(
+        `<strong>Pod</strong>: ${row.namespace}.${row.name}<br/>
+        <strong>CPU</strong>: ${row.maxCpu}m<br/>
+        <strong>RAM</strong>: ${row.maxMem}Mi<br/>
+        <strong>申请理由</strong>: ${row.reason}`,
+        '审核限额请求',
+        {
+          confirmButtonText: '允许',
+          cancelButtonText: '拒绝',
+          type: 'none',
+          // center: true,
+          dangerouslyUseHTMLString: true,
+          distinguishCancelAndClose: true,
+        },
+      )
+        .then(() => {
+          const config = {
+            params: {
+              id: row.id,
+            },
+          }
+          permitRequest(config)
+            .then(() => {
+              this.getDataByCurrentAndPageSize(this.currentPage, this.pageSize)
+              this.$message({
+                type: 'success',
+                message: '允许请求成功!',
+              })
+            })
+            .catch(() => {
+              this.$message({
+                type: 'error',
+                message: '允许请求失败!',
+              })
+            })
+        })
+        .catch((action) => {
+          if (action === 'cancel') {
+            const config = {
+              params: {
+                id: row.id,
+              },
+            }
+            denyRequest(config)
+              .then(() => {
+                this.getDataByCurrentAndPageSize(this.currentPage, this.pageSize)
+                this.$message({
+                  type: 'success',
+                  message: '拒绝请求成功!',
+                })
+              })
+              .catch(() => {
+                this.$message({
+                  type: 'error',
+                  message: '拒绝请求失败!',
+                })
+              })
+          }
+        })
+    },
+    getTotalPages(pageSize) {
+      const config = {
+        params: {
+          pageSize: pageSize,
+        },
+      }
+      getTotalRequests(config)
+        .then((res) => {
+          this.pageTotal = res.data.data
+        })
+        .catch((err) => {
+          console.log(err)
+        })
+    },
+    getDataByCurrentAndPageSize(current, pageSize) {
+      const config = {
+        params: {
+          pageNo: current - 1,
+          pageSize: pageSize,
+        },
+      }
+      getRequestsByCurrentAndSize(config)
+        .then((res) => {
+          this.requests = res.data.data
+          for (var i = 0; i < this.requests.length; ++i) {
+            if (!this.requests[i].handled) {
+              this.requests[i].permitted = '-'
+            } else {
+              this.requests[i].permitted = this.requests[i].permitted
+                ? '允许'
+                : '拒绝'
+            }
+            this.requests[i].handled = this.requests[i].handled
+              ? '已处理'
+              : '未处理'
+          }
+        })
+        .catch((err) => {
+          console.log(err)
+        })
+    },
+    // 切换每页大小
+    async handleSizeChange(val) {
+      this.pageSize = val
+      this.currentPage = 1
+      await this.getTotalPages(this.pageSize)
+      await this.getDataByCurrentAndPageSize(this.currentPage, this.pageSize)
+    },
+    // 切换页数
+    async handleCurrentChange(val) {
+      this.currentPage = val
+      await this.getDataByCurrentAndPageSize(this.currentPage, this.pageSize)
+    },
+    // 查看详情
+    viewDetails(row) {
+      console.log(row, row.deployName, row.namespace)
+      this.$router.push({
+        path: '/deploymentDetail',
+        query: {
+          namespace: row.namespace,
+          deployName: row.deployName,
+        },
+      })
+    },
+  },
 }
 </script>
 
-<style lang="scss">
+<style lang="scss" scoped>
+.body {
+  width: 90%;
+  height: 70vh;
+  margin: 0 auto;
+}
+.footer {
+  width: 80%;
+  margin: 0 auto;
+}
+.el-pagination {
+  text-align: center;
+}
 </style>

+ 159 - 4
src/views/OperationLog.vue

@@ -1,16 +1,171 @@
 <template>
   <div>
-    <div class="title">
-      操作日志
+    <div class="title">操作日志</div>
+    <div class="body">
+      <el-table
+        :data="locallogs.filter(data => !search || data.namespace.includes(search))"
+        :height="'70vh'"
+        :header-cell-style="{'text-align':'center'}"
+        :cell-style="{'text-align':'center', 'cursor': 'pointer'}"
+        :default-sort = "{prop: 'time', order: 'descending'}">
+        <el-table-column
+          prop="id"
+          label="ID"
+          width="120">
+        </el-table-column>
+        <el-table-column
+          prop="operator"
+          label="操作人"
+          width="120">
+        </el-table-column>
+        <el-table-column
+          prop="authority"
+          label="权限"
+          width="120">
+        </el-table-column>
+        <el-table-column
+          prop="success"
+          label="操作状态"
+          width="120">
+        </el-table-column>
+        <el-table-column
+          prop="time"
+          label="操作时间"
+          width="200"
+          sortable>
+        </el-table-column>
+        <el-table-column
+          align="right">
+          <template slot="header">
+            <el-input
+              v-model="search"
+              size="mini"
+              placeholder="输入关键字搜索"/>
+          </template>
+          <template slot-scope="scope">
+            <el-button
+              size="mini"
+              type="primary"
+              @click="openModal(scope.row)">查看详情</el-button>
+          </template>
+        </el-table-column>
+      </el-table>
+    </div>
+    <div class="footer">
+      <el-pagination
+        background
+        @size-change="handleSizeChange"
+        @current-change="handleCurrentChange"
+        :current-page="currentPage"
+        :page-sizes="[5, 10, 20]"
+        :page-size="pageSize"
+        layout="sizes, prev, pager, next"
+        :total="pageTotal">
+      </el-pagination>
     </div>
   </div>
 </template>
 
 <script>
+import { getLocallogsByCurrentAndSize, getTotalLocallogs } from '@/api/locallog'
 export default {
-  name: 'OperationLog'
+  name: 'OperationLog',
+  data() {
+    return {
+      pageTotal: 0,
+      pageSize: 10,
+      currentPage: 1,
+      locallogs: [],
+      search: ''
+    }
+  },
+  computed: {
+    totalItems() {
+      return this.pageSize * this.pageTotal
+    }
+  },
+  async mounted() {
+    await this.getTotalPages(this.pageSize);
+    await this.getDataByCurrentAndPageSize(this.currentPage, this.pageSize);
+  },
+  methods: {
+    openModal(row) {
+      console.log(row)
+      this.$alert(`<strong>操作人</strong>: ${row.operator}<br/>
+        <strong>角色</strong>: ${row.authority}<br/>
+        <strong>状态</strong>: ${row.success}<br/>
+        <strong>详情</strong>: ${row.message}`, '操作日志详情', {
+        type: 'none',
+        dangerouslyUseHTMLString: true,
+      }).then(() => {
+      })
+    },
+    getTotalPages(pageSize) {
+      const config = {
+        params: {
+          pageSize: pageSize
+        }
+      };
+      getTotalLocallogs(config).then(res => {
+        this.pageTotal = res.data.data;
+      }).catch(err => {
+        console.log(err);
+      })
+    },
+    getDataByCurrentAndPageSize(current, pageSize) {
+      const config = {
+        params: {
+          pageNo: current - 1,
+          pageSize: pageSize
+        }
+      };
+      getLocallogsByCurrentAndSize(config).then(res => {
+        this.locallogs = res.data.data;
+        for (var i = 0; i < this.locallogs.length; ++i) {
+          this.locallogs[i].success = this.locallogs[i].success ? '成功' : '失败'
+        }
+      }).catch(err => {
+        console.log(err);
+      })
+    },
+    // 切换每页大小
+    async handleSizeChange(val) {
+      this.pageSize = val;
+      this.currentPage = 1;
+      await this.getTotalPages(this.pageSize);
+      await this.getDataByCurrentAndPageSize(this.currentPage, this.pageSize);
+    },
+    // 切换页数
+    async handleCurrentChange(val) {
+      this.currentPage = val;
+      await this.getDataByCurrentAndPageSize(this.currentPage, this.pageSize);
+    },
+    // 查看详情
+    viewDetails(row) {
+      console.log(row, row.deployName, row.namespace);
+      this.$router.push({
+        path: '/deploymentDetail',
+        query: {
+          namespace: row.namespace,
+          deployName: row.deployName
+        }
+      })
+    }
+  }
 }
 </script>
 
-<style lang="scss">
+<style lang="scss" scoped>
+.body {
+  width: 80%;
+  height: 70vh;
+  margin: 0 auto;
+}
+.footer {
+  width: 80%;
+  margin: 0 auto;
+}
+.el-pagination {
+  text-align: center;
+}
 </style>