Просмотр исходного кода

add dark mode
add audit conn log

ljw 1 год назад
Родитель
Сommit
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
 <template>
1
 <template>
2
   <div class="setting">
2
   <div class="setting">
3
-    <div>
3
+    <div class="menu-item">
4
       <el-button size="small" @click="changeLang" style="width: 100px">{{ T('ChangeLang') }}</el-button>
4
       <el-button size="small" @click="changeLang" style="width: 100px">{{ T('ChangeLang') }}</el-button>
5
     </div>
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
     <el-dropdown class="menu-item">
19
     <el-dropdown class="menu-item">
7
       <div class="title">
20
       <div class="title">
8
         <!--        <el-image class="avatar" :src="user.avatar"></el-image>-->
21
         <!--        <el-image class="avatar" :src="user.avatar"></el-image>-->
@@ -30,6 +43,8 @@
30
   import changePwdDialog from '@/components/changePwdDialog.vue'
43
   import changePwdDialog from '@/components/changePwdDialog.vue'
31
   import { ref } from 'vue'
44
   import { ref } from 'vue'
32
   import { T } from '@/utils/i18n'
45
   import { T } from '@/utils/i18n'
46
+  import { useDark } from "@vueuse/core"
47
+  import {Sunny, Moon} from '@element-plus/icons'
33
 
48
 
34
   const userStore = useUserStore()
49
   const userStore = useUserStore()
35
   const user = userStore
50
   const user = userStore
@@ -47,6 +62,8 @@
47
   const changeLang = () => {
62
   const changeLang = () => {
48
     appStore.changeLang()
63
     appStore.changeLang()
49
   }
64
   }
65
+  const isDark = useDark();
66
+  // const toggleDark = useToggle(isDark)
50
 </script>
67
 </script>
51
 
68
 
52
 <style lang="scss" scoped>
69
 <style lang="scss" scoped>
@@ -55,7 +72,9 @@
55
   display: flex;
72
   display: flex;
56
   align-items: center;
73
   align-items: center;
57
   justify-content: space-around;
74
   justify-content: space-around;
58
-
75
+  .menu-item {
76
+    margin-left: 10px;
77
+  }
59
   .title {
78
   .title {
60
     color: #fff;
79
     color: #fff;
61
     display: flex;
80
     display: flex;

+ 1 - 0
src/main.js

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

+ 6 - 0
src/router/index.js

@@ -130,6 +130,12 @@ export const asyncRoutes = [
130
         meta: { title: 'LoginLog', icon: 'List' /*keepAlive: true*/ },
130
         meta: { title: 'LoginLog', icon: 'List' /*keepAlive: true*/ },
131
         component: () => import('@/views/login/log.vue'),
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
     margin-right: 5px;
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
   "Timeout": {
351
   "Timeout": {
352
     "One": "Timeout"
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
   "Timeout": {
338
   "Timeout": {
339
     "One": "超时"
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
     return T('YearsAgo', { param: num }, num)
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
     <el-card class="list-body" shadow="hover">
30
     <el-card class="list-body" shadow="hover">
31
       <!--      <el-tag type="danger" style="margin-bottom: 10px">不建议在此操作地址簿,可能会造成数据不同步</el-tag>-->
31
       <!--      <el-tag type="danger" style="margin-bottom: 10px">不建议在此操作地址簿,可能会造成数据不同步</el-tag>-->
32
       <el-table :data="listRes.list" v-loading="listRes.loading" border>
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
         <el-table-column :label="T('Owner')" align="center" width="200">
38
         <el-table-column :label="T('Owner')" align="center" width="200">
35
           <template #default="{row}">
39
           <template #default="{row}">
36
             <span v-if="row.user_id"> <el-tag>{{ allUsers?.find(u => u.id === row.user_id)?.username }}</el-tag> </span>
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
   import shareByWebClient from '@/views/address_book/components/shareByWebClient.vue'
166
   import shareByWebClient from '@/views/address_book/components/shareByWebClient.vue'
163
   import { connectByClient } from '@/utils/peer'
167
   import { connectByClient } from '@/utils/peer'
164
   import { useAppStore } from '@/store/app'
168
   import { useAppStore } from '@/store/app'
169
+  import { handleClipboard } from '@/utils/clipboard'
170
+  import { CopyDocument } from '@element-plus/icons'
165
 
171
 
166
   const appStore = useAppStore()
172
   const appStore = useAppStore()
167
   const route = useRoute()
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
     <el-card class="list-body" shadow="hover">
20
     <el-card class="list-body" shadow="hover">
21
       <!--      <el-tag type="danger" style="margin-bottom: 10px">不建议在此操作地址簿,可能会造成数据不同步</el-tag>-->
21
       <!--      <el-tag type="danger" style="margin-bottom: 10px">不建议在此操作地址簿,可能会造成数据不同步</el-tag>-->
22
       <el-table :data="listRes.list" v-loading="listRes.loading" border>
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
         <el-table-column prop="username" :label="T('Username')" align="center" width="150"/>
28
         <el-table-column prop="username" :label="T('Username')" align="center" width="150"/>
25
         <el-table-column prop="hostname" :label="T('Hostname')" align="center" width="150"/>
29
         <el-table-column prop="hostname" :label="T('Hostname')" align="center" width="150"/>
26
         <el-table-column prop="platform" :label="T('Platform')" align="center" width="120"/>
30
         <el-table-column prop="platform" :label="T('Platform')" align="center" width="120"/>
@@ -134,6 +138,8 @@
134
   import shareByWebClient from '@/views/address_book/components/shareByWebClient.vue'
138
   import shareByWebClient from '@/views/address_book/components/shareByWebClient.vue'
135
   import { useAppStore } from '@/store/app'
139
   import { useAppStore } from '@/store/app'
136
   import { connectByClient } from '@/utils/peer'
140
   import { connectByClient } from '@/utils/peer'
141
+  import { handleClipboard } from '@/utils/clipboard'
142
+  import { CopyDocument } from '@element-plus/icons'
137
 
143
 
138
   const appStore = useAppStore()
144
   const appStore = useAppStore()
139
   const tagList = ref([])
145
   const tagList = ref([])

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

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