1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-03-15 10:14:44 +08:00
2022-09-08 12:07:25 +08:00

319 lines
12 KiB
Vue

<template>
<el-row style="margin-top: 10px; margin-left: 10px" class="row-box" :gutter="20">
<el-col :span="8">
<el-card class="el-card">
<el-tooltip class="box-item" effect="dark" :content="$t('terminal.createConn')" placement="top-start">
<el-button icon="Plus" @click="restHostForm" size="small" />
</el-tooltip>
<el-tooltip class="box-item" effect="dark" :content="$t('terminal.createGroup')" placement="top-start">
<el-button icon="FolderAdd" @click="onGroupCreate" size="small" />
</el-tooltip>
<el-tooltip class="box-item" effect="dark" :content="$t('terminal.expand')" placement="top-start">
<el-button icon="Expand" @click="setTreeStatus(true)" size="small" />
</el-tooltip>
<el-tooltip class="box-item" effect="dark" :content="$t('terminal.fold')" placement="top-start">
<el-button icon="Fold" @click="setTreeStatus(false)" size="small" />
</el-tooltip>
<el-input
size="small"
@input="loadHostTree"
clearable
style="margin-top: 5px"
v-model="searcConfig.info"
>
<template #append><el-button icon="search" @click="loadHostTree" /></template>
</el-input>
<el-input
size="small"
v-if="groupInputShow"
clearable
style="margin-top: 5px"
v-model="groupInputValue"
>
<template #append>
<el-button-group>
<el-button icon="Check" @click="onCreateGroup" />
<el-button icon="Close" @click="groupInputShow = false" />
</el-button-group>
</template>
</el-input>
<el-tree
ref="tree"
:expand-on-click-node="false"
node-key="id"
:default-expand-all="true"
:data="hostTree"
:props="defaultProps"
>
<template #default="{ node, data }">
<span class="custom-tree-node" @mouseover="hover = data.id" @mouseleave="hover = null">
<span>
<a @click="onEdit(node, data)">{{ node.label }}</a>
</span>
<el-button-group
v-if="!(node.level === 1 && data.label === 'default') && data.id === hover"
>
<el-button icon="Edit" size="small" @click="onEdit(node, data)" />
<el-button icon="Delete" size="small" @click="onDelete(node, data)" />
</el-button-group>
</span>
</template>
</el-tree>
</el-card>
</el-col>
<el-col :span="16">
<el-card class="el-card">
<el-form ref="hostInfoRef" label-width="100px" label-position="left" :model="hostInfo" :rules="rules">
<el-form-item :label="$t('commons.table.name')" prop="name">
<el-input clearable v-model="hostInfo.name" />
</el-form-item>
<el-form-item :label="$t('commons.table.group')" prop="groupBelong">
<el-select filterable v-model="hostInfo.groupBelong" clearable style="width: 100%">
<el-option v-for="item in groupList" :key="item.id" :label="item.name" :value="item.name" />
</el-select>
</el-form-item>
<el-form-item label="IP" prop="addr">
<el-input clearable v-model="hostInfo.addr" />
</el-form-item>
<el-form-item :label="$t('terminal.port')" prop="port">
<el-input clearable v-model.number="hostInfo.port" />
</el-form-item>
<el-form-item :label="$t('terminal.user')" prop="user">
<el-input clearable v-model="hostInfo.user" />
</el-form-item>
<el-form-item :label="$t('terminal.authMode')" prop="authMode">
<el-radio-group v-model="hostInfo.authMode">
<el-radio label="password">{{ $t('terminal.passwordMode') }}</el-radio>
<el-radio label="key">{{ $t('terminal.keyMode') }}</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item
:label="$t('terminal.password')"
v-if="hostInfo.authMode === 'password'"
prop="password"
>
<el-input clearable show-password type="password" v-model="hostInfo.password" />
</el-form-item>
<el-form-item :label="$t('terminal.key')" v-if="hostInfo.authMode === 'key'" prop="privateKey">
<el-input clearable type="textarea" v-model="hostInfo.privateKey" />
</el-form-item>
<el-form-item :label="$t('commons.table.description')" prop="description">
<el-input clearable type="textarea" v-model="hostInfo.description" />
</el-form-item>
<el-form-item>
<el-button @click="restHostForm">
{{ $t('commons.button.reset') }}
</el-button>
<el-button @click="submitAddHost(hostInfoRef, 'testconn')">
{{ $t('terminal.testConn') }}
</el-button>
<el-button
v-if="hostOperation === 'create'"
type="primary"
@click="submitAddHost(hostInfoRef, 'create')"
>
{{ $t('commons.button.create') }}
</el-button>
<el-button
v-if="hostOperation === 'edit'"
type="primary"
@click="submitAddHost(hostInfoRef, 'edit')"
>
{{ $t('commons.button.confirm') }}
</el-button>
</el-form-item>
</el-form>
</el-card>
</el-col>
</el-row>
</template>
<script lang="ts" setup>
import { ref, reactive } from 'vue';
import type { ElForm } from 'element-plus';
import { Rules } from '@/global/form-rues';
import { Host } from '@/api/interface/host';
import { Group } from '@/api/interface/group';
import { testConn, getHostTree, getHostInfo, addHost, editHost, deleteHost } from '@/api/modules/host';
import { getGroupList, addGroup, editGroup, deleteGroup } from '@/api/modules/group';
import { useDeleteData } from '@/hooks/use-delete-data';
import { ElMessage } from 'element-plus';
import i18n from '@/lang';
import type Node from 'element-plus/es/components/tree/src/model/node';
type FormInstance = InstanceType<typeof ElForm>;
const hostInfoRef = ref<FormInstance>();
const rules = reactive({
name: [Rules.requiredInput, Rules.name],
group: [Rules.requiredSelect],
addr: [Rules.requiredInput, Rules.ip],
port: [Rules.requiredInput, Rules.port],
user: [Rules.requiredInput],
authMode: [Rules.requiredSelect],
password: [Rules.requiredInput],
privateKey: [Rules.requiredInput],
});
let hostOperation = ref<string>('create');
let hostInfo = reactive<Host.HostOperate>({
id: 0,
name: '',
groupBelong: 'default',
addr: '',
port: 22,
user: '',
authMode: 'password',
password: '',
privateKey: '',
description: '',
});
interface Tree {
id: number;
label: string;
children?: Tree[];
}
let searcConfig = reactive<Host.ReqSearch>({
info: '',
});
const tree = ref<any>(null);
const hover = ref();
const hostTree = ref<Array<Host.HostTree>>();
const defaultProps = {
label: 'label',
children: 'children',
};
const groupList = ref<Array<Group.GroupInfo>>();
let groupInputValue = ref();
let currentGroupID = ref();
let groupOperation = ref<string>('create');
let groupInputShow = ref<boolean>(false);
const loadHostTree = async () => {
const res = await getHostTree(searcConfig);
hostTree.value = res.data;
};
const loadGroups = async () => {
const res = await getGroupList({ type: 'host' });
groupList.value = res.data;
};
function setTreeStatus(expend: boolean) {
for (let i = 0; i < tree.value.store._getAllNodes().length; i++) {
tree.value.store._getAllNodes()[i].expanded = expend;
}
}
function restHostForm() {
if (hostInfoRef.value) {
hostInfoRef.value.resetFields();
}
}
const submitAddHost = (formEl: FormInstance | undefined, ops: string) => {
if (!formEl) return;
formEl.validate(async (valid) => {
if (!valid) return;
switch (ops) {
case 'create':
await addHost(hostInfo);
restHostForm();
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
loadHostTree();
break;
case 'edit':
await editHost(hostInfo);
restHostForm();
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
loadHostTree();
break;
case 'testconn':
await testConn(hostInfo);
ElMessage.success(i18n.global.t('terminal.connTestOk'));
break;
}
});
};
const onGroupCreate = () => {
groupInputShow.value = true;
groupInputValue.value = '';
groupOperation.value = 'create';
};
const onCreateGroup = async () => {
if (groupOperation.value === 'create') {
let group = { id: 0, name: groupInputValue.value, type: 'host' };
await addGroup(group);
groupOperation.value = '';
groupInputShow.value = false;
} else {
let group = { id: currentGroupID.value, name: groupInputValue.value, type: 'host' };
await editGroup(group);
}
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
groupOperation.value = '';
groupInputShow.value = false;
loadHostTree();
loadGroups();
};
const onDelete = async (node: Node, data: Tree) => {
if (node.level === 1 && data.label === 'default') {
return;
}
if (node.level === 1) {
await useDeleteData(deleteGroup, data.id - 10000, i18n.global.t('terminal.groupDeleteHelper'), true);
loadGroups();
} else {
await useDeleteData(deleteHost, data.id, 'commons.msg.delete', true);
}
loadHostTree();
loadGroups();
};
const onEdit = async (node: Node, data: Tree) => {
if (node.level === 1 && data.label === 'default') {
return;
}
if (node.level === 1) {
groupInputShow.value = true;
groupInputValue.value = data.label;
currentGroupID.value = data.id - 10000;
groupOperation.value = 'edit';
return;
} else {
const res = await getHostInfo(data.id);
hostInfo.id = res.data.id;
hostInfo.name = res.data.name;
hostInfo.groupBelong = res.data.groupBelong;
hostInfo.addr = res.data.addr;
hostInfo.port = res.data.port;
hostInfo.user = res.data.user;
hostInfo.description = res.data.description;
hostOperation.value = 'edit';
}
};
function onInit() {
loadHostTree();
loadGroups();
}
defineExpose({
onInit,
});
</script>
<style>
.custom-tree-node {
flex: 1;
display: flex;
align-items: center;
justify-content: space-between;
font-size: 14px;
padding-right: 8px;
}
</style>