diff --git a/dbm-ui/frontend/package.json b/dbm-ui/frontend/package.json index 6645e4df5b..34bb0d55d3 100644 --- a/dbm-ui/frontend/package.json +++ b/dbm-ui/frontend/package.json @@ -30,6 +30,7 @@ "bkui-vue": "2.0.1-beta.63", "date-fns": "3.6.0", "dayjs": "1.11.12", + "echarts": "^5.5.1", "html-to-image": "1.11.11", "js-cookie": "3.0.5", "jsencrypt": "3.3.2", @@ -49,7 +50,7 @@ "vue-router": "4.3.2", "vue-types": "5.1.2", "vuedraggable": "4.1.0", - "xlsx": "0.18.5" + "xlsx": "^0.18.5" }, "devDependencies": { "@commitlint/config-conventional": "19.2.2", @@ -110,4 +111,4 @@ "engines": { "node": ">=16.0.1" } -} \ No newline at end of file +} diff --git a/dbm-ui/frontend/src/common/const/machineTypes.ts b/dbm-ui/frontend/src/common/const/machineTypes.ts index 3cad0dd538..1d171dd876 100644 --- a/dbm-ui/frontend/src/common/const/machineTypes.ts +++ b/dbm-ui/frontend/src/common/const/machineTypes.ts @@ -11,6 +11,8 @@ export enum MachineTypes { TWEMPROXY = 'twemproxy', INFLUXDB = 'influxdb', RIAK = 'riak', + BROKER = 'broker', + ZOOKEEPER = 'zookeeper', } export enum MachineTypes { REDIS = 'redis', @@ -37,11 +39,7 @@ export enum MachineTypes { SQLSERVER_SINGLE = 'sqlserver_single', } export enum MachineTypes { - ZOOKEEPER = 'zookeeper', - PULSAR_ZOOKEEPER = 'pulsar_zookeeper', - PULSAR_BOOKKEEPER = 'pulsar_bookkeeper', -} -export enum MachineTypes { - BROKER = 'broker', PULSAR_BROKER = 'pulsar_broker', + PULSAR_BOOKKEEPER = 'pulsar_bookkeeper', + PULSAR_ZOOKEEPER = 'pulsar_zookeeper', } diff --git a/dbm-ui/frontend/src/locales/zh-cn.json b/dbm-ui/frontend/src/locales/zh-cn.json index 4d1cf9caed..817c5e33db 100644 --- a/dbm-ui/frontend/src/locales/zh-cn.json +++ b/dbm-ui/frontend/src/locales/zh-cn.json @@ -3467,5 +3467,23 @@ "确认继续所有人工确认节点": "确认继续所有人工确认节点", "仅可选择一种类型修改密码": "仅可选择一种类型修改密码", "DB 名处理:": "DB 名处理:", + "主机数量 - 按组件统计": "主机数量 - 按组件统计", + "分布情况": "分布情况", + "专业业务": "专业业务", + "地域 - 园区": "地域 - 园区", + "请选择园区": "请选择园区", + "数量 (台)": "数量 (台)", + "规格类型": "规格类型", + "园区分布(台)": "园区分布(台)", + "总数(台)": "总数(台)", + "聚合维度": "聚合维度", + "专用业务 + 地域 + 规格": "专用业务 + 地域 + 规格", + "专用业务 + 地域 + 机型(硬盘)": "专用业务 + 地域 + 机型(硬盘)", + "机型(硬盘)": "机型(硬盘)", + "导出列表内容": "导出列表内容", + "CPU 内存": "CPU 内存", + "数量(台)": "数量(台)", + "统计视图": "统计视图", + "主机列表": "主机列表", "这行勿动!新增翻译请在上一行添加!": "" } diff --git a/dbm-ui/frontend/src/services/model/db-resource/DbResource.ts b/dbm-ui/frontend/src/services/model/db-resource/DbResource.ts index 0ffbaaffd9..00591a7402 100644 --- a/dbm-ui/frontend/src/services/model/db-resource/DbResource.ts +++ b/dbm-ui/frontend/src/services/model/db-resource/DbResource.ts @@ -29,10 +29,10 @@ export default class DbResource { consume_time: string; create_time: string; device_class: string; - for_bizs: Array<{ + for_biz: { bk_biz_id: number; bk_biz_name: string; - }>; + }; ip: string; label: string; net_device_id: string; @@ -44,7 +44,7 @@ export default class DbResource { }; rack_id: string; raid: string; - resource_types: string[]; + resource_type: string; status: string; storage_device: { [key: string]: { @@ -75,7 +75,7 @@ export default class DbResource { this.consume_time = payload.consume_time; this.create_time = payload.create_time; this.device_class = payload.device_class; - this.for_bizs = payload.for_bizs || []; + this.for_biz = payload.for_biz; this.ip = payload.ip; this.label = payload.label; this.net_device_id = payload.net_device_id; @@ -85,7 +85,7 @@ export default class DbResource { this.permission = payload.permission; this.rack_id = payload.rack_id; this.raid = payload.raid; - this.resource_types = payload.resource_types || []; + this.resource_type = payload.resource_type; this.status = payload.status; this.storage_device = payload.storage_device || {}; this.sub_zone = payload.sub_zone; @@ -99,6 +99,6 @@ export default class DbResource { } get isAbnormal() { - return this.agent_status === 0 + return this.agent_status === 0; } } diff --git a/dbm-ui/frontend/src/services/model/db-resource/summary.ts b/dbm-ui/frontend/src/services/model/db-resource/summary.ts new file mode 100644 index 0000000000..61802a1c05 --- /dev/null +++ b/dbm-ui/frontend/src/services/model/db-resource/summary.ts @@ -0,0 +1,88 @@ +/* + * TencentBlueKing is pleased to support the open source community by making 蓝鲸智云-DB管理系统(BlueKing-BK-DBM) available. + * + * Copyright (C) 2017-2023 THL A29 Limited, a Tencent company. All rights reserved. + * + * Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at https://opensource.org/licenses/MIT + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed + * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for + * the specific language governing permissions and limitations under the License. + */ + +import { MachineTypes } from '@common/const'; + +import { t } from '@locales/index'; + +export default class Summary { + dedicated_biz: number; + for_biz_name: string; + city: string; + spec_id?: number; + spec_name?: string; + spec_machine_type?: MachineTypes; + device_class?: string; + disk_summary?: string; + cpu_mem_summary?: string; + count: number; + sub_zone_detail: Record; + + constructor(payload = {} as Summary) { + this.dedicated_biz = payload.dedicated_biz; + this.for_biz_name = payload.for_biz_name; + this.city = payload.city; + this.spec_id = payload.spec_id; + this.spec_name = payload.spec_name; + this.spec_machine_type = payload.spec_machine_type; + this.device_class = payload.device_class; + this.disk_summary = payload.disk_summary; + this.cpu_mem_summary = payload.cpu_mem_summary; + this.count = payload.count; + this.sub_zone_detail = payload.sub_zone_detail; + } + + get device_display() { + return `${this.device_class} (${this.disk_summary})`; + } + + get spec_machine_display() { + const machineTypeMap: Record = { + [MachineTypes.SINGLE]: t('后端存储机型'), + [MachineTypes.SPIDER]: t('接入层Master'), + [MachineTypes.REMOTE]: t('后端存储规格'), + [MachineTypes.PROXY]: t('Proxy机型'), + [MachineTypes.BACKEND]: t('后端存储机型'), + [MachineTypes.PREDIXY]: t('Proxy机型'), + [MachineTypes.TWEMPROXY]: t('Proxy机型'), + [MachineTypes.INFLUXDB]: t('后端存储机型'), + [MachineTypes.RIAK]: t('后端存储机型'), + [MachineTypes.BROKER]: t('Broker节点规格'), + [MachineTypes.ZOOKEEPER]: t('Zookeeper节点规格'), + [MachineTypes.REDIS]: t('后端存储机型'), + [MachineTypes.TENDISCACHE]: t('后端存储机型'), + [MachineTypes.TENDISSSD]: t('后端存储机型'), + [MachineTypes.TENDISPLUS]: t('后端存储机型'), + [MachineTypes.ES_DATANODE]: t('冷_热节点规格'), + [MachineTypes.ES_MASTER]: t('Master节点规格'), + [MachineTypes.ES_CLIENT]: t('Client节点规格'), + [MachineTypes.HDFS_MASTER]: t('NameNode_Zookeeper_JournalNode节点规格'), + [MachineTypes.HDFS_DATANODE]: t('DataNode节点规格'), + [MachineTypes.MONGOS]: t('Mongos规格'), + [MachineTypes.MONGODB]: t('ShardSvr规格'), + [MachineTypes.MONGO_CONFIG]: t('ConfigSvr规格'), + [MachineTypes.SQLSERVER_HA]: t('后端存储机型'), + [MachineTypes.SQLSERVER_SINGLE]: t('后端存储机型'), + [MachineTypes.PULSAR_BROKER]: t('Broker节点规格'), + [MachineTypes.PULSAR_BOOKKEEPER]: t('Bookkeeper节点规格'), + [MachineTypes.PULSAR_ZOOKEEPER]: t('Zookeeper节点规格'), + }; + return machineTypeMap[this.spec_machine_type as MachineTypes]; + } + + get sub_zone_detail_display() { + return `${Object.entries(this.sub_zone_detail) + .map(([zone, count]) => `${zone}: ${count}`) + .join(', ')};`; + } +} diff --git a/dbm-ui/frontend/src/services/source/dbresourceResource.ts b/dbm-ui/frontend/src/services/source/dbresourceResource.ts index cca4630c80..972093939d 100644 --- a/dbm-ui/frontend/src/services/source/dbresourceResource.ts +++ b/dbm-ui/frontend/src/services/source/dbresourceResource.ts @@ -14,6 +14,9 @@ import DbResourceModel from '@services/model/db-resource/DbResource'; import ImportHostModel from '@services/model/db-resource/import-host'; import OperationModel from '@services/model/db-resource/Operation'; +import SummaryModel from '@services/model/db-resource/summary'; + +import type { DBTypes } from '@common/const'; import http, { type IRequestPayload } from '../http'; import type { HostDetails, ListBase } from '../types'; @@ -48,19 +51,12 @@ export function fetchMountPoints() { return http.get(`${path}/get_mountpoints/`); } -/** - * 根据逻辑城市查询园区 - */ -export function fetchSubzones(params: { citys: string }) { - return http.get(`${path}/get_subzones/`, params); -} - /** * 资源池导入 */ export function importResource(params: { - for_bizs: number[]; - resource_types: string[]; + for_biz: number; + resource_type: string; hosts: Array<{ ip: string; host_id: number; @@ -170,9 +166,9 @@ export function getSpecResourceCount(params: { */ export function updateResource(params: { bk_host_ids: number[]; - for_bizs: number[]; + for_biz: number; rack_id: string; - resource_types: string[]; + resource_type: string; set_empty_biz: boolean; set_empty_resource_type: boolean; storage_device: Record; @@ -186,3 +182,30 @@ export function updateResource(params: { export function getOsTypeList(params: { offset?: number; limit?: number }) { return http.get(`${path}/get_os_types/`, params); } + +/** + * 按照组件统计资源数量 + */ +export function getGroupCount() { + return http.post<{ rs_type: string; count: number }[]>(`${path}/resource_group_count/`); +} + +/** + * 按照条件聚合资源统计 + */ +export function getSummaryList(params: { + group_by: string; + for_biz?: number; + city?: string; + sub_zones?: string[]; + spec_param: { + db_type: DBTypes; + machine_type?: string; + cluster_type?: string; + spec_id_list?: number[]; + }; +}) { + return http + .post(`${path}/resource_summary/`, params) + .then((data) => data.map((item) => new SummaryModel(item))); +} diff --git a/dbm-ui/frontend/src/services/source/infras.ts b/dbm-ui/frontend/src/services/source/infras.ts index 8957694ce0..cceece6d5a 100644 --- a/dbm-ui/frontend/src/services/source/infras.ts +++ b/dbm-ui/frontend/src/services/source/infras.ts @@ -29,6 +29,20 @@ export function getInfrasCities() { >(`${path}/cities/`); } +/** + * 查询城市园区信息 + */ +export function getInfrasSubzonesByCity(params: { city_code: string }) { + return http.get< + { + bk_city: number; + bk_city_code: string; + bk_sub_zone_id: number; + bk_sub_zone: string; + }[] + >(`${path}/cities/list_subzones/`, params); +} + /** * 主机提交格式 */ diff --git a/dbm-ui/frontend/src/utils/url.ts b/dbm-ui/frontend/src/utils/url.ts index 5cc3691471..5b13fd53fc 100644 --- a/dbm-ui/frontend/src/utils/url.ts +++ b/dbm-ui/frontend/src/utils/url.ts @@ -9,10 +9,11 @@ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for * the specific language governing permissions and limitations under the License. -*/ -import { createBkrepoAccessToken } from '@services/source/storage'; + */ import _ from 'lodash'; +import { createBkrepoAccessToken } from '@services/source/storage'; + export const parseURL = (url: string) => { const a = document.createElement('a'); a.href = url; @@ -30,7 +31,7 @@ export const parseURL = (url: string) => { }; export const buildURLParams = (params: any) => { - function forEach(obj:any, fn:any) { + function forEach(obj: any, fn: any) { // Don't bother if no value provided if (obj === null || typeof obj === 'undefined') { return; @@ -56,7 +57,7 @@ export const buildURLParams = (params: any) => { }); } } - function encode(val:string) { + function encode(val: string) { return encodeURIComponent(val) .replace(/%40/gi, '@') .replace(/%3A/gi, ':') @@ -72,7 +73,7 @@ export const buildURLParams = (params: any) => { } const parts: Array = []; - forEach(params, (val:any, key: any) => { + forEach(params, (val: any, key: any) => { if (val === null || typeof val === 'undefined') { return; } @@ -83,7 +84,7 @@ export const buildURLParams = (params: any) => { val = [val]; } - forEach(val, (v:any) => { + forEach(val, (v: any) => { if (_.isDate(v)) { v = v.toISOString(); } else if (_.isObject(v)) { @@ -96,6 +97,5 @@ export const buildURLParams = (params: any) => { }; // 根据 createBkrepoAccessToken 请求返回的响应对象组装bkrepo的下载链接 -export const generateBkRepoDownloadUrl = (tokenResult: ServiceReturnType) => `${tokenResult.url}/generic/temporary/download/${tokenResult.project}/${tokenResult.repo}/${tokenResult.path}?token=${tokenResult.token}&download=true` - - +export const generateBkRepoDownloadUrl = (tokenResult: ServiceReturnType) => + `${tokenResult.url}/generic/temporary/download/${tokenResult.project}/${tokenResult.repo}/${tokenResult.path}?token=${tokenResult.token}&download=true`; diff --git a/dbm-ui/frontend/src/views/quick-search/components/ResourcePool.vue b/dbm-ui/frontend/src/views/quick-search/components/ResourcePool.vue index 8dcf4e38fd..8bd0894c07 100644 --- a/dbm-ui/frontend/src/views/quick-search/components/ResourcePool.vue +++ b/dbm-ui/frontend/src/views/quick-search/components/ResourcePool.vue @@ -9,7 +9,7 @@