feat: 保存主机分组数据.
This commit is contained in:
@@ -36,9 +36,6 @@ public class HostGroupTreeVO implements Serializable {
|
||||
@Schema(description = "组名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "排序")
|
||||
private Integer sort;
|
||||
|
||||
@Schema(description = "子节点")
|
||||
private List<HostGroupTreeVO> children;
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ public class DataGroupRelServiceImpl implements DataGroupRelService {
|
||||
@Override
|
||||
public List<DataGroupRelCacheDTO> getGroupRelListByCache(String type, Long groupId) {
|
||||
return this.getGroupRelListByCache(
|
||||
DataGroupCacheKeyDefine.DATA_GROUP_REL_GROUP.format(type),
|
||||
DataGroupCacheKeyDefine.DATA_GROUP_REL_GROUP.format(groupId),
|
||||
DataGroupCacheKeyDefine.DATA_GROUP_REL_GROUP,
|
||||
() -> dataGroupRelDAO.of()
|
||||
.createWrapper()
|
||||
@@ -203,11 +203,11 @@ public class DataGroupRelServiceImpl implements DataGroupRelService {
|
||||
Supplier<List<DataGroupRelCacheDTO>> valueSupplier) {
|
||||
// 查询缓存
|
||||
List<DataGroupRelCacheDTO> list = RedisStrings.getJsonArray(key, define);
|
||||
if (list.isEmpty()) {
|
||||
if (Lists.isEmpty(list)) {
|
||||
// 查询数据库
|
||||
list = valueSupplier.get();
|
||||
// 添加默认值 防止穿透
|
||||
if (list.isEmpty()) {
|
||||
if (Lists.isEmpty(list)) {
|
||||
list.add(DataGroupRelCacheDTO.builder()
|
||||
.id(Const.NONE_ID)
|
||||
.build());
|
||||
|
||||
@@ -39,7 +39,7 @@ export interface HostGroupQueryResponse {
|
||||
*/
|
||||
export interface HostGroupRelUpdateRequest {
|
||||
groupId?: number;
|
||||
relIdList?: Array<number>;
|
||||
relIdList?: Array<string>;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,8 +80,8 @@ export function deleteHostGroup(id: number) {
|
||||
/**
|
||||
* 查询分组内主机
|
||||
*/
|
||||
export function getHostGroupRelList() {
|
||||
return axios.get<Array<number>>('/asset/host-group/rel-list');
|
||||
export function getHostGroupRelList(groupId: number) {
|
||||
return axios.get<Array<number>>('/asset/host-group/rel-list', { params: { groupId } });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,13 +3,13 @@ import { Message } from '@arco-design/web-vue';
|
||||
|
||||
export default function useCopy() {
|
||||
const { isSupported, copy: c, text, copied } = useClipboard();
|
||||
const copy = async (value: string, tips = `${ value } 已复制`) => {
|
||||
const copy = async (value: string, tips = `${value} 已复制`) => {
|
||||
try {
|
||||
await c(value);
|
||||
if (tips) {
|
||||
Message.success(tips);
|
||||
}
|
||||
} catch {
|
||||
} catch (e) {
|
||||
Message.error('复制失败');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import type { CacheState } from './types';
|
||||
import { defineStore } from 'pinia';
|
||||
|
||||
export type CacheType = 'users' | 'menus' | 'roles' | 'hostTags' | 'hostKeys' | 'hostIdentities' | 'dictKeys' | string
|
||||
export type CacheType = 'users' | 'menus' | 'roles'
|
||||
| 'host' | 'hostTags' | 'hostKeys' | 'hostIdentities'
|
||||
| 'dictKeys' | string
|
||||
|
||||
export default defineStore('cache', {
|
||||
state: (): CacheState => ({
|
||||
users: [],
|
||||
menus: [],
|
||||
roles: [],
|
||||
hosts: [],
|
||||
hostTags: [],
|
||||
hostKeys: [],
|
||||
hostIdentities: [],
|
||||
|
||||
@@ -5,12 +5,14 @@ import type { TagQueryResponse } from '@/api/meta/tag';
|
||||
import type { HostKeyQueryResponse } from '@/api/asset/host-key';
|
||||
import type { HostIdentityQueryResponse } from '@/api/asset/host-identity';
|
||||
import type { DictKeyQueryResponse } from '@/api/system/dict-key';
|
||||
import type { HostQueryResponse } from '@/api/asset/host';
|
||||
|
||||
export interface CacheState {
|
||||
users: UserQueryResponse[];
|
||||
menus: MenuQueryResponse[];
|
||||
roles: RoleQueryResponse[];
|
||||
hostTags: TagQueryResponse[];
|
||||
hosts: HostQueryResponse[];
|
||||
hostKeys: HostKeyQueryResponse[];
|
||||
hostIdentities: HostIdentityQueryResponse[];
|
||||
dictKeys: DictKeyQueryResponse[];
|
||||
|
||||
1
orion-ops-ui/src/types/arco.d.ts
vendored
1
orion-ops-ui/src/types/arco.d.ts
vendored
@@ -4,6 +4,5 @@ import type { NodeData } from './global';
|
||||
|
||||
declare module '@arco-design/web-vue' {
|
||||
interface TreeNodeData extends NodeData {
|
||||
[key: string]: any;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
<!-- 名称 -->
|
||||
<span v-else
|
||||
class="node-title-wrapper"
|
||||
@click="() => emits('selectKey', node.key)">
|
||||
@click="() => emits('selectNode', node)">
|
||||
{{ node.title }}
|
||||
</span>
|
||||
</template>
|
||||
@@ -94,7 +94,7 @@
|
||||
const props = defineProps({
|
||||
loading: Boolean
|
||||
});
|
||||
const emits = defineEmits(['loading', 'selectKey']);
|
||||
const emits = defineEmits(['loading', 'selectNode']);
|
||||
|
||||
const tree = ref();
|
||||
const modCount = ref(0);
|
||||
@@ -278,7 +278,14 @@
|
||||
emits('loading', true);
|
||||
const { data } = await getHostGroupTree();
|
||||
treeData.value = data;
|
||||
} catch {
|
||||
// 未选择则选择首个
|
||||
if (!tree.value?.getSelectedNodes()?.length && data.length) {
|
||||
await nextTick(() => {
|
||||
tree.value?.selectNode(data[0].key);
|
||||
emits('selectNode', data[0]);
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
} finally {
|
||||
emits('loading', false);
|
||||
}
|
||||
@@ -308,7 +315,17 @@
|
||||
color: var(--color-text-3);
|
||||
}
|
||||
|
||||
:deep(.arco-tree-node) {
|
||||
cursor: unset;
|
||||
|
||||
.arco-tree-node-switcher {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.arco-tree-node-selected) {
|
||||
background-color: var(--color-fill-2);
|
||||
|
||||
.arco-tree-node-title {
|
||||
&:hover {
|
||||
background-color: var(--color-fill-2);
|
||||
@@ -317,7 +334,8 @@
|
||||
}
|
||||
|
||||
:deep(.arco-tree-node-title) {
|
||||
padding-right: 48px;
|
||||
padding: 0 68px 0 0;
|
||||
height: 32px;
|
||||
|
||||
&:hover {
|
||||
background-color: var(--color-fill-1);
|
||||
@@ -325,17 +343,19 @@
|
||||
|
||||
.arco-tree-node-title-text {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
:deep(.arco-tree-node-selected) {
|
||||
background-color: var(--color-fill-2);
|
||||
}
|
||||
|
||||
.node-title-wrapper {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
.tree-icon {
|
||||
|
||||
@@ -28,13 +28,15 @@
|
||||
<host-group-tree ref="tree"
|
||||
:loading="treeLoading"
|
||||
@loading="setTreeLoading"
|
||||
@select-key="selectGroup" />
|
||||
@select-node="selectGroup" />
|
||||
</div>
|
||||
</a-spin>
|
||||
<!-- 身体部分 -->
|
||||
<a-spin class="simple-card view-body"
|
||||
:loading="dataLoading">
|
||||
<host-transfer ref="transfer" />
|
||||
<host-transfer ref="transfer"
|
||||
:group="currentGroup"
|
||||
@loading="setDataLoading" />
|
||||
</a-spin>
|
||||
</template>
|
||||
|
||||
@@ -45,6 +47,7 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { TreeNodeData } from '@arco-design/web-vue';
|
||||
import { ref } from 'vue';
|
||||
import useLoading from '@/hooks/loading';
|
||||
import HostGroupTree from './host-group-tree.vue';
|
||||
@@ -55,6 +58,7 @@
|
||||
|
||||
const tree = ref();
|
||||
const transfer = ref();
|
||||
const currentGroup = ref();
|
||||
|
||||
// 添加根节点
|
||||
const addRootNode = () => {
|
||||
@@ -67,28 +71,8 @@
|
||||
};
|
||||
|
||||
// 选中分组
|
||||
const selectGroup = (key: number) => {
|
||||
console.log(key);
|
||||
};
|
||||
|
||||
const { loading: treeLoading, setLoading: setTreeLoading } = useLoading();
|
||||
const { loading: dataLoading, setLoading: setDataLoading } = useLoading();
|
||||
|
||||
const tree = ref();
|
||||
|
||||
// 添加根节点
|
||||
const addRootNode = () => {
|
||||
tree.value.addRootNode();
|
||||
};
|
||||
|
||||
// 刷新树
|
||||
const refreshTree = () => {
|
||||
tree.value.fetchTreeData();
|
||||
};
|
||||
|
||||
// 选中分组
|
||||
const selectGroup = (key: number) => {
|
||||
console.log(key);
|
||||
const selectGroup = (group: TreeNodeData) => {
|
||||
currentGroup.value = group;
|
||||
};
|
||||
|
||||
</script>
|
||||
@@ -127,10 +111,14 @@
|
||||
display: flex;
|
||||
|
||||
.handler-icon-wrapper {
|
||||
margin-left: 8px;
|
||||
color: rgb(var(--primary-6));
|
||||
margin-left: 2px;
|
||||
padding: 4px;
|
||||
font-size: 16px;
|
||||
background: unset;
|
||||
|
||||
&:hover {
|
||||
background: var(--color-fill-3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,10 +3,21 @@
|
||||
<!-- 头部 -->
|
||||
<div class="transfer-header">
|
||||
<!-- 提示 -->
|
||||
<a-alert class="alert-wrapper">123123</a-alert>
|
||||
<a-alert class="alert-wrapper">
|
||||
<!-- 已选中分组 -->
|
||||
<template v-if="group.key">
|
||||
<span>当前编辑的分组为 <span class="span-blue">{{ group.title }}</span></span>
|
||||
</template>
|
||||
<!-- 未选中分组 -->
|
||||
<template v-else>
|
||||
<span>点击左侧分组即可加载组内数据</span>
|
||||
</template>
|
||||
</a-alert>
|
||||
<!-- 保存按钮 -->
|
||||
<a-button class="save-button"
|
||||
<a-button v-permission="['asset:host-group:update-rel']"
|
||||
class="save-button"
|
||||
type="primary"
|
||||
:disabled="!group.key"
|
||||
@click="save">
|
||||
保存
|
||||
<template #icon>
|
||||
@@ -19,10 +30,11 @@
|
||||
:data="data"
|
||||
:source-input-search-props="{ placeholder:'请输入主机名称/编码/IP' }"
|
||||
:target-input-search-props="{ placeholder:'请输入主机名称/编码/IP' }"
|
||||
:disabled="!group.key"
|
||||
show-search
|
||||
one-way>
|
||||
<!-- 主机列表 -->
|
||||
<template #source-title="{ countTotal, countSelected, checked, indeterminate, onSelectAllChange}">
|
||||
<template #source-title="{ countTotal, countSelected, checked, indeterminate, onSelectAllChange }">
|
||||
<!-- 左侧标题 -->
|
||||
<div class="source-title-container">
|
||||
<a-checkbox style="margin-right: 8px;"
|
||||
@@ -45,6 +57,10 @@
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<!-- 内容 -->
|
||||
<template #item="{ label }">
|
||||
<span v-html="renderLabel(label)" />
|
||||
</template>
|
||||
</a-transfer>
|
||||
</div>
|
||||
</template>
|
||||
@@ -57,25 +73,79 @@
|
||||
|
||||
<script lang="ts" setup>
|
||||
import type { TransferItem } from '@arco-design/web-vue/es/transfer/interface';
|
||||
import { onMounted, ref } from 'vue';
|
||||
import type { TreeNodeData } from '@arco-design/web-vue';
|
||||
import type { PropType } from 'vue';
|
||||
import { onMounted, ref, watch } from 'vue';
|
||||
import { useCacheStore } from '@/store';
|
||||
import { getHostGroupRelList, updateHostGroupRel } from '@/api/asset/host-group';
|
||||
import { Message } from '@arco-design/web-vue';
|
||||
|
||||
const props = defineProps({
|
||||
group: {
|
||||
type: Object as PropType<TreeNodeData>,
|
||||
default: () => {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
const emits = defineEmits(['loading']);
|
||||
|
||||
const cacheStore = useCacheStore();
|
||||
|
||||
const data = ref<Array<TransferItem>>([]);
|
||||
const value = ref([]);
|
||||
const value = ref<Array<string>>([]);
|
||||
|
||||
// 渲染 label
|
||||
const renderLabel = (label: string) => {
|
||||
const last = label.lastIndexOf('-');
|
||||
const prefix = label.substring(0, last);
|
||||
const ip = label.substring(last + 1, label.length);
|
||||
return `${prefix} - <span class="span-blue">${ip}</span>`;
|
||||
};
|
||||
|
||||
// 保存
|
||||
const save = () => {
|
||||
console.log(value.value);
|
||||
const save = async () => {
|
||||
try {
|
||||
emits('loading', true);
|
||||
await updateHostGroupRel({
|
||||
groupId: props.group?.key as number,
|
||||
relIdList: value.value
|
||||
});
|
||||
Message.success('保存成功');
|
||||
} catch (e) {
|
||||
} finally {
|
||||
emits('loading', false);
|
||||
}
|
||||
};
|
||||
|
||||
// 查询组内数据
|
||||
watch(() => props.group?.key, async (groupId) => {
|
||||
if (groupId) {
|
||||
// 加载组内数据
|
||||
try {
|
||||
emits('loading', true);
|
||||
const { data } = await getHostGroupRelList(groupId as number);
|
||||
value.value = data.map(String);
|
||||
} catch (e) {
|
||||
} finally {
|
||||
emits('loading', false);
|
||||
}
|
||||
} else {
|
||||
// 重置
|
||||
value.value = [];
|
||||
}
|
||||
});
|
||||
|
||||
// 加载主机
|
||||
onMounted(() => {
|
||||
const cacheStore = useCacheStore();
|
||||
data.value = Array(200).fill(undefined).map((_, index) => ({
|
||||
value: `option${index + 1}`,
|
||||
label: `Option ${index + 1}`,
|
||||
disabled: false
|
||||
}));
|
||||
data.value = cacheStore.hosts.map(s => {
|
||||
return {
|
||||
value: String(s.id),
|
||||
label: `${s.name}(${s.code})-${s.address}`,
|
||||
disabled: false
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
@@ -16,41 +16,25 @@
|
||||
import { computed, ref, onBeforeMount, onUnmounted } from 'vue';
|
||||
import { useAppStore, useCacheStore, useDictStore } from '@/store';
|
||||
import HostGroupView from './components/host-group-view.vue';
|
||||
import { getHostList } from '@/api/asset/host';
|
||||
|
||||
const render = ref(false);
|
||||
const table = ref();
|
||||
const card = ref();
|
||||
const modal = ref();
|
||||
const config = ref();
|
||||
const appStore = useAppStore();
|
||||
const cacheStore = useCacheStore();
|
||||
|
||||
// 添加回调
|
||||
const modalAddCallback = () => {
|
||||
table.value.addedCallback();
|
||||
};
|
||||
|
||||
// 修改回调
|
||||
const modalUpdateCallback = () => {
|
||||
table.value.updatedCallback();
|
||||
};
|
||||
|
||||
// 加载 tags
|
||||
const loadTags = async () => {
|
||||
// 加载主机列表
|
||||
const loadHostList = async () => {
|
||||
try {
|
||||
const { data } = await getHostList();
|
||||
// 设置到缓存
|
||||
// cacheStore.set('hostTags', data);
|
||||
} catch {
|
||||
cacheStore.set('hosts', data);
|
||||
} catch (e) {
|
||||
Message.error('tag加载失败');
|
||||
}
|
||||
};
|
||||
|
||||
onBeforeMount(async () => {
|
||||
// 加载角色列表
|
||||
|
||||
// 加载用户列表
|
||||
|
||||
// 加载主机列表
|
||||
await loadHostList();
|
||||
render.value = true;
|
||||
});
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
const { data } = await getTagList('HOST');
|
||||
// 设置到缓存
|
||||
cacheStore.set('hostTags', data);
|
||||
} catch {
|
||||
} catch (e) {
|
||||
Message.error('tag加载失败');
|
||||
}
|
||||
};
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
const { data } = await getDictKeyList();
|
||||
// 设置到缓存
|
||||
cacheStore.set('dictKeys', data);
|
||||
} catch {
|
||||
} catch (e) {
|
||||
Message.error('配置项加载失败');
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user