From f7cf59059304432f737dfc5de06174eaa6804795 Mon Sep 17 00:00:00 2001 From: chenwenchang <479999519@qq.com> Date: Fri, 25 Oct 2024 16:38:42 +0800 Subject: [PATCH] =?UTF-8?q?fix(frontend):=20=E4=BF=AE=E5=A4=8Dredis?= =?UTF-8?q?=E6=95=B4=E6=9C=BA=E6=9B=BF=E6=8D=A2=E9=97=AE=E9=A2=98=20#7596?= =?UTF-8?q?=20#=20Reviewed,=20transaction=20id:=2022878?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../generateCloneData/redis/clusterCutoff.ts | 57 ++--- .../services/model/ticket/details/redis.ts | 9 + dbm-ui/frontend/src/services/source/redis.ts | 1 + .../redis/db-replace/pages/page1/Index.vue | 228 ++++++++++-------- .../components/RenderRedis.vue | 79 ++++-- .../components/RenderRedisHost.vue | 46 ++-- .../demand-factory/redis/DBReplace.vue | 87 +------ 7 files changed, 239 insertions(+), 268 deletions(-) diff --git a/dbm-ui/frontend/src/hooks/useTicketCloneInfo/generateCloneData/redis/clusterCutoff.ts b/dbm-ui/frontend/src/hooks/useTicketCloneInfo/generateCloneData/redis/clusterCutoff.ts index da754f6ba6..f7c724a585 100644 --- a/dbm-ui/frontend/src/hooks/useTicketCloneInfo/generateCloneData/redis/clusterCutoff.ts +++ b/dbm-ui/frontend/src/hooks/useTicketCloneInfo/generateCloneData/redis/clusterCutoff.ts @@ -19,47 +19,22 @@ import { random } from '@utils'; export function generateRedisClusterCutoffCloneData(ticketData: TicketModel) { const { clusters, infos, specs } = ticketData.details; return Promise.resolve({ - tableDataList: infos.reduce( - (dataList, item) => { - const roleList = ['proxy', 'redis_master', 'redis_slave'] as ['proxy', 'redis_master', 'redis_slave']; - const roleMap = { - redis_master: 'master', - redis_slave: 'slave', - proxy: 'proxy', - }; - roleList.forEach((role) => { - if (item[role].length > 0) { - item[role].forEach((info) => { - dataList.push({ - rowKey: random(), - isLoading: false, - ip: info.ip, - role: roleMap[role], - clusterIds: item.cluster_ids, - bkCloudId: item.bk_cloud_id, - cluster: { - domain: item.cluster_ids.map((id) => clusters[id].immute_domain).join(','), - isStart: false, - isGeneral: true, - rowSpan: 1, - }, - spec: specs[info.spec_id], - }); - }); - } - }); - return dataList; - }, - [] as { - rowKey: string; - isLoading: boolean; - ip: string; - role: string; - clusterIds: number[]; - bkCloudId: number; - cluster: any; - spec: any; - }[], + tableDataList: infos.flatMap((info) => + info.display_info.data.map((curr) => ({ + rowKey: random(), + isLoading: false, + ip: curr.ip, + role: curr.role, + clusterIds: info.cluster_ids, + bkCloudId: info.bk_cloud_id, + cluster: { + domain: info.cluster_ids.map((id) => clusters[id].immute_domain).join(','), + isStart: false, + isGeneral: true, + rowSpan: 1, + }, + spec: specs[curr.spec_id], + })), ), remark: ticketData.remark, }); diff --git a/dbm-ui/frontend/src/services/model/ticket/details/redis.ts b/dbm-ui/frontend/src/services/model/ticket/details/redis.ts index e0ecc9a8cb..0a5d736f04 100644 --- a/dbm-ui/frontend/src/services/model/ticket/details/redis.ts +++ b/dbm-ui/frontend/src/services/model/ticket/details/redis.ts @@ -256,6 +256,15 @@ export interface RedisDBReplaceDetails extends DetailBase { ip: string; spec_id: number; }[]; + display_info: { + data: { + ip: string; + role: string; + cluster_domain: string; + spec_id: number; + spec_name: string; + }[]; + }; }[]; specs: DetailSpecs; } diff --git a/dbm-ui/frontend/src/services/source/redis.ts b/dbm-ui/frontend/src/services/source/redis.ts index 7cd5fb4129..e4a93d888c 100644 --- a/dbm-ui/frontend/src/services/source/redis.ts +++ b/dbm-ui/frontend/src/services/source/redis.ts @@ -181,6 +181,7 @@ export const getRedisClusterList = async (params: { bk_biz_id: number; domain?: export function getRedisMachineList(params: { limit?: number; offset?: number; + extra?: number; bk_host_id?: number; ip?: string; cluster_ids?: string; diff --git a/dbm-ui/frontend/src/views/db-manage/redis/db-replace/pages/page1/Index.vue b/dbm-ui/frontend/src/views/db-manage/redis/db-replace/pages/page1/Index.vue index d3bc426808..7a02aee324 100644 --- a/dbm-ui/frontend/src/views/db-manage/redis/db-replace/pages/page1/Index.vue +++ b/dbm-ui/frontend/src/views/db-manage/redis/db-replace/pages/page1/Index.vue @@ -83,7 +83,7 @@ import TicketRemark from '@components/ticket-remark/Index.vue'; - import { switchToNormalRole } from '@utils'; + import { random } from '@utils'; import RenderData from './components/Index.vue'; import InstanceSelector, { type InstanceSelectorValues } from './components/instance-selector/Index.vue'; @@ -101,6 +101,15 @@ proxy: SpecItem[]; redis_master: SpecItem[]; redis_slave: SpecItem[]; + display_info: { + data: { + ip: string; + role: string; + cluster_domain: string; + spec_id: number; + spec_name: string; + }[]; + }; } const { currentBizId } = useGlobalBizs(); @@ -131,9 +140,16 @@ const totalNum = computed(() => tableData.value.filter((item) => Boolean(item.ip)).length); const inputedIps = computed(() => tableData.value.map((item) => item.ip)); + // ip 是否已存在表格的映射表 + let ipMemo = {} as Record; // slave <-> master const slaveMasterMap: Record = {}; + // Master 批量选择 + const handleShowMasterBatchSelector = () => { + isShowMasterInstanceSelector.value = true; + }; + // 检测列表是否为空 const checkListEmpty = (list: Array) => { if (list.length === 0) { @@ -166,44 +182,52 @@ }); }; - // Master 批量选择 - const handleShowMasterBatchSelector = () => { - isShowMasterInstanceSelector.value = true; + // 表格排序,方便合并集群显示 + const sortTableByCluster = () => { + const clusterMap = tableData.value.reduce>((acc, item) => { + const { domain } = item.cluster; + acc[domain] = acc[domain] || []; + acc[domain].push(item); + return acc; + }, {}); + + tableData.value = Object.values(clusterMap).flatMap((sameArr) => { + const isGeneral = sameArr.length <= 1; + return sameArr.map((item, index) => ({ + ...item, + cluster: { + ...item.cluster, + isStart: index === 0, + rowSpan: index === 0 ? sameArr.length : 1, + isGeneral, + }, + })); + }); }; - // ip 是否已存在表格的映射表 - let ipMemo = {} as Record; - // 批量选择 const handelMasterProxyChange = async (data: InstanceSelectorValues) => { selected.value = data; - const dalaList = data.idleHosts; + const dataList = data.idleHosts; const listResult = await getRedisMachineList({ - ip: dalaList.map((item) => item.ip).join(','), + ip: dataList.map((item) => item.ip).join(','), add_role_count: true, }); - const machineIpMap = listResult.results.reduce( - (results, item) => { - Object.assign(results, { - [item.ip]: item, - }); - return results; - }, - {} as Record['results'][number]>, - ); - const newList: IDataRow[] = []; - dalaList.forEach((item) => { + + const machineIpMap = Object.fromEntries(listResult.results.map((item) => [item.ip, item])); + + const newList = dataList.reduce((acc, item) => { const { ip } = item; if (!ipMemo[ip]) { - newList.push({ - rowKey: ip, + acc.push({ + rowKey: random(), isLoading: false, ip, role: item.role, - clusterIds: machineIpMap[ip].related_clusters.map((item) => item.id), + clusterIds: machineIpMap[ip].related_clusters.map((cluster) => cluster.id), bkCloudId: item.bk_cloud_id, cluster: { - domain: machineIpMap[ip].related_clusters.map((item) => item.immute_domain).join(','), + domain: machineIpMap[ip].related_clusters.map((cluster) => cluster.immute_domain).join(','), isStart: false, isGeneral: true, rowSpan: 1, @@ -212,12 +236,9 @@ }); ipMemo[ip] = true; } - }); - if (checkListEmpty(tableData.value)) { - tableData.value = newList; - } else { - tableData.value = [...tableData.value, ...newList]; - } + return acc; + }, []); + tableData.value = checkListEmpty(tableData.value) ? newList : [...tableData.value, ...newList]; sortTableByCluster(); updateSlaveMasterMap(); window.changeConfirm = true; @@ -226,39 +247,71 @@ // 输入IP后查询详细信息 const handleChangeHostIp = async (index: number, ip: string) => { if (!ip) { - const { ip } = tableData.value[index]; - ipMemo[ip] = false; + const currentIp = tableData.value[index].ip; + ipMemo[currentIp] = false; tableData.value[index].ip = ''; return; } + tableData.value[index].isLoading = true; tableData.value[index].ip = ip; - const result = await getRedisMachineList({ - ip, - add_role_count: true, - }).finally(() => { + + try { + const result = await getRedisMachineList({ ip, add_role_count: true }); + const data = result.results[0]; + const relatedClusters = data.related_clusters; + const clusterDomain = relatedClusters.map((item) => item.immute_domain).join(','); + + const row: IDataRow = { + rowKey: tableData.value[index].rowKey, + isLoading: false, + ip, + role: data.instance_role, + clusterIds: relatedClusters.map((item) => item.id), + bkCloudId: data.bk_cloud_id, + cluster: { + domain: clusterDomain, + isStart: false, + isGeneral: true, + rowSpan: 1, + }, + spec: data.spec_config, + }; + tableData.value[index] = row; + + const appendItem = { + ip, + bk_host_id: data.bk_host_id, + bk_cloud_id: data.bk_cloud_id, + role: data.instance_role, + cluster_domain: clusterDomain, + spec_config: data.spec_config, + }; + selected.value.idleHosts.push(appendItem); + ipMemo[ip] = true; + sortTableByCluster(); + await updateSlaveMasterMap(); + + if (data.instance_role === 'redis_master') { + const slaveIp = slaveMasterMap[ip]; + const slaveClusterInfo = { + role: 'redis_slave', + ip: slaveIp, + }; + tableData.value[index + 1] = { + ...row, + rowKey: random(), + ...slaveClusterInfo, + }; + selected.value.idleHosts.push({ + ...appendItem, + ...slaveClusterInfo, + }); + sortTableByCluster(); + } + } finally { tableData.value[index].isLoading = false; - }); - const data = result.results[0]; - const obj: IDataRow = { - rowKey: tableData.value[index].rowKey, - isLoading: false, - ip, - role: switchToNormalRole(data.instance_role), - clusterIds: data.related_clusters.map((item) => item.id), - bkCloudId: data.bk_cloud_id, - cluster: { - domain: data.related_clusters.map((item) => item.immute_domain).join(','), - isStart: false, - isGeneral: true, - rowSpan: 1, - }, - spec: data.spec_config, - }; - tableData.value[index] = obj; - ipMemo[ip] = true; - sortTableByCluster(); - updateSlaveMasterMap(); + } }; // 追加一个集群 @@ -314,17 +367,14 @@ // 根据表格数据生成提交单据请求参数 const generateRequestParam = () => { - const clusterMap: Record = {}; - tableData.value.forEach((item) => { + const clusterMap = tableData.value.reduce>((acc, item) => { if (item.ip) { const clusterName = item.cluster.domain; - if (!clusterMap[clusterName]) { - clusterMap[clusterName] = [item]; - } else { - clusterMap[clusterName].push(item); - } + acc[clusterName] = acc[clusterName] || []; + acc[clusterName].push(item); } - }); + return acc; + }, {}); const domains = Object.keys(clusterMap); const infos = domains.map((domain) => { const sameArr = clusterMap[domain]; @@ -335,6 +385,9 @@ proxy: [], redis_master: [], redis_slave: [], + display_info: { + data: [], + }, }; const needDeleteSlaves: string[] = []; sameArr.forEach((item) => { @@ -357,6 +410,15 @@ }); // 当选择了master的时候,对应的slave不要传给后端 infoItem.redis_slave = infoItem.redis_slave.filter((item) => !needDeleteSlaves.includes(item.ip)); + infoItem.display_info = { + data: tableData.value.map((item) => ({ + ip: item.ip, + role: item.role, + cluster_domain: item.cluster.domain, + spec_id: item.spec?.id ?? 0, + spec_name: item.spec?.name ?? '', + })), + }; return infoItem; }); return infos; @@ -403,42 +465,6 @@ ipMemo = {}; window.changeConfirm = false; }; - - // 表格排序,方便合并集群显示 - const sortTableByCluster = () => { - const arr = tableData.value; - const clusterMap: Record = {}; - arr.forEach((item) => { - const { domain } = item.cluster; - if (!clusterMap[domain]) { - clusterMap[domain] = [item]; - } else { - clusterMap[domain].push(item); - } - }); - const keys = Object.keys(clusterMap); - const retArr = []; - for (const key of keys) { - const sameArr = clusterMap[key]; - let isFirst = true; - let isGeneral = true; - if (sameArr.length > 1) { - isGeneral = false; - } - for (const item of sameArr) { - if (isFirst) { - item.cluster.isStart = true; - item.cluster.rowSpan = sameArr.length; - isFirst = false; - } else { - item.cluster.isStart = false; - } - item.cluster.isGeneral = isGeneral; - retArr.push(item); - } - } - tableData.value = retArr; - };