授权主机选择模态框.

This commit is contained in:
lijiahang
2024-03-07 15:54:51 +08:00
parent 079622d776
commit 6a7615e294
20 changed files with 680 additions and 189 deletions

View File

@@ -9,10 +9,12 @@
:columns="hostIdentityColumns"
v-model:selected-keys="selectedKeys"
:row-selection="rowSelection"
row-class="pointer"
:sticky-header="true"
:data="hostIdentities"
:pagination="false"
:bordered="false">
:bordered="false"
@row-click="clickRow">
<!-- 秘钥名称 -->
<template #keyId="{ record }">
<a-tag color="arcoblue" v-if="record.keyId">
@@ -30,6 +32,7 @@
</script>
<script lang="ts" setup>
import type { TableData } from '@arco-design/web-vue/es/table/interface';
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';
@@ -81,6 +84,16 @@
}
};
// 点击行
const clickRow = ({ id }: TableData) => {
const index = selectedKeys.value.indexOf(id);
if (index === -1) {
selectedKeys.value.push(id);
} else {
selectedKeys.value.splice(index, 1);
}
};
// 初始化数据
onMounted(async () => {
setLoading(true);

View File

@@ -9,10 +9,12 @@
:columns="hostKeyColumns"
v-model:selected-keys="selectedKeys"
:row-selection="rowSelection"
row-class="pointer"
:sticky-header="true"
:data="hostKeys"
:pagination="false"
:bordered="false" />
:bordered="false"
@row-click="clickRow" />
</grant-layout>
</template>
@@ -23,6 +25,7 @@
</script>
<script lang="ts" setup>
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';
@@ -71,6 +74,16 @@
}
};
// 点击行
const clickRow = ({ id }: TableData) => {
const index = selectedKeys.value.indexOf(id);
if (index === -1) {
selectedKeys.value.push(id);
} else {
selectedKeys.value.splice(index, 1);
}
};
// 初始化数据
onMounted(async () => {
setLoading(true);

View File

@@ -176,13 +176,13 @@
import { computed, reactive, ref, onMounted } from 'vue';
import useLoading from '@/hooks/loading';
import { dataColor, objectTruthKeyCount, resetObject } from '@/utils';
import fieldConfig from '../types/host.card.fields';
import fieldConfig from '../types/card.fields';
import { deleteHost, getHostPage } from '@/api/asset/host';
import { Message, Modal } from '@arco-design/web-vue';
import { tagColor } from '../types/const';
import TagMultiSelector from '@/components/meta/tag/tag-multi-selector.vue';
import useCopy from '@/hooks/copy';
import { GrantKey, GrantRouteName } from '@/views/asset/grant/types/const';
import TagMultiSelector from '@/components/meta/tag/tag-multi-selector.vue';
const emits = defineEmits(['openAdd', 'openUpdate', 'openUpdateConfig', 'openHostGroup']);

View File

@@ -63,13 +63,13 @@
import { ref } from 'vue';
import useLoading from '@/hooks/loading';
import useVisible from '@/hooks/visible';
import formRules from '../types/host.form.rules';
import formRules from '../types/form.rules';
import { createHost, getHost, updateHost } from '@/api/asset/host';
import { Message } from '@arco-design/web-vue';
import { pick } from 'lodash';
import { tagColor } from '@/views/asset/host-list/types/const';
import TagMultiSelector from '@/components/meta/tag/tag-multi-selector.vue';
import HostGroupTreeSelector from '@/components/asset/host-group/host-group-tree-selector.vue';
import { tagColor } from '@/views/asset/host-list/types/const';
const { visible, setVisible } = useVisible();
const { loading, setLoading } = useLoading();

View File

@@ -112,7 +112,9 @@
</template>
<!-- 标签 -->
<template #tags="{ record }">
<a-space v-if="record.tags">
<a-space v-if="record.tags"
style="margin-bottom: -8px;"
:wrap="true">
<a-tag v-for="tag in record.tags"
:key="tag.id"
:color="dataColor(tag.name, tagColor)">
@@ -166,14 +168,14 @@
import { reactive, ref, onMounted } from 'vue';
import { deleteHost, getHostPage } from '@/api/asset/host';
import { Message } from '@arco-design/web-vue';
import useLoading from '@/hooks/loading';
import columns from '../types/host.table.columns';
import { tagColor } from '../types/const';
import { usePagination } from '@/types/table';
import useLoading from '@/hooks/loading';
import useCopy from '@/hooks/copy';
import columns from '../types/table.columns';
import { dataColor } from '@/utils';
import TagMultiSelector from '@/components/meta/tag/tag-multi-selector.vue';
import { GrantKey, GrantRouteName } from '@/views/asset/grant/types/const';
import TagMultiSelector from '@/components/meta/tag/tag-multi-selector.vue';
const tagSelector = ref();
const tableRenderData = ref<HostQueryResponse[]>([]);

View File

@@ -31,7 +31,6 @@
</a-grid-item>
</a-grid>
</div>
<authorized-host-modal />
</div>
</template>
@@ -40,7 +39,6 @@
import QuickOperation from './components/quick-operation.vue';
import Docs from './components/docs.vue';
import OperatorLogSimpleTable from '@/views/user/operator-log/components/operator-log-simple-table.vue';
import AuthorizedHostModal from '@/components/asset/authorized-host-modal/index.vue';
</script>
<script lang="ts">

View File

@@ -27,55 +27,55 @@
<span class="host-item-left-name">
<!-- 名称文本 -->
<template v-if="!item.editable">
<!-- 文本 -->
<a-tooltip position="top"
:mini="true"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
:content="item.alias || `${item.name} (${item.code})`">
<span class="host-item-text host-item-left-name-text">
<template v-if="item.alias">
{{ item.alias }}
</template>
<template v-else>
{{ `${item.name} (${item.code})` }}
</template>
</span>
</a-tooltip>
<!-- 文本 -->
<a-tooltip position="top"
:mini="true"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
:content="item.alias || `${item.name} (${item.code})`">
<span class="host-item-text host-item-left-name-text">
<template v-if="item.alias">
{{ item.alias }}
</template>
<template v-else>
{{ `${item.name} (${item.code})` }}
</template>
</span>
</a-tooltip>
<!-- 修改别名 -->
<a-tooltip position="top"
:mini="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
content="修改别名">
<icon-edit class="host-item-left-name-edit"
@click="clickEditAlias(item)" />
</a-tooltip>
</template>
<a-tooltip position="top"
:mini="true"
:auto-fix-position="false"
content-class="terminal-tooltip-content"
arrow-class="terminal-tooltip-content"
content="修改别名">
<icon-edit class="host-item-left-name-edit"
@click="clickEditAlias(item)" />
</a-tooltip>
</template>
<!-- 名称输入框 -->
<template v-else>
<a-input v-model="item.alias"
ref="aliasNameInput"
class="host-item-left-name-input"
:max-length="32"
:disabled="item.loading"
size="mini"
:placeholder="item.name"
@blur="saveAlias(item)"
@pressEnter="saveAlias(item)"
@change="saveAlias(item)">
<template #suffix>
<!-- 加载中 -->
<icon-loading v-if="item.loading" />
<!-- 保存 -->
<icon-check v-else
class="pointer"
title="保存"
@click="saveAlias(item)" />
</template>
</a-input>
</template>
<a-input v-model="item.alias"
ref="aliasNameInput"
class="host-item-left-name-input"
:max-length="32"
:disabled="item.loading"
size="mini"
:placeholder="item.name"
@blur="saveAlias(item)"
@pressEnter="saveAlias(item)"
@change="saveAlias(item)">
<template #suffix>
<!-- 加载中 -->
<icon-loading v-if="item.loading" />
<!-- 保存 -->
<icon-check v-else
class="pointer"
title="保存"
@click="saveAlias(item)" />
</template>
</a-input>
</template>
</span>
</div>
<!-- 中间ip -->

View File

@@ -8,19 +8,9 @@
:host-list="hostList"
:filter-value="filterValue" />
<!-- 列表视图 -->
<host-list-view v-if="NewConnectionType.LIST === newConnectionType"
:hostList="hostList"
empty-value="无授权主机/主机未启用 SSH 配置!" />
<!-- 我的收藏 -->
<host-list-view v-if="NewConnectionType.FAVORITE === newConnectionType"
class="list-view-container"
:hostList="hostList"
empty-value="无收藏记录, 快去点击主机右侧的进行收藏吧!" />
<!-- 最近连接 -->
<host-list-view v-if="NewConnectionType.LATEST === newConnectionType"
class="list-view-container"
:hostList="hostList"
empty-value="暂无连接记录, 快去体验吧!" />
<host-list-view v-else
:host-list="hostList"
:empty-value="emptyMessage" />
<!-- 主机设置模态框 -->
<host-setting-modal ref="settingModal" />
</div>
@@ -33,7 +23,7 @@
</script>
<script lang="ts" setup>
import { onMounted, provide, ref, watch } from 'vue';
import { computed, onMounted, provide, ref, watch } from 'vue';
import { NewConnectionType, openSettingModalKey } from '../../types/terminal.const';
import { AuthorizedHostQueryResponse } from '@/api/asset/asset-authorized-data';
import { HostQueryResponse } from '@/api/asset/host';
@@ -56,6 +46,20 @@
);
const settingModal = ref();
const emptyMessage = computed(() => {
if (props.newConnectionType === NewConnectionType.LIST) {
// 列表
return '无授权主机/主机未启用 SSH 配置!';
} else if (props.newConnectionType === NewConnectionType.FAVORITE) {
// 收藏
return '无收藏记录, 快去点击主机右侧的⭐进行收藏吧!';
} else if (props.newConnectionType === NewConnectionType.LATEST) {
// 最近连接
return '暂无连接记录, 快去体验吧!';
}
return '';
});
// 暴露打开 ssh 配置模态框
provide(openSettingModalKey, (record: any) => {
settingModal.value?.open(record);

View File

@@ -17,8 +17,8 @@
placeholder="别名/名称/编码/IP @标签"
:allow-clear="true"
:data="filterOptions"
:filter-option="searchFilter">
<template #option="{ data: { raw: { label, isTag} } }">
:filter-option="tagLabelFilter">
<template #option="{ data: { raw: { label, isTag } } }">
<!-- tag -->
<a-tag v-if="isTag" :color="dataColor(label, tagColor)">
{{ label }}
@@ -72,7 +72,9 @@
import { useDictStore, useTerminalStore } from '@/store';
import { TerminalPreferenceItem } from '@/store/modules/terminal';
import { dataColor } from '@/utils';
import { tagLabelFilter } from '@/types/form';
import { tagColor } from '@/views/asset/host-list/types/const';
import { getAuthorizedHostOptions } from '@/types/options';
import HostsView from './hosts-view.vue';
const { toRadioOptions } = useDictStore();
@@ -82,39 +84,10 @@
const filterValue = ref('');
const filterOptions = ref<Array<SelectOptionData>>([]);
// 过滤输入
const searchFilter = (searchValue: string, option: SelectOptionData) => {
if (searchValue.startsWith('@')) {
// tag 过滤
return option.isTag && (option.label as string).toLowerCase().startsWith(searchValue.substring(1, searchValue.length).toLowerCase());
} else {
// 文本过滤
return !option.isTag && (option.label as string).toLowerCase().indexOf(searchValue.toLowerCase()) > -1;
}
};
// 初始化过滤器项
const initFilterOptions = () => {
// 添加 tags
const tagNames = hosts.hostList?.map(s => s.tags)
.filter(s => s?.length)
.flat(1)
.sort((o1, o2) => o1.id - o2.id)
.map(s => s.name);
[...new Set(tagNames)].map(value => {
return { label: value, value: `@${value}`, isTag: true };
}).forEach(s => filterOptions.value.push(s));
// 添加主机信息
const hostMeta = hosts.hostList?.map(s => {
return [s.name, s.code, s.address, s.alias];
}).filter(Boolean).flat(1);
[...new Set(hostMeta)].map(value => {
return { label: value, value };
}).forEach(s => filterOptions.value.push(s));
};
// 初始化过滤器项
onBeforeMount(initFilterOptions);
onBeforeMount(() => {
filterOptions.value = getAuthorizedHostOptions(hosts.hostList);
});
</script>