Browse Source

feat: Add import

lejianwen 10 months ago
parent
commit
f822e5bebf
4 changed files with 1387 additions and 928 deletions
  1. 1304 921
      package-lock.json
  2. 3 3
      package.json
  3. 1 1
      src/layout/index.vue
  4. 79 3
      src/views/peer/index.vue

File diff suppressed because it is too large
+ 1304 - 921
package-lock.json


+ 3 - 3
package.json

@@ -15,8 +15,8 @@
15 15
     "marked": "^15.0.4",
16 16
     "normalize.css": "^8.0.1",
17 17
     "nprogress": "^0.2.0",
18
-    "pinia": "2.0.3",
19
-    "vue": "3.2.37",
18
+    "pinia": "2.2.8",
19
+    "vue": "3.5.13",
20 20
     "vue-router": "^4.0.12"
21 21
   },
22 22
   "devDependencies": {
@@ -27,6 +27,6 @@
27 27
     "sass": "^1.43.4",
28 28
     "sass-loader": "^12.3.0",
29 29
     "ts-proto": "^1.141.1",
30
-    "vite": "^2.9.18"
30
+    "vite": "6.0.9"
31 31
   }
32 32
 }

+ 1 - 1
src/layout/index.vue

@@ -15,7 +15,7 @@
15 15
         <el-main class="app-main">
16 16
           <router-view v-slot="{ Component }">
17 17
             <transition mode="out-in" name="el-fade-in-linear">
18
-              <keep-alive :include="[...cachedTags]">
18
+              <keep-alive :include="cachedTags">
19 19
                 <component :is="Component"/>
20 20
               </keep-alive>
21 21
             </transition>

+ 79 - 3
src/views/peer/index.vue

@@ -8,7 +8,7 @@
8 8
         <el-form-item :label="T('Hostname')">
9 9
           <el-input v-model="listQuery.hostname" clearable/>
10 10
         </el-form-item>
11
-        <el-form-item :label="T('LastOnlineTime')"  label-width="100px">
11
+        <el-form-item :label="T('LastOnlineTime')" label-width="100px">
12 12
           <el-select v-model="listQuery.time_ago" clearable>
13 13
             <el-option
14 14
                 v-for="item in timeFilters"
@@ -29,6 +29,35 @@
29 29
           <el-button type="primary" @click="handlerQuery">{{ T('Filter') }}</el-button>
30 30
           <el-button type="danger" @click="toAdd">{{ T('Add') }}</el-button>
31 31
           <el-button type="success" @click="toExport">{{ T('Export') }}</el-button>
32
+          <el-popover :visible="showImport" placement="bottom" :width="600">
33
+            <el-upload
34
+                class="upload-demo"
35
+                drag
36
+                accept=".csv"
37
+                :before-upload="parseCsv"
38
+            >
39
+              <el-icon class="el-icon--upload">
40
+                <upload-filled/>
41
+              </el-icon>
42
+              <div class="el-upload__text">
43
+                Drop file here or <em>click to upload</em>
44
+              </div>
45
+              <template #tip>
46
+                <div class="el-upload__tip">
47
+                  please upload csv file <br>
48
+                  columns: <span style="font-weight: bold;font-size: 15px">id,cpu,hostname,memory,os,username,uuid,version,group_id</span>
49
+                  <br>
50
+                  <span>you can see export file</span>
51
+                </div>
52
+
53
+              </template>
54
+
55
+            </el-upload>
56
+            <el-button @click="showImport=false" type="primary">{{ T('Cancel') }}</el-button>
57
+            <template #reference>
58
+              <el-button @click="showImport=true" type="danger">{{ T('Import') }}</el-button>
59
+            </template>
60
+          </el-popover>
32 61
           <el-button type="danger" @click="toBatchDelete">{{ T('BatchDelete') }}</el-button>
33 62
           <el-button type="primary" @click="toBatchAddToAB">{{ T('BatchAddToAB') }}</el-button>
34 63
         </el-form-item>
@@ -187,6 +216,7 @@
187 216
   import { batchCreateFromPeers } from '@/api/address_book'
188 217
   import { useRepositories as useCollectionRepositories } from '@/views/address_book/collection'
189 218
   import createABForm from '@/views/peer/createABForm.vue'
219
+  import { UploadFilled } from '@element-plus/icons-vue'
190 220
 
191 221
   const appStore = useAppStore()
192 222
 
@@ -210,8 +240,6 @@
210 240
   onMounted(getGroupList)
211 241
   //
212 242
 
213
-
214
-
215 243
   const listRes = reactive({
216 244
     list: [], total: 0, loading: false,
217 245
   })
@@ -344,6 +372,54 @@
344 372
     }
345 373
   }
346 374
 
375
+  const showImport = ref(false)
376
+  const canKeys = ['id', 'cpu', 'hostname', 'memory', 'os', 'username', 'uuid', 'version', 'group_id']
377
+  const parseCsv = (file) => {
378
+    const reader = new FileReader()
379
+    reader.onload = async (e) => {
380
+      const data = e.target.result
381
+      console.log(data)
382
+      //组装数据
383
+      const rows = data.split('\n')
384
+      const keys = rows[0].split(',')
385
+      console.log(keys, rows.slice(1).map(row => row.split(',')))
386
+      const values = rows.slice(1).map(row => {
387
+        const obj = {}
388
+        row.split(/,(?=(?:(?:[^"]*"){2})*[^"]*$)/).forEach((v, i) => {
389
+          //去掉两边的"
390
+          obj[keys[i]] = v.trim().replace(/^"|"$/g, '')
391
+        })
392
+        return obj
393
+      }).filter(item => item.id)
394
+      // console.log(values)
395
+      //移除不需要的key
396
+      values.forEach(item => {
397
+        item.group_id = parseInt(item.group_id)
398
+        Object.keys(item).forEach(key => {
399
+          if (!canKeys.includes(key)) {
400
+            delete item[key]
401
+          }
402
+        })
403
+      })
404
+      console.log(values)
405
+      const pa = []
406
+      values.map(item => {
407
+        pa.push(create(item))
408
+      })
409
+      const res = await Promise.all(pa).catch(_ => false)
410
+      if (res) {
411
+        ElMessage.success(T('OperationSuccess'))
412
+        getList()
413
+      }
414
+
415
+    }
416
+    reader.readAsText(file)
417
+    return false
418
+  }
419
+  const toImport = () => {
420
+    ElMessage.warning('暂未实现')
421
+  }
422
+
347 423
   const ABFormVisible = ref(false)
348 424
   const clickRow = ref({})
349 425
   const toAddressBook = (row) => {