feat: 修改主机额外配置.

This commit is contained in:
lijiahang
2023-12-25 19:03:24 +08:00
parent b2a697f6ba
commit f7cbd7b507
34 changed files with 321 additions and 59 deletions

View File

@@ -12,7 +12,7 @@
:cancel-button-props="{ disabled: loading }"
:on-before-ok="handlerOk"
@close="handleClose">
<a-spin :loading="loading">
<a-spin class="full" :loading="loading">
<a-form :model="formModel"
ref="formRef"
label-align="right"

View File

@@ -26,9 +26,9 @@
label="用户名"
:rules="usernameRules"
label-col-flex="60px"
:help="AuthType.IDENTITY === formModel.authType ? '将使用主机身份的用户名' : undefined">
:help="SshAuthType.IDENTITY === formModel.authType ? '将使用主机身份的用户名' : undefined">
<a-input v-model="formModel.username"
:disabled="AuthType.IDENTITY === formModel.authType"
:disabled="SshAuthType.IDENTITY === formModel.authType"
placeholder="请输入用户名" />
</a-form-item>
<!-- SSH 端口 -->
@@ -48,10 +48,10 @@
<a-radio-group type="button"
class="auth-type-group usn"
v-model="formModel.authType"
:options="toOptions(authTypeKey)" />
:options="toOptions(sshAuthTypeKey)" />
</a-form-item>
<!-- 主机密码 -->
<a-form-item v-if="AuthType.PASSWORD === formModel.authType"
<a-form-item v-if="SshAuthType.PASSWORD === formModel.authType"
field="password"
label="主机密码"
:rules="passwordRules"
@@ -68,7 +68,7 @@
unchecked-text="使用原密码" />
</a-form-item>
<!-- 主机秘钥 -->
<a-form-item v-if="AuthType.KEY === formModel.authType"
<a-form-item v-if="SshAuthType.KEY === formModel.authType"
field="keyId"
label="主机秘钥"
:hide-asterisk="true"
@@ -76,7 +76,7 @@
<host-key-selector v-model="formModel.keyId" />
</a-form-item>
<!-- 主机身份 -->
<a-form-item v-if="AuthType.IDENTITY === formModel.authType"
<a-form-item v-if="SshAuthType.IDENTITY === formModel.authType"
field="identityId"
label="主机身份"
:hide-asterisk="true"
@@ -140,7 +140,7 @@
import type { HostSshConfig } from './types/const';
import { reactive, ref, watch } from 'vue';
import { updateHostConfigStatus, updateHostConfig } from '@/api/asset/host-config';
import { authTypeKey, AuthType } from './types/const';
import { sshAuthTypeKey, SshAuthType } from './types/const';
import rules from './types/form.rules';
import { Message } from '@arco-design/web-vue';
import useLoading from '@/hooks/loading';
@@ -170,7 +170,7 @@
username: undefined,
port: undefined,
password: undefined,
authType: AuthType.PASSWORD,
authType: SshAuthType.PASSWORD,
keyId: undefined,
identityId: undefined,
connectTimeout: undefined,
@@ -195,7 +195,7 @@
cb('用户名长度不能大于128位');
return;
}
if (formModel.value.authType !== AuthType.IDENTITY && !value) {
if (formModel.value.authType !== SshAuthType.IDENTITY && !value) {
cb('请输入用户名');
return;
}

View File

@@ -14,8 +14,8 @@ export interface HostSshConfig {
hasPassword?: boolean;
}
// 主机验证方式
export const AuthType = {
// 主机 ssh 验证方式
export const SshAuthType = {
// 密码验证
PASSWORD: 'PASSWORD',
// 秘钥验证
@@ -25,7 +25,7 @@ export const AuthType = {
};
// 主机验证方式 字典项
export const authTypeKey = 'hostAuthTypeType';
export const sshAuthTypeKey = 'hostSshAuthType';
// 加载的字典值
export const dictKeys = [authTypeKey];
export const dictKeys = [sshAuthTypeKey];

View File

@@ -12,7 +12,7 @@
:cancel-button-props="{ disabled: loading }"
:on-before-ok="handlerOk"
@close="handleClose">
<a-spin :loading="loading">
<a-spin class="full" :loading="loading">
<a-form :model="formModel"
ref="formRef"
label-align="right"

View File

@@ -60,7 +60,7 @@
:max-length="32"
:disabled="item.loading"
size="mini"
placeholder="主机别名"
:placeholder="`${item.name} (${item.code})`"
@blur="saveAlias(item)"
@pressEnter="saveAlias(item)"
@change="saveAlias(item)"
@@ -164,11 +164,12 @@
<script lang="ts" setup>
import type { HostQueryResponse } from '@/api/asset/host';
import { ref, nextTick, inject } from 'vue';
import useFavorite from '@/hooks/favorite';
import { dataColor } from '@/utils';
import { tagColor } from '@/views/asset/host-list/types/const';
import { ref, nextTick } from 'vue';
import { updateHostAlias } from '@/api/asset/host-extra';
import { sshModalKey } from '../../types/terminal.const';
const props = defineProps<{
hostList: Array<HostQueryResponse>,
@@ -183,7 +184,7 @@
const clickEditAlias = (item: HostQueryResponse) => {
item.editable = true;
if (!item.alias) {
item.alias = `${item.name} (${item.code})`;
item.alias = '';
}
nextTick(() => {
aliasNameInput.value?.focus();
@@ -217,9 +218,7 @@
};
// 打开配置
const openSetting = (item: HostQueryResponse) => {
console.log('set', item);
};
const openSetting = inject<(record: HostQueryResponse) => void>(sshModalKey);
// 设置收藏
const setFavorite = async (item: HostQueryResponse) => {

View File

@@ -21,6 +21,8 @@
class="list-view-container"
:hostList="hostList"
empty-value="暂无连接记录, 快去体验吧!" />
<!-- 修改主机设置模态框 -->
<ssh-extra-modal ref="sshModal" />
</div>
</template>
@@ -31,12 +33,13 @@
</script>
<script lang="ts" setup>
import { onMounted, ref, watch } from 'vue';
import { NewConnectionType } from '../../types/terminal.const';
import { onMounted, provide, ref, watch } from 'vue';
import { NewConnectionType, sshModalKey } from '../../types/terminal.const';
import { AuthorizedHostQueryResponse } from '@/api/asset/asset-authorized-data';
import { HostQueryResponse } from '@/api/asset/host';
import HostGroupView from './host-group-view.vue';
import HostListView from './host-list-view.vue';
import SshExtraModal from './ssh-extra-modal.vue';
const props = defineProps<{
hosts: AuthorizedHostQueryResponse,
@@ -51,6 +54,12 @@
? props.hosts.groupTree[0].key
: 0
);
const sshModal = ref();
// 暴露打开 ssh 配置模态框
provide(sshModalKey, (record: any) => {
sshModal.value?.open(record);
});
// 主机数据处理
const shuffleHosts = () => {

View File

@@ -0,0 +1,146 @@
<template>
<a-modal v-model:visible="visible"
body-class="modal-form"
title-align="start"
:title="title"
:top="80"
:align-center="false"
:draggable="true"
:mask-closable="false"
:unmount-on-close="true"
ok-text="保存"
:ok-button-props="{ disabled: loading }"
:cancel-button-props="{ disabled: loading }"
:on-before-ok="handlerOk"
@close="handleClose">
<a-spin class="full" :loading="loading">
<a-form :model="formModel"
ref="formRef"
label-align="right"
:style="{ width: '460px' }"
:label-col-props="{ span: 6 }"
:wrapper-col-props="{ span: 18 }"
:rules="{}">
<!-- 验证方式 -->
<a-form-item field="authType" label="验证方式">
<a-radio-group type="button"
v-model="formModel.authType"
:options="toOptions(extraSshAuthTypeKey)" />
</a-form-item>
<!-- 用户名 -->
<a-form-item v-if="formModel.authType === ExtraSshAuthType.CUSTOM_KEY"
field="username"
label="用户名">
<a-input v-model="formModel.username" placeholder="请输入用户名" />
</a-form-item>
<!-- 主机秘钥 -->
<a-form-item v-if="formModel.authType === ExtraSshAuthType.CUSTOM_KEY"
field="keyId"
label="主机秘钥"
:rules="{ required: true, message: '请选择主机秘钥' }">
<host-key-selector v-model="formModel.keyId"
:authorized="true" />
</a-form-item>
<!-- 主机身份 -->
<a-form-item v-if="formModel.authType === ExtraSshAuthType.CUSTOM_IDENTITY"
field="identityId"
label="主机身份"
:rules="{ required: true, message: '请选择主机身份' }">
<host-identity-selector v-model="formModel.identityId"
:authorized="true" />
</a-form-item>
</a-form>
</a-spin>
</a-modal>
</template>
<script lang="ts">
export default {
name: 'ssh-extra-modal'
};
</script>
<script lang="ts" setup>
import type { HostQueryResponse } from '@/api/asset/host';
import type { SshExtraModel } from '../../types/terminal.const';
import { ref } from 'vue';
import useLoading from '@/hooks/loading';
import useVisible from '@/hooks/visible';
import { Message } from '@arco-design/web-vue';
import { getHostExtraItem, updateHostExtra } from '@/api/asset/host-extra';
import { ExtraSshAuthType, extraSshAuthTypeKey } from '../../types/terminal.const';
import { useDictStore } from '@/store';
import HostIdentitySelector from '@/components/asset/host-identity/host-identity-selector.vue';
import HostKeySelector from '@/components/asset/host-key/host-key-selector.vue';
const { toOptions } = useDictStore();
const { visible, setVisible } = useVisible();
const { loading, setLoading } = useLoading();
const title = ref<string>();
const hostId = ref<number>();
const formRef = ref();
const formModel = ref<SshExtraModel>({});
// 打开配置
const open = (record: HostQueryResponse) => {
hostId.value = record.id;
title.value = record.alias || `${record.name} (${record.code})`;
renderForm();
setVisible(true);
};
defineExpose({ open });
// 渲染表单
const renderForm = async () => {
try {
setLoading(true);
const { data } = await getHostExtraItem<SshExtraModel>({ hostId: hostId.value, item: 'ssh' });
formModel.value = data;
} catch (e) {
} finally {
setLoading(false);
}
};
// 确定
const handlerOk = async () => {
setLoading(true);
try {
// 验证参数
const error = await formRef.value.validate();
if (error) {
return false;
}
// 修改
await updateHostExtra({
hostId: hostId.value,
item: 'ssh',
extra: JSON.stringify(formModel.value)
});
Message.success('保存成功');
// 清空
handlerClear();
} catch (e) {
return false;
} finally {
setLoading(false);
}
};
// 关闭
const handleClose = () => {
handlerClear();
};
// 清空
const handlerClear = () => {
setLoading(false);
};
</script>
<style lang="less" scoped>
</style>

View File

@@ -34,9 +34,9 @@
<script lang="ts" setup>
import type { TabItem } from './types/terminal.const';
import { ref, onBeforeMount } from 'vue';
import { ref, onBeforeMount, onUnmounted } from 'vue';
import { TabType, InnerTabs, dictKeys } from './types/terminal.const';
import { useDictStore, useTerminalStore } from '@/store';
import { useCacheStore, useDictStore, useTerminalStore } from '@/store';
import TerminalHeader from './components/layout/terminal-header.vue';
import TerminalLeftSidebar from './components/layout/terminal-left-sidebar.vue';
import TerminalRightSidebar from './components/layout/terminal-right-sidebar.vue';
@@ -46,6 +46,7 @@
const terminalStore = useTerminalStore();
const dictStore = useDictStore();
const cacheStore = useCacheStore();
const render = ref(false);
const activeKey = ref(InnerTabs.NEW_CONNECTION.key);
@@ -93,6 +94,11 @@
await dictStore.loadKeys([...dictKeys]);
});
// 卸载时清除 cache
onUnmounted(() => {
cacheStore.reset('authorizedHostKeys', 'authorizedHostIdentities');
});
</script>
<style lang="less" scoped>

View File

@@ -51,6 +51,27 @@ export const NewConnectionType = {
LATEST: 'latest'
};
// ssh 额外配置
export interface SshExtraModel {
authType?: string;
username?: string;
keyId?: number;
identityId?: number;
}
// 主机额外配置 ssh 认证方式
export const ExtraSshAuthType = {
// 使用默认认证方式
DEFAULT: 'DEFAULT',
// 自定义秘钥
CUSTOM_KEY: 'CUSTOM_KEY',
// 自定义身份
CUSTOM_IDENTITY: 'CUSTOM_IDENTITY',
};
// 打开 sshModal key
export const sshModalKey = Symbol();
// 字体后缀 兜底
export const fontFamilySuffix = ',courier-new, courier, monospace';
@@ -72,9 +93,13 @@ export const cursorStyleKey = 'terminalCursorStyle';
// 终端新建连接类型
export const NewConnectionTypeKey = 'terminalNewConnectionType';
// 终端新建连接类型
export const extraSshAuthTypeKey = 'hostExtraSshAuthType';
// 加载的字典值
export const dictKeys = [
darkThemeKey, fontFamilyKey,
fontSizeKey, fontWeightKey,
cursorStyleKey, NewConnectionTypeKey
cursorStyleKey, NewConnectionTypeKey,
extraSshAuthTypeKey
];

View File

@@ -13,7 +13,7 @@
:cancel-button-props="{ disabled: loading }"
:on-before-ok="handlerOk"
@close="handleClose">
<a-spin :loading="loading">
<a-spin class="full" :loading="loading">
<a-form :model="formModel"
ref="formRef"
label-align="right"

View File

@@ -12,7 +12,7 @@
:cancel-button-props="{ disabled: loading }"
:on-before-ok="handlerOk"
@close="handleClose">
<a-spin :loading="loading">
<a-spin class="full" :loading="loading">
<a-form :model="formModel"
ref="formRef"
label-align="right"

View File

@@ -12,7 +12,7 @@
:cancel-button-props="{ disabled: loading }"
:on-before-ok="handlerOk"
@close="handleClose">
<a-spin :loading="loading">
<a-spin class="full" :loading="loading">
<a-form :model="formModel"
ref="formRef"
label-align="right"

View File

@@ -12,7 +12,7 @@
:cancel-button-props="{ disabled: loading }"
:on-before-ok="handlerOk"
@close="handleClose">
<a-spin :loading="loading">
<a-spin class="full" :loading="loading">
<a-form :model="formModel"
ref="formRef"
label-align="right"

View File

@@ -12,7 +12,7 @@
:cancel-button-props="{ disabled: loading }"
:on-before-ok="handlerOk"
@close="handleClose">
<a-spin :loading="loading">
<a-spin class="full" :loading="loading">
<a-form :model="formModel"
ref="formRef"
label-align="right"

View File

@@ -12,7 +12,7 @@
:cancel-button-props="{ disabled: loading }"
:on-before-ok="handlerOk"
@close="handleClose">
<a-spin :loading="loading">
<a-spin class="full" :loading="loading">
<a-form :model="formModel"
ref="formRef"
label-align="right"

View File

@@ -12,7 +12,7 @@
:cancel-button-props="{ disabled: loading }"
:on-before-ok="handlerOk"
@close="handleClose">
<a-spin :loading="loading">
<a-spin class="full" :loading="loading">
<a-form :model="formModel"
ref="formRef"
label-align="right"

View File

@@ -127,6 +127,7 @@
<!-- 分配角色 -->
<a-button type="text"
size="mini"
:disabled="record.id === userStore.id"
v-permission="['infra:system-user:grant-role']"
@click="emits('openGrantRole', record)">
分配角色