2024-11-01 21:00:59 +08:00

255 lines
8.2 KiB
Vue

<template>
<div class="server_group_container">
<div class="server_group_header">
<!-- <el-button v-show="selectHosts.length" 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">
{{ hiddenIp ? '显示IP' : '隐藏IP' }}
</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-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="handleBatchSSH">连接终端</el-dropdown-item>
<el-dropdown-item @click="handleBatchModify">批量修改</el-dropdown-item>
<el-dropdown-item @click="handleBatchRemove">批量删除</el-dropdown-item>
<el-dropdown-item @click="handleBatchOnekey">安装客户端</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
</div>
<div class="server_group_collapse">
<div v-if="isNoHost">
<el-empty description="暂无实例">
<el-button type="primary" @click="hostFormVisible = true">添加实例配置</el-button>
<span class="or">或</span>
<el-button type="primary" @click="importVisible = true">批量导入实例</el-button>
</el-empty>
</div>
<el-collapse v-else v-model="activeGroup">
<el-collapse-item v-for="(hosts, groupName) in groupHostList" :key="groupName" :name="groupName">
<template #title>
<div class="group_title">
{{ `${groupName}`+`${hosts.length ? `(${hosts.length})` : ''}` }}
</div>
</template>
<HostTable
ref="hostTableRefs"
:hosts="hosts"
@update-host="handleUpdateHost"
@update-list="handleUpdateList"
/>
</el-collapse-item>
</el-collapse>
</div>
<HostForm
v-model:show="hostFormVisible"
:default-data="updateHostData"
:is-batch-modify="isBatchModify"
:batch-hosts="selectHosts"
@update-list="handleUpdateList"
@closed="hostFormClosed"
/>
<ImportHost
v-model:show="importVisible"
@update-list="handleUpdateList"
/>
</div>
</template>
<script setup>
import { h, ref, getCurrentInstance, computed, watch } from 'vue'
// import HostCard from './components/host-card.vue'
import HostTable from './components/host-table.vue'
import HostForm from './components/host-form.vue'
import ImportHost from './components/import-host.vue'
import { ArrowDown } from '@element-plus/icons-vue'
import { exportFile } from '@/utils'
const { proxy: { $api, $store, $router, $message, $messageBox, $tools } } = getCurrentInstance()
let updateHostData = ref(null)
let hostFormVisible = ref(false)
let importVisible = ref(false)
let selectHosts = ref([])
let isBatchModify = ref(false)
const hostTableRefs = ref([])
let hiddenIp = ref(Number(localStorage.getItem('hiddenIp') || 0))
let activeGroup = ref([])
let handleUpdateList = async () => {
try {
await $store.getHostList()
} catch (err) {
$message.error('获取实例列表失败')
console.error('获取实例列表失败: ', err)
}
}
// 收集选中的实例
let collectSelectHost = () => {
let allSelectHosts = []
hostTableRefs.value.map(item => {
if (item) allSelectHosts = allSelectHosts.concat(item.getSelectHosts())
})
selectHosts.value = allSelectHosts
}
let handleBatchSSH = () => {
collectSelectHost()
if (!selectHosts.value.length) return $message.warning('请选择要批量操作的实例')
let ids = selectHosts.value.filter(item => item.isConfig).map(item => item.id)
if (!ids.length) return $message.warning('所选实例未配置ssh连接信息')
if (ids.length < selectHosts.value.length) $message.warning('部分实例未配置ssh连接信息,已忽略')
$router.push({ path: '/terminal', query: { hostIds: ids.join(',') } })
}
let handleBatchModify = async () => {
collectSelectHost()
if (!selectHosts.value.length) return $message.warning('请选择要批量操作的实例')
isBatchModify.value = true
hostFormVisible.value = true
}
let handleBatchRemove = async () => {
collectSelectHost()
if (!selectHosts.value.length) return $message.warning('请选择要批量操作的实例')
let ids = selectHosts.value.map(item => item.id)
let names = selectHosts.value.map(item => item.name)
$messageBox.confirm(() => h('p', { style: 'line-height: 18px;' }, `确认删除\n${ names.join(', ') }吗?`), 'Warning', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(async () => {
let { data } = await $api.removeHost({ ids })
$message({ message: data, type: 'success', center: true })
selectHosts.value = []
await handleUpdateList()
hostTableRefs.value.forEach(item => item.clearSelection())
})
}
let handleUpdateHost = (defaultData) => {
hostFormVisible.value = true
updateHostData.value = defaultData
}
let handleBatchOnekey = async () => {
collectSelectHost()
if (!selectHosts.value.length) return $message.warning('请选择要批量操作的实例')
let ids = selectHosts.value.map(item => item.id).join(',')
$router.push({ path: '/onekey', query: { hostIds: ids, execClientInstallScript: 'true' } })
}
let handleBatchExport = () => {
collectSelectHost()
if (!selectHosts.value.length) return $message.warning('请选择要批量操作的实例')
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 = () => {
hiddenIp.value = hiddenIp.value ? 0 : 1
localStorage.setItem('hiddenIp', String(hiddenIp.value))
}
let hostList = computed(() => $store.hostList)
let groupHostList = computed(() => {
let res = {}
let groupList = $store.groupList
groupList.forEach(group => {
res[group.name] = []
})
hostList.value.forEach(item => {
const group = groupList.find(group => group.id === item.group)
if (group) {
res[group.name].push(item)
} else {
res['默认分组'].push(item)
}
})
Object.keys(res).map(groupName => {
if (res[groupName].length === 0) delete res[groupName]
})
return res
})
watch(groupHostList, () => {
activeGroup.value = [...Object.keys(groupHostList.value),]
}, {
immediate: true,
deep: false
})
let isNoHost = computed(() => Object.keys(groupHostList.value).length === 0)
let hostFormClosed = () => {
updateHostData.value = null
isBatchModify.value = false
selectHosts.value = []
hostTableRefs.value.forEach(item => item.clearSelection())
}
</script>
<style lang="scss" scoped>
.server_group_container {
.server_group_header {
padding: 15px;
display: flex;
align-items: center;
justify-content: end;
.add_host_btn {
margin-right: 12px;
}
.group_action_btn {
margin-right: 12px;
}
}
.server_group_collapse {
:deep(.el-card__body) {
padding: 0;
}
:deep(.el-collapse-item__header) {
padding: 0 35px;
}
.group_title {
// margin: 0 15px;
font-size: 14px;
font-weight: 600;
line-height: 22px;
}
.or {
color: var(--el-text-color-secondary);
font-size: var(--el-font-size-base);
margin: 0 25px;
}
}
}
</style>