refactor: 修改缓存加载逻辑.
This commit is contained in:
@@ -30,7 +30,7 @@ public @interface OperatorLog {
|
|||||||
* - {@link org.springframework.web.bind.annotation.PathVariable}
|
* - {@link org.springframework.web.bind.annotation.PathVariable}
|
||||||
* <p>
|
* <p>
|
||||||
* 使用 @IgnoreParameter 可以忽略参数记录 {@link IgnoreParameter}
|
* 使用 @IgnoreParameter 可以忽略参数记录 {@link IgnoreParameter}
|
||||||
* 如果只需要忽略某个字段可以使用 @Desensitize(toEmpty = true) 标注
|
* 如果只需要忽略某个字段可以使用 {@code @Desensitize(toEmpty = true)} 标注
|
||||||
*/
|
*/
|
||||||
boolean parameter() default true;
|
boolean parameter() default true;
|
||||||
|
|
||||||
|
|||||||
@@ -45,23 +45,16 @@ public class CodeGenerators {
|
|||||||
// .color("blue", "gray", "red", "green", "white")
|
// .color("blue", "gray", "red", "green", "white")
|
||||||
// .valueUseFields()
|
// .valueUseFields()
|
||||||
// .build(),
|
// .build(),
|
||||||
Template.create("code_snippet", "代码片段", "snippet")
|
Template.create("command_template", "命令模板", "command")
|
||||||
.disableUnitTest()
|
.disableUnitTest()
|
||||||
.cache("code:snippet:{}", "代码片段")
|
.cache("command:template:list", "命令模板列表")
|
||||||
.expire(1, TimeUnit.DAYS)
|
.expire(1, TimeUnit.DAYS)
|
||||||
.vue("asset", "snippet")
|
.vue("asset", "snippet")
|
||||||
.enableCardView()
|
|
||||||
.enableDrawerForm()
|
.enableDrawerForm()
|
||||||
.dict("codeSnippetType", "type")
|
.dict("commandTemplateRender", "prepare_render")
|
||||||
.comment("代码片段类型")
|
|
||||||
.fields("COMMAND", "TEMPLATE")
|
|
||||||
.labels("命令", "模板")
|
|
||||||
.extra("icon", "icon-code-block", "icon-code")
|
|
||||||
.valueUseFields()
|
|
||||||
.dict("codeSnippetRender", "prepare_render")
|
|
||||||
.comment("是否使用脚本渲染")
|
.comment("是否使用脚本渲染")
|
||||||
.fields("UN_RENDER", "RENDER")
|
.fields("UNUSED", "USED")
|
||||||
.labels("不渲染", "渲染")
|
.labels("不使用", "使用")
|
||||||
.values(0, 1)
|
.values(0, 1)
|
||||||
.build(),
|
.build(),
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
### 查询当前用户已授权的主机分组及主机
|
### 查询当前用户已授权的主机
|
||||||
GET {{baseUrl}}/asset/authorized-data/current-host-group
|
GET {{baseUrl}}/asset/authorized-data/current-host
|
||||||
Authorization: {{token}}
|
Authorization: {{token}}
|
||||||
|
|
||||||
### 查询当前用户已授权的主机秘钥
|
### 查询当前用户已授权的主机秘钥
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import com.orion.ops.framework.log.core.annotation.IgnoreLog;
|
|||||||
import com.orion.ops.framework.log.core.enums.IgnoreLogMode;
|
import com.orion.ops.framework.log.core.enums.IgnoreLogMode;
|
||||||
import com.orion.ops.framework.security.core.utils.SecurityUtils;
|
import com.orion.ops.framework.security.core.utils.SecurityUtils;
|
||||||
import com.orion.ops.framework.web.core.annotation.RestWrapper;
|
import com.orion.ops.framework.web.core.annotation.RestWrapper;
|
||||||
import com.orion.ops.module.asset.entity.vo.AuthorizedHostGroupWrapperVO;
|
import com.orion.ops.module.asset.entity.vo.AuthorizedHostWrapperVO;
|
||||||
import com.orion.ops.module.asset.entity.vo.HostIdentityVO;
|
import com.orion.ops.module.asset.entity.vo.HostIdentityVO;
|
||||||
import com.orion.ops.module.asset.entity.vo.HostKeyVO;
|
import com.orion.ops.module.asset.entity.vo.HostKeyVO;
|
||||||
import com.orion.ops.module.asset.service.AssetAuthorizedDataService;
|
import com.orion.ops.module.asset.service.AssetAuthorizedDataService;
|
||||||
@@ -38,9 +38,9 @@ public class AssetAuthorizedDataServiceController {
|
|||||||
private AssetAuthorizedDataService assetAuthorizedDataService;
|
private AssetAuthorizedDataService assetAuthorizedDataService;
|
||||||
|
|
||||||
@IgnoreLog(IgnoreLogMode.RET)
|
@IgnoreLog(IgnoreLogMode.RET)
|
||||||
@GetMapping("/current-host-group")
|
@GetMapping("/current-host")
|
||||||
@Operation(summary = "查询当前用户已授权的主机分组及主机")
|
@Operation(summary = "查询当前用户已授权的主机")
|
||||||
public AuthorizedHostGroupWrapperVO getCurrentAuthorizedHostGroup() {
|
public AuthorizedHostWrapperVO getCurrentAuthorizedHostGroup() {
|
||||||
return assetAuthorizedDataService.getUserAuthorizedHostGroup(SecurityUtils.getLoginUserId());
|
return assetAuthorizedDataService.getUserAuthorizedHostGroup(SecurityUtils.getLoginUserId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import lombok.Data;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 已授权的主机分组 视图响应对象
|
* 已授权的主机分组 视图响应对象
|
||||||
@@ -20,7 +22,7 @@ import java.util.List;
|
|||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
@Schema(name = "AuthorizedHostGroupWrapperVO", description = "已授权的主机分组 视图响应对象")
|
@Schema(name = "AuthorizedHostGroupWrapperVO", description = "已授权的主机分组 视图响应对象")
|
||||||
public class AuthorizedHostGroupWrapperVO {
|
public class AuthorizedHostWrapperVO {
|
||||||
|
|
||||||
@Schema(description = "授权的主机分组")
|
@Schema(description = "授权的主机分组")
|
||||||
private List<HostGroupTreeVO> groupTree;
|
private List<HostGroupTreeVO> groupTree;
|
||||||
@@ -28,4 +30,7 @@ public class AuthorizedHostGroupWrapperVO {
|
|||||||
@Schema(description = "授权的主机列表")
|
@Schema(description = "授权的主机列表")
|
||||||
private List<HostVO> hostList;
|
private List<HostVO> hostList;
|
||||||
|
|
||||||
|
@Schema(description = "分组树节点映射 'groupId':hostIdList")
|
||||||
|
private Map<String, Set<Long>> treeNodes;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -44,7 +44,4 @@ public class HostGroupTreeVO implements TreeNode<HostGroupTreeVO>, Serializable
|
|||||||
@Schema(description = "子节点")
|
@Schema(description = "子节点")
|
||||||
private List<HostGroupTreeVO> children;
|
private List<HostGroupTreeVO> children;
|
||||||
|
|
||||||
@Schema(description = "分组内主机")
|
|
||||||
private List<HostVO> hostList;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package com.orion.ops.module.asset.service;
|
package com.orion.ops.module.asset.service;
|
||||||
|
|
||||||
import com.orion.ops.module.asset.entity.request.asset.AssetAuthorizedDataQueryRequest;
|
import com.orion.ops.module.asset.entity.request.asset.AssetAuthorizedDataQueryRequest;
|
||||||
import com.orion.ops.module.asset.entity.vo.AuthorizedHostGroupWrapperVO;
|
import com.orion.ops.module.asset.entity.vo.AuthorizedHostWrapperVO;
|
||||||
import com.orion.ops.module.asset.entity.vo.HostIdentityVO;
|
import com.orion.ops.module.asset.entity.vo.HostIdentityVO;
|
||||||
import com.orion.ops.module.asset.entity.vo.HostKeyVO;
|
import com.orion.ops.module.asset.entity.vo.HostKeyVO;
|
||||||
import com.orion.ops.module.infra.enums.DataPermissionTypeEnum;
|
import com.orion.ops.module.infra.enums.DataPermissionTypeEnum;
|
||||||
@@ -27,12 +27,12 @@ public interface AssetAuthorizedDataService {
|
|||||||
List<Long> getAuthorizedDataRelId(DataPermissionTypeEnum type, AssetAuthorizedDataQueryRequest request);
|
List<Long> getAuthorizedDataRelId(DataPermissionTypeEnum type, AssetAuthorizedDataQueryRequest request);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询用户已授权的主机分组和主机
|
* 查询用户已授权的主机主机
|
||||||
*
|
*
|
||||||
* @param userId userId
|
* @param userId userId
|
||||||
* @return group
|
* @return group
|
||||||
*/
|
*/
|
||||||
AuthorizedHostGroupWrapperVO getUserAuthorizedHostGroup(Long userId);
|
AuthorizedHostWrapperVO getUserAuthorizedHostGroup(Long userId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询用户已授权的主机秘钥
|
* 查询用户已授权的主机秘钥
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AuthorizedHostGroupWrapperVO getUserAuthorizedHostGroup(Long userId) {
|
public AuthorizedHostWrapperVO getUserAuthorizedHostGroup(Long userId) {
|
||||||
if (systemUserApi.isAdminUser(userId)) {
|
if (systemUserApi.isAdminUser(userId)) {
|
||||||
// 管理员查询所有
|
// 管理员查询所有
|
||||||
return this.buildUserAuthorizedHostGroup(null);
|
return this.buildUserAuthorizedHostGroup(null);
|
||||||
@@ -83,7 +83,7 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic
|
|||||||
List<Long> authorizedIdList = dataPermissionApi.getUserAuthorizedRelIdList(DataPermissionTypeEnum.HOST_GROUP, userId);
|
List<Long> authorizedIdList = dataPermissionApi.getUserAuthorizedRelIdList(DataPermissionTypeEnum.HOST_GROUP, userId);
|
||||||
if (authorizedIdList.isEmpty()) {
|
if (authorizedIdList.isEmpty()) {
|
||||||
// 无数据
|
// 无数据
|
||||||
return AuthorizedHostGroupWrapperVO.builder()
|
return AuthorizedHostWrapperVO.builder()
|
||||||
.groupTree(Lists.empty())
|
.groupTree(Lists.empty())
|
||||||
.hostList(Lists.empty())
|
.hostList(Lists.empty())
|
||||||
.build();
|
.build();
|
||||||
@@ -142,60 +142,103 @@ public class AssetAuthorizedDataServiceImpl implements AssetAuthorizedDataServic
|
|||||||
* @param authorizedGroupIdList authorizedGroupIdList
|
* @param authorizedGroupIdList authorizedGroupIdList
|
||||||
* @return tree
|
* @return tree
|
||||||
*/
|
*/
|
||||||
private AuthorizedHostGroupWrapperVO buildUserAuthorizedHostGroup(List<Long> authorizedGroupIdList) {
|
private AuthorizedHostWrapperVO buildUserAuthorizedHostGroup(List<Long> authorizedGroupIdList) {
|
||||||
final boolean allData = Lists.isEmpty(authorizedGroupIdList);
|
final boolean allData = Lists.isEmpty(authorizedGroupIdList);
|
||||||
AuthorizedHostGroupWrapperVO wrapper = new AuthorizedHostGroupWrapperVO();
|
AuthorizedHostWrapperVO wrapper = new AuthorizedHostWrapperVO();
|
||||||
// 查询主机列表
|
// TODO async get 最近连接
|
||||||
List<HostVO> hosts = hostService.getHostListByCache();
|
// TODO async get 我的收藏
|
||||||
Map<Long, HostVO> hostMap = hosts.stream()
|
|
||||||
.collect(Collectors.toMap(HostVO::getId, Function.identity(), Functions.right()));
|
|
||||||
// 查询分组引用
|
|
||||||
Map<Long, Set<Long>> groupRel = dataGroupRelApi.getGroupRelList(DataGroupTypeEnum.HOST);
|
|
||||||
// 查询分组
|
// 查询分组
|
||||||
List<DataGroupDTO> dataGroup = dataGroupApi.getDataGroupList(DataGroupTypeEnum.HOST);
|
List<DataGroupDTO> dataGroup = dataGroupApi.getDataGroupList(DataGroupTypeEnum.HOST);
|
||||||
// 过滤分组
|
// 查询分组引用
|
||||||
|
Map<Long, Set<Long>> dataGroupRel = dataGroupRelApi.getGroupRelList(DataGroupTypeEnum.HOST);
|
||||||
|
// 过滤已经授权的分组
|
||||||
if (!allData) {
|
if (!allData) {
|
||||||
// 构建已授权的分组
|
// 构建已授权的分组
|
||||||
List<DataGroupDTO> relNodes = new ArrayList<>();
|
List<DataGroupDTO> relNodes = new ArrayList<>();
|
||||||
TreeUtils.getAllNodes(dataGroup, authorizedGroupIdList, relNodes);
|
TreeUtils.getAllNodes(dataGroup, authorizedGroupIdList, relNodes);
|
||||||
dataGroup = new ArrayList<>(new HashSet<>(relNodes));
|
dataGroup = new ArrayList<>(new HashSet<>(relNodes));
|
||||||
}
|
}
|
||||||
// 设置组内数据
|
// 设置主机分组树
|
||||||
|
wrapper.setGroupTree(this.getAuthorizedHostGroupTree(dataGroup));
|
||||||
|
// 设置主机分组下的主机
|
||||||
|
wrapper.setTreeNodes(this.getAuthorizedHostGroupNodes(allData, dataGroup, dataGroupRel, authorizedGroupIdList));
|
||||||
|
// 设置已授权的所有主机
|
||||||
|
wrapper.setHostList(this.getAuthorizedHostList(allData, dataGroup, dataGroupRel, authorizedGroupIdList));
|
||||||
|
// TODO set 最近连接
|
||||||
|
// TODO set 我的收藏
|
||||||
|
|
||||||
|
return wrapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构建主机分组树
|
||||||
|
*
|
||||||
|
* @param dataGroup dataGroup
|
||||||
|
* @return tree
|
||||||
|
*/
|
||||||
|
private List<HostGroupTreeVO> getAuthorizedHostGroupTree(List<DataGroupDTO> dataGroup) {
|
||||||
List<HostGroupTreeVO> groupList = HostGroupConvert.MAPPER.toList(dataGroup);
|
List<HostGroupTreeVO> groupList = HostGroupConvert.MAPPER.toList(dataGroup);
|
||||||
groupList.stream()
|
|
||||||
// 因为可能父菜单没有授权 这里需要判断组
|
|
||||||
.filter(s -> allData || authorizedGroupIdList.contains(s.getId()))
|
|
||||||
.forEach(s -> {
|
|
||||||
List<HostVO> groupHosts = Lists.stream(groupRel.get(s.getId()))
|
|
||||||
.map(hostMap::get)
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
s.setHostList(groupHosts);
|
|
||||||
});
|
|
||||||
// 构建主机树
|
|
||||||
HostGroupTreeVO rootNode = HostGroupTreeVO.builder()
|
HostGroupTreeVO rootNode = HostGroupTreeVO.builder()
|
||||||
.id(Const.ROOT_PARENT_ID)
|
.id(Const.ROOT_PARENT_ID)
|
||||||
.sort(Const.DEFAULT_SORT)
|
.sort(Const.DEFAULT_SORT)
|
||||||
.build();
|
.build();
|
||||||
TreeUtils.buildGroupTree(rootNode, groupList);
|
TreeUtils.buildGroupTree(rootNode, groupList);
|
||||||
wrapper.setGroupTree(rootNode.getChildren());
|
return rootNode.getChildren();
|
||||||
// 设置授权的主机
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取主机分组树 主机节点映射
|
||||||
|
*
|
||||||
|
* @param allData allData
|
||||||
|
* @param dataGroup dataGroup
|
||||||
|
* @param dataGroupRel dataGroupRel
|
||||||
|
* @param authorizedGroupIdList authorizedGroupIdList
|
||||||
|
* @return hostGroupId:hostIdList
|
||||||
|
*/
|
||||||
|
private Map<String, Set<Long>> getAuthorizedHostGroupNodes(boolean allData,
|
||||||
|
List<DataGroupDTO> dataGroup,
|
||||||
|
Map<Long, Set<Long>> dataGroupRel,
|
||||||
|
List<Long> authorizedGroupIdList) {
|
||||||
|
Map<String, Set<Long>> result = new HashMap<>();
|
||||||
|
dataGroup.stream()
|
||||||
|
.map(DataGroupDTO::getId)
|
||||||
|
// 因为可能父菜单没有授权 这里需要判断分组权限
|
||||||
|
.filter(id -> allData || authorizedGroupIdList.contains(id))
|
||||||
|
.forEach(s -> result.put(String.valueOf(s), dataGroupRel.get(s)));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询已授权的所有主机
|
||||||
|
*
|
||||||
|
* @param allData allData
|
||||||
|
* @param dataGroup dataGroup
|
||||||
|
* @param dataGroupRel dataGroupRel
|
||||||
|
* @param authorizedGroupIdList authorizedGroupIdList
|
||||||
|
* @return hosts
|
||||||
|
*/
|
||||||
|
private List<HostVO> getAuthorizedHostList(boolean allData,
|
||||||
|
List<DataGroupDTO> dataGroup,
|
||||||
|
Map<Long, Set<Long>> dataGroupRel,
|
||||||
|
List<Long> authorizedGroupIdList) {
|
||||||
|
// 查询主机列表
|
||||||
|
List<HostVO> hosts = hostService.getHostListByCache();
|
||||||
|
// 全部数据直接返回
|
||||||
if (allData) {
|
if (allData) {
|
||||||
// 设置全部数据
|
return hosts;
|
||||||
wrapper.setHostList(hosts);
|
|
||||||
} else {
|
|
||||||
// 仅设置已授权的数据
|
|
||||||
List<HostVO> groupHosts = groupList.stream()
|
|
||||||
.filter(s -> authorizedGroupIdList.contains(s.getId()))
|
|
||||||
.map(s -> groupRel.get(s.getId()))
|
|
||||||
.filter(Lists::isNoneEmpty)
|
|
||||||
.flatMap(Collection::stream)
|
|
||||||
.map(hostMap::get)
|
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
wrapper.setHostList(groupHosts);
|
|
||||||
}
|
}
|
||||||
return wrapper;
|
Map<Long, HostVO> hostMap = hosts.stream()
|
||||||
|
.collect(Collectors.toMap(HostVO::getId, Function.identity(), Functions.right()));
|
||||||
|
// 仅设置已授权的数据
|
||||||
|
return dataGroup.stream()
|
||||||
|
.map(DataGroupDTO::getId)
|
||||||
|
.filter(authorizedGroupIdList::contains)
|
||||||
|
.map(dataGroupRel::get)
|
||||||
|
.filter(Lists::isNoneEmpty)
|
||||||
|
.flatMap(Collection::stream)
|
||||||
|
.map(hostMap::get)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,18 +5,19 @@ import type { HostIdentityQueryResponse } from './host-identity';
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 已授权的主机分组 查询响应
|
* 已授权的主机 查询响应
|
||||||
*/
|
*/
|
||||||
export interface AuthorizedHostGroupQueryResponse {
|
export interface AuthorizedHostQueryResponse {
|
||||||
groupTree: Array<HostGroupQueryResponse>;
|
groupTree: Array<HostGroupQueryResponse>;
|
||||||
hostList: Array<HostQueryResponse>;
|
hostList: Array<HostQueryResponse>;
|
||||||
|
treeNodes: Record<string, Array<number>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询当前用户已授权的主机分组
|
* 查询当前用户已授权的主机
|
||||||
*/
|
*/
|
||||||
export function getCurrentAuthorizedHostGroup() {
|
export function getCurrentAuthorizedHost() {
|
||||||
return axios.get<AuthorizedHostGroupQueryResponse>('/asset/authorized-data/current-host-group');
|
return axios.get<AuthorizedHostQueryResponse>('/asset/authorized-data/current-host');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import type { HostQueryResponse } from './host';
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -34,7 +33,6 @@ export interface HostGroupQueryResponse {
|
|||||||
parentId: number;
|
parentId: number;
|
||||||
title: string;
|
title: string;
|
||||||
children: Array<HostGroupQueryResponse>;
|
children: Array<HostGroupQueryResponse>;
|
||||||
hostList: Array<HostQueryResponse>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
export type TagType = 'HOST'
|
export type TagType = 'HOST' | string
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* tag 创建对象
|
* tag 创建对象
|
||||||
@@ -29,5 +29,5 @@ export function createTag(request: TagCreateRequest) {
|
|||||||
* 查询标签
|
* 查询标签
|
||||||
*/
|
*/
|
||||||
export function getTagList(type: TagType) {
|
export function getTagList(type: TagType) {
|
||||||
return axios.get<TagQueryResponse>('/infra/tag/list', { params: { type } });
|
return axios.get<Array<TagQueryResponse>>('/infra/tag/list', { params: { type } });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,15 +44,10 @@
|
|||||||
const treeData = ref<Array<TreeNodeData>>([]);
|
const treeData = ref<Array<TreeNodeData>>([]);
|
||||||
|
|
||||||
// 初始化选项
|
// 初始化选项
|
||||||
onBeforeMount(async () => {
|
onBeforeMount(() => {
|
||||||
if (cacheStore.hostGroups.length) {
|
cacheStore.loadHostGroups().then(s => {
|
||||||
treeData.value = cacheStore.hostGroups;
|
treeData.value = s;
|
||||||
} else {
|
});
|
||||||
// 加载数据
|
|
||||||
const { data } = await getHostGroupTree();
|
|
||||||
treeData.value = data;
|
|
||||||
cacheStore.set('hostGroups', data);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
ref="tree"
|
ref="tree"
|
||||||
class="tree-container"
|
class="tree-container"
|
||||||
:blockNode="true"
|
:blockNode="true"
|
||||||
:draggable="draggable"
|
:draggable="editable"
|
||||||
:data="treeData"
|
:data="treeData"
|
||||||
:checkable="checkable"
|
:checkable="checkable"
|
||||||
v-model:checked-keys="checkedKeys"
|
v-model:checked-keys="checkedKeys"
|
||||||
@@ -20,7 +20,6 @@
|
|||||||
v-model="currName"
|
v-model="currName"
|
||||||
style="width: 138px;"
|
style="width: 138px;"
|
||||||
placeholder="名称"
|
placeholder="名称"
|
||||||
autofocus
|
|
||||||
:max-length="32"
|
:max-length="32"
|
||||||
:disabled="node.loading"
|
:disabled="node.loading"
|
||||||
@blur="() => saveNode(node.key)"
|
@blur="() => saveNode(node.key)"
|
||||||
@@ -77,7 +76,7 @@
|
|||||||
<!-- 无数据 -->
|
<!-- 无数据 -->
|
||||||
<div v-else-if="!loading" class="empty-container">
|
<div v-else-if="!loading" class="empty-container">
|
||||||
<span>暂无数据</span>
|
<span>暂无数据</span>
|
||||||
<span>点击上方 '<icon-plus />' 添加一个分组吧~</span>
|
<span v-if="editable">点击上方 '<icon-plus />' 添加一个分组吧~</span>
|
||||||
</div>
|
</div>
|
||||||
</a-scrollbar>
|
</a-scrollbar>
|
||||||
</template>
|
</template>
|
||||||
@@ -99,7 +98,7 @@
|
|||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
loading: Boolean,
|
loading: Boolean,
|
||||||
draggable: {
|
editable: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true
|
default: true
|
||||||
},
|
},
|
||||||
@@ -313,20 +312,13 @@
|
|||||||
|
|
||||||
// 加载数据
|
// 加载数据
|
||||||
const fetchTreeData = async (force = false) => {
|
const fetchTreeData = async (force = false) => {
|
||||||
if (cacheStore.hostGroups.length && !force) {
|
try {
|
||||||
// 缓存有数据并且非强制加载 直接从缓存中加载
|
const groups = await cacheStore.loadHostGroups(force);
|
||||||
treeData.value = cacheStore.hostGroups;
|
emits('loading', true);
|
||||||
} else {
|
treeData.value = groups;
|
||||||
// 无数据/强制加载
|
} catch (e) {
|
||||||
try {
|
} finally {
|
||||||
emits('loading', true);
|
emits('loading', false);
|
||||||
const { data } = await getHostGroupTree();
|
|
||||||
treeData.value = data;
|
|
||||||
cacheStore.hostGroups = data;
|
|
||||||
} catch (e) {
|
|
||||||
} finally {
|
|
||||||
emits('loading', false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// 未选择则选择首个
|
// 未选择则选择首个
|
||||||
if (!tree.value?.getSelectedNodes()?.length && treeData.value.length) {
|
if (!tree.value?.getSelectedNodes()?.length && treeData.value.length) {
|
||||||
|
|||||||
@@ -40,11 +40,13 @@
|
|||||||
|
|
||||||
// 初始化选项
|
// 初始化选项
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
optionData.value = cacheStore.hostIdentities.map(s => {
|
cacheStore.loadHostIdentities().then(hostIdentities => {
|
||||||
return {
|
optionData.value = hostIdentities.map(s => {
|
||||||
label: `${s.name} (${s.username})`,
|
return {
|
||||||
value: s.id,
|
label: `${s.name} (${s.username})`,
|
||||||
};
|
value: s.id,
|
||||||
|
};
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -40,11 +40,13 @@
|
|||||||
|
|
||||||
// 初始化选项
|
// 初始化选项
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
optionData.value = cacheStore.hostKeys.map(s => {
|
cacheStore.loadHostKeys().then(hostKeys => {
|
||||||
return {
|
optionData.value = hostKeys.map(s => {
|
||||||
label: s.name,
|
return {
|
||||||
value: s.id,
|
label: s.name,
|
||||||
};
|
value: s.id,
|
||||||
|
};
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
<a-select v-model:model-value="value"
|
<a-select v-model:model-value="value"
|
||||||
:placeholder="placeholder"
|
:placeholder="placeholder"
|
||||||
:options="optionData"
|
:options="optionData"
|
||||||
|
:loading="loading"
|
||||||
:limit="limit as number"
|
:limit="limit as number"
|
||||||
:allow-create="allowCreate"
|
:allow-create="allowCreate"
|
||||||
@exceed-limit="() => { emits('onLimited', limit, `最多选择${limit}个tag`) }"
|
@exceed-limit="() => { emits('onLimited', limit, `最多选择${limit}个tag`) }"
|
||||||
@@ -24,6 +25,7 @@
|
|||||||
import { useCacheStore } from '@/store';
|
import { useCacheStore } from '@/store';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
import { createTag } from '@/api/meta/tag';
|
import { createTag } from '@/api/meta/tag';
|
||||||
|
import useLoading from '@/hooks/loading';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: Array as PropType<Array<number>>,
|
modelValue: Array as PropType<Array<number>>,
|
||||||
@@ -31,11 +33,11 @@
|
|||||||
limit: Number,
|
limit: Number,
|
||||||
type: String,
|
type: String,
|
||||||
allowCreate: Boolean,
|
allowCreate: Boolean,
|
||||||
tagType: String,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const emits = defineEmits(['update:modelValue', 'onLimited']);
|
const emits = defineEmits(['update:modelValue', 'onLimited']);
|
||||||
|
|
||||||
|
const { loading, setLoading } = useLoading();
|
||||||
const cacheStore = useCacheStore();
|
const cacheStore = useCacheStore();
|
||||||
|
|
||||||
const value = computed<Array<number>>({
|
const value = computed<Array<number>>({
|
||||||
@@ -51,12 +53,13 @@
|
|||||||
|
|
||||||
// 初始化选项
|
// 初始化选项
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
const tagCache = cacheStore[props.tagType as string] as Array<any>;
|
cacheStore.loadTags(props.type as string).then((tags) => {
|
||||||
optionData.value = tagCache.map(s => {
|
optionData.value = tags.map(s => {
|
||||||
return {
|
return {
|
||||||
label: s.name,
|
label: s.name,
|
||||||
value: s.id,
|
value: s.id,
|
||||||
};
|
};
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -78,12 +81,16 @@
|
|||||||
tags.splice(i, 1);
|
tags.splice(i, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 不存在则创建 tag
|
||||||
|
setLoading(true);
|
||||||
try {
|
try {
|
||||||
// 创建 tag
|
// 创建 tag
|
||||||
tags[i] = await doCreateTag(tag);
|
tags[i] = await doCreateTag(tag);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// 失败删除
|
// 失败删除
|
||||||
tags.splice(i, 1);
|
tags.splice(i, 1);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -95,8 +102,8 @@
|
|||||||
type: props.type
|
type: props.type
|
||||||
} as unknown as TagCreateRequest);
|
} as unknown as TagCreateRequest);
|
||||||
// 插入缓存
|
// 插入缓存
|
||||||
const tagCache = cacheStore[props.tagType as string] as Array<any>;
|
const tagCache = await cacheStore.loadTags(props.type as string);
|
||||||
tagCache.push({ id, name });
|
tagCache && tagCache.push({ id, name });
|
||||||
// 插入 options
|
// 插入 options
|
||||||
optionData.value.push({
|
optionData.value.push({
|
||||||
label: name,
|
label: name,
|
||||||
|
|||||||
@@ -41,18 +41,18 @@
|
|||||||
},
|
},
|
||||||
set(e) {
|
set(e) {
|
||||||
if (typeof e === 'string') {
|
if (typeof e === 'string') {
|
||||||
// 创建的值
|
// 创建的值 这里必须为 null, 否则 table 的重置不生效
|
||||||
emits('update:modelValue', undefined);
|
emits('update:modelValue', null);
|
||||||
emits('change', {
|
emits('change', {
|
||||||
id: undefined,
|
id: null,
|
||||||
keyName: e
|
keyName: e
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// 已有的值
|
// 已有的值
|
||||||
emits('update:modelValue', e);
|
emits('update:modelValue', e);
|
||||||
const find = cacheStore.dictKeys.find(s => s.id === e);
|
const find = optionData.value.find(s => s.value === e);
|
||||||
if (find) {
|
if (find) {
|
||||||
emits('change', find);
|
emits('change', find.origin);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,11 +61,14 @@
|
|||||||
|
|
||||||
// 初始化选项
|
// 初始化选项
|
||||||
onBeforeMount(() => {
|
onBeforeMount(() => {
|
||||||
optionData.value = cacheStore.dictKeys.map(s => {
|
cacheStore.loadDictKeys().then(dictKeys => {
|
||||||
return {
|
optionData.value = dictKeys.map(s => {
|
||||||
label: `${s.keyName} - ${s.description || ''}`,
|
return {
|
||||||
value: s.id,
|
label: `${s.keyName} - ${s.description || ''}`,
|
||||||
};
|
value: s.id,
|
||||||
|
origin: s
|
||||||
|
};
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -67,7 +67,9 @@
|
|||||||
unTriggerChange.value = true;
|
unTriggerChange.value = true;
|
||||||
checkedKeys.value = keys;
|
checkedKeys.value = keys;
|
||||||
if (!menuData.value.length) {
|
if (!menuData.value.length) {
|
||||||
menuData.value = [...cacheStore.menus];
|
cacheStore.loadMenus().then(menus => {
|
||||||
|
menuData.value = [...menus];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<a-tree-select v-model:model-value="value"
|
<a-tree-select v-model:model-value="value"
|
||||||
:data="treeData()"
|
:data="treeData"
|
||||||
:disabled="disabled"
|
:disabled="disabled"
|
||||||
:allow-search="true"
|
:allow-search="true"
|
||||||
:filter-tree-node="filterTreeNode"
|
:filter-tree-node="titleFilter"
|
||||||
placeholder="请选择菜单" />
|
placeholder="请选择菜单" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -16,8 +16,9 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import type { TreeNodeData } from '@arco-design/web-vue';
|
import type { TreeNodeData } from '@arco-design/web-vue';
|
||||||
import { useCacheStore } from '@/store';
|
import { useCacheStore } from '@/store';
|
||||||
import { computed } from 'vue';
|
import { computed, onBeforeMount, ref } from 'vue';
|
||||||
import { MenuType } from '../types/const';
|
import { MenuType } from '@/views/system/menu/types/const';
|
||||||
|
import { titleFilter } from '@/types/form';
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: Number,
|
modelValue: Number,
|
||||||
@@ -26,6 +27,10 @@
|
|||||||
|
|
||||||
const emits = defineEmits(['update:modelValue']);
|
const emits = defineEmits(['update:modelValue']);
|
||||||
|
|
||||||
|
const cacheStore = useCacheStore();
|
||||||
|
|
||||||
|
const treeData = ref<Array<TreeNodeData>>([]);
|
||||||
|
|
||||||
const value = computed({
|
const value = computed({
|
||||||
get() {
|
get() {
|
||||||
return props.modelValue;
|
return props.modelValue;
|
||||||
@@ -35,9 +40,7 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 树数据
|
onBeforeMount(() => {
|
||||||
const cacheStore = useCacheStore();
|
|
||||||
const treeData = (): TreeNodeData[] => {
|
|
||||||
let render = (arr: any[]): TreeNodeData[] => {
|
let render = (arr: any[]): TreeNodeData[] => {
|
||||||
return arr.map((s) => {
|
return arr.map((s) => {
|
||||||
// 为 function 返回空
|
// 为 function 返回空
|
||||||
@@ -57,17 +60,14 @@
|
|||||||
return node;
|
return node;
|
||||||
}).filter(Boolean);
|
}).filter(Boolean);
|
||||||
};
|
};
|
||||||
return [{
|
cacheStore.loadMenus().then(menus => {
|
||||||
key: 0,
|
treeData.value = [{
|
||||||
title: '根目录',
|
key: 0,
|
||||||
children: render([...cacheStore.menus])
|
title: '根目录',
|
||||||
}];
|
children: render([...menus])
|
||||||
};
|
}];
|
||||||
|
});
|
||||||
// 搜索
|
});
|
||||||
const filterTreeNode = (searchValue: string, nodeData: { title: string; }) => {
|
|
||||||
return nodeData.title.toLowerCase().indexOf(searchValue.toLowerCase()) > -1;
|
|
||||||
};
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
68
orion-ops-ui/src/store/modules/cache/index.ts
vendored
68
orion-ops-ui/src/store/modules/cache/index.ts
vendored
@@ -1,24 +1,23 @@
|
|||||||
import type { CacheState } from './types';
|
import type { CacheState } from './types';
|
||||||
import type { AxiosResponse } from 'axios';
|
import type { AxiosResponse } from 'axios';
|
||||||
|
import type { TagType } from '@/api/meta/tag';
|
||||||
|
import { getTagList } from '@/api/meta/tag';
|
||||||
import { defineStore } from 'pinia';
|
import { defineStore } from 'pinia';
|
||||||
import { getUserList } from '@/api/user/user';
|
import { getUserList } from '@/api/user/user';
|
||||||
import { getRoleList } from '@/api/user/role';
|
import { getRoleList } from '@/api/user/role';
|
||||||
|
import { getDictKeyList } from '@/api/system/dict-key';
|
||||||
|
import { getHostKeyList } from '@/api/asset/host-key';
|
||||||
|
import { getHostIdentityList } from '@/api/asset/host-identity';
|
||||||
|
import { getHostList } from '@/api/asset/host';
|
||||||
|
import { getHostGroupTree } from '@/api/asset/host-group';
|
||||||
|
import { getMenuList } from '@/api/system/menu';
|
||||||
|
|
||||||
export type CacheType = 'users' | 'menus' | 'roles'
|
export type CacheType = 'users' | 'menus' | 'roles'
|
||||||
| 'host' | 'hostGroups' | 'hostTags' | 'hostKeys' | 'hostIdentities'
|
| 'host' | 'hostGroups' | 'hostKeys' | 'hostIdentities'
|
||||||
| 'dictKeys' | string
|
| 'dictKeys' | string
|
||||||
|
|
||||||
export default defineStore('cache', {
|
export default defineStore('cache', {
|
||||||
state: (): CacheState => ({
|
state: (): CacheState => ({}),
|
||||||
menus: [],
|
|
||||||
roles: [],
|
|
||||||
hosts: [],
|
|
||||||
hostGroups: [],
|
|
||||||
hostTags: [],
|
|
||||||
hostKeys: [],
|
|
||||||
hostIdentities: [],
|
|
||||||
dictKeys: [],
|
|
||||||
}),
|
|
||||||
|
|
||||||
getters: {},
|
getters: {},
|
||||||
|
|
||||||
@@ -41,9 +40,9 @@ export default defineStore('cache', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 加载数据
|
// 加载数据
|
||||||
async load<T>(name: CacheType, loader: () => Promise<AxiosResponse<T>>, onErrorValue = []) {
|
async load<T>(name: CacheType, loader: () => Promise<AxiosResponse<T>>, force = false, onErrorValue = []) {
|
||||||
// 尝试直接从缓存中获取数据
|
// 尝试直接从缓存中获取数据
|
||||||
if (this[name]) {
|
if (this[name] && !force) {
|
||||||
return this[name] as T;
|
return this[name] as T;
|
||||||
}
|
}
|
||||||
// 加载数据
|
// 加载数据
|
||||||
@@ -57,13 +56,48 @@ export default defineStore('cache', {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// 获取用户列表
|
// 获取用户列表
|
||||||
async loadUsers() {
|
async loadUsers(force = false) {
|
||||||
return await this.load('users', getUserList);
|
return await this.load('users', getUserList, force);
|
||||||
},
|
},
|
||||||
|
|
||||||
// 获取角色列表
|
// 获取角色列表
|
||||||
async loadRoles() {
|
async loadRoles(force = false) {
|
||||||
return await this.load('roles', getRoleList);
|
return await this.load('roles', getRoleList, force);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取菜单列表
|
||||||
|
async loadMenus(force = false) {
|
||||||
|
return await this.load('menus', () => getMenuList({}), force);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取主机分组列表
|
||||||
|
async loadHostGroups(force = false) {
|
||||||
|
return await this.load('hostGroups', getHostGroupTree, force);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取主机列表
|
||||||
|
async loadHosts(force = false) {
|
||||||
|
return await this.load('hosts', getHostList, force);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取主机秘钥列表
|
||||||
|
async loadHostKeys(force = false) {
|
||||||
|
return await this.load('hostKeys', getHostKeyList, force);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取主机身份列表
|
||||||
|
async loadHostIdentities(force = false) {
|
||||||
|
return await this.load('hostIdentities', getHostIdentityList, force);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 获取字典配置项列表
|
||||||
|
async loadDictKeys(force = false) {
|
||||||
|
return await this.load('dictKeys', getDictKeyList, force);
|
||||||
|
},
|
||||||
|
|
||||||
|
// 加载 tags
|
||||||
|
async loadTags(type: TagType, force = false) {
|
||||||
|
return await this.load(`${type}_Tags`, () => getTagList(type), force);
|
||||||
},
|
},
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import type { UserQueryResponse } from '@/api/user/user';
|
import type { UserQueryResponse } from '@/api/user/user';
|
||||||
import type { MenuQueryResponse } from '@/api/system/menu';
|
import type { MenuQueryResponse } from '@/api/system/menu';
|
||||||
import type { RoleQueryResponse } from '@/api/user/role';
|
import type { RoleQueryResponse } from '@/api/user/role';
|
||||||
import type { TagQueryResponse } from '@/api/meta/tag';
|
|
||||||
import type { HostQueryResponse } from '@/api/asset/host';
|
import type { HostQueryResponse } from '@/api/asset/host';
|
||||||
import type { HostGroupQueryResponse } from '@/api/asset/host-group';
|
import type { HostGroupQueryResponse } from '@/api/asset/host-group';
|
||||||
import type { HostKeyQueryResponse } from '@/api/asset/host-key';
|
import type { HostKeyQueryResponse } from '@/api/asset/host-key';
|
||||||
@@ -12,7 +11,6 @@ export interface CacheState {
|
|||||||
users?: UserQueryResponse[];
|
users?: UserQueryResponse[];
|
||||||
menus?: MenuQueryResponse[];
|
menus?: MenuQueryResponse[];
|
||||||
roles?: RoleQueryResponse[];
|
roles?: RoleQueryResponse[];
|
||||||
hostTags?: TagQueryResponse[];
|
|
||||||
hosts?: HostQueryResponse[];
|
hosts?: HostQueryResponse[];
|
||||||
hostGroups?: HostGroupQueryResponse[];
|
hostGroups?: HostGroupQueryResponse[];
|
||||||
hostKeys?: HostKeyQueryResponse[];
|
hostKeys?: HostKeyQueryResponse[];
|
||||||
|
|||||||
@@ -2,3 +2,8 @@
|
|||||||
export const labelFilter = (searchValue: string, option: { label: string; }) => {
|
export const labelFilter = (searchValue: string, option: { label: string; }) => {
|
||||||
return option.label.toLowerCase().indexOf(searchValue.toLowerCase()) > -1;
|
return option.label.toLowerCase().indexOf(searchValue.toLowerCase()) > -1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 通过 title 进行过滤
|
||||||
|
export const titleFilter = (searchValue: string, option: { title: string; }) => {
|
||||||
|
return option.title.toLowerCase().indexOf(searchValue.toLowerCase()) > -1;
|
||||||
|
};
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
<host-group-tree outer-class="group-main-tree"
|
<host-group-tree outer-class="group-main-tree"
|
||||||
:checkable="true"
|
:checkable="true"
|
||||||
:checked-keys="checkedGroups"
|
:checked-keys="checkedGroups"
|
||||||
:draggable="false"
|
:editable="false"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
@loading="setLoading"
|
@loading="setLoading"
|
||||||
@select-node="e => selectedGroup = e"
|
@select-node="e => selectedGroup = e"
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
<!-- 分组 -->
|
<!-- 分组 -->
|
||||||
<host-group-tree outer-class="group-main-tree"
|
<host-group-tree outer-class="group-main-tree"
|
||||||
:checked-keys="checkedGroups"
|
:checked-keys="checkedGroups"
|
||||||
:draggable="false"
|
:editable="false"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
@loading="setLoading"
|
@loading="setLoading"
|
||||||
@select-node="e => selectedGroup = e"
|
@select-node="e => selectedGroup = e"
|
||||||
|
|||||||
@@ -36,10 +36,8 @@
|
|||||||
import type { PropType } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
import useLoading from '@/hooks/loading';
|
import useLoading from '@/hooks/loading';
|
||||||
import { useCacheStore } from '@/store';
|
import { useCacheStore } from '@/store';
|
||||||
import { onBeforeMount, ref, watch } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
import { getHostGroupRelList } from '@/api/asset/host-group';
|
import { getHostGroupRelList } from '@/api/asset/host-group';
|
||||||
import { getHostList } from '@/api/asset/host';
|
|
||||||
import { Message } from '@arco-design/web-vue';
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
group: {
|
group: {
|
||||||
@@ -64,7 +62,8 @@
|
|||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const { data } = await getHostGroupRelList(groupId as number);
|
const { data } = await getHostGroupRelList(groupId as number);
|
||||||
selectedGroupHosts.value = data.map(s => cacheStore.hosts.find(h => h.id === s) as HostQueryResponse)
|
const hosts = await cacheStore.loadHosts();
|
||||||
|
selectedGroupHosts.value = data.map(s => hosts.find(h => h.id === s) as HostQueryResponse)
|
||||||
.filter(Boolean);
|
.filter(Boolean);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
} finally {
|
} finally {
|
||||||
@@ -72,24 +71,6 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 加载主机列表
|
|
||||||
const loadHostList = async () => {
|
|
||||||
try {
|
|
||||||
const { data } = await getHostList();
|
|
||||||
// 设置到缓存
|
|
||||||
cacheStore.set('hosts', data);
|
|
||||||
} catch (e) {
|
|
||||||
Message.error('主机列表加载失败');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
|
||||||
if (!cacheStore.hosts.length) {
|
|
||||||
// 加载用户列表
|
|
||||||
await loadHostList();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="less" scoped>
|
<style lang="less" scoped>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-container" v-if="render">
|
<div class="layout-container">
|
||||||
<!-- 列表-表格 -->
|
<!-- 列表-表格 -->
|
||||||
<host-identity-table v-if="renderTable"
|
<host-identity-table v-if="renderTable"
|
||||||
ref="table"
|
ref="table"
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
<host-identity-form-modal ref="modal"
|
<host-identity-form-modal ref="modal"
|
||||||
@added="modalAddCallback"
|
@added="modalAddCallback"
|
||||||
@updated="modalUpdateCallback" />
|
@updated="modalUpdateCallback" />
|
||||||
<!-- 添加修改模态框 -->
|
<!-- 主机秘钥抽屉 -->
|
||||||
<host-key-form-drawer ref="keyDrawer" />
|
<host-key-form-drawer ref="keyDrawer" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -28,17 +28,13 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
import { ref, computed, onUnmounted } from 'vue';
|
||||||
|
import { useAppStore, useCacheStore } from '@/store';
|
||||||
import HostIdentityCardList from './components/host-identity-card-list.vue';
|
import HostIdentityCardList from './components/host-identity-card-list.vue';
|
||||||
import HostIdentityTable from './components/host-identity-table.vue';
|
import HostIdentityTable from './components/host-identity-table.vue';
|
||||||
import HostIdentityFormModal from './components/host-identity-form-modal.vue';
|
import HostIdentityFormModal from './components/host-identity-form-modal.vue';
|
||||||
import HostKeyFormDrawer from '../host-key/components/host-key-form-drawer.vue';
|
import HostKeyFormDrawer from '../host-key/components/host-key-form-drawer.vue';
|
||||||
import { getHostKeyList } from '@/api/asset/host-key';
|
|
||||||
|
|
||||||
import { ref, computed, onBeforeMount, onUnmounted } from 'vue';
|
|
||||||
import { useAppStore, useCacheStore } from '@/store';
|
|
||||||
import { Message } from '@arco-design/web-vue';
|
|
||||||
|
|
||||||
const render = ref(false);
|
|
||||||
const table = ref();
|
const table = ref();
|
||||||
const card = ref();
|
const card = ref();
|
||||||
const modal = ref();
|
const modal = ref();
|
||||||
@@ -66,22 +62,6 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 获取主机秘钥列表
|
|
||||||
const fetchHostKeyList = async () => {
|
|
||||||
try {
|
|
||||||
const { data } = await getHostKeyList();
|
|
||||||
cacheStore.set('hostKeys', data);
|
|
||||||
} catch (e) {
|
|
||||||
Message.error('主机秘钥加载失败');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
|
||||||
// 加载主机秘钥
|
|
||||||
await fetchHostKeyList();
|
|
||||||
render.value = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 卸载时清除 cache
|
// 卸载时清除 cache
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
const cacheStore = useCacheStore();
|
const cacheStore = useCacheStore();
|
||||||
|
|||||||
@@ -36,8 +36,6 @@
|
|||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
import { getHostConfigAll } from '@/api/asset/host';
|
import { getHostConfigAll } from '@/api/asset/host';
|
||||||
import { useCacheStore, useDictStore } from '@/store';
|
import { useCacheStore, useDictStore } from '@/store';
|
||||||
import { getHostKeyList } from '@/api/asset/host-key';
|
|
||||||
import { getHostIdentityList } from '@/api/asset/host-identity';
|
|
||||||
import { dictKeys as sshDictKeys } from './ssh/types/const';
|
import { dictKeys as sshDictKeys } from './ssh/types/const';
|
||||||
import SshConfigForm from './ssh/ssh-config-form.vue';
|
import SshConfigForm from './ssh/ssh-config-form.vue';
|
||||||
|
|
||||||
@@ -77,32 +75,10 @@
|
|||||||
|
|
||||||
defineExpose({ open });
|
defineExpose({ open });
|
||||||
|
|
||||||
// 加载主机秘钥
|
|
||||||
const fetchHostKeys = async () => {
|
|
||||||
try {
|
|
||||||
const { data } = await getHostKeyList();
|
|
||||||
cacheStore.set('hostKeys', data);
|
|
||||||
} catch (e) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 加载主机身份
|
|
||||||
const fetchHostIdentities = async () => {
|
|
||||||
try {
|
|
||||||
const { data } = await getHostIdentityList();
|
|
||||||
cacheStore.set('hostIdentities', data);
|
|
||||||
} catch (e) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
onBeforeMount(async () => {
|
||||||
// 加载字典值
|
// 加载字典值
|
||||||
const dictStore = useDictStore();
|
const dictStore = useDictStore();
|
||||||
await dictStore.loadKeys([...sshDictKeys]);
|
await dictStore.loadKeys([...sshDictKeys]);
|
||||||
// 加载主机秘钥
|
|
||||||
await fetchHostKeys();
|
|
||||||
// 加载主机身份
|
|
||||||
await fetchHostIdentities();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -52,9 +52,7 @@
|
|||||||
import type { PropType } from 'vue';
|
import type { PropType } from 'vue';
|
||||||
import { onMounted, ref, watch, computed } from 'vue';
|
import { onMounted, ref, watch, computed } from 'vue';
|
||||||
import { useCacheStore } from '@/store';
|
import { useCacheStore } from '@/store';
|
||||||
import { getHostGroupRelList, updateHostGroupRel } from '@/api/asset/host-group';
|
import { getHostGroupRelList } from '@/api/asset/host-group';
|
||||||
import { Message } from '@arco-design/web-vue';
|
|
||||||
import { getHostList } from '@/api/asset/host';
|
|
||||||
|
|
||||||
const props = defineProps({
|
const props = defineProps({
|
||||||
modelValue: {
|
modelValue: {
|
||||||
@@ -114,31 +112,15 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// 加载主机列表
|
onMounted(() => {
|
||||||
const loadHostList = async () => {
|
cacheStore.loadHosts().then(hosts => {
|
||||||
emits('loading', true);
|
data.value = hosts.map(s => {
|
||||||
try {
|
return {
|
||||||
const { data } = await getHostList();
|
value: String(s.id),
|
||||||
// 设置到缓存
|
label: `${s.name}(${s.code})-${s.address}`,
|
||||||
cacheStore.set('hosts', data);
|
disabled: false
|
||||||
} catch (e) {
|
};
|
||||||
Message.error('主机列表加载失败');
|
});
|
||||||
} finally {
|
|
||||||
emits('loading', false);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onMounted(async () => {
|
|
||||||
if (!cacheStore.hosts.length) {
|
|
||||||
// 加载主机列表
|
|
||||||
await loadHostList();
|
|
||||||
}
|
|
||||||
data.value = cacheStore.hosts.map(s => {
|
|
||||||
return {
|
|
||||||
value: String(s.id),
|
|
||||||
label: `${s.name}(${s.code})-${s.address}`,
|
|
||||||
disabled: false
|
|
||||||
};
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -78,7 +78,6 @@
|
|||||||
:allowCreate="false"
|
:allowCreate="false"
|
||||||
:limit="0"
|
:limit="0"
|
||||||
type="HOST"
|
type="HOST"
|
||||||
tag-type="hostTags"
|
|
||||||
placeholder="请选择主机标签" />
|
placeholder="请选择主机标签" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-form>
|
</a-form>
|
||||||
|
|||||||
@@ -43,7 +43,6 @@
|
|||||||
:allowCreate="true"
|
:allowCreate="true"
|
||||||
:limit="5"
|
:limit="5"
|
||||||
type="HOST"
|
type="HOST"
|
||||||
tag-type="hostTags"
|
|
||||||
placeholder="请选择主机标签"
|
placeholder="请选择主机标签"
|
||||||
@onLimited="onLimitedTag" />
|
@onLimited="onLimitedTag" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
|
|||||||
@@ -32,7 +32,6 @@
|
|||||||
:allowCreate="false"
|
:allowCreate="false"
|
||||||
:limit="0"
|
:limit="0"
|
||||||
type="HOST"
|
type="HOST"
|
||||||
tag-type="hostTags"
|
|
||||||
placeholder="请选择主机标签" />
|
placeholder="请选择主机标签" />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
</a-query-header>
|
</a-query-header>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-container" v-if="render">
|
<div class="layout-container">
|
||||||
<!-- 列表-表格 -->
|
<!-- 列表-表格 -->
|
||||||
<host-table v-if="renderTable"
|
<host-table v-if="renderTable"
|
||||||
ref="table"
|
ref="table"
|
||||||
@@ -32,10 +32,8 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { computed, ref, onBeforeMount, onUnmounted } from 'vue';
|
import { computed, ref, onUnmounted } from 'vue';
|
||||||
import { useAppStore, useCacheStore } from '@/store';
|
import { useAppStore, useCacheStore } from '@/store';
|
||||||
import { getTagList } from '@/api/meta/tag';
|
|
||||||
import { Message } from '@arco-design/web-vue';
|
|
||||||
import HostTable from './components/host-table.vue';
|
import HostTable from './components/host-table.vue';
|
||||||
import HostCardList from './components/host-card-list.vue';
|
import HostCardList from './components/host-card-list.vue';
|
||||||
import HostFormModal from './components/host-form-modal.vue';
|
import HostFormModal from './components/host-form-modal.vue';
|
||||||
@@ -72,26 +70,9 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// 加载 tags
|
|
||||||
const loadTags = async () => {
|
|
||||||
try {
|
|
||||||
const { data } = await getTagList('HOST');
|
|
||||||
// 设置到缓存
|
|
||||||
cacheStore.set('hostTags', data);
|
|
||||||
} catch (e) {
|
|
||||||
Message.error('tag加载失败');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
|
||||||
// 加载 tags
|
|
||||||
await loadTags();
|
|
||||||
render.value = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 卸载时清除 cache
|
// 卸载时清除 cache
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
cacheStore.reset('hosts', 'hostTags', 'hostKeys', 'hostIdentities', 'hostGroups');
|
cacheStore.reset('hosts', 'hostKeys', 'hostIdentities', 'hostGroups', 'HOST_Tags');
|
||||||
});
|
});
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -139,10 +139,11 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 渲染表单
|
// 渲染表单
|
||||||
const renderForm = (record: any) => {
|
const renderForm = async (record: any) => {
|
||||||
formModel.value = Object.assign({}, record);
|
formModel.value = Object.assign({}, record);
|
||||||
// schema
|
// schema
|
||||||
const find = record.keyId && cacheStore.dictKeys.find((item) => item.id === record.keyId);
|
const dictKeys = await cacheStore.loadDictKeys();
|
||||||
|
const find = record.keyId && dictKeys.find((item) => item.id === record.keyId);
|
||||||
keyExtraSchemas.value = (find && find.extraSchema && JSON.parse(find.extraSchema)) || [];
|
keyExtraSchemas.value = (find && find.extraSchema && JSON.parse(find.extraSchema)) || [];
|
||||||
// 额外参数
|
// 额外参数
|
||||||
extraValue.value = (formModel.value.extra && JSON.parse(formModel.value.extra)) || {};
|
extraValue.value = (formModel.value.extra && JSON.parse(formModel.value.extra)) || {};
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
<a-form-item field="keyId" label="配置项" label-col-flex="50px">
|
<a-form-item field="keyId" label="配置项" label-col-flex="50px">
|
||||||
<dict-key-selector v-model="formModel.keyId"
|
<dict-key-selector v-model="formModel.keyId"
|
||||||
@change="changeKey"
|
@change="changeKey"
|
||||||
|
allow-create
|
||||||
allow-clear />
|
allow-clear />
|
||||||
</a-form-item>
|
</a-form-item>
|
||||||
<!-- 配置值 -->
|
<!-- 配置值 -->
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="layout-container" v-if="render">
|
<div class="layout-container">
|
||||||
<!-- 列表-表格 -->
|
<!-- 列表-表格 -->
|
||||||
<dict-value-table ref="table"
|
<dict-value-table ref="table"
|
||||||
@openAdd="() => modal.openAdd()"
|
@openAdd="() => modal.openAdd()"
|
||||||
@@ -27,14 +27,11 @@
|
|||||||
import DictValueTable from './components/dict-value-table.vue';
|
import DictValueTable from './components/dict-value-table.vue';
|
||||||
import DictValueFormModal from './components/dict-value-form-modal.vue';
|
import DictValueFormModal from './components/dict-value-form-modal.vue';
|
||||||
import HistoryValueModal from '@/components/meta/history/history-value-modal.vue';
|
import HistoryValueModal from '@/components/meta/history/history-value-modal.vue';
|
||||||
import { ref, onBeforeMount, onUnmounted } from 'vue';
|
import { ref, onUnmounted } from 'vue';
|
||||||
import { historyType } from './types/const';
|
import { historyType } from './types/const';
|
||||||
import { useCacheStore } from '@/store';
|
import { useCacheStore } from '@/store';
|
||||||
import { getDictKeyList } from '@/api/system/dict-key';
|
|
||||||
import { Message } from '@arco-design/web-vue';
|
|
||||||
import { rollbackDictValue } from '@/api/system/dict-value';
|
import { rollbackDictValue } from '@/api/system/dict-value';
|
||||||
|
|
||||||
const render = ref(false);
|
|
||||||
const table = ref();
|
const table = ref();
|
||||||
const modal = ref();
|
const modal = ref();
|
||||||
const history = ref();
|
const history = ref();
|
||||||
@@ -55,23 +52,6 @@
|
|||||||
await rollbackDictValue({ id, valueId });
|
await rollbackDictValue({ id, valueId });
|
||||||
};
|
};
|
||||||
|
|
||||||
// 加载字典配置项
|
|
||||||
const loadDictKeys = async () => {
|
|
||||||
try {
|
|
||||||
const { data } = await getDictKeyList();
|
|
||||||
// 设置到缓存
|
|
||||||
cacheStore.set('dictKeys', data);
|
|
||||||
} catch (e) {
|
|
||||||
Message.error('配置项加载失败');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
onBeforeMount(async () => {
|
|
||||||
// 加载字典值
|
|
||||||
await loadDictKeys();
|
|
||||||
render.value = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 卸载时清除 cache
|
// 卸载时清除 cache
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
cacheStore.reset('dictKeys');
|
cacheStore.reset('dictKeys');
|
||||||
|
|||||||
@@ -125,12 +125,11 @@
|
|||||||
import formRules from '../types/form.rules';
|
import formRules from '../types/form.rules';
|
||||||
import { menuCacheKey, sortStep } from '../types/const';
|
import { menuCacheKey, sortStep } from '../types/const';
|
||||||
import { menuVisibleKey, menuTypeKey, MenuType, MenuVisible, MenuCache } from '../types/const';
|
import { menuVisibleKey, menuTypeKey, MenuType, MenuVisible, MenuCache } from '../types/const';
|
||||||
|
|
||||||
import IconPicker from '@sanqi377/arco-vue-icon-picker';
|
|
||||||
import MenuTreeSelector from './menu-tree-selector.vue';
|
|
||||||
import { createMenu, updateMenu } from '@/api/system/menu';
|
import { createMenu, updateMenu } from '@/api/system/menu';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
import { useDictStore } from '@/store';
|
import { useDictStore } from '@/store';
|
||||||
|
import IconPicker from '@sanqi377/arco-vue-icon-picker';
|
||||||
|
import MenuTreeSelector from '@/components/system/menu/selector/menu-tree-selector.vue';
|
||||||
|
|
||||||
const { visible, setVisible } = useVisible();
|
const { visible, setVisible } = useVisible();
|
||||||
const { loading, setLoading } = useLoading();
|
const { loading, setLoading } = useLoading();
|
||||||
|
|||||||
@@ -263,7 +263,6 @@
|
|||||||
setFetchLoading(true);
|
setFetchLoading(true);
|
||||||
const { data } = await getMenuList(formModel);
|
const { data } = await getMenuList(formModel);
|
||||||
tableRenderData.value = data as MenuQueryResponse[];
|
tableRenderData.value = data as MenuQueryResponse[];
|
||||||
cacheStore.set('menus', tableRenderData.value);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
} finally {
|
} finally {
|
||||||
setFetchLoading(false);
|
setFetchLoading(false);
|
||||||
|
|||||||
@@ -57,10 +57,8 @@
|
|||||||
import useVisible from '@/hooks/visible';
|
import useVisible from '@/hooks/visible';
|
||||||
import { getRoleMenuId, grantRoleMenu } from '@/api/user/role';
|
import { getRoleMenuId, grantRoleMenu } from '@/api/user/role';
|
||||||
import { Message } from '@arco-design/web-vue';
|
import { Message } from '@arco-design/web-vue';
|
||||||
import { useCacheStore } from '@/store';
|
|
||||||
import { getMenuList } from '@/api/system/menu';
|
|
||||||
import MenuGrantTable from '@/components/system/menu/grant/menu-grant-table.vue';
|
|
||||||
import { quickGrantMenuOperator } from '../types/const';
|
import { quickGrantMenuOperator } from '../types/const';
|
||||||
|
import MenuGrantTable from '@/components/system/menu/grant/menu-grant-table.vue';
|
||||||
|
|
||||||
const { visible, setVisible } = useVisible();
|
const { visible, setVisible } = useVisible();
|
||||||
const { loading, setLoading } = useLoading();
|
const { loading, setLoading } = useLoading();
|
||||||
@@ -74,13 +72,6 @@
|
|||||||
setVisible(true);
|
setVisible(true);
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
// 获取菜单列表
|
|
||||||
const cacheStore = useCacheStore();
|
|
||||||
if (!cacheStore.menus?.length) {
|
|
||||||
// 加载菜单
|
|
||||||
const { data: menuData } = await getMenuList({});
|
|
||||||
cacheStore.set('menus', menuData);
|
|
||||||
}
|
|
||||||
// 获取角色菜单
|
// 获取角色菜单
|
||||||
const { data: roleMenuIdList } = await getRoleMenuId(record.id);
|
const { data: roleMenuIdList } = await getRoleMenuId(record.id);
|
||||||
table.value.init(roleMenuIdList);
|
table.value.init(roleMenuIdList);
|
||||||
|
|||||||
@@ -18,10 +18,11 @@ const columns = [
|
|||||||
dataIndex: 'code',
|
dataIndex: 'code',
|
||||||
slotName: 'code',
|
slotName: 'code',
|
||||||
}, {
|
}, {
|
||||||
title: '角色状态',
|
title: '状态',
|
||||||
dataIndex: 'status',
|
dataIndex: 'status',
|
||||||
slotName: 'status',
|
slotName: 'status',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
|
width: 84,
|
||||||
}, {
|
}, {
|
||||||
title: '创建时间',
|
title: '创建时间',
|
||||||
dataIndex: 'createTime',
|
dataIndex: 'createTime',
|
||||||
|
|||||||
Reference in New Issue
Block a user