diff --git a/0001-Modify-host-group-input-parameter-verification.patch b/0001-Modify-host-group-input-parameter-verification.patch new file mode 100644 index 0000000000000000000000000000000000000000..8402b94448f3f0a81e0281b936de19921a537c19 --- /dev/null +++ b/0001-Modify-host-group-input-parameter-verification.patch @@ -0,0 +1,193 @@ +From 1e59894bd65c00ecc8d7b546b034df40c79c6494 Mon Sep 17 00:00:00 2001 +From: Hu Gang <18768366022@163.com> +Date: Wed, 27 Nov 2024 11:25:40 +0800 +Subject: [PATCH] Modify host group input parameter verification + +--- + .eslintignore | 1 + + .eslintrc.js | 3 ++ + src/locales/lang/en.json | 4 +- + src/locales/lang/zh-cn.json | 4 +- + .../assests/components/AddHostGroupModal.vue | 41 ++++++++----------- + src/views/execution/Scripts.vue | 8 +++- + 6 files changed, 30 insertions(+), 31 deletions(-) + +diff --git a/.eslintignore b/.eslintignore +index 2b26093..b33de94 100644 +--- a/.eslintignore ++++ b/.eslintignore +@@ -4,3 +4,4 @@ package.json + + .vscode + .idea ++.eslintrc.js +diff --git a/.eslintrc.js b/.eslintrc.js +index c83a20c..5942158 100644 +--- a/.eslintrc.js ++++ b/.eslintrc.js +@@ -32,5 +32,8 @@ module.exports = { + indent: ["error", 2], + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-unused-expressions": 'off', ++ "vue/valid-define-props": "off", ++ "vue/valid-define-emits": "off", ++ "vue/multi-word-component-names": "off" + }, + } +diff --git a/src/locales/lang/en.json b/src/locales/lang/en.json +index 4440bbe..a9f9f06 100644 +--- a/src/locales/lang/en.json ++++ b/src/locales/lang/en.json +@@ -138,9 +138,9 @@ + "descriptionTwo": "There cannot be a >< symbol", + "hostGroup": "Please select the host group", + "hostGroup_input": "Please enter a host group name", +- "hostGroup_one": "It must start with a lowercase letter and cannot end with an underscore.", ++ "hostGroup_one": "The host group name must start with a lowercase letter and not end with an underscore.", + "hostGroup_three": "The name should consist of numbers, lowercase letters, and underscores.", +- "hostGroup_two": "It must start with a lowercase letter and cannot end with an underscore.", ++ "hostGroup_two": "The host group name should be less than 20 characters long.", + "hostName": "The host name length should be less than 50", + "hostName_one": "No leading or trailing spaces are allowed", + "hostName_two": "No full spaces allowed", +diff --git a/src/locales/lang/zh-cn.json b/src/locales/lang/zh-cn.json +index e8d58d5..207110f 100644 +--- a/src/locales/lang/zh-cn.json ++++ b/src/locales/lang/zh-cn.json +@@ -138,9 +138,9 @@ + "descriptionTwo": "不能有><符号", + "hostGroup": "请选择所属主机组", + "hostGroup_input": "请输入主机组名称", +- "hostGroup_one": "以小写字母开头,且结尾不能是英文下划线", ++ "hostGroup_one": "主机组名称以小写字母开头,且不以英文下划线结尾", + "hostGroup_three": "名称应由数字、小写字母、英文下划线组成", +- "hostGroup_two": "以小写字母开头,且结尾不能是英文下划线", ++ "hostGroup_two": "主机组名称长度应小于20", + "hostName": "主机名长度应小于50", + "hostName_one": "首尾不允许空格", + "hostName_two": "不允许全空格", +diff --git a/src/views/assests/components/AddHostGroupModal.vue b/src/views/assests/components/AddHostGroupModal.vue +index 205e904..ecac117 100644 +--- a/src/views/assests/components/AddHostGroupModal.vue ++++ b/src/views/assests/components/AddHostGroupModal.vue +@@ -44,12 +44,15 @@ const form = reactive
({ + * @param value + */ + function validateGroupName(_rule: Rule, value: string) { +- if (/[^0-9a-z_]/.test(value)) +- return Promise.reject(new Error(t('assests.validateMsg.hostGroup_one'))) +- if (/^[^a-z]/.test(value)) ++ if (!value) { ++ return Promise.resolve() ++ } ++ if (value.length > 20) { + return Promise.reject(new Error(t('assests.validateMsg.hostGroup_two'))) +- if (value.endsWith('_')) +- return Promise.reject(new Error(t('assests.validateMsg.hostGroup_three'))) ++ } ++ if (!/^[a-z](?:[^\n]{0,18})(? 60) +- return Promise.reject(new Error(t('assests.validateMsg.descriptionOne'))) +- if (/[<>]/.test(value)) +- return Promise.reject(new Error(t('assests.validateMsg.descriptionTwo'))) ++ if (value.length > 60) return Promise.reject(new Error(t('assests.validateMsg.descriptionOne'))) ++ if (/[<>]/.test(value)) return Promise.reject(new Error(t('assests.validateMsg.descriptionTwo'))) + return Promise.resolve() + } + +@@ -74,10 +75,7 @@ async function addNewHostGroup() { + try { + await formRef.value.validate() + +- const params: Record< +- string, +- { host_group_name: string, description: string, cluster_id: string } +- > = {} ++ const params: Record = {} + params[form.cluster_id!] = { + description: form.desc, + host_group_name: form.hostName, +@@ -91,19 +89,16 @@ async function addNewHostGroup() { + message: t('common.fail'), + description: Object.values(res)[0].label, + }) +- } +- else { ++ } else { + message.success(t('common.succeed')) + } + visible.value = false + emits('success') + formRef.value.resetFields() + } +- } +- catch { ++ } catch { + isLoading.value = false +- } +- finally { ++ } finally { + isLoading.value = false + } + } +@@ -139,9 +134,7 @@ function handleClose() { + + + +@@ -164,9 +157,7 @@ function handleClose() { + :placeholder="t('assests.placeHolder.hostGroupInput')" + > + +diff --git a/src/views/execution/Scripts.vue b/src/views/execution/Scripts.vue +index ae98301..00959f7 100644 +--- a/src/views/execution/Scripts.vue ++++ b/src/views/execution/Scripts.vue +@@ -108,6 +108,11 @@ function handleRefresh() { + getScripts() + } + ++function handleNewScriptCanceled() { ++ tableState.selectedScriptId = '' ++ isModalVisible.value = false ++} ++ + onMounted(() => { + getScripts() + }) +@@ -168,9 +173,8 @@ onMounted(() => { + :visible="isModalVisible" + :script-id="tableState.selectedScriptId" + @success="handleSuccess" +- @cancel="isModalVisible = false" ++ @cancel="handleNewScriptCanceled" + /> + + + +- +-- +2.33.0 + diff --git a/0002-set-the-default-language-for-requests.patch b/0002-set-the-default-language-for-requests.patch new file mode 100644 index 0000000000000000000000000000000000000000..17d55c15fa08c9ad655e4a47750e58920655449a --- /dev/null +++ b/0002-set-the-default-language-for-requests.patch @@ -0,0 +1,105 @@ +From d18757fd6acf0315052267c8cf60061d9bd0285b Mon Sep 17 00:00:00 2001 +From: Hu Gang <18768366022@163.com> +Date: Mon, 2 Dec 2024 15:43:31 +0800 +Subject: [PATCH] fix: Coset the default language for requests + +--- + .eslintrc.js | 1 - + src/api/request.ts | 34 ++++++++++++++++++++-------------- + src/views/account/Auth.vue | 2 +- + 3 files changed, 21 insertions(+), 16 deletions(-) + +diff --git a/.eslintrc.js b/.eslintrc.js +index 5942158..b4dbe94 100644 +--- a/.eslintrc.js ++++ b/.eslintrc.js +@@ -29,7 +29,6 @@ module.exports = { + }, + plugins: ["@typescript-eslint", "vue"], + rules: { +- indent: ["error", 2], + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-unused-expressions": 'off', + "vue/valid-define-props": "off", +diff --git a/src/api/request.ts b/src/api/request.ts +index 9644c2f..d7f93db 100644 +--- a/src/api/request.ts ++++ b/src/api/request.ts +@@ -56,7 +56,7 @@ request.interceptors.request.use( + } + + const { lang } = useLangStore() +- config.headers['Accept-Language'] = lang === 'zh_cn' ? 'zh' : 'en' ++ config.headers['Accept-Language'] = lang === 'en' ? 'en' : 'zh' + + const aopsInfo = localStorage.getItem('aops') + if (aopsInfo) { +@@ -96,6 +96,7 @@ function dealBlobResponse(resp: AxiosResponse) { + } + downloadBlobFile(resp.data, filename) + } ++let isAuthing = false + + request.interceptors.response.use( + async (response: AxiosResponse): Promise => { +@@ -125,19 +126,23 @@ request.interceptors.response.use( + if (!code.toString().match(/^2\d{2}$/)) { + switch (Number(code)) { + case 1201: +- notification.error({ +- message: `${t('account.sentence.validationFailed')}`, +- description: response.data.message, +- }) +- setTimeout(async () => { +- const { clearInfo } = useAccountStore() +- const { getAuthRedirectUrl } = useAccountStore() +- const url = await getAuthRedirectUrl() +- if (url) { +- clearInfo() +- window.location.href = url +- } +- }, 1000) ++ if (!isAuthing) { ++ notification.error({ ++ message: `${t('account.sentence.validationFailed')}`, ++ description: response.data.message, ++ }) ++ isAuthing = true ++ setTimeout(async () => { ++ const { clearInfo } = useAccountStore() ++ const { getAuthRedirectUrl } = useAccountStore() ++ const url = await getAuthRedirectUrl() ++ if (url) { ++ clearInfo() ++ window.location.href = url ++ } ++ }, 1000) ++ } ++ + break + case 1207: + if (response.config.url !== `/accounts/refreshtoken`) { +@@ -189,6 +194,7 @@ request.interceptors.response.use( + } + return Promise.reject(result) + } ++ isAuthing = false + return data + }, + (error: AxiosError) => { +diff --git a/src/views/account/Auth.vue b/src/views/account/Auth.vue +index 55f81cc..4b8a33b 100644 +--- a/src/views/account/Auth.vue ++++ b/src/views/account/Auth.vue +@@ -21,7 +21,7 @@ async function auth(code: string) { + type: res.type || '', + }) + setTimeout(() => { +- router.push('/dashboard') ++ router.replace('/') + isAuthing.value = false + }, 1000) + } else { +-- +2.33.0 + diff --git a/001-bugfix-and-adapt-rollback-tasks.patch b/001-bugfix-and-adapt-rollback-tasks.patch deleted file mode 100644 index a389f0bc536f957bdf405affd9a8d081a6c4a066..0000000000000000000000000000000000000000 --- a/001-bugfix-and-adapt-rollback-tasks.patch +++ /dev/null @@ -1,1025 +0,0 @@ -From bba113a5899bb0b17916b2179e1f5594756dc58e Mon Sep 17 00:00:00 2001 -From: Hu gang <18768366022@163.com> -Date: Wed, 13 Dec 2023 15:15:59 +0800 -Subject: [PATCH] feat: add host management status, adaptation rollback tsak - ---- - src/api/assest.js | 1 + - src/api/leaks.js | 24 +-- - src/config/router.config.js | 4 + - src/vendor/ant-design-pro/utils/request.js | 14 +- - src/views/assests/HostDetail.vue | 39 ++-- - src/views/assests/HostManagement.vue | 82 ++++--- - src/views/leaks/LeakTaskDetail.vue | 203 ++++++++++-------- - src/views/leaks/LeakTaskList.vue | 4 + - src/views/leaks/TaskResultReport.vue | 76 +++++-- - .../components/CreateRepairTaskDrawer.vue | 36 ++-- - 10 files changed, 277 insertions(+), 206 deletions(-) - -diff --git a/src/api/assest.js b/src/api/assest.js -index a0f70ec..94015d3 100644 ---- a/src/api/assest.js -+++ b/src/api/assest.js -@@ -55,6 +55,7 @@ export function hostList({tableInfo, ...parameter}) { - ...parameter, - host_group_list: tableInfo.filters.host_group_name || [], - management, -+ search_key: tableInfo.filters.searchKey, - sort: tableInfo.sorter.field, - direction: directionMap[tableInfo.sorter.order], - page: tableInfo.pagination.current, -diff --git a/src/api/leaks.js b/src/api/leaks.js -index 8daf70d..c6f704b 100644 ---- a/src/api/leaks.js -+++ b/src/api/leaks.js -@@ -44,15 +44,15 @@ const api = { - getRpmUnderCve: '/vulnerability/cve/packages/host/get', // 查询cve影响的rpm包的主机列表 - getCvefixLeakRpm: '/vulnerability/task/cve/rpm/get', // 修复任务详情中cve列表的二级package - getCveRpmHostUnderLeak: '/vulnerability/task/cve/rpm/host/get', // 查询修复任务下的cve影响的rpm包的主机列表 -- getCveListInFixDetail: '/vulnerability/task/cve-fix/info/get', // 新接口取代api.getCveUnderCveTask 获取修复任务详情下的cve列表 - getRpmListInFixDetail: '/vulnerability/task/cve-fix/rpm/get', // 新接口取代api.getCvefixLeakRpm,获取修复任务详情下指定主机和任务下的rpm列表 - getCveFixReport: '/vulnerability/task/cve-fix/result/get', // 新接口取代api.getCveTaskResult ,获取修复任务的报告 -- getCveRollvackReport: ' /vulnerability/task/rollback/result/get', // 获取回滚任务报告 -+ getCveRollvackReport: '/vulnerability/task/cve-rollback/result/get', // 获取回滚任务报告 - generateHotPathRemoveTask: '/vulnerability/task/hotpatch-remove/generate', // 新接口取代api.generateRollbackTask ,生成热补丁移除任务 -- getRpmListInRollbackDetail: '/vulnerability/task/rollback/rpm/get', // 获取回滚任务详情列表下的rpm信息 -- getCveListInRollbackDetail: '/vulnerability/task/rollback/cve-info/get', // 获取回滚任务详情下的列表信息 -+ getRpmListInRollbackDetail: '/vulnerability/task/cve-rollback/rpm/get', // 获取回滚任务详情列表下的rpm信息 - generateRollbackTask: '/vulnerability/task/cve-rollback/generate', // 生成回滚任务 -+ getCveListInRollbackDetail: '/vulnerability/task/cve-rollback/info/get', // 获取回滚任务详情下的列表信息 - getCveHotpatchRemoveDetail: '/vulnerability/task/hotpatch-remove/info/get', // 获取热补丁移除任务详情 -+ getCveListInFixDetail: '/vulnerability/task/cve-fix/info/get', // 新接口取代api.getCveUnderCveTask 获取修复任务详情下的cve列表 - getHotpatchRemoveTaskReport: '/vulnerability/task/hotpatch-remove/result/get', // 获取热补丁移除任务报告 - getAllHostInDetail: '/vulnerability/task/host/get' // 获取详情页面下所有的hostid - }; -@@ -132,6 +132,7 @@ export function getCveListInRollbackDetail({tableInfo, ...params}) { - task_id: params.taskId, - direction: sorterMap[tableInfo.sorter.order], - filter: { -+ search_key: tableInfo.filters.searchKey, - status: tableInfo.filters.status - }, - page: tableInfo.pagination.current, -@@ -140,7 +141,7 @@ export function getCveListInRollbackDetail({tableInfo, ...params}) { - }); - } - --// 创建热补丁回退任务 -+// 创建热补丁移除任务 - export function generateHotPatchRemoveTask(params) { - return request({ - url: api.generateHotPathRemoveTask, -@@ -196,6 +197,7 @@ export function getCveListInFixDetail({tableInfo, ...params}) { - task_id: params.taskId, - direction: sorterMap[tableInfo.sorter.order], - filter: { -+ search_key: tableInfo.filters.searchKey, - status: tableInfo.filters.status - }, - page: tableInfo.pagination.current, -@@ -267,18 +269,6 @@ export function getCveFixRpm(parameters) { - }); - } - --// export function generateRollbackTask(parameters) { --// return request({ --// url: api.generateRollbackTask, --// method: 'post', --// data: { --// task_name: parameters.task_name, --// description: parameters.description, --// info: parameters.info || [] --// } --// }); --// } -- - export function getCveExport(parameter) { - return request({ - url: api.getCveExport, -diff --git a/src/config/router.config.js b/src/config/router.config.js -index b92011f..5f1d4df 100644 ---- a/src/config/router.config.js -+++ b/src/config/router.config.js -@@ -575,6 +575,10 @@ export const asyncRouterMap = [ - breadcrumbName: routeMap.leaks.children.leakTaskView.children.leakTaskList.title, - path: routeMap.leaks.children.leakTaskView.children.leakTaskList.path - }, -+ { -+ breadcrumbName: routeMap.leaks.children.leakTaskView.children.leakTaskDetail.title, -+ path: routeMap.leaks.children.leakTaskView.children.leakTaskDetail.path -+ }, - { - breadcrumbName: routeMap.leaks.children.leakTaskView.children.taskResultReport.title, - path: routeMap.leaks.children.leakTaskView.children.taskResultReport.path -diff --git a/src/vendor/ant-design-pro/utils/request.js b/src/vendor/ant-design-pro/utils/request.js -index d9320d8..661bfd0 100644 ---- a/src/vendor/ant-design-pro/utils/request.js -+++ b/src/vendor/ant-design-pro/utils/request.js -@@ -101,7 +101,7 @@ request.interceptors.response.use((response) => { - const code = response.data.code || response.status; - // 不处理所有2xx的状态码 - if (!code.toString().match(/^2[0-9]{2,2}$/)) { -- let err = null; -+ // let err = null; - switch (code) { - case '1201': - if (!timestamp1 || timestamp1 + 1632252465 < new Date().getTime()) { -@@ -166,10 +166,14 @@ request.interceptors.response.use((response) => { - }); - return retryRequest; - default: -- err = new Error(response.data.message); -- err.data = response.data.data; -- err.response = response.data; -- throw err; -+ notification.error({ -+ message: response.data.label, -+ description: response.data.message -+ }); -+ // err = new Error(response.data.message); -+ // err.data = response.data.data; -+ // err.response = response.data; -+ // throw err; - } - } - if (response.headers['content-type'] === 'application/octet-stream') { -diff --git a/src/views/assests/HostDetail.vue b/src/views/assests/HostDetail.vue -index 8286caf..6eadb05 100644 ---- a/src/views/assests/HostDetail.vue -+++ b/src/views/assests/HostDetail.vue -@@ -49,38 +49,37 @@ export default { - }; - }, - methods: { -- fetchHostInfo(This) { -- const _this = This; -- This.basicHostInfoIsLoading = true; -- getHostDetail(This.hostId, true) -- .then(function (res) { -- _this.basicHostInfo = res.data.host_infos[0]; -- _this.scene = This.basicHostInfo.scene; -+ fetchHostInfo() { -+ this.basicHostInfoIsLoading = true; -+ getHostDetail(Number(this.hostId), true) -+ .then((res) => { -+ this.basicHostInfo = res.data.host_infos[0]; -+ this.scene = this.basicHostInfo.scene; - }) -- .catch(function (err) { -- _this.$message.error(err.response.message); -+ .catch((err) => { -+ this.$message.error(err.response.message); - }) - .finally(() => { -- _this.basicHostInfoIsLoading = false; -+ this.basicHostInfoIsLoading = false; - }); -- This.basicInfoIsLoading = true; -- getHostDetail(This.hostId, false) -- .then(function (res) { -- _this.basicInfo = res.data.host_infos[0]; -+ this.basicInfoIsLoading = true; -+ getHostDetail(Number(this.hostId), false) -+ .then((res) => { -+ this.basicInfo = res.data.host_infos[0]; - }) -- .catch(function (err) { -- _this.$message.error(err.response.message); -+ .catch((err) => { -+ this.$message.error(err.response.message); - }) - .finally(() => { -- _this.basicInfoIsLoading = false; -+ this.basicInfoIsLoading = false; - }); - }, - reFetchHostInfo() { -- this.$options.methods.fetchHostInfo(this); -+ this.fetchHostInfo(); - } - }, -- mounted: function () { -- this.$options.methods.fetchHostInfo(this); -+ mounted() { -+ this.fetchHostInfo(); - } - }; - -diff --git a/src/views/assests/HostManagement.vue b/src/views/assests/HostManagement.vue -index aaa86a8..77e0ed8 100644 ---- a/src/views/assests/HostManagement.vue -+++ b/src/views/assests/HostManagement.vue -@@ -17,7 +17,8 @@ - - - -- 重置条件 -+ -+ - - - -@@ -59,26 +60,19 @@ - >{{ hostName }} - {{ isMana ? '是' : '否' }} -- {{ hostStatusMap[status] }} -+ -+ -+ {{ hostStatusMap[status] }} -+ - {{ scene ? (scene === 'normal' ? '通用' : scene) : '暂无' }} - -- - 编辑 -- | -- 删除 -+ >编辑 -+ -+ 删除 - -- - - - -@@ -94,7 +88,7 @@ import MyPageHeaderWrapper from '@/views/utils/MyPageHeaderWrapper'; - import {getSelectedRow} from '@/views/utils/getSelectedRow'; - import HostDetailDrawer from './components/HostDetailDrawer'; - // import HostTerminal from '@/views/assests/components/HostTerminal'; --import {hostList, deleteHost, hostGroupList} from '@/api/assest'; -+import {hostList, deleteHost, hostGroupList, getHostListWithStatus} from '@/api/assest'; - - const hostStatusMap = { - 0: '在线', -@@ -214,6 +208,9 @@ export default { - } - }, - methods: { -+ async getAllHostStatus() { -+ const res = await getHostListWithStatus(); -+ }, - handleTableChange(pagination, filters, sorter) { - // 存储翻页状态 - this.pagination = pagination; -@@ -230,14 +227,13 @@ export default { - this.selectedRowsAll = getSelectedRow(selectedRowKeys, this.selectedRowsAll, this.tableData, 'host_id'); - }, - // 获取列表数据 -- getHostList() { -- const _this = this; -+ async getHostList() { - this.tableIsLoading = true; - const pagination = this.pagination || {}; - const filters = this.filters || {}; - const sorter = this.sorter || {}; - -- hostList({ -+ const hostListRes = await hostList({ - tableInfo: { - pagination: { - current: pagination.current, -@@ -249,22 +245,28 @@ export default { - order: sorter.order - } - } -- }) -- .then(function (res) { -- _this.tableData = res.data.host_infos || []; -- _this.pagination = { -- ..._this.pagination, -- current: pagination.current, -- pageSize: pagination.pageSize, -- total: res.data.total_count || (res.data.total_count === 0 ? 0 : pagination.total) -- }; -- }) -- .catch(function (err) { -- _this.$message.error(err.response.message); -- }) -- .finally(function () { -- _this.tableIsLoading = false; -- }); -+ }); -+ if (hostListRes) { -+ this.tableData = hostListRes.data.host_infos || []; -+ this.pagination = { -+ ...this.pagination, -+ current: pagination.current, -+ pageSize: pagination.pageSize, -+ total: hostListRes.data.total_count || (hostListRes.data.total_count === 0 ? 0 : pagination.total) -+ }; -+ const hostIdList = this.tableData.map((item) => item.host_id); -+ this.tableIsLoading = false; -+ const res = await getHostListWithStatus(hostIdList); -+ if (res) { -+ this.tableData.forEach((item) => { -+ const s = res.data.find((s) => item.host_id === s.host_id); -+ if (s) { -+ item.status = s.status; -+ } -+ }); -+ this.tableData = JSON.parse(JSON.stringify(this.tableData)); -+ } -+ } - }, - editHost(record) { - this.$message.success('连接到主机' + record.host_ip); -@@ -384,6 +386,16 @@ export default { - duration: 5 - }); - }, -+ handleSearch(text = '') { -+ this.pagination = defaultPagination; -+ this.sorter = null; -+ if (!this.filters) { -+ this.filters = {}; -+ } -+ this.selectedRowKeys = []; -+ this.filters.searchKey = text !== '' ? text : undefined; -+ this.getHostList(); -+ }, - handleReset() { - this.pagination = defaultPagination; - this.sorter = null; -diff --git a/src/views/leaks/LeakTaskDetail.vue b/src/views/leaks/LeakTaskDetail.vue -index 27e919e..f7f7438 100644 ---- a/src/views/leaks/LeakTaskDetail.vue -+++ b/src/views/leaks/LeakTaskDetail.vue -@@ -111,7 +111,9 @@ - - - -- 生成回滚任务 -+ 生成回滚任务 - - - -@@ -236,12 +238,13 @@ import { - getTaskProgress, - generateRollbackTask, - getCveProgressUnderCveTask, -- getAllHostInDetail -+ getAllHostInDetail, -+ getHostScanStatus - } from '@/api/leaks'; - import configs from '@/config/defaultSettings'; - - const taskTypeMap = { -- 'cve fix': '漏洞修复', -+ 'cve fix': 'cve修复', - 'repo set': 'REPO设置', - 'cve rollback': 'cve回滚', - 'hotpatch remove': '热补丁移除' -@@ -307,6 +310,8 @@ export default { - }, - data() { - return { -+ // 生成回滚任务按钮是否loading -+ isRollBackButtonLoading: false, - expandedRowKeys: [], - rpmrecord: {}, - propType: '', -@@ -379,7 +384,7 @@ export default { - { - dataIndex: 'host_name', - key: 'host_name', -- title: '主机', -+ title: '主机名', - scopedSlots: {customRender: 'hostName'} - }, - { -@@ -391,7 +396,7 @@ export default { - { - dataIndex: 'cve_num', - key: 'cve_num', -- title: '修复的CVE', -+ title: 'CVE数量', - scopedSlots: {customRender: 'cveNum'} - }, - { -@@ -405,26 +410,27 @@ export default { - {text: '修复成功', value: 'succeed'}, - {text: '待修复', value: 'fail'}, - {text: '运行中', value: 'running'}, -- {text: '未知', value: 'None'} -+ {text: '未知', value: 'unknown'} - ] - : [ - {text: '回滚成功', value: 'succeed'}, - {text: '待回滚', value: 'fail'}, - {text: '运行中', value: 'running'}, -- {text: '未知', value: 'None'} -+ {text: '未知', value: 'unknown'} - ], - filteredValue: filters.status || null, - onFilter: (value, record) => record.status.includes(value) - } - ]; - }, -+ - repoColumns() { - let {filters} = this; - filters = filters || {}; - return [ - { - dataIndex: 'host_name', -- title: '主机名称', -+ title: '主机名', - scopedSlots: {customRender: 'host_name'} - }, - { -@@ -452,27 +458,28 @@ export default { - }, - // 展开后的列表列号 - innerColumns() { -+ const {taskType} = this; - return [ - { - dataIndex: 'installed_rpm', - key: 'installed_rpm', -- title: '受影响rpm' -+ title: taskType === 'cve fix' ? '受影响rpm' : '已安装rpm' - }, - { -- dataIndex: 'available_rpm', -- key: 'available_rpm', -- title: '待安装rpm', -- scopedSlots: {customRender: 'available_rpm'} -+ dataIndex: taskType === 'cve fix' ? 'available_rpm' : 'target_rpm', -+ key: taskType === 'cve fix' ? 'available_rpm' : 'target_rpm', -+ title: taskType === 'cve fix' ? '待安装rpm' : '目标rpm', -+ scopedSlots: {customRender: 'rpm'} - }, - { - dataIndex: 'cves', - key: 'cves', -- title: '修复cve' -+ title: 'CVE' - }, - { - dataIndex: 'status', - key: 'rpm_status', -- title: '状态', -+ title: this.taskType === 'cve fix' ? '修复状态' : '回滚状态', - scopedSlots: {customRender: 'status'}, - filter: - this.taskType === 'cve fix' -@@ -480,13 +487,13 @@ export default { - {text: '修复成功', value: 'succeed'}, - {text: '待修复', value: 'fail'}, - {text: '运行中', value: 'running'}, -- {text: '未知', value: 'None'} -+ {text: '未知', value: 'unknown'} - ] - : [ - {text: '回滚成功', value: 'succeed'}, - {text: '待回滚', value: 'fail'}, - {text: '运行中', value: 'running'}, -- {text: '未知', value: 'None'} -+ {text: '未知', value: 'unknown'} - ] - } - ]; -@@ -563,50 +570,43 @@ export default { - clearInterval(this.jumpModalInterval); - this.isRollbackModelvisible = false; - this.$router.push({ -- path: `/leaks/task/${this.taskType}/${this.rollbackTaskId}`, -+ path: `/leaks/task/cve rollback/${this.rollbackTaskId}`, - query: { - task_id: this.rollbackTaskId - } - }); -+ this.expandedRowKeys = []; -+ this.taskType = 'cve rollback'; - this.taskId = this.rollbackTaskId; - localStorage.setItem('taskId', this.taskId); - this.getInitalData(); - }, - async generateRollbackTask() { -+ this.isRollBackButtonLoading = true; - if (this.detail.statuses['running'] > 0) { - this.$warning({ - title: '有任务正在运行,不能回滚。' - }); -+ this.isRollBackButtonLoading = false; - return; - } -- this.$confirm({ -- title: ( --

-- 回滚后无法恢复 --
-- 请确认回滚CVE修复任务: --

-- ), -- icon: () => , -- onOk: async () => { -- const res = await generateRollbackTask(this.taskId); -- if (res) { -- this.rollbackTaskId = res.data.task_id; -- this.countDown = 5; -- this.isRollbackModelvisible = true; -- this.jumpModalInterval = setInterval(() => { -- this.countDown = this.countDown - 1; -- if (this.countDown === 0) { -- clearInterval(this.jumpModalInterval); -- this.isRollbackModelvisible = false; -- } -- }, 1000); -+ const res = await generateRollbackTask(this.taskId); -+ if (res) { -+ this.rollbackTaskId = res.data.task_id; -+ this.countDown = 5; -+ this.isRollbackModelvisible = true; -+ this.jumpModalInterval = setInterval(() => { -+ this.countDown = this.countDown - 1; -+ if (this.countDown === 0) { -+ clearInterval(this.jumpModalInterval); -+ this.isRollbackModelvisible = false; - } -- } -- }); -+ }, 1000); -+ this.isRollBackButtonLoading = false; -+ } else { -+ } - }, - dateFormat, -- - jumptoResult(value) { - this.$router.push({ - path: `/leaks/task-report/${this.taskType}/${this.taskId}`, -@@ -633,7 +633,6 @@ export default { - }); - return res || null; - }, -- - // 展开详情列表 - async expand(expanded, record) { - if (!expanded) return; -@@ -739,7 +738,7 @@ export default { - current: pagination.current, - pageSize: pagination.pageSize - }, -- filters: filters, -+ filters, - sorter: { - field: sorter.field, - order: sorter.order -@@ -770,7 +769,7 @@ export default { - return res || null; - }, - // 获取热补丁回退列表 -- async getCveListWithHotpathRemove() { -+ async getCveListWithHotpathRemove(needScan = false) { - this.tableIsLoading = true; - const pagination = this.pagination || {}; - const filters = this.filters || {}; -@@ -800,12 +799,13 @@ export default { - this.tableIsLoading = false; - await this.updateCveProgress( - this.taskId, -- res.data.result.map((cve) => cve.cve_id) -+ res.data.result.map((cve) => cve.cve_id), -+ needScan - ); - } - }, -- // for cve task -- async getCveList() { -+ // 获取cve列表(修复,回滚) -+ async getCveList(needScan = false) { - this.tableIsLoading = true; - const res = this.taskType === 'cve fix' ? await this.getCveListWithFix() : await this.getCveListWithRollback(); - if (res) { -@@ -814,34 +814,67 @@ export default { - rpms: [] - })); - this.reportvisible = this.getReportVisible(res.data.result); -- this.expandedRowKeys = []; -+ // this.expandedRowKeys = []; - this.pagination = { - ...this.pagination, - total: res.data.total_count || (res.data.total_count === 0 ? 0 : this.pagination.total) - }; -- await this.updateHostProgress(); -+ !this.reportvisible && (await this.updateHostProgress(needScan)); - this.tableIsLoading = false; - } - }, - // 修复,回滚任务running时刷新列表状态 -- async updateHostProgress() { -+ async updateHostProgress(needScan = false) { - clearTimeout(this.CveScanStatueTimeout); - const res = this.taskType === 'cve fix' ? await this.getCveListWithFix() : await this.getCveListWithRollback(); - const progressRes = res.data.result; -- this.tableData = progressRes.map((item) => ({ -- ...item, -- rpms: [] -- })); -+ progressRes.forEach((item) => { -+ const i = this.tableData.findIndex((t) => t.host_id === item.host_id); -+ if (i > -1 && this.tableData[i].status !== item.status) { -+ this.tableData[i].status = item.status; -+ if (this.expandedRowKeys.includes(this.tableData[i].host_id)) this.expand(true, this.tableData[i]); -+ } -+ }); -+ - const list = progressRes.filter((item) => item.status === 'running'); - this.reportvisible = list.length === 0; - if (list.length > 0) { - this.CveScanStatueTimeout = setTimeout(() => { -- this.updateHostProgress(); -+ this.updateHostProgress(needScan); - }, configs.taskProgressUpdateInterval); -+ } else { -+ needScan && (await this.sacnHostAfterExcute()); - } - }, -- // 更新热补丁回退的执行进度 -- async updateCveProgress(taskId, cveList) { -+ -+ // 在任务执行完成之后进行主机扫描 -+ async sacnHostAfterExcute() { -+ const hostList = await this.getAllHostId(); -+ const res = await getHostScanStatus({hostList}); -+ if (!res) return; -+ const hostStatusList = res.data.result; -+ const needScanList = Object.keys(hostStatusList).map((h) => { -+ if (hostStatusList[h] !== 3 && hostList.includes(Number(h))) return Number(h); -+ }); -+ this.scanLeakAfterExecuteTask(needScanList); -+ }, -+ // 返回扫描状态的主机 -+ getScanningHost(scanMap, hostList) { -+ const arr = []; -+ hostList.forEach((host) => { -+ if (scanMap[host.host_id] === 3) { -+ arr.push(host); -+ } -+ }); -+ return arr; -+ }, -+ /** -+ * 更新热补丁回退的执行进度 -+ * @param {*} taskId 任务id -+ * @param {*} cveList cve 列表 -+ * @param {*} needScan 是否需要扫描主机 -+ */ -+ async updateCveProgress(taskId, cveList, needScan = false) { - clearTimeout(this.CveScanStatueTimeout); - const processRes = await getCveProgressUnderCveTask({ - taskId, -@@ -852,8 +885,10 @@ export default { - this.runningCveIds = this.getRunningCve(processRes.data.result); - if (this.runningCveIds.length > 0) { - this.CveScanStatueTimeout = setTimeout(() => { -- this.updateCveProgress(taskId, cveList); -+ this.updateCveProgress(taskId, cveList, needScan); - }, configs.taskProgressUpdateInterval); -+ } else { -+ needScan && (await this.sacnHostAfterExcute()); - } - }, - // 将查询到的cve进度更新到表格数据中,用于数据展示 -@@ -954,26 +989,23 @@ export default { - title: `确定执行任务${this.detail.task_name}?`, - icon: () => , - okText: '执行', -- onOk: () => { -- return executeTask(this.taskId) -- .then((res) => { -- this.$message.success(res.message); -- this.scanLeakAfterExecuteTask(); -- // 执行任务成功后刷新 -- setTimeout(() => { -- this.getInitalData(); -- this.expandedRowKeys = []; -- }, 3000); -- }) -- .catch((err) => { -- this.$message.error(err.response.message); -- }); -+ onOk: async () => { -+ const excuteRes = await executeTask(this.taskId); -+ if (excuteRes) { -+ // 获取详情任务所有处理的hostid列表 -+ this.$message.success(excuteRes.message); -+ // 执行任务成功后刷新 -+ setTimeout(() => { -+ this.getInitalData(true); -+ this.expandedRowKeys = []; -+ }, 3000); -+ } - } - }); - }, -- async scanLeakAfterExecuteTask() { -+ async scanLeakAfterExecuteTask(hostList) { - await scanHost({ -- hostList: this.hostList, -+ hostList, - filter: null - }); - }, -@@ -981,7 +1013,7 @@ export default { - async getAllHostId() { - const res = await getAllHostInDetail(this.taskId); - if (res) { -- this.hostList = res.data; -+ return res.data; - } - }, - showHostListUnderCve(type, record) { -@@ -992,16 +1024,17 @@ export default { - closeHostListUnderCve() { - this.hostListUnderCveVisible = false; - }, -- getInitalData() { -+ /** -+ * isFresh 是第一次初始化还是后续的刷新数据 -+ */ -+ getInitalData(isFresh = false) { - this.getInfo(); -- // 获取详情任务所有处理的hostid列表 -- this.getAllHostId(); - if (this.taskType === 'repo set') { - this.getHostList(); - } else if (this.taskType === 'hotpatch remove') { -- this.getCveListWithHotpathRemove(); -+ this.getCveListWithHotpathRemove(isFresh); - } else { -- this.getCveList(); -+ this.getCveList(isFresh); - } - }, - -@@ -1023,9 +1056,9 @@ export default { - } - if (this.taskType === 'cve fix' || this.taskType === 'cve rollback') { - if (text !== '') { -- this.filters.host_name = text; -+ this.filters.searchKey = text; - } else { -- this.filters.host_name = undefined; -+ this.filters.searchKey = undefined; - } - this.getCveList(); - } else { -@@ -1065,7 +1098,7 @@ export default { - localStorage.setItem('taskId', this.taskId); - }, - mounted() { -- this.getInitalData(); -+ this.getInitalData(false); - }, - beforeDestroy() { - // 离开页面前,若当前存在轮询,清除轮询 -diff --git a/src/views/leaks/LeakTaskList.vue b/src/views/leaks/LeakTaskList.vue -index be0ce82..08cb5e4 100644 ---- a/src/views/leaks/LeakTaskList.vue -+++ b/src/views/leaks/LeakTaskList.vue -@@ -193,6 +193,10 @@ export default { - { - text: 'cve rollback', - value: 'cve rollback' -+ }, -+ { -+ text: 'hotpatch remove', -+ value: 'hotpatch remove' - } - ] - }, -diff --git a/src/views/leaks/TaskResultReport.vue b/src/views/leaks/TaskResultReport.vue -index ca8d031..e702b06 100644 ---- a/src/views/leaks/TaskResultReport.vue -+++ b/src/views/leaks/TaskResultReport.vue -@@ -1,4 +1,3 @@ -- -