From 934c59cf9655741c32aad472e5bc40072184fe05 Mon Sep 17 00:00:00 2001 From: lijiahangmax Date: Tue, 19 Dec 2023 01:06:09 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E4=B8=BB=E6=9C=BA=E5=88=AB=E5=90=8D.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../request/host/HostAliasUpdateRequest.java | 1 + .../ops/module/asset/entity/vo/HostVO.java | 3 + .../impl/AssetAuthorizedDataServiceImpl.java | 23 ++- .../entity/dto/data/DataAliasUpdateDTO.java | 1 + .../service/impl/DataAliasServiceImpl.java | 2 + orion-ops-ui/src/api/asset/host.ts | 20 ++ .../asset/host-group/host-group-tree.vue | 42 ++--- .../components/group/host-transfer.vue | 7 +- .../new-connection/host-list-view.vue | 173 ++++++++++++++---- 9 files changed, 206 insertions(+), 66 deletions(-) diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/request/host/HostAliasUpdateRequest.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/request/host/HostAliasUpdateRequest.java index 8a8b8011..f929f814 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/request/host/HostAliasUpdateRequest.java +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/request/host/HostAliasUpdateRequest.java @@ -28,6 +28,7 @@ public class HostAliasUpdateRequest implements Serializable { @Schema(description = "id") private Long id; + @NotNull @Size(max = 32) @Schema(description = "别名") private String name; diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/vo/HostVO.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/vo/HostVO.java index 87cfb745..a25d8176 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/vo/HostVO.java +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/entity/vo/HostVO.java @@ -61,4 +61,7 @@ public class HostVO implements Serializable { @Schema(description = "分组 id") private Set groupIdList; + @Schema(description = "别名") + private String alias; + } diff --git a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/AssetAuthorizedDataServiceImpl.java b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/AssetAuthorizedDataServiceImpl.java index 3f8832ff..591f139a 100644 --- a/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/AssetAuthorizedDataServiceImpl.java +++ b/orion-ops-module-asset/orion-ops-module-asset-service/src/main/java/com/orion/ops/module/asset/service/impl/AssetAuthorizedDataServiceImpl.java @@ -2,6 +2,7 @@ package com.orion.ops.module.asset.service.impl; import com.orion.lang.function.Functions; import com.orion.lang.utils.collect.Lists; +import com.orion.lang.utils.collect.Maps; import com.orion.ops.framework.common.constant.Const; import com.orion.ops.framework.common.utils.TreeUtils; import com.orion.ops.framework.common.utils.Valid; @@ -15,10 +16,7 @@ import com.orion.ops.module.asset.service.HostService; import com.orion.ops.module.infra.api.*; import com.orion.ops.module.infra.entity.dto.data.DataGroupDTO; import com.orion.ops.module.infra.entity.dto.tag.TagDTO; -import com.orion.ops.module.infra.enums.DataGroupTypeEnum; -import com.orion.ops.module.infra.enums.DataPermissionTypeEnum; -import com.orion.ops.module.infra.enums.FavoriteTypeEnum; -import com.orion.ops.module.infra.enums.TagTypeEnum; +import com.orion.ops.module.infra.enums.*; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -67,6 +65,9 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic @Resource private TagRelApi tagRelApi; + @Resource + private DataAliasApi dataAliasApi; + @Override public List getAuthorizedDataRelId(DataPermissionTypeEnum type, AssetAuthorizedDataQueryRequest request) { Long userId = request.getUserId(); @@ -157,6 +158,8 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic AuthorizedHostWrapperVO wrapper = new AuthorizedHostWrapperVO(); // 查询我的收藏 Future> favoriteResult = favoriteApi.getFavoriteRelIdListAsync(FavoriteTypeEnum.HOST, userId); + // 查询数据别名 + Future> dataAliasResult = dataAliasApi.getDataAliasAsync(userId, DataAliasTypeEnum.HOST); // 查询分组 List dataGroup = dataGroupApi.getDataGroupList(DataGroupTypeEnum.HOST); // 查询分组引用 @@ -181,7 +184,9 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic dataGroupRel, authorizedGroupIdList)); // 设置主机拓展信息 - this.getAuthorizedHostExtra(wrapper.getHostList(), favoriteResult.get()); + this.getAuthorizedHostExtra(wrapper.getHostList(), + favoriteResult.get(), + dataAliasResult.get()); return wrapper; } @@ -263,9 +268,11 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic * * @param hosts hosts * @param favorite favorite + * @param aliasMap aliasMap */ private void getAuthorizedHostExtra(List hosts, - List favorite) { + List favorite, + Map aliasMap) { if (Lists.isEmpty(hosts)) { return; } @@ -281,6 +288,10 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic for (int i = 0; i < hosts.size(); i++) { hosts.get(i).setTags(tags.get(i)); } + // 设置主机别名 + if (!Maps.isEmpty(aliasMap)) { + hosts.forEach(s -> s.setAlias(aliasMap.get(s.getId()))); + } } } diff --git a/orion-ops-module-infra/orion-ops-module-infra-provider/src/main/java/com/orion/ops/module/infra/entity/dto/data/DataAliasUpdateDTO.java b/orion-ops-module-infra/orion-ops-module-infra-provider/src/main/java/com/orion/ops/module/infra/entity/dto/data/DataAliasUpdateDTO.java index fef6dae6..3ee1aec2 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-provider/src/main/java/com/orion/ops/module/infra/entity/dto/data/DataAliasUpdateDTO.java +++ b/orion-ops-module-infra/orion-ops-module-infra-provider/src/main/java/com/orion/ops/module/infra/entity/dto/data/DataAliasUpdateDTO.java @@ -34,6 +34,7 @@ public class DataAliasUpdateDTO implements Serializable { @Schema(description = "数据id") private Long relId; + @NotNull @Size(max = 32) @Schema(description = "别名") private String alias; diff --git a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/DataAliasServiceImpl.java b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/DataAliasServiceImpl.java index c8026786..64faf5b1 100644 --- a/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/DataAliasServiceImpl.java +++ b/orion-ops-module-infra/orion-ops-module-infra-service/src/main/java/com/orion/ops/module/infra/service/impl/DataAliasServiceImpl.java @@ -17,6 +17,7 @@ import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Function; import java.util.stream.Collectors; @@ -83,6 +84,7 @@ public class DataAliasServiceImpl implements DataAliasService { .eq(DataAliasDO::getType, type) .then() .stream() + .filter(s -> Objects.nonNull(s.getAlias())) .collect(Collectors.toMap( s -> String.valueOf(s.getRelId()), DataAliasDO::getAlias, diff --git a/orion-ops-ui/src/api/asset/host.ts b/orion-ops-ui/src/api/asset/host.ts index d30deb9f..f3b62974 100644 --- a/orion-ops-ui/src/api/asset/host.ts +++ b/orion-ops-ui/src/api/asset/host.ts @@ -46,8 +46,13 @@ export interface HostQueryResponse extends TableData { creator: string; updater: string; favorite: boolean; + alias: string; tags: Array<{ id: number, name: string }>; groupIdList: Array; + + editable: boolean; + loading: boolean; + modCount: number; } /** @@ -72,6 +77,14 @@ export interface HostConfigQueryResponse { config: Record; } +/** + * 主机别名更新请求 + */ +export interface HostAliasUpdateRequest { + id?: number; + name?: string; +} + /** * 创建主机 */ @@ -114,6 +127,13 @@ export function deleteHost(id: number) { return axios.delete('/asset/host/delete', { params: { id } }); } +/** + * 修改主机别名 + */ +export function updateHostAlias(request: HostAliasUpdateRequest) { + return axios.put('/asset/host/update-alias', request); +} + /** * 查询主机配置 */ diff --git a/orion-ops-ui/src/components/asset/host-group/host-group-tree.vue b/orion-ops-ui/src/components/asset/host-group/host-group-tree.vue index 4c69f26a..9c0efdc8 100644 --- a/orion-ops-ui/src/components/asset/host-group/host-group-tree.vue +++ b/orion-ops-ui/src/components/asset/host-group/host-group-tree.vue @@ -17,14 +17,14 @@ @@ -116,9 +116,7 @@ const cacheStore = useCacheStore(); const tree = ref(); - const modCount = ref(0); const renameInput = ref(); - const currName = ref(); const treeData = ref>([]); const checkedKeys = computed>({ @@ -140,7 +138,6 @@ if (!node) { return; } - currName.value = title; node.editable = true; nextTick(() => { renameInput.value?.focus(); @@ -178,14 +175,13 @@ const addRootNode = () => { const newKey = `${createGroupGroupPrefix}${Date.now()}`; treeData.value.push({ - title: '新分组', + title: '', key: newKey }); // 编辑子节点 const newNode = findNode(newKey, treeData.value); if (newNode) { newNode.editable = true; - currName.value = ''; nextTick(() => { renameInput.value?.focus(); }); @@ -197,7 +193,7 @@ const newKey = `${createGroupGroupPrefix}${Date.now()}`; const children = parentNode.children || []; children.push({ - title: '新分组', + title: '', key: newKey }); parentNode.children = children; @@ -209,7 +205,6 @@ const newNode = findNode(newKey, treeData.value); if (newNode) { newNode.editable = true; - currName.value = ''; nextTick(() => { renameInput.value?.focus(); }); @@ -217,18 +212,16 @@ }); }; + // FIXME 测试 // 保存节点 - const saveNode = async (key: string | number) => { - modCount.value++; - if (modCount.value !== 1) { + const saveNode = async (node: TreeNodeData) => { + const key = node.key + const newTitle = node.title + node.modCount = (node.modCount || 0) + 1; + if (node.modCount != 1) { return; } - // 寻找节点 - const node = findNode(key, treeData.value); - if (!node) { - return; - } - if (currName.value) { + if (newTitle) { node.loading = true; try { // 创建节点 @@ -240,17 +233,16 @@ // 创建 const { data } = await createHostGroup({ parentId: parent.key as number, - name: currName.value + name: newTitle }); node.key = data; } else { // 重命名节点 await updateHostGroupName({ id: key as unknown as number, - name: currName.value + name: newTitle }); } - node.title = currName.value; node.editable = false; } catch (e) { // 重复 重新聚焦 @@ -282,7 +274,7 @@ } node.editable = false; } - modCount.value = 0; + node.modCount = 0; }; // 移动分组 diff --git a/orion-ops-ui/src/views/asset/host-list/components/group/host-transfer.vue b/orion-ops-ui/src/views/asset/host-list/components/group/host-transfer.vue index 721d931b..00202cc5 100644 --- a/orion-ops-ui/src/views/asset/host-list/components/group/host-transfer.vue +++ b/orion-ops-ui/src/views/asset/host-list/components/group/host-transfer.vue @@ -86,11 +86,12 @@ } }); + // FIXME 省略和tooltip // 渲染 label const renderLabel = (label: string) => { const last = label.lastIndexOf('-'); - const prefix = label.substring(0, last); - const ip = label.substring(last + 1, label.length); + const prefix = label.substring(0, last - 1); + const ip = label.substring(last + 2, label.length); return `${prefix} - ${ip}`; }; @@ -117,7 +118,7 @@ data.value = hosts.map(s => { return { value: String(s.id), - label: `${s.name}(${s.code})-${s.address}`, + label: `${s.name} (${s.code}) - ${s.address}`, disabled: false }; }); diff --git a/orion-ops-ui/src/views/host-ops/terminal/components/new-connection/host-list-view.vue b/orion-ops-ui/src/views/host-ops/terminal/components/new-connection/host-list-view.vue index f8fcf575..078f961c 100644 --- a/orion-ops-ui/src/views/host-ops/terminal/components/new-connection/host-list-view.vue +++ b/orion-ops-ui/src/views/host-ops/terminal/components/new-connection/host-list-view.vue @@ -21,18 +21,62 @@
- - - - - - {{ `${item.name} (${item.code})` }} + + + + + + + + -
@@ -123,6 +167,8 @@ 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'; const props = defineProps<{ hostList: Array, @@ -131,18 +177,52 @@ const { toggle: toggleFavorite, loading: favoriteLoading } = useFavorite('HOST'); + const aliasNameInput = ref(); + + // 点击修改别名 + const clickEditAlias = (item: HostQueryResponse) => { + item.editable = true; + if (!item.alias) { + item.alias = `${item.name} (${item.code})`; + } + nextTick(() => { + aliasNameInput.value?.focus(); + }); + }; + + // 保存别名 + const saveAlias = async (item: HostQueryResponse) => { + item.loading = true; + item.modCount = (item.modCount || 0) + 1; + if (item.modCount != 1) { + return; + } + try { + // 修改别名 + await updateHostAlias({ + id: item.id, + name: item.alias || '' + }); + item.editable = false; + } catch (e) { + } finally { + item.loading = false; + item.modCount = 0; + } + }; + // 打开终端 - const openTerminal = (item: any) => { + const openTerminal = (item: HostQueryResponse) => { console.log('ter', item); }; // 打开配置 - const openSetting = (item: any) => { + const openSetting = (item: HostQueryResponse) => { console.log('set', item); }; // 设置收藏 - const setFavorite = async (item: any) => { + const setFavorite = async (item: HostQueryResponse) => { if (favoriteLoading.value) { return; } @@ -184,11 +264,11 @@ .host-item { width: 100%; - padding: 0 18px; + height: @host-item-height; display: flex; justify-content: space-between; align-items: center; - height: @host-item-height; + position: relative; &-text { display: inline-block; @@ -197,10 +277,27 @@ overflow: hidden; text-overflow: ellipsis; } + + &:hover { + .host-item-left-name-edit { + display: inline; + } + + .host-item-right-tags { + display: none; + } + + .host-item-right-actions { + display: flex; + } + } } .host-item-left { width: 35%; + height: 100%; + padding-left: 18px; + position: absolute; &-icon { width: 32px; @@ -216,12 +313,36 @@ } &-name { - max-width: calc(100% - 32px - 12px - 8px); + // 100% - icon-width - icon-margin-right + width: calc(100% - 42px); + display: flex; + align-items: center; + + &-text { + // 100% - edit-margin-left - edit-font-size + max-width: calc(100% - 18px); + } + + &-edit { + display: none; + margin-left: 4px; + cursor: pointer; + color: rgb(var(--blue-6)); + font-size: 14px; + } + + &-input { + width: 80%; + } } } .host-item-center { width: 25%; + height: 100%; + left: 35%; + padding: 0 8px; + position: absolute; &-address { max-width: 100%; @@ -231,34 +352,22 @@ .host-item-right { width: 40%; height: 100%; + left: 60%; + padding-right: 18px; flex-direction: column; justify-content: center; - position: relative; + position: absolute; &-tags { - // 必须设置 最外层用的是 min-width - position: absolute; width: 100%; } &-actions { - position: absolute; display: none; width: 100%; justify-content: flex-end; } } - - &:hover { - .host-item-right-tags { - display: none; - } - - .host-item-right-actions { - display: flex; - } - } - } .favorite {