feat: 修改主机额外配置.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
:cancel-button-props="{ disabled: loading }"
|
||||
:on-before-ok="handlerOk"
|
||||
@cancel="handleClose">
|
||||
<a-spin :loading="loading">
|
||||
<a-spin class="full" :loading="loading">
|
||||
<a-form :model="formModel"
|
||||
ref="formRef"
|
||||
label-align="right"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -58,7 +58,7 @@ public class HostExtraController {
|
||||
return hostExtraService.getHostExtraList(request);
|
||||
}
|
||||
|
||||
@GetMapping("/update")
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "修改主机拓展信息")
|
||||
public Integer updateHostExtra(@Validated @RequestBody HostExtraUpdateRequest request) {
|
||||
return hostExtraService.updateHostExtra(request);
|
||||
|
||||
@@ -15,14 +15,14 @@ public enum HostExtraSshAuthTypeEnum {
|
||||
DEFAULT,
|
||||
|
||||
/**
|
||||
* 秘钥验证
|
||||
* 自定义秘钥验证
|
||||
*/
|
||||
KEY,
|
||||
CUSTOM_KEY,
|
||||
|
||||
/**
|
||||
* 身份验证
|
||||
* 自定义身份验证
|
||||
*/
|
||||
IDENTITY,
|
||||
CUSTOM_IDENTITY,
|
||||
|
||||
;
|
||||
|
||||
|
||||
@@ -55,9 +55,9 @@ public class HostSshExtraStrategy implements MapDataStrategy<HostSshExtraModel>
|
||||
Long keyId = model.getKeyId();
|
||||
Long identityId = model.getIdentityId();
|
||||
// 必填验证
|
||||
if (HostExtraSshAuthTypeEnum.KEY.equals(authType)) {
|
||||
if (HostExtraSshAuthTypeEnum.CUSTOM_KEY.equals(authType)) {
|
||||
Valid.notNull(keyId);
|
||||
} else if (HostExtraSshAuthTypeEnum.IDENTITY.equals(authType)) {
|
||||
} else if (HostExtraSshAuthTypeEnum.CUSTOM_IDENTITY.equals(authType)) {
|
||||
Valid.notNull(identityId);
|
||||
}
|
||||
// 验证主机秘钥是否存在
|
||||
|
||||
@@ -243,7 +243,6 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic
|
||||
List<Long> authorizedGroupIdList) {
|
||||
// 查询主机列表
|
||||
List<HostVO> hosts = hostService.getHostListByCache();
|
||||
|
||||
// 全部数据直接返回
|
||||
if (allData) {
|
||||
return hosts;
|
||||
@@ -258,6 +257,7 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic
|
||||
.map(dataGroupRel::get)
|
||||
.filter(Lists::isNoneEmpty)
|
||||
.flatMap(Collection::stream)
|
||||
.distinct()
|
||||
.map(hostMap::get)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
@@ -149,14 +149,17 @@ public class DataPermissionServiceImpl implements DataPermissionService {
|
||||
List<Long> list = RedisLists.range(cacheKey, Long::valueOf);
|
||||
if (list.isEmpty()) {
|
||||
LambdaQueryWrapper<DataPermissionDO> wrapper = dataPermissionDAO.lambda()
|
||||
.eq(DataPermissionDO::getType, type)
|
||||
.eq(DataPermissionDO::getUserId, userId);
|
||||
// 查询用户角色
|
||||
.eq(DataPermissionDO::getType, type);
|
||||
if (dataType.isToRole()) {
|
||||
// 查询用户角色
|
||||
List<Long> roleIdList = systemUserRoleDAO.selectRoleIdByUserId(userId);
|
||||
if (!roleIdList.isEmpty()) {
|
||||
wrapper.or().in(DataPermissionDO::getRoleId, roleIdList);
|
||||
}
|
||||
wrapper.and(s -> s.eq(DataPermissionDO::getUserId, userId)
|
||||
.or()
|
||||
.in(!roleIdList.isEmpty(), DataPermissionDO::getRoleId, roleIdList)
|
||||
);
|
||||
} else {
|
||||
// 单用户
|
||||
wrapper.eq(DataPermissionDO::getUserId, userId);
|
||||
}
|
||||
// 查询数据库
|
||||
list = dataPermissionDAO.of()
|
||||
|
||||
@@ -26,7 +26,11 @@
|
||||
UPDATE data_extra
|
||||
SET value = JSON_REPLACE(value,
|
||||
"$.keyId", NULL,
|
||||
"$.authType", IF(JSON_EXTRACT(value, "$.authType") = 'KEY', 'DEFAULT', JSON_EXTRACT(value, "$.authType")))
|
||||
"$.authType", IF(
|
||||
JSON_EXTRACT(value, "$.authType") = 'CUSTOM_KEY',
|
||||
'DEFAULT',
|
||||
JSON_EXTRACT(value, "$.authType")
|
||||
))
|
||||
WHERE deleted = 0
|
||||
AND type = 'HOST'
|
||||
AND item = 'ssh'
|
||||
@@ -37,7 +41,11 @@
|
||||
UPDATE data_extra
|
||||
SET value = JSON_REPLACE(value,
|
||||
"$.identityId", NULL,
|
||||
"$.authType", IF(JSON_EXTRACT(value, "$.authType") = 'IDENTITY', 'DEFAULT', JSON_EXTRACT(value, "$.authType")))
|
||||
"$.authType", IF(
|
||||
JSON_EXTRACT(value, "$.authType") = 'CUSTOM_IDENTITY',
|
||||
'DEFAULT',
|
||||
JSON_EXTRACT(value, "$.authType")
|
||||
))
|
||||
WHERE deleted = 0
|
||||
AND type = 'HOST'
|
||||
AND item = 'ssh'
|
||||
|
||||
@@ -24,12 +24,12 @@ export function getCurrentAuthorizedHost() {
|
||||
* 查询当前用户已授权的主机秘钥
|
||||
*/
|
||||
export function getCurrentAuthorizedHostKey() {
|
||||
return axios.get<HostKeyQueryResponse>('/asset/authorized-data/current-host-key');
|
||||
return axios.get<Array<HostKeyQueryResponse>>('/asset/authorized-data/current-host-key');
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询当前用户已授权的主机身份
|
||||
*/
|
||||
export function getCurrentAuthorizedHostIdentity() {
|
||||
return axios.get<HostIdentityQueryResponse>('/asset/authorized-data/current-host-identity');
|
||||
return axios.get<Array<HostIdentityQueryResponse>>('/asset/authorized-data/current-host-identity');
|
||||
}
|
||||
|
||||
@@ -8,9 +8,48 @@ export interface HostAliasUpdateRequest {
|
||||
name?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 主机拓展信息查询请求
|
||||
*/
|
||||
export interface HostExtraQueryRequest {
|
||||
hostId?: number;
|
||||
item: string;
|
||||
items?: Array<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
* 主机拓展信息更新请求
|
||||
*/
|
||||
export interface HostExtraUpdateRequest {
|
||||
hostId?: number;
|
||||
item: string;
|
||||
extra: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改主机别名
|
||||
*/
|
||||
export function updateHostAlias(request: HostAliasUpdateRequest) {
|
||||
return axios.put('/asset/host-extra/update-alias', request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取主机拓展信息
|
||||
*/
|
||||
export function getHostExtraItem<T>(params: HostExtraQueryRequest) {
|
||||
return axios.get<T>('/asset/host-extra/get', { params });
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取多个主机拓展信息
|
||||
*/
|
||||
export function getHostExtraItemList(request: HostExtraQueryRequest) {
|
||||
return axios.post<Record<string, Record<string, any>>>('/asset/host-extra/list', request);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改主机拓展信息
|
||||
*/
|
||||
export function updateHostExtra(request: HostExtraUpdateRequest) {
|
||||
return axios.put('/asset/host-extra/update', request);
|
||||
}
|
||||
|
||||
@@ -94,6 +94,11 @@ body {
|
||||
border-color: rgb(var(--gray-2));
|
||||
}
|
||||
|
||||
.full {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@@ -256,10 +256,10 @@
|
||||
const localeRef = ref();
|
||||
|
||||
// 打开应用设置
|
||||
const openAppSetting = inject(openAppSettingKey) as () => void;
|
||||
const openAppSetting = inject<() => void>(openAppSettingKey);
|
||||
|
||||
// 注入收缩菜单
|
||||
const toggleDrawerMenu = inject(toggleDrawerMenuKey) as () => void;
|
||||
const toggleDrawerMenu = inject<() => void>(toggleDrawerMenuKey);
|
||||
|
||||
// 切换主题
|
||||
const handleToggleTheme = () => {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: Number,
|
||||
authorized: Boolean
|
||||
});
|
||||
|
||||
const emits = defineEmits(['update:modelValue']);
|
||||
@@ -45,7 +46,9 @@
|
||||
onBeforeMount(async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const hostIdentities = await cacheStore.loadHostIdentities();
|
||||
const hostIdentities = props.authorized
|
||||
? await cacheStore.loadAuthorizedHostIdentities()
|
||||
: await cacheStore.loadHostIdentities();
|
||||
optionData.value = hostIdentities.map(s => {
|
||||
return {
|
||||
label: `${s.name} (${s.username})`,
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: Number,
|
||||
authorized: Boolean
|
||||
});
|
||||
|
||||
const emits = defineEmits(['update:modelValue']);
|
||||
@@ -45,7 +46,9 @@
|
||||
onBeforeMount(async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const hostKeys = await cacheStore.loadHostKeys();
|
||||
const hostKeys = props.authorized
|
||||
? await cacheStore.loadAuthorizedHostKeys()
|
||||
: await cacheStore.loadHostKeys();
|
||||
optionData.value = hostKeys.map(s => {
|
||||
return {
|
||||
label: s.name,
|
||||
|
||||
@@ -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"
|
||||
|
||||
15
orion-ops-ui/src/store/modules/cache/index.ts
vendored
15
orion-ops-ui/src/store/modules/cache/index.ts
vendored
@@ -11,10 +11,13 @@ import { getHostIdentityList } from '@/api/asset/host-identity';
|
||||
import { getHostList } from '@/api/asset/host';
|
||||
import { getHostGroupTree } from '@/api/asset/host-group';
|
||||
import { getMenuList } from '@/api/system/menu';
|
||||
import { getCurrentAuthorizedHostIdentity, getCurrentAuthorizedHostKey } from '@/api/asset/asset-authorized-data';
|
||||
|
||||
export type CacheType = 'users' | 'menus' | 'roles'
|
||||
| 'host' | 'hostGroups' | 'hostKeys' | 'hostIdentities'
|
||||
| 'dictKeys' | string
|
||||
| 'dictKeys'
|
||||
| 'authorizedHostKeys' | 'authorizedHostIdentities'
|
||||
| string
|
||||
|
||||
export default defineStore('cache', {
|
||||
state: (): CacheState => ({}),
|
||||
@@ -98,5 +101,15 @@ export default defineStore('cache', {
|
||||
return await this.load(`${type}_Tags`, () => getTagList(type), force);
|
||||
},
|
||||
|
||||
// 获取已授权的主机秘钥列表
|
||||
async loadAuthorizedHostKeys(force = false) {
|
||||
return await this.load('authorizedHostKeys', getCurrentAuthorizedHostKey, force);
|
||||
},
|
||||
|
||||
// 获取已授权的主机身份列表
|
||||
async loadAuthorizedHostIdentities(force = false) {
|
||||
return await this.load('authorizedHostIdentities', getCurrentAuthorizedHostIdentity, force);
|
||||
},
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
@@ -16,6 +16,8 @@ export interface CacheState {
|
||||
hostKeys?: HostKeyQueryResponse[];
|
||||
hostIdentities?: HostIdentityQueryResponse[];
|
||||
dictKeys?: DictKeyQueryResponse[];
|
||||
authorizedHostKeys?: HostKeyQueryResponse[];
|
||||
authorizedHostIdentities?: HostIdentityQueryResponse[];
|
||||
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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 = () => {
|
||||
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
];
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)">
|
||||
分配角色
|
||||
|
||||
Reference in New Issue
Block a user