✨ 新增导出功能&服务器列表排序缓存
This commit is contained in:
parent
ba67533e9a
commit
d83795d7af
@ -5,11 +5,15 @@ async function getHostList({ res }) {
|
|||||||
let data = await readHostList()
|
let data = await readHostList()
|
||||||
data?.sort((a, b) => Number(b.index || 0) - Number(a.index || 0))
|
data?.sort((a, b) => Number(b.index || 0) - Number(a.index || 0))
|
||||||
for (const item of data) {
|
for (const item of data) {
|
||||||
let { username, port, authType, _id: id, credential } = item
|
try {
|
||||||
// console.log('解密凭证title: ', credential)
|
let { username, port, authType, _id: id, credential } = item
|
||||||
if (credential) credential = await AESDecryptSync(credential)
|
// console.log('解密凭证title: ', credential)
|
||||||
const isConfig = Boolean(username && port && (item[authType]))
|
if (credential) credential = await AESDecryptSync(credential)
|
||||||
Object.assign(item, { id, isConfig, password: '', privateKey: '', credential })
|
const isConfig = Boolean(username && port && (item[authType]))
|
||||||
|
Object.assign(item, { id, isConfig, password: '', privateKey: '', credential })
|
||||||
|
} catch (error) {
|
||||||
|
consola.error('getHostList error: ', error.message)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
res.success({ data })
|
res.success({ data })
|
||||||
}
|
}
|
||||||
@ -119,13 +123,13 @@ async function removeHost({
|
|||||||
hostList.splice(hostIdx, 1)
|
hostList.splice(hostIdx, 1)
|
||||||
}
|
}
|
||||||
writeHostList(hostList)
|
writeHostList(hostList)
|
||||||
res.success({ data: `${ host }已移除` })
|
res.success({ data: '已移除' })
|
||||||
}
|
}
|
||||||
|
|
||||||
async function importHost({
|
async function importHost({
|
||||||
res, request
|
res, request
|
||||||
}) {
|
}) {
|
||||||
let { body: { importHost } } = request
|
let { body: { importHost, isEasyNodeJson = false } } = request
|
||||||
if (!Array.isArray(importHost)) return res.fail({ msg: '参数错误' })
|
if (!Array.isArray(importHost)) return res.fail({ msg: '参数错误' })
|
||||||
let hostList = await readHostList()
|
let hostList = await readHostList()
|
||||||
// 过滤已存在的host
|
// 过滤已存在的host
|
||||||
@ -134,15 +138,26 @@ async function importHost({
|
|||||||
let newHostListLen = newHostList.length
|
let newHostListLen = newHostList.length
|
||||||
if (newHostListLen === 0) return res.fail({ msg: '导入的实例已存在' })
|
if (newHostListLen === 0) return res.fail({ msg: '导入的实例已存在' })
|
||||||
|
|
||||||
let extraFiels = {
|
if (isEasyNodeJson) {
|
||||||
expired: null, expiredNotify: false, group: 'default', consoleUrl: '', remark: '',
|
newHostList = newHostList.map((item) => {
|
||||||
authType: 'privateKey', password: '', privateKey: '', credential: '', command: ''
|
item.credential = ''
|
||||||
|
item.isConfig = false
|
||||||
|
delete item.id
|
||||||
|
delete item.isConfig
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let extraFiels = {
|
||||||
|
expired: null, expiredNotify: false, group: 'default', consoleUrl: '', remark: '',
|
||||||
|
authType: 'privateKey', password: '', privateKey: '', credential: '', command: ''
|
||||||
|
}
|
||||||
|
newHostList = newHostList.map((item, index) => {
|
||||||
|
item.port = Number(item.port) || 0
|
||||||
|
item.index = newHostListLen - index
|
||||||
|
return Object.assign(item, { ...extraFiels })
|
||||||
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
newHostList = newHostList.map((item, index) => {
|
|
||||||
item.port = Number(item.port) || 0
|
|
||||||
item.index = newHostListLen - index
|
|
||||||
return Object.assign(item, { ...extraFiels })
|
|
||||||
})
|
|
||||||
hostList.push(...newHostList)
|
hostList.push(...newHostList)
|
||||||
writeHostList(hostList)
|
writeHostList(hostList)
|
||||||
res.success({ data: { len: newHostList.length } })
|
res.success({ data: { len: newHostList.length } })
|
||||||
|
@ -15,7 +15,7 @@ async function getClientsInfo(clientSockets) {
|
|||||||
})
|
})
|
||||||
hostList
|
hostList
|
||||||
.map(({ host, name }) => {
|
.map(({ host, name }) => {
|
||||||
if (clientSockets.some(item => item.host === host)) return { name, isIo: true } // 已经建立io连接(无论是否连接成功)的host不再重复建立连接
|
if (clientSockets.some(item => item.host === host)) return { name, isIo: true } // 已经建立io连接(无论是否连接成功)的host不再重复建立连接,因为存在多次(reconnectionAttempts)的重试机制
|
||||||
let clientSocket = ClientIO(`http://${ host }:${ clientPort }`, {
|
let clientSocket = ClientIO(`http://${ host }:${ clientPort }`, {
|
||||||
path: '/client/os-info',
|
path: '/client/os-info',
|
||||||
forceNew: true,
|
forceNew: true,
|
||||||
@ -34,7 +34,7 @@ async function getClientsInfo(clientSockets) {
|
|||||||
.forEach((item) => {
|
.forEach((item) => {
|
||||||
if (item.isIo) return // console.log('已经建立io连接的host不再重复建立连接', item.name)
|
if (item.isIo) return // console.log('已经建立io连接的host不再重复建立连接', item.name)
|
||||||
const { host, name, clientSocket } = item
|
const { host, name, clientSocket } = item
|
||||||
clientsData[host] = { connect: false }
|
// clientsData[host] = { connect: false }
|
||||||
clientSocket
|
clientSocket
|
||||||
.on('connect', () => {
|
.on('connect', () => {
|
||||||
consola.success('client connect success:', host, name)
|
consola.success('client connect success:', host, name)
|
||||||
|
@ -17,7 +17,7 @@ export default {
|
|||||||
return `${ (netSpeedMB * 1024).toFixed(1) } KB/s`
|
return `${ (netSpeedMB * 1024).toFixed(1) } KB/s`
|
||||||
},
|
},
|
||||||
// format: time OR date
|
// format: time OR date
|
||||||
formatTimestamp: (timestamp, format = 'time') => {
|
formatTimestamp: (timestamp, format = 'time', afterSeparator = ':') => {
|
||||||
if(typeof(timestamp) !== 'number') return '--'
|
if(typeof(timestamp) !== 'number') return '--'
|
||||||
let date = new Date(timestamp)
|
let date = new Date(timestamp)
|
||||||
let padZero = (num) => String(num).padStart(2, '0')
|
let padZero = (num) => String(num).padStart(2, '0')
|
||||||
@ -31,9 +31,9 @@ export default {
|
|||||||
case 'date':
|
case 'date':
|
||||||
return `${ year }-${ mounth }-${ day }`
|
return `${ year }-${ mounth }-${ day }`
|
||||||
case 'time':
|
case 'time':
|
||||||
return `${ year }-${ mounth }-${ day } ${ hours }:${ minute }:${ second }`
|
return `${ year }-${ mounth }-${ day } ${ hours }${ afterSeparator }${ minute }${ afterSeparator }${ second }`
|
||||||
default:
|
default:
|
||||||
return `${ year }-${ mounth }-${ day } ${ hours }:${ minute }:${ second }`
|
return `${ year }-${ mounth }-${ day } ${ hours }${ afterSeparator }${ minute }${ afterSeparator }${ second }`
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ping
|
ping
|
||||||
|
@ -114,3 +114,17 @@ export const downloadFile = ({ buffer, name }) => {
|
|||||||
export const getSuffix = (name = '') => {
|
export const getSuffix = (name = '') => {
|
||||||
return String(name).split(/\./).pop()
|
return String(name).split(/\./).pop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const exportFile = (data, filename, mimeType = 'application/json') =>{
|
||||||
|
const blob = new Blob([JSON.stringify(data),], { type: mimeType })
|
||||||
|
const url = window.URL.createObjectURL(blob)
|
||||||
|
|
||||||
|
const link = document.createElement('a')
|
||||||
|
link.href = url
|
||||||
|
link.setAttribute('download', filename)
|
||||||
|
|
||||||
|
document.body.appendChild(link)
|
||||||
|
link.click()
|
||||||
|
document.body.removeChild(link)
|
||||||
|
window.URL.revokeObjectURL(url)
|
||||||
|
}
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
ref="tableRef"
|
ref="tableRef"
|
||||||
:data="hosts"
|
:data="hosts"
|
||||||
row-key="host"
|
row-key="host"
|
||||||
|
:default-sort="defaultSort"
|
||||||
|
@sort-change="handleSortChange"
|
||||||
@selection-change="handleSelectionChange"
|
@selection-change="handleSelectionChange"
|
||||||
>
|
>
|
||||||
<el-table-column type="expand">
|
<el-table-column type="expand">
|
||||||
@ -43,8 +45,18 @@
|
|||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column type="selection" reserve-selection />
|
<el-table-column type="selection" reserve-selection />
|
||||||
<el-table-column prop="index" label="序号" width="100px" />
|
<el-table-column
|
||||||
<el-table-column label="名称">
|
property="index"
|
||||||
|
label="序号"
|
||||||
|
sortable
|
||||||
|
width="100px"
|
||||||
|
/>
|
||||||
|
<el-table-column
|
||||||
|
label="名称"
|
||||||
|
property="name"
|
||||||
|
sortable
|
||||||
|
:sort-method="(a, b) => a.name - b.name"
|
||||||
|
>
|
||||||
<template #default="scope">{{ scope.row.name }}</template>
|
<template #default="scope">{{ scope.row.name }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column property="username" label="用户名" />
|
<el-table-column property="username" label="用户名" />
|
||||||
@ -53,9 +65,15 @@
|
|||||||
<!-- <el-table-column property="port" label="认证类型">
|
<!-- <el-table-column property="port" label="认证类型">
|
||||||
<template #default="scope">{{ scope.row.authType === 'password' ? '密码' : '密钥' }}</template>
|
<template #default="scope">{{ scope.row.authType === 'password' ? '密码' : '密钥' }}</template>
|
||||||
</el-table-column> -->
|
</el-table-column> -->
|
||||||
<el-table-column label="监控服务">
|
<el-table-column
|
||||||
|
label="监控服务"
|
||||||
|
property="monitorData"
|
||||||
|
sortable
|
||||||
|
:sort-method="(a, b) => a.monitorData?.connect - b.monitorData?.connect"
|
||||||
|
>
|
||||||
<template #default="scope">
|
<template #default="scope">
|
||||||
<el-tag v-if="scope.row.monitorData?.connect" type="success">已安装</el-tag>
|
<el-tag v-if="typeof(scope.row.monitorData?.connect) !== 'boolean'" type="info">连接中</el-tag>
|
||||||
|
<el-tag v-else-if="scope.row.monitorData?.connect" type="success">已安装</el-tag>
|
||||||
<el-tag v-else type="warning">未安装</el-tag>
|
<el-tag v-else type="warning">未安装</el-tag>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -70,7 +88,7 @@
|
|||||||
>
|
>
|
||||||
<el-button type="success" :disabled="!row.isConfig" @click="handleSSH(row)">连接终端</el-button>
|
<el-button type="success" :disabled="!row.isConfig" @click="handleSSH(row)">连接终端</el-button>
|
||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
<el-button type="primary" @click="handleUpdate(row)">修改</el-button>
|
<el-button type="primary" @click="handleUpdate(row)">配置</el-button>
|
||||||
<el-button type="danger" @click="handleRemoveHost(row)">删除</el-button>
|
<el-button type="danger" @click="handleRemoveHost(row)">删除</el-button>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
@ -127,6 +145,15 @@ const handleOnekey = async (row) => {
|
|||||||
$router.push({ path: '/onekey', query: { host, execClientInstallScript: 'true' } })
|
$router.push({ path: '/onekey', query: { host, execClientInstallScript: 'true' } })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let defaultSortLocal = localStorage.getItem('host_table_sort')
|
||||||
|
defaultSortLocal = defaultSortLocal ? JSON.parse(defaultSortLocal) : { prop: 'index', order: 'ascending' }
|
||||||
|
let defaultSort = ref(defaultSortLocal)
|
||||||
|
|
||||||
|
const handleSortChange = (sortObj) => {
|
||||||
|
defaultSort.value = sortObj
|
||||||
|
localStorage.setItem('host_table_sort', JSON.stringify(sortObj))
|
||||||
|
}
|
||||||
|
|
||||||
let selectHosts = ref([])
|
let selectHosts = ref([])
|
||||||
const handleSelectionChange = (val) => {
|
const handleSelectionChange = (val) => {
|
||||||
// console.log('select: ', val)
|
// console.log('select: ', val)
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
@change="handleCsvFile"
|
@change="handleCsvFile"
|
||||||
>
|
>
|
||||||
</li>
|
</li>
|
||||||
<li @click="handleFromJson">
|
<li @click="handleFromJson(false)">
|
||||||
<svg-icon name="icon-json" class="icon" />
|
<svg-icon name="icon-json" class="icon" />
|
||||||
<span class="from">FinalShell</span>
|
<span class="from">FinalShell</span>
|
||||||
<span class="type">(json)</span>
|
<span class="type">(json)</span>
|
||||||
@ -35,19 +35,24 @@
|
|||||||
multiple
|
multiple
|
||||||
name="jsonInput"
|
name="jsonInput"
|
||||||
style="display: none;"
|
style="display: none;"
|
||||||
|
@click.stop
|
||||||
@change="handleJsonFile"
|
@change="handleJsonFile"
|
||||||
>
|
>
|
||||||
</li>
|
</li>
|
||||||
|
<li @click="handleFromJson(true)">
|
||||||
|
<svg-icon name="icon-json" class="icon" />
|
||||||
|
<span class="from">EadyNode</span>
|
||||||
|
<span class="type">(json)</span>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, reactive, computed, getCurrentInstance, nextTick } from 'vue'
|
import { ref, computed, getCurrentInstance } from 'vue'
|
||||||
import { RSAEncrypt, AESEncrypt, randomStr } from '@utils/index.js'
|
|
||||||
import { parse } from 'csv-parse/browser/esm/sync'
|
import { parse } from 'csv-parse/browser/esm/sync'
|
||||||
|
|
||||||
const { proxy: { $api, $router, $message, $store } } = getCurrentInstance()
|
const { proxy: { $api, $message } } = getCurrentInstance()
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
show: {
|
show: {
|
||||||
@ -69,7 +74,11 @@ function handleFromCsv() {
|
|||||||
csvInputRef.value.click()
|
csvInputRef.value.click()
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleFromJson() {
|
let isEasyNodeJson = ref(false)
|
||||||
|
|
||||||
|
function handleFromJson(isENJson) {
|
||||||
|
isEasyNodeJson.value = isENJson
|
||||||
|
console.log('isEasyNodeJson:', isEasyNodeJson.value)
|
||||||
jsonInputRef.value.click()
|
jsonInputRef.value.click()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,7 +115,8 @@ const handleCsvFile = (event) => {
|
|||||||
|
|
||||||
Promise.all(readerPromises)
|
Promise.all(readerPromises)
|
||||||
.then(jsonContents => {
|
.then(jsonContents => {
|
||||||
let formatJson = jsonContents.map(item => {
|
let formatJson = jsonContents.flat(Infinity)
|
||||||
|
formatJson = formatJson.map(item => {
|
||||||
const { name, host, port, user_name: username } = item
|
const { name, host, port, user_name: username } = item
|
||||||
return { name, host, port, username }
|
return { name, host, port, username }
|
||||||
})
|
})
|
||||||
@ -116,6 +126,9 @@ const handleCsvFile = (event) => {
|
|||||||
$message.error('导入失败: ', error.message)
|
$message.error('导入失败: ', error.message)
|
||||||
console.error('导入失败: ', error)
|
console.error('导入失败: ', error)
|
||||||
})
|
})
|
||||||
|
.finally(() => {
|
||||||
|
event.target.value = null
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleJsonFile = (event) => {
|
const handleJsonFile = (event) => {
|
||||||
@ -143,22 +156,28 @@ const handleJsonFile = (event) => {
|
|||||||
|
|
||||||
Promise.all(readerPromises)
|
Promise.all(readerPromises)
|
||||||
.then(jsonContents => {
|
.then(jsonContents => {
|
||||||
let formatJson = jsonContents.map(item => {
|
let formatJson = jsonContents.flat(Infinity)
|
||||||
const { name, host, port, user_name: username } = item
|
if (!isEasyNodeJson.value) {
|
||||||
return { name, host, port, username }
|
formatJson = formatJson.map(item => {
|
||||||
})
|
const { name, host, port, user_name: username } = item
|
||||||
|
return { name, host, port, username }
|
||||||
|
})
|
||||||
|
}
|
||||||
handleImportHost(formatJson)
|
handleImportHost(formatJson)
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
$message.error('导入失败: ', error.message)
|
$message.error('导入失败: ', error.message)
|
||||||
console.error('导入失败: ', error)
|
console.error('导入失败: ', error)
|
||||||
})
|
})
|
||||||
|
.finally(() => {
|
||||||
|
event.target.value = null
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleImportHost(importHost) {
|
async function handleImportHost(importHost) {
|
||||||
// console.log('导入: ', importHost)
|
// console.log('导入: ', importHost)
|
||||||
try {
|
try {
|
||||||
let { data: { len } } = await $api.importHost({ importHost })
|
let { data: { len } } = await $api.importHost({ importHost, isEasyNodeJson: isEasyNodeJson.value })
|
||||||
$message({ type: 'success', center: true, message: `成功导入实例: ${ len }台` })
|
$message({ type: 'success', center: true, message: `成功导入实例: ${ len }台` })
|
||||||
emit('update-list')
|
emit('update-list')
|
||||||
visible.value = false
|
visible.value = false
|
||||||
|
@ -2,11 +2,22 @@
|
|||||||
<div class="server_group_container">
|
<div class="server_group_container">
|
||||||
<div class="server_group_header">
|
<div class="server_group_header">
|
||||||
<!-- <el-button v-show="selectHosts.length" type="primary" @click="hostFormVisible = true">批量操作</el-button> -->
|
<!-- <el-button v-show="selectHosts.length" type="primary" @click="hostFormVisible = true">批量操作</el-button> -->
|
||||||
<el-button type="primary" @click="hostFormVisible = true">添加实例</el-button>
|
<el-button type="primary" class="add_host_btn" @click="hostFormVisible = true">添加实例</el-button>
|
||||||
<!-- <el-button type="primary" @click="handleHiddenIP">
|
<!-- <el-button type="primary" @click="handleHiddenIP">
|
||||||
{{ hiddenIp ? '显示IP' : '隐藏IP' }}
|
{{ hiddenIp ? '显示IP' : '隐藏IP' }}
|
||||||
</el-button> -->
|
</el-button> -->
|
||||||
<el-button type="primary" @click="importVisible = true">导入实例</el-button>
|
<!-- <el-button type="primary" @click="importVisible = true">导入实例</el-button> -->
|
||||||
|
<el-dropdown trigger="click">
|
||||||
|
<el-button type="primary" class="group_action_btn">
|
||||||
|
导入导出<el-icon class="el-icon--right"><arrow-down /></el-icon>
|
||||||
|
</el-button>
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item @click="importVisible = true">导入实例</el-dropdown-item>
|
||||||
|
<el-dropdown-item @click="handleBatchExport">导出实例</el-dropdown-item>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown>
|
||||||
<el-dropdown trigger="click">
|
<el-dropdown trigger="click">
|
||||||
<el-button type="primary" class="group_action_btn">
|
<el-button type="primary" class="group_action_btn">
|
||||||
批量操作<el-icon class="el-icon--right"><arrow-down /></el-icon>
|
批量操作<el-icon class="el-icon--right"><arrow-down /></el-icon>
|
||||||
@ -77,8 +88,9 @@ import HostTable from './components/host-table.vue'
|
|||||||
import HostForm from './components/host-form.vue'
|
import HostForm from './components/host-form.vue'
|
||||||
import ImportHost from './components/import-host.vue'
|
import ImportHost from './components/import-host.vue'
|
||||||
import { ArrowDown } from '@element-plus/icons-vue'
|
import { ArrowDown } from '@element-plus/icons-vue'
|
||||||
|
import { exportFile } from '@/utils'
|
||||||
|
|
||||||
const { proxy: { $api, $store, $router, $message, $messageBox } } = getCurrentInstance()
|
const { proxy: { $api, $store, $router, $message, $messageBox, $tools } } = getCurrentInstance()
|
||||||
|
|
||||||
let updateHostData = ref(null)
|
let updateHostData = ref(null)
|
||||||
let hostFormVisible = ref(false)
|
let hostFormVisible = ref(false)
|
||||||
@ -155,6 +167,20 @@ let handleBatchOnekey = async () => {
|
|||||||
$router.push({ path: '/onekey', query: { host: ips, execClientInstallScript: 'true' } })
|
$router.push({ path: '/onekey', query: { host: ips, execClientInstallScript: 'true' } })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let handleBatchExport = () => {
|
||||||
|
collectSelectHost()
|
||||||
|
if (!selectHosts.value.length) return $message.warning('请选择要批量操作的实例')
|
||||||
|
console.log(selectHosts.value)
|
||||||
|
let exportData = JSON.parse(JSON.stringify(selectHosts.value))
|
||||||
|
exportData = exportData.map(item => {
|
||||||
|
delete item.monitorData
|
||||||
|
return item
|
||||||
|
})
|
||||||
|
const fileName = `easynode-${ $tools.formatTimestamp(Date.now(), 'time', '.') }.json`
|
||||||
|
exportFile(exportData, fileName, 'application/json')
|
||||||
|
hostTableRefs.value.forEach(item => item.clearSelection())
|
||||||
|
}
|
||||||
|
|
||||||
let handleHiddenIP = () => {
|
let handleHiddenIP = () => {
|
||||||
hiddenIp.value = hiddenIp.value ? 0 : 1
|
hiddenIp.value = hiddenIp.value ? 0 : 1
|
||||||
localStorage.setItem('hiddenIp', String(hiddenIp.value))
|
localStorage.setItem('hiddenIp', String(hiddenIp.value))
|
||||||
@ -207,8 +233,11 @@ let hostFormClosed = () => {
|
|||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: end;
|
justify-content: end;
|
||||||
|
.add_host_btn {
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
.group_action_btn {
|
.group_action_btn {
|
||||||
margin: 0 12px;
|
margin-right: 12px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@
|
|||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
v-else
|
v-else
|
||||||
type="success"
|
type="primary"
|
||||||
link
|
link
|
||||||
@click="handleUpdateHost(row)"
|
@click="handleUpdateHost(row)"
|
||||||
>
|
>
|
||||||
|
@ -1,22 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div>
|
|
||||||
<!-- <codemirror /> -->
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// import codemirror from '@/components/codemirror/index.vue'
|
|
||||||
|
|
||||||
export default {
|
|
||||||
name: 'Test',
|
|
||||||
// components: { codemirror },
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
|
||||||
|
|
||||||
</style>
|
|
Loading…
x
Reference in New Issue
Block a user