Browse Source

add dark mode
add audit conn log

ljw 1 year ago
parent
commit
d7291d81a4

+ 16 - 0
src/api/audit.js

@@ -0,0 +1,16 @@
1
+import request from '@/utils/request'
2
+
3
+export function list (params) {
4
+  return request({
5
+    url: '/audit_conn/list',
6
+    params,
7
+  })
8
+}
9
+
10
+export function remove (data) {
11
+  return request({
12
+    url: '/audit_conn/delete',
13
+    method: 'post',
14
+    data,
15
+  })
16
+}

+ 21 - 2
src/layout/components/setting/index.vue

@@ -1,8 +1,21 @@
1 1
 <template>
2 2
   <div class="setting">
3
-    <div>
3
+    <div class="menu-item">
4 4
       <el-button size="small" @click="changeLang" style="width: 100px">{{ T('ChangeLang') }}</el-button>
5 5
     </div>
6
+    <div class="menu-item">
7
+        <el-switch
8
+            v-model="isDark"
9
+            style="--el-switch-on-color:#18222c"
10
+            >
11
+          <template #active-action>
12
+           <el-icon><Moon/></el-icon>
13
+          </template>
14
+          <template #inactive-action>
15
+            <el-icon ><Sunny color="#000"/></el-icon>
16
+          </template>
17
+        </el-switch>
18
+    </div>
6 19
     <el-dropdown class="menu-item">
7 20
       <div class="title">
8 21
         <!--        <el-image class="avatar" :src="user.avatar"></el-image>-->
@@ -30,6 +43,8 @@
30 43
   import changePwdDialog from '@/components/changePwdDialog.vue'
31 44
   import { ref } from 'vue'
32 45
   import { T } from '@/utils/i18n'
46
+  import { useDark } from "@vueuse/core"
47
+  import {Sunny, Moon} from '@element-plus/icons'
33 48
 
34 49
   const userStore = useUserStore()
35 50
   const user = userStore
@@ -47,6 +62,8 @@
47 62
   const changeLang = () => {
48 63
     appStore.changeLang()
49 64
   }
65
+  const isDark = useDark();
66
+  // const toggleDark = useToggle(isDark)
50 67
 </script>
51 68
 
52 69
 <style lang="scss" scoped>
@@ -55,7 +72,9 @@
55 72
   display: flex;
56 73
   align-items: center;
57 74
   justify-content: space-around;
58
-
75
+  .menu-item {
76
+    margin-left: 10px;
77
+  }
59 78
   .title {
60 79
     color: #fff;
61 80
     display: flex;

+ 1 - 0
src/main.js

@@ -7,6 +7,7 @@ import { router } from '@/router'
7 7
 import 'normalize.css/normalize.css'
8 8
 import { pinia } from '@/store'
9 9
 import '@/permission'
10
+import 'element-plus/theme-chalk/dark/css-vars.css'
10 11
 import '@/styles/style.scss'
11 12
 import * as ElementIcons from '@element-plus/icons'
12 13
 

+ 6 - 0
src/router/index.js

@@ -130,6 +130,12 @@ export const asyncRoutes = [
130 130
         meta: { title: 'LoginLog', icon: 'List' /*keepAlive: true*/ },
131 131
         component: () => import('@/views/login/log.vue'),
132 132
       },
133
+      {
134
+        path: '/auditConn',
135
+        name: 'AuditConn',
136
+        meta: { title: 'AuditConnLog', icon: 'Tickets' /*keepAlive: true*/ },
137
+        component: () => import('@/views/audit/connList.vue'),
138
+      },
133 139
     ],
134 140
   },
135 141
 ]

+ 4 - 0
src/styles/style.scss

@@ -37,3 +37,7 @@ $sideBarWidth: 210px;
37 37
     margin-right: 5px;
38 38
   }
39 39
 }
40
+html.dark {
41
+  /* 自定义深色背景颜色 */
42
+  //--el-bg-color: #626aef;
43
+}

+ 16 - 0
src/utils/i18n/en.json

@@ -350,5 +350,21 @@
350 350
   },
351 351
   "Timeout": {
352 352
     "One": "Timeout"
353
+  },
354
+  "AuditConnLog": {
355
+    "One": "Connection Log"
356
+  },
357
+  "Peer": {
358
+    "One": "Peer",
359
+    "Other": "Peers"
360
+  },
361
+  "FromPeer": {
362
+    "One": "From Peer"
363
+  },
364
+  "FromName": {
365
+    "One": "From Name"
366
+  },
367
+  "CloseTime": {
368
+    "One": "Close Time"
353 369
   }
354 370
 }

+ 15 - 0
src/utils/i18n/zh_CN.json

@@ -337,5 +337,20 @@
337 337
   },
338 338
   "Timeout": {
339 339
     "One": "超时"
340
+  },
341
+  "AuditConnLog": {
342
+    "One": "连接日志"
343
+  },
344
+  "Peer": {
345
+    "One": "设备"
346
+  },
347
+  "FromPeer": {
348
+    "One": "来源设备"
349
+  },
350
+  "FromName": {
351
+    "One": "来源名称"
352
+  },
353
+  "CloseTime": {
354
+    "One": "关闭时间"
340 355
   }
341 356
 }

+ 22 - 0
src/utils/time.js

@@ -23,3 +23,25 @@ export function timeAgo (time) {
23 23
     return T('YearsAgo', { param: num }, num)
24 24
   }
25 25
 }
26
+
27
+export function formatTime (unix, format = 'yyyy-MM-dd hh:mm:ss') {
28
+  let date = new Date(unix)
29
+  let o = {
30
+    'M+': date.getMonth() + 1,
31
+    'd+': date.getDate(),
32
+    'h+': date.getHours(),
33
+    'm+': date.getMinutes(),
34
+    's+': date.getSeconds(),
35
+    'q+': Math.floor((date.getMonth() + 3) / 3),
36
+    S: date.getMilliseconds(),
37
+  }
38
+  if (/(y+)/.test(format)) {
39
+    format = format.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
40
+  }
41
+  for (let k in o) {
42
+    if (new RegExp('(' + k + ')').test(format)) {
43
+      format = format.replace(RegExp.$1, RegExp.$1.length === 1 ? o[k] : ('00' + o[k]).substr(('' + o[k]).length))
44
+    }
45
+  }
46
+  return format
47
+}

+ 7 - 1
src/views/address_book/index.vue

@@ -30,7 +30,11 @@
30 30
     <el-card class="list-body" shadow="hover">
31 31
       <!--      <el-tag type="danger" style="margin-bottom: 10px">不建议在此操作地址簿,可能会造成数据不同步</el-tag>-->
32 32
       <el-table :data="listRes.list" v-loading="listRes.loading" border>
33
-        <el-table-column prop="id" label="id" align="center" width="200"/>
33
+        <el-table-column prop="id" label="id" align="center" width="200">
34
+          <template #default="{row}">
35
+            <span>{{ row.id }} <el-icon @click="handleClipboard(row.id, $event)"><CopyDocument/></el-icon></span>
36
+          </template>
37
+        </el-table-column>
34 38
         <el-table-column :label="T('Owner')" align="center" width="200">
35 39
           <template #default="{row}">
36 40
             <span v-if="row.user_id"> <el-tag>{{ allUsers?.find(u => u.id === row.user_id)?.username }}</el-tag> </span>
@@ -162,6 +166,8 @@
162 166
   import shareByWebClient from '@/views/address_book/components/shareByWebClient.vue'
163 167
   import { connectByClient } from '@/utils/peer'
164 168
   import { useAppStore } from '@/store/app'
169
+  import { handleClipboard } from '@/utils/clipboard'
170
+  import { CopyDocument } from '@element-plus/icons'
165 171
 
166 172
   const appStore = useAppStore()
167 173
   const route = useRoute()

+ 69 - 0
src/views/audit/connList.vue

@@ -0,0 +1,69 @@
1
+<template>
2
+  <div>
3
+    <el-card class="list-query" shadow="hover">
4
+      <el-form inline label-width="80px">
5
+        <el-form-item :label="T('Peer')">
6
+          <el-input v-model="listQuery.peer_id" clearable></el-input>
7
+        </el-form-item>
8
+        <el-form-item :label="T('FromPeer')">
9
+          <el-input v-model="listQuery.from_peer" clearable></el-input>
10
+        </el-form-item>
11
+        <el-form-item>
12
+          <el-button type="primary" @click="handlerQuery">筛选</el-button>
13
+        </el-form-item>
14
+      </el-form>
15
+    </el-card>
16
+    <el-card class="list-body" shadow="hover">
17
+      <!--      <el-tag type="danger" style="margin-bottom: 10px">不建议在此操作地址簿,可能会造成数据不同步</el-tag>-->
18
+      <el-table :data="listRes.list" v-loading="listRes.loading" border>
19
+        <el-table-column prop="id" label="id" align="center" width="100"/>
20
+        <el-table-column :label="T('Peer')" prop="peer_id" align="center" width="120"/>
21
+        <el-table-column :label="T('FromPeer')" prop="from_peer" align="center" width="120"/>
22
+        <el-table-column :label="T('FromName')" prop="from_name" align="center" width="120"/>
23
+        <el-table-column prop="uuid" label="uuid" align="center" width="120" show-overflow-tooltip/>
24
+        <el-table-column prop="created_at" :label="T('CreatedAt')" align="center"/>
25
+        <el-table-column :label="T('CloseTime')" prop="close_time" align="center"/>
26
+        <el-table-column :label="T('Actions')" align="center" width="400">
27
+          <template #default="{row}">
28
+            <el-button type="danger" @click="del(row)">{{ T('Delete') }}</el-button>
29
+          </template>
30
+        </el-table-column>
31
+      </el-table>
32
+    </el-card>
33
+    <el-card class="list-page" shadow="hover">
34
+      <el-pagination background
35
+                     layout="prev, pager, next, sizes, jumper"
36
+                     :page-sizes="[10,20,50,100]"
37
+                     v-model:page-size="listQuery.page_size"
38
+                     v-model:current-page="listQuery.page"
39
+                     :total="listRes.total">
40
+      </el-pagination>
41
+    </el-card>
42
+  </div>
43
+</template>
44
+
45
+<script setup>
46
+  import { onActivated, onMounted, watch } from 'vue'
47
+  import { useRepositories } from '@/views/audit/reponsitories'
48
+  import { T } from '@/utils/i18n'
49
+
50
+  const {
51
+    listRes,
52
+    listQuery,
53
+    getList,
54
+    handlerQuery,
55
+    del,
56
+  } = useRepositories()
57
+
58
+  onMounted(getList)
59
+  onActivated(getList)
60
+
61
+  watch(() => listQuery.page, getList)
62
+
63
+  watch(() => listQuery.page_size, handlerQuery)
64
+
65
+</script>
66
+
67
+<style scoped lang="scss">
68
+
69
+</style>

+ 61 - 0
src/views/audit/reponsitories.js

@@ -0,0 +1,61 @@
1
+import { reactive } from 'vue'
2
+import { list, remove } from '@/api/audit'
3
+import { ElMessage, ElMessageBox } from 'element-plus'
4
+import { useRoute } from 'vue-router'
5
+import {formatTime} from '@/utils/time'
6
+export function useRepositories () {
7
+  const listRes = reactive({
8
+    list: [], total: 0, loading: false,
9
+  })
10
+  const listQuery = reactive({
11
+    page: 1,
12
+    page_size: 10,
13
+    peer_id: null,
14
+    from_peer: null,
15
+  })
16
+
17
+  const getList = async () => {
18
+    listRes.loading = true
19
+    const res = await list(listQuery).catch(_ => false)
20
+    listRes.loading = false
21
+    if (res) {
22
+      listRes.list = res.data.list.map(item => {
23
+        item.close_time = item.close_time ? formatTime(item.close_time*1000) : '-'
24
+        return item
25
+      })
26
+      listRes.total = res.data.total
27
+    }
28
+  }
29
+  const handlerQuery = () => {
30
+    if (listQuery.page === 1) {
31
+      getList()
32
+    } else {
33
+      listQuery.page = 1
34
+    }
35
+  }
36
+
37
+  const del = async (row) => {
38
+    const cf = await ElMessageBox.confirm('确定删除么?', {
39
+      confirmButtonText: '确定',
40
+      cancelButtonText: '取消',
41
+      type: 'warning',
42
+    }).catch(_ => false)
43
+    if (!cf) {
44
+      return false
45
+    }
46
+
47
+    const res = await remove({ id: row.id }).catch(_ => false)
48
+    if (res) {
49
+      ElMessage.success('操作成功')
50
+      getList()
51
+    }
52
+  }
53
+
54
+  return {
55
+    listRes,
56
+    listQuery,
57
+    getList,
58
+    handlerQuery,
59
+    del,
60
+  }
61
+}

+ 7 - 1
src/views/my/address_book/index.vue

@@ -20,7 +20,11 @@
20 20
     <el-card class="list-body" shadow="hover">
21 21
       <!--      <el-tag type="danger" style="margin-bottom: 10px">不建议在此操作地址簿,可能会造成数据不同步</el-tag>-->
22 22
       <el-table :data="listRes.list" v-loading="listRes.loading" border>
23
-        <el-table-column prop="id" label="id" align="center" width="200"/>
23
+        <el-table-column prop="id" label="id" align="center" width="200">
24
+          <template #default="{row}">
25
+            <span>{{ row.id }} <el-icon @click="handleClipboard(row.id, $event)"><CopyDocument/></el-icon></span>
26
+          </template>
27
+        </el-table-column>
24 28
         <el-table-column prop="username" :label="T('Username')" align="center" width="150"/>
25 29
         <el-table-column prop="hostname" :label="T('Hostname')" align="center" width="150"/>
26 30
         <el-table-column prop="platform" :label="T('Platform')" align="center" width="120"/>
@@ -134,6 +138,8 @@
134 138
   import shareByWebClient from '@/views/address_book/components/shareByWebClient.vue'
135 139
   import { useAppStore } from '@/store/app'
136 140
   import { connectByClient } from '@/utils/peer'
141
+  import { handleClipboard } from '@/utils/clipboard'
142
+  import { CopyDocument } from '@element-plus/icons'
137 143
 
138 144
   const appStore = useAppStore()
139 145
   const tagList = ref([])

+ 7 - 1
src/views/peer/index.vue

@@ -30,7 +30,11 @@
30 30
     <el-card class="list-body" shadow="hover">
31 31
       <el-table :data="listRes.list" v-loading="listRes.loading" border size="small" @selection-change="handleSelectionChange">
32 32
         <el-table-column type="selection" width="55" align="center"/>
33
-        <el-table-column prop="id" label="id" align="center" width="150"/>
33
+        <el-table-column prop="id" label="id" align="center" width="150">
34
+          <template #default="{row}">
35
+            <span>{{ row.id }} <el-icon @click="handleClipboard(row.id, $event)"><CopyDocument/></el-icon></span>
36
+          </template>
37
+        </el-table-column>
34 38
         <el-table-column prop="cpu" label="cpu" align="center" width="100" show-overflow-tooltip/>
35 39
         <el-table-column prop="hostname" :label="T('Hostname')" align="center" width="120"/>
36 40
         <el-table-column prop="memory" :label="T('Memory')" align="center" width="120"/>
@@ -169,6 +173,8 @@
169 173
   import { batchCreate } from '@/api/address_book'
170 174
   import { useAppStore } from '@/store/app'
171 175
   import { connectByClient } from '@/utils/peer'
176
+  import { CopyDocument } from '@element-plus/icons'
177
+  import { handleClipboard } from '@/utils/clipboard'
172 178
 
173 179
   const appStore = useAppStore()
174 180
   const listRes = reactive({