refactor: 优化查询主机逻辑.
This commit is contained in:
@@ -34,6 +34,6 @@ public class AuthorizedHostWrapperVO {
|
|||||||
private Map<String, Set<Long>> treeNodes;
|
private Map<String, Set<Long>> treeNodes;
|
||||||
|
|
||||||
@Schema(description = "最近访问的主机")
|
@Schema(description = "最近访问的主机")
|
||||||
private List<Long> latestHosts;
|
private Set<Long> latestHosts;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic
|
|||||||
favoriteResult.get(),
|
favoriteResult.get(),
|
||||||
dataAliasResult.get());
|
dataAliasResult.get());
|
||||||
// 设置最近连接的主机
|
// 设置最近连接的主机
|
||||||
wrapper.setLatestHosts(latestConnectHostIdList.get());
|
wrapper.setLatestHosts(new LinkedHashSet<>(latestConnectHostIdList.get()));
|
||||||
return wrapper;
|
return wrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
<select id="selectLatestConnectHostId" resultType="java.lang.Long">
|
<select id="selectLatestConnectHostId" resultType="java.lang.Long">
|
||||||
SELECT DISTINCT host_id
|
SELECT host_id
|
||||||
FROM host_connect_log
|
FROM host_connect_log
|
||||||
WHERE deleted = 0
|
WHERE deleted = 0
|
||||||
AND type = #{type}
|
AND type = #{type}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ export interface AuthorizedHostQueryResponse {
|
|||||||
groupTree: Array<HostGroupQueryResponse>;
|
groupTree: Array<HostGroupQueryResponse>;
|
||||||
hostList: Array<HostQueryResponse>;
|
hostList: Array<HostQueryResponse>;
|
||||||
treeNodes: Record<string, Array<number>>;
|
treeNodes: Record<string, Array<number>>;
|
||||||
|
latestHosts: Array<number>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import type {
|
|||||||
TerminalSessionSetting,
|
TerminalSessionSetting,
|
||||||
TerminalState
|
TerminalState
|
||||||
} from './types';
|
} from './types';
|
||||||
|
import type { AuthorizedHostQueryResponse } from '@/api/asset/asset-authorized-data';
|
||||||
|
import { getCurrentAuthorizedHost } from '@/api/asset/asset-authorized-data';
|
||||||
import type { TerminalTheme } from '@/api/asset/host-terminal';
|
import type { TerminalTheme } from '@/api/asset/host-terminal';
|
||||||
import { getTerminalThemes } from '@/api/asset/host-terminal';
|
import { getTerminalThemes } from '@/api/asset/host-terminal';
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
@@ -44,6 +46,7 @@ export default defineStore('terminal', {
|
|||||||
pluginsSetting: {} as TerminalPluginsSetting,
|
pluginsSetting: {} as TerminalPluginsSetting,
|
||||||
sessionSetting: {} as TerminalSessionSetting,
|
sessionSetting: {} as TerminalSessionSetting,
|
||||||
},
|
},
|
||||||
|
hosts: {} as AuthorizedHostQueryResponse,
|
||||||
tabManager: new TerminalTabManager(),
|
tabManager: new TerminalTabManager(),
|
||||||
sessionManager: new TerminalSessionManager()
|
sessionManager: new TerminalSessionManager()
|
||||||
}),
|
}),
|
||||||
@@ -55,7 +58,7 @@ export default defineStore('terminal', {
|
|||||||
// 加载偏好
|
// 加载偏好
|
||||||
const { data } = await getPreference<TerminalPreference>('TERMINAL');
|
const { data } = await getPreference<TerminalPreference>('TERMINAL');
|
||||||
// theme 不存在则默认加载第一个
|
// theme 不存在则默认加载第一个
|
||||||
if (!data.theme) {
|
if (!data.theme?.name) {
|
||||||
const { data: themes } = await getTerminalThemes();
|
const { data: themes } = await getTerminalThemes();
|
||||||
data.theme = themes[0];
|
data.theme = themes[0];
|
||||||
// 更新默认主题偏好
|
// 更新默认主题偏好
|
||||||
@@ -91,6 +94,22 @@ export default defineStore('terminal', {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// 加载主机列表
|
||||||
|
async loadHosts() {
|
||||||
|
if (this.hosts.hostList?.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { data } = await getCurrentAuthorizedHost();
|
||||||
|
Object.keys(data).forEach(k => {
|
||||||
|
this.hosts[k as keyof AuthorizedHostQueryResponse] = data[k as keyof AuthorizedHostQueryResponse] as any;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// 添加到最近连接列表
|
||||||
|
addToLatestConnect(hostId: number) {
|
||||||
|
this.hosts.latestHosts = [...new Set([hostId, ...this.hosts.latestHosts])];
|
||||||
|
}
|
||||||
|
|
||||||
},
|
},
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import type { ITerminalSessionManager, ITerminalTabManager } from '@/views/host/terminal/types/terminal.type';
|
import type { ITerminalSessionManager, ITerminalTabManager } from '@/views/host/terminal/types/terminal.type';
|
||||||
import type { TerminalTheme } from '@/api/asset/host-terminal';
|
import type { TerminalTheme } from '@/api/asset/host-terminal';
|
||||||
|
import type { AuthorizedHostQueryResponse } from '@/api/asset/asset-authorized-data';
|
||||||
|
|
||||||
export interface TerminalState {
|
export interface TerminalState {
|
||||||
preference: TerminalPreference;
|
preference: TerminalPreference;
|
||||||
|
hosts: AuthorizedHostQueryResponse;
|
||||||
tabManager: ITerminalTabManager;
|
tabManager: ITerminalTabManager;
|
||||||
sessionManager: ITerminalSessionManager;
|
sessionManager: ITerminalSessionManager;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -176,7 +176,7 @@
|
|||||||
emptyValue: string
|
emptyValue: string
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const { tabManager } = useTerminalStore();
|
const { tabManager, addToLatestConnect } = useTerminalStore();
|
||||||
const { toggle: toggleFavorite, loading: favoriteLoading } = useFavorite('HOST');
|
const { toggle: toggleFavorite, loading: favoriteLoading } = useFavorite('HOST');
|
||||||
|
|
||||||
const aliasNameInput = ref();
|
const aliasNameInput = ref();
|
||||||
@@ -215,6 +215,8 @@
|
|||||||
|
|
||||||
// 打开终端
|
// 打开终端
|
||||||
const openTerminal = (record: HostQueryResponse) => {
|
const openTerminal = (record: HostQueryResponse) => {
|
||||||
|
// 添加到最近连接
|
||||||
|
addToLatestConnect(record.id);
|
||||||
// 获取 seq
|
// 获取 seq
|
||||||
const tabSeqArr = tabManager.items
|
const tabSeqArr = tabManager.items
|
||||||
.map(s => s.seq)
|
.map(s => s.seq)
|
||||||
|
|||||||
@@ -44,8 +44,7 @@
|
|||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
hosts: AuthorizedHostQueryResponse,
|
hosts: AuthorizedHostQueryResponse,
|
||||||
filterValue: string,
|
filterValue: string,
|
||||||
newConnectionType: string,
|
newConnectionType: string
|
||||||
latestHosts: Array<number>
|
|
||||||
}>();
|
}>();
|
||||||
|
|
||||||
const hostList = ref<Array<HostQueryResponse>>([]);
|
const hostList = ref<Array<HostQueryResponse>>([]);
|
||||||
@@ -94,19 +93,26 @@
|
|||||||
list = list.filter(item => item.favorite);
|
list = list.filter(item => item.favorite);
|
||||||
} else if (NewConnectionType.LATEST === props.newConnectionType) {
|
} else if (NewConnectionType.LATEST === props.newConnectionType) {
|
||||||
// 过滤-最近连接
|
// 过滤-最近连接
|
||||||
list = list.filter(s => props.latestHosts.includes(s.id));
|
list = props.hosts.latestHosts
|
||||||
|
.map(s => list.find(item => item.id === s) as HostQueryResponse)
|
||||||
|
.filter(Boolean);
|
||||||
}
|
}
|
||||||
// 排序
|
// 非最近连接排序
|
||||||
hostList.value = list?.sort((o1, o2) => {
|
if (NewConnectionType.LATEST !== props.newConnectionType) {
|
||||||
if (o1.favorite || o2.favorite) {
|
hostList.value = list.sort((o1, o2) => {
|
||||||
if (o1.favorite && o2.favorite) {
|
if (o1.favorite || o2.favorite) {
|
||||||
|
if (o1.favorite && o2.favorite) {
|
||||||
|
return o2.id < o1.id ? 1 : -1;
|
||||||
|
}
|
||||||
|
return o2.favorite ? 1 : -1;
|
||||||
|
} else {
|
||||||
return o2.id < o1.id ? 1 : -1;
|
return o2.id < o1.id ? 1 : -1;
|
||||||
}
|
}
|
||||||
return o2.favorite ? 1 : -1;
|
});
|
||||||
} else {
|
} else {
|
||||||
return o2.id < o1.id ? 1 : -1;
|
// 最近连接不排序
|
||||||
}
|
hostList.value = list;
|
||||||
});
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 监听搜索值变化
|
// 监听搜索值变化
|
||||||
|
|||||||
@@ -60,8 +60,7 @@
|
|||||||
class="host-view-container"
|
class="host-view-container"
|
||||||
:hosts="hosts"
|
:hosts="hosts"
|
||||||
:filter-value="filterValue"
|
:filter-value="filterValue"
|
||||||
:new-connection-type="newConnectionType"
|
:new-connection-type="newConnectionType" />
|
||||||
:latest-hosts="latestHosts" />
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -76,27 +75,22 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { SelectOptionData } from '@arco-design/web-vue';
|
import type { SelectOptionData } from '@arco-design/web-vue';
|
||||||
import type { AuthorizedHostQueryResponse } from '@/api/asset/asset-authorized-data';
|
|
||||||
import { getCurrentAuthorizedHost } from '@/api/asset/asset-authorized-data';
|
|
||||||
import { onBeforeMount, ref } from 'vue';
|
import { onBeforeMount, ref } from 'vue';
|
||||||
import { NewConnectionType, newConnectionTypeKey } from '../../types/terminal.const';
|
import { NewConnectionType, newConnectionTypeKey } from '../../types/terminal.const';
|
||||||
import useLoading from '@/hooks/loading';
|
import useLoading from '@/hooks/loading';
|
||||||
import { useAppStore, useDictStore, useTerminalStore } from '@/store';
|
import { useDictStore, useTerminalStore } from '@/store';
|
||||||
import { PreferenceItem } from '@/store/modules/terminal';
|
import { PreferenceItem } from '@/store/modules/terminal';
|
||||||
import { dataColor } from '@/utils';
|
import { dataColor } from '@/utils';
|
||||||
import { tagColor } from '@/views/asset/host-list/types/const';
|
import { tagColor } from '@/views/asset/host-list/types/const';
|
||||||
import { getLatestConnectHostId } from '@/api/asset/host-connect-log';
|
|
||||||
import HostsView from './hosts-view.vue';
|
import HostsView from './hosts-view.vue';
|
||||||
|
|
||||||
const { loading, setLoading } = useLoading();
|
const { loading, setLoading } = useLoading();
|
||||||
const { toRadioOptions } = useDictStore();
|
const { toRadioOptions } = useDictStore();
|
||||||
const { preference, updateTerminalPreference } = useTerminalStore();
|
const { preference, updateTerminalPreference, hosts, loadHosts } = useTerminalStore();
|
||||||
|
|
||||||
const newConnectionType = ref(preference.newConnectionType || NewConnectionType.GROUP);
|
const newConnectionType = ref(preference.newConnectionType || NewConnectionType.GROUP);
|
||||||
const filterValue = ref('');
|
const filterValue = ref('');
|
||||||
const filterOptions = ref<Array<SelectOptionData>>([]);
|
const filterOptions = ref<Array<SelectOptionData>>([]);
|
||||||
const hosts = ref<AuthorizedHostQueryResponse>({} as AuthorizedHostQueryResponse);
|
|
||||||
const latestHosts = ref<Array<number>>([]);
|
|
||||||
|
|
||||||
// 过滤输入
|
// 过滤输入
|
||||||
const searchFilter = (searchValue: string, option: SelectOptionData) => {
|
const searchFilter = (searchValue: string, option: SelectOptionData) => {
|
||||||
@@ -112,7 +106,7 @@
|
|||||||
// 初始化过滤器项
|
// 初始化过滤器项
|
||||||
const initFilterOptions = () => {
|
const initFilterOptions = () => {
|
||||||
// 添加 tags
|
// 添加 tags
|
||||||
const tagNames = hosts.value.hostList?.map(s => s.tags)
|
const tagNames = hosts.hostList?.map(s => s.tags)
|
||||||
.filter(s => s?.length)
|
.filter(s => s?.length)
|
||||||
.flat(1)
|
.flat(1)
|
||||||
.sort((o1, o2) => o1.id - o2.id)
|
.sort((o1, o2) => o1.id - o2.id)
|
||||||
@@ -121,7 +115,7 @@
|
|||||||
return { label: value, value: `@${value}`, isTag: true };
|
return { label: value, value: `@${value}`, isTag: true };
|
||||||
}).forEach(s => filterOptions.value.push(s));
|
}).forEach(s => filterOptions.value.push(s));
|
||||||
// 添加主机信息
|
// 添加主机信息
|
||||||
const hostMeta = hosts.value.hostList?.map(s => {
|
const hostMeta = hosts.hostList?.map(s => {
|
||||||
return [s.name, s.code, s.address, s.alias];
|
return [s.name, s.code, s.address, s.alias];
|
||||||
}).filter(Boolean).flat(1);
|
}).filter(Boolean).flat(1);
|
||||||
[...new Set(hostMeta)].map(value => {
|
[...new Set(hostMeta)].map(value => {
|
||||||
@@ -134,8 +128,7 @@
|
|||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
// 加载主机信息
|
// 加载主机信息
|
||||||
const { data } = await getCurrentAuthorizedHost();
|
await loadHosts();
|
||||||
hosts.value = data;
|
|
||||||
// 初始化过滤项
|
// 初始化过滤项
|
||||||
initFilterOptions();
|
initFilterOptions();
|
||||||
} finally {
|
} finally {
|
||||||
@@ -143,24 +136,9 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 加载最近连接主机
|
|
||||||
const loadLatestConnectHost = async () => {
|
|
||||||
try {
|
|
||||||
setLoading(true);
|
|
||||||
// 加载最近连接主机
|
|
||||||
const { data } = await getLatestConnectHostId('SSH', useAppStore().defaultTablePageSize);
|
|
||||||
latestHosts.value = data;
|
|
||||||
} finally {
|
|
||||||
setLoading(false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 加载主机信息
|
// 加载主机信息
|
||||||
onBeforeMount(initHosts);
|
onBeforeMount(initHosts);
|
||||||
|
|
||||||
// 加载最近连接主机
|
|
||||||
onBeforeMount(loadLatestConnectHost);
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|||||||
@@ -82,7 +82,8 @@
|
|||||||
const terminalRef = ref();
|
const terminalRef = ref();
|
||||||
const session = ref<ITerminalSession>();
|
const session = ref<ITerminalSession>();
|
||||||
|
|
||||||
// FIXME
|
// TODO
|
||||||
|
// index 页面
|
||||||
// 搜索 search color 配置
|
// 搜索 search color 配置
|
||||||
// 右键菜单补充 启用右键菜单 enableRightClickMenu 粘贴逻辑
|
// 右键菜单补充 启用右键菜单 enableRightClickMenu 粘贴逻辑
|
||||||
// 快捷键补充 粘贴逻辑
|
// 快捷键补充 粘贴逻辑
|
||||||
|
|||||||
Reference in New Issue
Block a user