🎨 优化主机分组授权显示.

This commit is contained in:
lijiahang
2024-12-30 15:54:07 +08:00
parent c2311f0682
commit 0557c41454
12 changed files with 140 additions and 144 deletions

View File

@@ -5,7 +5,7 @@
@grant="doGrant"
@select-all="selectAll"
@reverse="reverseSelect">
<!-- 分组 -->
<!-- 主机分组 -->
<host-group-tree v-model:checked-keys="checkedGroups"
ref="tree"
outer-class="group-main-tree"
@@ -15,8 +15,36 @@
@set-loading="setLoading"
@selected-node="(e) => selectedGroup = e"
@on-selected="clickGroup" />
<!-- 主机列表 -->
<host-list class="group-main-hosts sticky-list" :group="selectedGroup" />
<a-divider direction="vertical" />
<!-- 主机表格 -->
<a-table class="group-main-hosts"
row-key="id"
:sticky-header="true"
:loading="loading"
:columns="hostColumns"
:data="selectedGroupHosts"
:pagination="false"
:bordered="false">
<!-- 空状态 -->
<template #empty>
<a-empty style="margin: 32px 0;" description="当前分组内无主机" />
</template>
<!-- 主机类型 -->
<template #type="{ record }">
<a-tag class="flex-center" :color="getDictValue(hostTypeKey, record.type, 'color')">
<!-- 系统类型图标 -->
<component v-if="HostOsType[record.osType as keyof typeof HostOsType]"
:is="HostOsType[record.osType as keyof typeof HostOsType].icon"
class="os-icon" />
<!-- 主机类型 -->
<span>{{ getDictValue(hostTypeKey, record.type) }}</span>
</a-tag>
</template>
<!-- 地址 -->
<template #address="{ record }">
{{ record.address }}:{{ record.port }}
</template>
</a-table>
</grant-layout>
</template>
@@ -28,15 +56,18 @@
<script lang="ts" setup>
import type { TreeNodeData } from '@arco-design/web-vue';
import type { HostQueryResponse } from '@/api/asset/host';
import type { AssetAuthorizedDataQueryRequest, AssetDataGrantRequest } from '@/api/asset/asset-data-grant';
import { ref } from 'vue';
import { ref, watch } from 'vue';
import useLoading from '@/hooks/loading';
import { getAuthorizedHostGroup, grantHostGroup } from '@/api/asset/asset-data-grant';
import { useCacheStore } from '@/store';
import { useCacheStore, useDictStore } from '@/store';
import { flatNodeKeys } from '@/utils/tree';
import { Message } from '@arco-design/web-vue';
import { hostColumns } from '../types/table.columns';
import { HostOsType, hostTypeKey } from '@/views/asset/host-list/types/const';
import { getHostGroupRelList } from '@/api/asset/host-group';
import HostGroupTree from '@/components/asset/host-group/tree/index.vue';
import HostList from './host-list.vue';
import GrantLayout from './grant-layout.vue';
const props = defineProps<{
@@ -44,12 +75,32 @@
}>();
const cacheStore = useCacheStore();
const { getDictValue } = useDictStore();
const { loading, setLoading } = useLoading();
const tree = ref();
const authorizedGroups = ref<Array<number>>([]);
const checkedGroups = ref<Array<number>>([]);
const selectedGroup = ref<TreeNodeData>({});
const selectedGroupHosts = ref<Array<HostQueryResponse>>([]);
// 监听分组变化 加载组内数据
watch(() => selectedGroup.value?.key, async (groupId) => {
if (!groupId) {
return;
}
setLoading(true);
try {
// 加载组内数据
const { data } = await getHostGroupRelList(groupId as number);
const hosts = await cacheStore.loadHosts('');
selectedGroupHosts.value = data.map(s => hosts.find(h => h.id === s) as HostQueryResponse)
.filter(Boolean);
} catch (e) {
} finally {
setLoading(false);
}
});
// 点击分组
const clickGroup = (groups: Array<number>) => {
@@ -117,12 +168,18 @@
<style lang="less" scoped>
.group-main-tree {
width: calc(60% - 16px);
width: calc(100% - 496px);
height: 100%;
margin-right: 16px;
}
.group-main-hosts {
width: 40%;
width: 480px;
height: 100%;
.os-icon {
width: 16px;
height: 16px;
margin-right: 6px;
}
}
</style>

View File

@@ -51,7 +51,7 @@
import type { AssetAuthorizedDataQueryRequest, AssetDataGrantRequest } from '@/api/asset/asset-data-grant';
import type { HostIdentityQueryResponse } from '@/api/asset/host-identity';
import type { HostKeyQueryResponse } from '@/api/asset/host-key';
import { ref, onMounted } from 'vue';
import { ref, onMounted, onActivated } from 'vue';
import useLoading from '@/hooks/loading';
import { useRowSelection } from '@/hooks/table';
import { getAuthorizedHostIdentity, grantHostIdentity } from '@/api/asset/asset-data-grant';
@@ -125,23 +125,23 @@
}
};
// 初始化身份数据
onMounted(async () => {
// 初始化主机身份
const initIdentities = async () => {
setLoading(true);
try {
// 加载主机身份
hostIdentities.value = await cacheStore.loadHostIdentities();
// 加载主机密钥
hostKeys.value = await cacheStore.loadHostKeys();
} catch (e) {
} finally {
setLoading(false);
}
});
};
// 初始化密钥数据
onMounted(async () => {
// 加载主机密钥
hostKeys.value = await cacheStore.loadHostKeys();
});
// 初始化身份数据
onMounted(initIdentities);
onActivated(initIdentities);
</script>

View File

@@ -30,7 +30,7 @@
import type { TableData } from '@arco-design/web-vue/es/table/interface';
import type { AssetAuthorizedDataQueryRequest, AssetDataGrantRequest } from '@/api/asset/asset-data-grant';
import type { HostKeyQueryResponse } from '@/api/asset/host-key';
import { ref, onMounted } from 'vue';
import { ref, onMounted, onActivated } from 'vue';
import { getAuthorizedHostKey, grantHostKey } from '@/api/asset/asset-data-grant';
import useLoading from '@/hooks/loading';
import { useRowSelection } from '@/hooks/table';
@@ -101,8 +101,8 @@
}
};
// 初始化数据
onMounted(async () => {
// 初始化主机密钥
const initKeys = async () => {
setLoading(true);
try {
hostKeys.value = await cacheStore.loadHostKeys();
@@ -110,7 +110,11 @@
} finally {
setLoading(false);
}
});
};
// 初始化主机密钥
onMounted(initKeys);
onActivated(initKeys);
</script>

View File

@@ -1,112 +0,0 @@
<template>
<a-list size="small"
max-height="100%"
:hoverable="true"
:data="selectedGroupHosts"
:loading="loading">
<!-- 表头 -->
<template #header>
<span class="hosts-header-title">组内数据</span>
<span class="span-blue">{{ group?.title }}</span>
</template>
<!-- 空数据 -->
<template #empty>
<span class="host-list-empty">当前分组未配置主机</span>
</template>
<!-- 数据 -->
<template #item="{ item }">
<a-tooltip :content="`${item.name} - ${item.address}`">
<a-list-item>
<icon-desktop class="host-list-icon" />
<span>{{ `${item.name} - ` }}</span>
<span class="span-blue">{{ item.address }}</span>
</a-list-item>
</a-tooltip>
</template>
</a-list>
</template>
<script lang="ts">
export default {
name: 'hostList'
};
</script>
<script lang="ts" setup>
import type { TreeNodeData } from '@arco-design/web-vue';
import type { HostQueryResponse } from '@/api/asset/host';
import useLoading from '@/hooks/loading';
import { useCacheStore } from '@/store';
import { ref, watch } from 'vue';
import { getHostGroupRelList } from '@/api/asset/host-group';
const props = defineProps<Partial<{
group: TreeNodeData;
}>>();
const cacheStore = useCacheStore();
const { loading, setLoading } = useLoading();
const selectedGroupHosts = ref<Array<HostQueryResponse>>([]);
// 监听分组变化 加载组内数据
watch(() => props.group?.key, async (groupId) => {
if (!groupId) {
return;
}
// 加载组内数据
try {
setLoading(true);
const { data } = await getHostGroupRelList(groupId as number);
const hosts = await cacheStore.loadHosts(undefined);
selectedGroupHosts.value = data.map(s => hosts.find(h => h.id === s) as HostQueryResponse)
.filter(Boolean);
} catch (e) {
} finally {
setLoading(false);
}
});
</script>
<style lang="less" scoped>
.hosts-header-title {
&:after {
content: '-';
margin: 0 8px;
}
}
.host-list-empty {
padding: 16px 24px;
text-align: center;
color: var(--color-text-2);
display: block;
}
:deep(.arco-scrollbar) {
width: 100%;
height: 100%;
}
:deep(.arco-list-item-content) {
display: flex;
align-items: center;
color: var(--color-text-1);
overflow: hidden;
word-break: keep-all;
white-space: pre;
.host-list-icon {
font-size: 24px;
padding: 4px;
display: flex;
align-items: center;
justify-content: center;
color: var(--color-white);
background: rgb(var(--blue-6));
margin-right: 8px;
border-radius: 4px;
}
}
</style>

View File

@@ -74,8 +74,14 @@ export const GrantTabs = [
},
];
// 主机类型 字典项
export const hostTypeKey = 'hostType';
// 主机系统类型 字典项
export const hostOsTypeKey = 'hostOsType';
// 身份类型 字典项
export const identityTypeKey = 'hostIdentityType';
// 加载的字典值
export const dictKeys = [identityTypeKey];
export const dictKeys = [hostTypeKey, hostOsTypeKey, identityTypeKey];

View File

@@ -1,6 +1,36 @@
import type { TableColumnData } from '@arco-design/web-vue/es/table/interface';
import { dateFormat } from '@/utils';
// 主机列
export const hostColumns = [
{
title: 'id',
dataIndex: 'id',
slotName: 'id',
width: 68,
align: 'left',
fixed: 'left',
}, {
title: '主机类型',
dataIndex: 'type',
slotName: 'type',
align: 'center',
width: 100,
}, {
title: '主机名称',
dataIndex: 'name',
slotName: 'name',
ellipsis: true,
tooltip: true,
}, {
title: '主机地址',
dataIndex: 'address',
slotName: 'address',
ellipsis: true,
tooltip: true,
},
] as TableColumnData[];
// 主机密钥列
export const hostKeyColumns = [
{

View File

@@ -53,7 +53,7 @@
<script lang="ts" setup>
import type { TransferItem } from '@arco-design/web-vue/es/transfer/interface';
import type { TreeNodeData } from '@arco-design/web-vue';
import { onMounted, ref, watch, computed } from 'vue';
import { onMounted, ref, watch, computed, onActivated } from 'vue';
import { useCacheStore } from '@/store';
import { getHostGroupRelList } from '@/api/asset/host-group';
@@ -111,8 +111,9 @@
}
});
onMounted(() => {
cacheStore.loadHosts(undefined).then(hosts => {
// 加载主机列表
const loadHosts = () => {
cacheStore.loadHosts('').then(hosts => {
data.value = hosts.map(s => {
return {
value: String(s.id),
@@ -121,7 +122,10 @@
};
});
});
});
};
onMounted(loadHosts);
onActivated(loadHosts);
</script>

View File

@@ -324,7 +324,7 @@
// 重新加载数据
fetchCardData();
// 清空缓存
cacheStore.reset('host_SSH');
cacheStore.reset('host_', 'host_SSH');
};
defineExpose({ reload });

View File

@@ -364,13 +364,11 @@
// 重新加载数据
fetchTableData();
// 清空缓存
cacheStore.reset('host_SSH');
cacheStore.reset('host_', 'host_SSH');
};
defineExpose({ reload });
defineExpose({ reload });
// 加载数据
const doFetchTableData = async (request: HostQueryRequest) => {
try {

View File

@@ -30,7 +30,6 @@ export const HostOsType = {
},
};
// 主机类型 字典项
export const hostTypeKey = 'hostType';

View File

@@ -11,6 +11,7 @@
</span>
</div>
<div class="card-body">
<!-- 表格 -->
<a-table row-key="id"
:loading="loading"
:columns="batchExecColumns"
@@ -18,6 +19,10 @@
:pagination="false"
:bordered="false"
:scroll="{ y: 258 }">
<!-- 空状态 -->
<template #empty>
<a-empty style="margin-top: 42px;" description="暂无批量执行记录" />
</template>
<!-- 执行状态 -->
<template #status="{ record }">
<a-tag :color="getDictValue(execHostStatusKey, record.status, 'color')">

View File

@@ -11,6 +11,7 @@
</span>
</div>
<div class="card-body">
<!-- 表格 -->
<a-table row-key="id"
:loading="loading"
:columns="terminalLogColumns"
@@ -18,6 +19,10 @@
:pagination="false"
:bordered="false"
:scroll="{ y: 258 }">
<!-- 空状态 -->
<template #empty>
<a-empty style="margin-top: 42px;" description="暂无连接记录" />
</template>
<!-- 连接主机 -->
<template #hostName="{ record }">
<span class="table-cell-value" :title="record.hostName">