💄 修改主机配置模态框样式.
This commit is contained in:
@@ -44,8 +44,8 @@ demo: http://101.43.254.243:1081/#/
|
||||
* 资产管理: 支持灵活配置主机分组, 统一管理主机、秘钥和身份。
|
||||
* 资产授权: 可将资产数据授权给指定角色和用户。
|
||||
* 权限控制: 全面管理用户角色, 支持动态菜单配置和强制下线等功能。
|
||||
* 在线终端: 提供便捷的在线 Web 终端服务, 支持自定义快捷键和主题风格。
|
||||
* 文件管理: 实现远程主机文件的批量上传、下载和在线编辑等操作。
|
||||
* 在线终端: 提供便捷的在线 Web 终端服务, 支持快捷命令、自定义快捷键和主题风格。
|
||||
* 文件管理: 实现远程主机大文件的批量上传、下载和在线编辑等操作。
|
||||
* 可扩展性: 前后端代码规范统一, 代码质量高、健壮且易于阅读和扩展。
|
||||
|
||||
[comment]: <> ( FIXME * 批量操作: 支持远程主机批量执行命令 以及 批量执行上传文件)
|
||||
|
||||
@@ -44,8 +44,8 @@ demo: http://101.43.254.243:1081/#/
|
||||
* 资产管理: 支持灵活配置主机分组, 统一管理主机、秘钥和身份。
|
||||
* 资产授权: 可将资产数据授权给指定角色和用户。
|
||||
* 权限控制: 全面管理用户角色, 支持动态菜单配置和强制下线等功能。
|
||||
* 在线终端: 提供便捷的在线 Web 终端服务, 支持自定义快捷键和主题风格。
|
||||
* 文件管理: 实现远程主机文件的批量上传、下载和在线编辑等操作。
|
||||
* 在线终端: 提供便捷的在线 Web 终端服务, 支持快捷命令、自定义快捷键和主题风格。
|
||||
* 文件管理: 实现远程主机大文件的批量上传、下载和在线编辑等操作。
|
||||
* 可扩展性: 前后端代码规范统一, 代码质量高、健壮且易于阅读和扩展。
|
||||
|
||||
[comment]: <> ( FIXME * 批量操作: 支持远程主机批量执行命令 以及 批量执行上传文件)
|
||||
|
||||
@@ -147,7 +147,6 @@ public class DataExtraServiceImpl implements DataExtraService {
|
||||
|
||||
@Override
|
||||
public Map<Long, String> getExtraItemValuesByCache(Long userId, String type, String item) {
|
||||
// todo TEST
|
||||
// 查询缓存
|
||||
String key = DataExtraCacheKeyDefine.DATA_EXTRA.format(userId, type, item);
|
||||
Map<String, String> entities = RedisMaps.entities(key);
|
||||
@@ -187,7 +186,6 @@ public class DataExtraServiceImpl implements DataExtraService {
|
||||
|
||||
@Override
|
||||
public Integer deleteByUserId(Long userId) {
|
||||
// 查询数据 TODO TEST
|
||||
List<DataExtraDO> list = this.getCacheSelectWrapper()
|
||||
.eq(DataExtraDO::getUserId, userId)
|
||||
.then()
|
||||
@@ -204,7 +202,6 @@ public class DataExtraServiceImpl implements DataExtraService {
|
||||
|
||||
@Override
|
||||
public Integer deleteByRelId(String type, Long relId) {
|
||||
// 查询数据 TODO TEST
|
||||
List<DataExtraDO> list = this.getCacheSelectWrapper()
|
||||
.eq(DataExtraDO::getType, type)
|
||||
.eq(DataExtraDO::getRelId, relId)
|
||||
|
||||
@@ -160,7 +160,7 @@
|
||||
</li>
|
||||
<!-- 用户信息 -->
|
||||
<li>
|
||||
<a-dropdown trigger="click">
|
||||
<a-dropdown trigger="click" position="br">
|
||||
<!-- 头像 -->
|
||||
<a-avatar draggable="false"
|
||||
:size="32"
|
||||
@@ -256,10 +256,10 @@
|
||||
const localeRef = ref();
|
||||
|
||||
// 打开应用设置
|
||||
const openAppSetting = inject<() => void>(openAppSettingKey);
|
||||
const openAppSetting = inject(openAppSettingKey) as () => void;
|
||||
|
||||
// 注入收缩菜单
|
||||
const toggleDrawerMenu = inject<() => void>(toggleDrawerMenuKey);
|
||||
const toggleDrawerMenu = inject(toggleDrawerMenuKey) as () => void;
|
||||
|
||||
// 切换主题
|
||||
const handleToggleTheme = () => {
|
||||
|
||||
@@ -137,13 +137,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</a-tooltip>
|
||||
<!-- 连接设置 -->
|
||||
<!-- 主机设置 -->
|
||||
<a-tooltip position="top"
|
||||
:mini="true"
|
||||
:auto-fix-position="false"
|
||||
content-class="terminal-tooltip-content"
|
||||
arrow-class="terminal-tooltip-content"
|
||||
content="连接设置">
|
||||
content="主机设置">
|
||||
<div class="terminal-sidebar-icon-wrapper">
|
||||
<div class="terminal-sidebar-icon" @click="openSetting(item)">
|
||||
<icon-settings />
|
||||
@@ -185,7 +185,7 @@
|
||||
import { dataColor } from '@/utils';
|
||||
import { tagColor } from '@/views/asset/host-list/types/const';
|
||||
import { updateHostAlias } from '@/api/asset/host-extra';
|
||||
import { openSshSettingModalKey, PanelSessionType } from '../../types/terminal.const';
|
||||
import { openSettingModalKey, PanelSessionType } from '../../types/terminal.const';
|
||||
import { useTerminalStore } from '@/store';
|
||||
|
||||
const props = defineProps<{
|
||||
@@ -231,7 +231,7 @@
|
||||
};
|
||||
|
||||
// 打开配置
|
||||
const openSetting = inject(openSshSettingModalKey) as (record: HostQueryResponse) => void;
|
||||
const openSetting = inject(openSettingModalKey) as (record: HostQueryResponse) => void;
|
||||
|
||||
// 设置收藏
|
||||
const setFavorite = async (item: HostQueryResponse) => {
|
||||
|
||||
@@ -21,8 +21,8 @@
|
||||
class="list-view-container"
|
||||
:hostList="hostList"
|
||||
empty-value="暂无连接记录, 快去体验吧!" />
|
||||
<!-- 修改主机设置模态框 -->
|
||||
<ssh-extra-modal ref="sshModal" />
|
||||
<!-- 主机设置模态框 -->
|
||||
<host-setting-modal ref="settingModal" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -34,12 +34,12 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { onMounted, provide, ref, watch } from 'vue';
|
||||
import { NewConnectionType, openSshSettingModalKey } from '../../types/terminal.const';
|
||||
import { NewConnectionType, openSettingModalKey } 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 '../setting/ssh-extra-modal.vue';
|
||||
import HostSettingModal from '../setting/extra/host-setting-modal.vue';
|
||||
|
||||
const props = defineProps<{
|
||||
hosts: AuthorizedHostQueryResponse,
|
||||
@@ -54,11 +54,11 @@
|
||||
? props.hosts.groupTree[0].key
|
||||
: 0
|
||||
);
|
||||
const sshModal = ref();
|
||||
const settingModal = ref();
|
||||
|
||||
// 暴露打开 ssh 配置模态框
|
||||
provide(openSshSettingModalKey, (record: any) => {
|
||||
sshModal.value?.open(record);
|
||||
provide(openSettingModalKey, (record: any) => {
|
||||
settingModal.value?.open(record);
|
||||
});
|
||||
|
||||
// 主机数据处理
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<a-modal v-model:visible="visible"
|
||||
title-align="start"
|
||||
:title="title"
|
||||
:top="180"
|
||||
:width="600"
|
||||
:align-center="false"
|
||||
:draggable="true"
|
||||
:mask-closable="false"
|
||||
:unmount-on-close="true"
|
||||
ok-text="保存当前页"
|
||||
cancel-text="关闭"
|
||||
:ok-button-props="{ disabled: loading }"
|
||||
:cancel-button-props="{ disabled: loading }"
|
||||
:on-before-ok="handlerOk"
|
||||
@close="handleClose">
|
||||
<a-spin class="full" :loading="loading">
|
||||
<a-tabs v-model="item"
|
||||
position="left"
|
||||
type="rounded"
|
||||
:lazy-load="true">
|
||||
<!-- SSH 配置 -->
|
||||
<a-tab-pane :key="ExtraSettingItems.SSH" title="SSH 配置">
|
||||
<ssh-setting-form ref="sshForm"
|
||||
:host-id="hostId as number"
|
||||
:item="ExtraSettingItems.SSH" />
|
||||
</a-tab-pane>
|
||||
<!-- 标签颜色 -->
|
||||
<a-tab-pane :key="ExtraSettingItems.COLOR" title="标签颜色">
|
||||
<!-- TODO -->
|
||||
<span>颜色</span>
|
||||
</a-tab-pane>
|
||||
</a-tabs>
|
||||
</a-spin>
|
||||
</a-modal>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'hostSettingModal'
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { HostQueryResponse } from '@/api/asset/host';
|
||||
import { ref } from 'vue';
|
||||
import useLoading from '@/hooks/loading';
|
||||
import useVisible from '@/hooks/visible';
|
||||
import { ExtraSettingItems } from '../../../types/terminal.const';
|
||||
import SshSettingForm from './ssh-setting-form.vue';
|
||||
import { updateHostExtra } from '@/api/asset/host-extra';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
const { visible, setVisible } = useVisible();
|
||||
const { loading, setLoading } = useLoading();
|
||||
|
||||
const item = ref<string>(ExtraSettingItems.SSH);
|
||||
const title = ref<string>();
|
||||
const hostId = ref<number>();
|
||||
const sshForm = ref();
|
||||
const colorForm = ref();
|
||||
|
||||
// 打开配置
|
||||
const open = (record: HostQueryResponse) => {
|
||||
hostId.value = record.id;
|
||||
title.value = record.alias || `${record.name} (${record.code})`;
|
||||
setVisible(true);
|
||||
};
|
||||
|
||||
defineExpose({ open });
|
||||
|
||||
// 确定
|
||||
const handlerOk = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
let value;
|
||||
if (item.value === ExtraSettingItems.SSH) {
|
||||
// SSH 配置
|
||||
value = await sshForm.value.getValue();
|
||||
} else if (item.value === ExtraSettingItems.COLOR) {
|
||||
// 颜色配置
|
||||
value = await colorForm.value.getValue();
|
||||
}
|
||||
if (!value) {
|
||||
return false;
|
||||
}
|
||||
// 保存
|
||||
await updateHostExtra({
|
||||
hostId: hostId.value,
|
||||
item: item.value,
|
||||
extra: value as string
|
||||
});
|
||||
Message.success('保存成功');
|
||||
} catch (e) {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// 关闭
|
||||
const handleClose = () => {
|
||||
handlerClear();
|
||||
};
|
||||
|
||||
// 清空
|
||||
const handlerClear = () => {
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
:deep(.arco-tabs-pane) {
|
||||
border-left: 1px var(--color-neutral-3) solid;
|
||||
padding-left: 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<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="toRadioOptions(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>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {
|
||||
name: 'sshSettingForm'
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { SshExtraModel } from '../../../types/terminal.type';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import { getHostExtraItem } from '@/api/asset/host-extra';
|
||||
import { ExtraSshAuthType, extraSshAuthTypeKey } from '../../../types/terminal.const';
|
||||
import { useDictStore } from '@/store';
|
||||
import HostKeySelector from '@/components/asset/host-key/host-key-selector.vue';
|
||||
import HostIdentitySelector from '@/components/asset/host-identity/host-identity-selector.vue';
|
||||
|
||||
const props = defineProps<{
|
||||
hostId: number,
|
||||
item: string
|
||||
}>();
|
||||
|
||||
const { toRadioOptions } = useDictStore();
|
||||
|
||||
const formRef = ref();
|
||||
const formModel = ref<SshExtraModel>({});
|
||||
|
||||
// 渲染表单
|
||||
const renderForm = async () => {
|
||||
const { data } = await getHostExtraItem<SshExtraModel>({ hostId: props.hostId, item: props.item });
|
||||
formModel.value = data;
|
||||
};
|
||||
|
||||
// 获取值
|
||||
const getValue = async () => {
|
||||
// 验证参数
|
||||
const error = await formRef.value.validate();
|
||||
if (error) {
|
||||
return false;
|
||||
}
|
||||
return JSON.stringify(formModel.value);
|
||||
};
|
||||
|
||||
defineExpose({ getValue });
|
||||
|
||||
onMounted(renderForm);
|
||||
|
||||
</script>
|
||||
|
||||
<style lang="less" scoped>
|
||||
|
||||
</style>
|
||||
@@ -1,146 +0,0 @@
|
||||
<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="toRadioOptions(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: 'sshExtraModal'
|
||||
};
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { HostQueryResponse } from '@/api/asset/host';
|
||||
import type { SshExtraModel } from '../../types/terminal.type';
|
||||
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 { toRadioOptions } = 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>
|
||||
@@ -42,6 +42,12 @@ export const NewConnectionType = {
|
||||
LATEST: 'latest'
|
||||
};
|
||||
|
||||
// 主机额外配置项
|
||||
export const ExtraSettingItems = {
|
||||
SSH: 'ssh',
|
||||
COLOR: 'color'
|
||||
};
|
||||
|
||||
// 主机额外配置 ssh 认证方式
|
||||
export const ExtraSshAuthType = {
|
||||
// 使用默认认证方式
|
||||
@@ -318,8 +324,8 @@ export const TransferReceiverType = {
|
||||
DOWNLOAD_ERROR: 'downloadError',
|
||||
};
|
||||
|
||||
// 打开 sshSettingModal key
|
||||
export const openSshSettingModalKey = Symbol();
|
||||
// 打开 settingModal key
|
||||
export const openSettingModalKey = Symbol();
|
||||
|
||||
// 打开 sftpCreateModal key
|
||||
export const openSftpCreateModalKey = Symbol();
|
||||
|
||||
Reference in New Issue
Block a user