diff --git a/dbm-ui/frontend/src/common/const/machineEvents.ts b/dbm-ui/frontend/src/common/const/machineEvents.ts new file mode 100644 index 0000000000..f710b87112 --- /dev/null +++ b/dbm-ui/frontend/src/common/const/machineEvents.ts @@ -0,0 +1,26 @@ +import { t } from '@locales/index'; + +/** + * 机器事件统类型 + */ +export const enum MachineEvents { + IMPORT_RESOURCE = 'import_resource', + APPLY_RESOURCE = 'apply_resource', + RETURN_RESOURCE = 'return_resource', + TO_DIRTY = 'to_dirty', + TO_RECYCLE = 'to_recycle', + TO_FAULT = 'to_fault', + UNDO_IMPORT = 'undo_import', + RECYCLED = 'recycled', +} + +export const machineEventsDisplayMap = { + [MachineEvents.IMPORT_RESOURCE]: t('导入资源池'), + [MachineEvents.APPLY_RESOURCE]: t('申请资源'), + [MachineEvents.RETURN_RESOURCE]: t('退回资源'), + [MachineEvents.TO_DIRTY]: t('转入污点池'), + [MachineEvents.TO_RECYCLE]: t('转入待回收池'), + [MachineEvents.TO_FAULT]: t('转入故障池'), + [MachineEvents.UNDO_IMPORT]: t('撤销导入'), + [MachineEvents.RECYCLED]: t('回收'), +}; diff --git a/dbm-ui/frontend/src/locales/en.json b/dbm-ui/frontend/src/locales/en.json index b36c179bc5..ab5f4d51f9 100644 --- a/dbm-ui/frontend/src/locales/en.json +++ b/dbm-ui/frontend/src/locales/en.json @@ -1655,5 +1655,18 @@ "Mongo分片集群": "", "sqlserver单节点版": "", "sqlserver主从版": "", + "操作明细": "", + "导入资源池": "", + "申请资源": "", + "退回资源": "", + "转入污点池": "", + "转入待回收池": "", + "撤销导入": "", + "回收": "", + "业务主机退回资源池": "", + "资源池主机转入待回收池": "", + "资源池主机转入故障池": "", + "业务主机转入故障池": "", + "全局资源池": "", "这行勿动!新增翻译请在上一行添加!": "" } diff --git a/dbm-ui/frontend/src/locales/zh-cn.json b/dbm-ui/frontend/src/locales/zh-cn.json index 70b0516607..bc77337bb5 100644 --- a/dbm-ui/frontend/src/locales/zh-cn.json +++ b/dbm-ui/frontend/src/locales/zh-cn.json @@ -3897,11 +3897,9 @@ "已选择以下n台主机": "已选择以下 {0} 台主机", "资源监控": "资源监控", "系统管理": "系统管理", - "撤销导入": "撤销导入", "确认后,主机将从资源池移回原有模块": "确认后,主机将从资源池移回原有模块", "所属DB": "所属DB", "转入故障池": "转入故障池", - "转入待回收池": "转入待回收池", "资源归属": "资源归属", "确认批量将 {n} 台主机转入回收池?": "确认批量将 {n} 台主机转入回收池?", "确认批量将 {n} 台主机转入故障池?": "确认批量将 {n} 台主机转入故障池?", @@ -3934,8 +3932,6 @@ "确认转入待故障池?": "确认转入待故障池?", "跳转管理页": "跳转管理页", "确认批量回收 {n} 台主机?": "确认批量回收 {n} 台主机?", - "回收": "回收", - "导入资源池": "导入资源池", "确认回收该机器?": "确认回收该机器?", "待回收池": "待回收池", "故障池": "故障池", @@ -3952,7 +3948,6 @@ "所有 IP": "所有 IP", "已选 IP": "已选 IP", "业务资源池": "业务资源池", - "冷/热节点": "冷/热节点", "退回公共资源池": "退回公共资源池", "确认转入业务资源池?": "确认转入业务资源池?", "转入业务资源池": "转入业务资源池", @@ -3965,6 +3960,40 @@ "清空主机现有的所属 DB 和标签,重新进行设置": "清空主机现有的所属 DB 和标签,重新进行设置", "清空主机现有的所属业务、所属 DB 、标签,重新进行设置": "清空主机现有的所属业务、所属 DB 、标签,重新进行设置", "添加属性": "添加属性", + "目标集群:": "目标集群:", + "目标 DB:": "目标 DB:", + "目标表名:": "目标表名:", + "where 条件:": "where 条件:", + "导出数据:": "导出数据:", + "脚本来源:": "脚本来源:", + "脚本执行内容:": "脚本执行内容:", + "MySQL单节点集群": "MySQL 单节点集群", + "MySQL高可用集群": "MySQL 高可用集群", + "TendisCache集群": "TendisCache集群", + "RedisCache主从版": "RedisCache主从版", + "Kafka集群": "Kafka 集群", + "Hdfs集群": "Hdfs 集群", + "Pulsar集群": "Pulsar 集群", + "Riak集群": "Riak 集群", + "Mongo分片集群": "Mongo 分片集群", + "sqlserver单节点版": "sqlserver 单节点版", + "sqlserver主从版": "sqlserver 主从版", + "操作明细": "操作明细", + "导入资源池": "导入资源池", + "申请资源": "申请资源", + "退回资源": "退回资源", + "转入污点池": "转入污点池", + "转入待回收池": "转入待回收池", + "撤销导入": "撤销导入", + "回收": "回收", + "从「n」业务 CMDB空闲机模块导入": "从「{n}」业务 CMDB空闲机模块导入", + "退回「n」业务 CMDB 空闲机模块": "退回「{n}」业务 CMDB 空闲机模块", + "退回「n」业务 CMDB 待回收模块": "退回「{n}」业务 CMDB 待回收模块", + "业务主机退回资源池": "业务主机退回资源池", + "资源池主机转入待回收池": "资源池主机转入待回收池", + "资源池主机转入故障池": "资源池主机转入故障池", + "业务主机转入故障池": "业务主机转入故障池", + "全局资源池": "全局资源池", "这行勿动!新增翻译请在上一行添加!": "" } diff --git a/dbm-ui/frontend/src/services/model/db-resource/machineEvent.ts b/dbm-ui/frontend/src/services/model/db-resource/machineEvent.ts new file mode 100644 index 0000000000..11e9bfdccb --- /dev/null +++ b/dbm-ui/frontend/src/services/model/db-resource/machineEvent.ts @@ -0,0 +1,76 @@ +import { MachineEvents, machineEventsDisplayMap } from '@common/const/machineEvents'; + +import { utcDisplayTime } from '@utils'; + +import { t } from '@locales/index'; + +export default class MachineEvent { + bk_biz_id: number | undefined; + bk_biz_name: string | undefined; + bk_host_id: number; + clusters: string[]; + creator: string; + create_at: string; + db_app_abbr: string; + event: MachineEvents; + id: number; + ip: string; + ticket: number | null; + ticket_type_display: string; + to: string; + updater: string; + update_at: string; + + constructor(payload = {} as MachineEvent) { + this.bk_biz_id = payload.bk_biz_id; + this.bk_biz_name = payload.bk_biz_name; + this.bk_host_id = payload.bk_host_id; + this.clusters = payload.clusters; + this.creator = payload.creator; + this.create_at = payload.create_at; + this.db_app_abbr = payload.db_app_abbr; + this.event = payload.event; + this.id = payload.id; + this.ip = payload.ip; + this.ticket = payload.ticket; + this.ticket_type_display = payload.ticket_type_display; + this.to = payload.to; + this.updater = payload.updater; + this.update_at = payload.update_at; + } + + get bizDisplay() { + return this.bk_biz_id ? `${this.bk_biz_name}(#${this.bk_biz_id},${this.db_app_abbr})` : '--'; + } + + get eventDisplay() { + return machineEventsDisplayMap[this.event]; + } + + get updateAtDisplay() { + return utcDisplayTime(this.update_at); + } + + get operationDetail() { + switch (this.event) { + case MachineEvents.IMPORT_RESOURCE: + return `${this.eventDisplay}(${t('从「n」业务 CMDB空闲机模块导入', { n: this.bk_biz_name })})`; + case MachineEvents.APPLY_RESOURCE: + return this.eventDisplay; + case MachineEvents.RETURN_RESOURCE: + return t('业务主机退回资源池'); + case MachineEvents.TO_DIRTY: + return this.eventDisplay; + case MachineEvents.TO_RECYCLE: + return t('资源池主机转入待回收池'); + case MachineEvents.TO_FAULT: + return this.bk_biz_id ? t('资源池主机转入故障池') : t('业务主机转入故障池'); + case MachineEvents.UNDO_IMPORT: + return `${this.eventDisplay}(${t('退回「n」业务 CMDB 空闲机模块', { n: this.bk_biz_name })})`; + case MachineEvents.RECYCLED: + return `${this.eventDisplay}(${t('退回「n」业务 CMDB 待回收模块', { n: this.bk_biz_name })})`; + default: + return this.event; + } + } +} diff --git a/dbm-ui/frontend/src/services/model/function-controller/functionController.ts b/dbm-ui/frontend/src/services/model/function-controller/functionController.ts index 9dcaee07a0..771db7ecb1 100644 --- a/dbm-ui/frontend/src/services/model/function-controller/functionController.ts +++ b/dbm-ui/frontend/src/services/model/function-controller/functionController.ts @@ -77,6 +77,7 @@ export default class FunctionController { 'resourceManage.faultPool': ControllerItem; 'resourceManage.toRecyclePool': ControllerItem; 'resourceManage.dirtyHostManage': ControllerItem; + 'resourceManage.resourceTagsManagement': ControllerItem; 'resourceManage.resourceOperationRecord': ControllerItem; bizConfigManage: ControllerItem; 'bizConfigManage.monitorStrategy': ControllerItem; diff --git a/dbm-ui/frontend/src/services/source/dbdirty.ts b/dbm-ui/frontend/src/services/source/dbdirty.ts index 366cc13391..d05811114d 100644 --- a/dbm-ui/frontend/src/services/source/dbdirty.ts +++ b/dbm-ui/frontend/src/services/source/dbdirty.ts @@ -13,6 +13,7 @@ import DirtyMachinesModel from '@services/model/db-resource/dirtyMachines'; import FaultOrRecycleMachineModel from '@services/model/db-resource/FaultOrRecycleMachine'; +import MachineEventModel from '@services/model/db-resource/machineEvent'; import type { ListBase } from '@services/types'; import http from '../http'; @@ -40,6 +41,26 @@ export function getDirtyMachines(params: { limit: number; offset: number }) { })); } +/** + * 机器事件列表 + */ +export function getMachineEvents(params: { + operator?: string; + bk_biz_id?: number; + events?: string; + ips?: string; + create_at__lte?: string; + create_at__gte?: string; + domain?: string; + limit?: number; + offset?: number; +}) { + return http.get>(`${path}/list_machine_events/`, params).then((data) => ({ + ...data, + results: data.results.map((item) => new MachineEventModel(item)), + })); +} + /** * 将污点池主机转移至待回收模块 */ diff --git a/dbm-ui/frontend/src/views/resource-manage/dirty-machine/Index.vue b/dbm-ui/frontend/src/views/resource-manage/dirty-machine/Index.vue deleted file mode 100644 index 67ddd51690..0000000000 --- a/dbm-ui/frontend/src/views/resource-manage/dirty-machine/Index.vue +++ /dev/null @@ -1,560 +0,0 @@ - - - - - - diff --git a/dbm-ui/frontend/src/views/resource-manage/record/Index.vue b/dbm-ui/frontend/src/views/resource-manage/record/Index.vue index bec0ac49ff..18b6304932 100644 --- a/dbm-ui/frontend/src/views/resource-manage/record/Index.vue +++ b/dbm-ui/frontend/src/views/resource-manage/record/Index.vue @@ -17,6 +17,7 @@ style="width: 500px" unique-select :validate-values="validateSearchValues" + value-behavior="need-key" @change="handleSearchValueChange" /> @@ -34,26 +36,27 @@ import dayjs from 'dayjs'; import { useI18n } from 'vue-i18n'; import { useRequest } from 'vue-request'; - import { useRoute } from 'vue-router'; - import OperationModel from '@services/model/db-resource/Operation'; - import { fetchOperationList } from '@services/source/dbresourceResource'; + import { getMachineEvents } from '@services/source/dbdirty'; import { getTicketTypes } from '@services/source/ticket'; import { getUserList } from '@services/source/user'; import { useLinkQueryColumnSerach } from '@hooks'; + import { useGlobalBizs } from '@stores' + + import { MachineEvents , machineEventsDisplayMap } from '@common/const/machineEvents'; + import { getMenuListSearch, getSearchSelectorParams } from '@utils'; - import HostDetail from './components/HostDetail.vue'; + type MachineEvent = ServiceReturnType['results'][number] - const route = useRoute(); const { t } = useI18n(); - + const globalBizStore = useGlobalBizs(); const { searchValue, sortValue, - columnCheckedMap, + // columnCheckedMap, columnFilterChange, columnSortChange, clearSearchValue, @@ -65,7 +68,7 @@ fetchDataFn: () => fetchData(), }); - const dataSource = fetchOperationList; + const dataSource = getMachineEvents; const tableRef = ref(); const operationDateTime = ref<[string, string]>([ @@ -76,212 +79,136 @@ const ticketTypes = ref>([]); const searchSelectData = computed(() => [ - { - name: t('操作类型'), - id: 'operation_type', - children: [ - { - id: [OperationModel.OPERATIN_TYPE_IMPORTED], - name: t('导入主机'), - - }, - { - id: [OperationModel.OPERATIN_TYPE_CONSUMED], - name: t('消费主机'), - }, - ], + { + name: 'IP', + id: 'ips', + multiple: true, }, { - name: t('单据类型'), - id: 'ticket_types', + name: t('操作类型'), + id: 'events', multiple: true, - children: ticketTypes.value, + children: Object.entries(machineEventsDisplayMap).map(([key, value]) => ({ id: key, name: value })), }, { - name: t('关联单据'), - id: 'ticket_ids', + name: t('操作人'), + id: 'operator', }, { - name: t('关联任务'), - id: 'task_ids', + name: t('所属业务'), + id: 'bk_biz_id', + // multiple: true, + children: globalBizStore.bizs.map((item) => ({ id: item.bk_biz_id, name: item.name })) }, { - name: t('操作状态'), - id: 'status', - children: [ - { - id: [OperationModel.STATUS_PENDING], - name: t('等待执行'), - - }, - { - id: [OperationModel.STATUS_RUNNING], - name: t('执行中'), - - }, - { - id: [OperationModel.STATUS_SUCCEEDED], - name: t('执行成功'), - - }, - { - id: [OperationModel.STATUS_FAILED], - name: t('执行失败'), - - }, - { - id: [OperationModel.STATUS_REVOKED], - name: t('执行失败'), - }, - ], - }, - { - name: t('操作人'), - id: 'operator', + name: t('集群'), + multiple: true, + id: 'domain', }, + // { + // name: t('单据类型'), + // id: 'ticket_types', + // multiple: true, + // children: ticketTypes.value, + // }, + // { + // name: t('关联单据'), + // id: 'ticket', + // }, + ] as ISearchItem[]); const tableColumn = computed(() => [ { - label: t('操作时间'), - field: 'update_time', + label: 'IP', + field: 'ip', fixed: 'left', width: 200, - sort: true, - render: ({ data }: {data: OperationModel}) => data.updateTimeDisplay, - }, - { - label: t('操作主机明细(台)'), - field: 'total_count', - sort: true, - render: ({ data }: {data: OperationModel}) => ( - - ), + render: ({ data }: {data: MachineEvent}) => data.ip, }, { label: t('操作类型'), - field: 'operation_type', + field: 'event', filter: { - list: [ - { - value: [OperationModel.OPERATIN_TYPE_IMPORTED], - text: t('导入主机'), - }, - { - value: [OperationModel.OPERATIN_TYPE_CONSUMED], - text: t('消费主机'), - }, - ], - checked: columnCheckedMap.value.operation_type, + list: Object.entries(machineEventsDisplayMap).map(([key, value]) => ({ value: key, text: value })), + // checked: columnCheckedMap.value.operation_type, }, - render: ({ data }: {data: OperationModel}) => data.operationTypeText, + render: ({ data }: {data: MachineEvent}) => data.eventDisplay, }, { - label: t('单据类型'), - field: 'ticket_types', - filter: { - list: ticketTypes.value.map(item => ({ - value: item.id, - text: item.name, - })), - checked: columnCheckedMap.value.ticket_types, - }, - render: ({ data }: {data: OperationModel}) => data.ticket_type_display || '--', + label: t('操作人'), + field: 'updater', + }, + { + label: t('操作时间'), + field: 'update_at', + width: 200, + // sort: true, + render: ({ data }: {data: MachineEvent}) => data.updateAtDisplay, + }, + { + label: t('所属业务'), + field: 'bizDisplay', }, { label: t('关联单据'), - field: 'ticket_id', + field: 'ticket', width: 170, - render: ({ data }: {data: OperationModel}) => (data.ticket_id - ? (data.ticket + ? - {data.ticket_id} - + {data.ticket} + : '--'), }, { - label: t('关联任务'), - field: 'task_id', - render: ({ data }: {data: OperationModel}) => (data.task_id - ? - {data.task_id} - - : '--'), + label: t('单据类型'), + field: 'ticket_type_display', + // filter: { + // list: ticketTypes.value.map(item => ({ + // value: item.id, + // text: item.name, + // })), + // checked: columnCheckedMap.value.ticket_types, + // }, + render: ({ data }: {data: MachineEvent}) => data.ticket_type_display || '--' }, + { - label: t('操作人'), - field: 'operator', + label: t('集群'), + field: 'clusters', + render: ({ data }: {data: MachineEvent}) => data.clusters.length ? data.clusters.join(', ') : '--' }, - { - label: t('操作结果'), - field: 'status', - width: 150, - filter: { - list: [ - { - value: [OperationModel.STATUS_PENDING], - text: t('等待执行'), - }, - { - value: [OperationModel.STATUS_RUNNING], - text: t('执行中'), - - }, - { - value: [OperationModel.STATUS_SUCCEEDED], - text: t('执行成功'), - - }, - { - value: [OperationModel.STATUS_FAILED], - text: t('执行失败'), + { + label: t('操作明细'), + field: 'operationDetail', + width: 430, + render: ({ data }: {data: MachineEvent}) => { + if ([MachineEvents.APPLY_RESOURCE, MachineEvents.RETURN_RESOURCE].includes(data.event) || (data.event === MachineEvents.TO_FAULT && data.ticket)) { + return + {data.operationDetail}({t('关联单据')}: + + {data.ticket} + ) + ; + } - }, - { - value: [OperationModel.STATUS_REVOKED], - text: t('执行失败'), - }, - ], - checked: columnCheckedMap.value.status, - }, - render: ({ data }: {data: OperationModel}) => ( -
- - {data.statusText} -
- ), + return {data.operationDetail}; + } }, ]); @@ -326,21 +253,6 @@ return searchSelectData.value.find(set => set.id === item.id)?.children || []; }; - // const serachValidateValues = ( - // payload: Record<'id'|'name', string>, - // values: Array>, - // ) => { - // if (payload.id === 'ticket_ids') { - // const [{ id }] = values; - // return Promise.resolve(_.every(id.split(','), item => /^\d+?/.test(item))); - // } - // if (payload.id === 'ip_list') { - // const [{ id }] = values; - // return Promise.resolve(_.every(id.split(','), item => ipv4.test(item))); - // } - // return Promise.resolve(true); - // }; - // 获取数据 const fetchData = () => { const searchParams = getSearchSelectorParams(searchValue.value); @@ -349,10 +261,11 @@ endTime, ] = operationDateTime.value; tableRef.value.fetchData({ + bk_biz_id: searchParams.bk_biz_id, ...searchParams, ...sortValue, - begin_time: beginTime ? dayjs(beginTime).format('YYYY-MM-DD HH:mm:ss') : '', - end_time: endTime ? dayjs(endTime).format('YYYY-MM-DD HH:mm:ss') : '', + create_at__gte: beginTime ? dayjs(beginTime).format('YYYY-MM-DD HH:mm:ss') : '', + create_at__lte: endTime ? dayjs(endTime).format('YYYY-MM-DD HH:mm:ss') : '', }); }; @@ -366,16 +279,6 @@ operationDateTime.value = ['', '']; clearSearchValue(); }; - - // const handleGoTicketDetail = (data: OperationModel) => { - // const { href } = router.resolve({ - // name: 'bizTicketManage', - // query: { - // id: data.ticket_id, - // }, - // }); - // window.open(href.replace(/(\d)+/, `${data.bk_biz_id}`)); - // };