|
|
@@ -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) => {
|