diff --git a/frontend/env.d.ts b/frontend/env.d.ts index 37dae94665ee2c966aadd5061ab7767bc2b5f8bc..5b53a15905653c5e56bcf10e9c84ed8bb99c44bf 100644 --- a/frontend/env.d.ts +++ b/frontend/env.d.ts @@ -4,4 +4,5 @@ declare module '*.vue' { import type { DefineComponent } from 'vue' const component: DefineComponent<{}, {}, any> export default component -} \ No newline at end of file +} +declare module 'file-saver'; \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json index 244a871f1557ad665d3701efb3494d5f82ae8392..82e3fc65e253dffa6f9b73fe25243e1e24fc7663 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -15,12 +15,14 @@ "axios": "^1.6.1", "echarts": "^5.4.3", "element-plus": "^2.4.2", + "file-saver": "^2.0.5", "js-cookie": "^3.0.5", "pinia": "^2.1.7", "pinia-plugin-persistedstate": "^3.2.1", "sass": "^1.69.5", "vue": "^3.3.4", - "vue-router": "^4.2.5" + "vue-router": "^4.2.5", + "xlsx": "^0.18.5" }, "devDependencies": { "@tsconfig/node18": "^18.2.2", diff --git a/frontend/src/assets/user.png b/frontend/src/assets/user.png new file mode 100644 index 0000000000000000000000000000000000000000..4f9ab3ce9c0e80149aea750c4578634b2c27aa39 Binary files /dev/null and b/frontend/src/assets/user.png differ diff --git a/frontend/src/components/AuthButton.vue b/frontend/src/components/AuthButton.vue index 5eef014d8eae6cae9a9f0c9d5fe4d3dffe8ac831..ae1263310562763eb8a1636ca92fd5f25aa7ba9e 100644 --- a/frontend/src/components/AuthButton.vue +++ b/frontend/src/components/AuthButton.vue @@ -1,7 +1,7 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/frontend/src/components/PGTable.vue b/frontend/src/components/PGTable.vue index 31dac21bcd25454bfe852c3b72b835562446cc58..e60bb155cd08573defc8a87a6f38b468a6654b52 100644 --- a/frontend/src/components/PGTable.vue +++ b/frontend/src/components/PGTable.vue @@ -1,135 +1,152 @@ \ No newline at end of file diff --git a/frontend/src/components/PGTree.vue b/frontend/src/components/PGTree.vue index b96b16c4ac7e69a34de44fa3aa22872b51f8e208..00d2b1da0baf613b7ea95def0654a2ce32590c48 100644 --- a/frontend/src/components/PGTree.vue +++ b/frontend/src/components/PGTree.vue @@ -1,180 +1,185 @@ \ No newline at end of file diff --git a/frontend/src/main.ts b/frontend/src/main.ts index 7039b10595295bc4f47757b963a1ede7992bf7f2..94e4c30f999d2f0d09d74c7158965cdcf4a45550 100644 --- a/frontend/src/main.ts +++ b/frontend/src/main.ts @@ -1,4 +1,4 @@ -import './styles/main.css' +import './styles/main.scss' import { createApp } from 'vue' import pinia from '@/stores' diff --git a/frontend/src/module/permission.ts b/frontend/src/module/permission.ts index 0c86336f7cfbcab61ed39592ff972f4827249924..8ab4866a6ec08af563366909b7a269237c3c73bb 100644 --- a/frontend/src/module/permission.ts +++ b/frontend/src/module/permission.ts @@ -3,6 +3,7 @@ import { ElMessage } from 'element-plus'; import { getPermission } from "@/request/user"; import { RespCodeOK } from "@/request/request"; +import { updateSidebarItems } from "@/router"; const userPermissions = ref({}) @@ -20,7 +21,8 @@ export function hasPermisson(permission: string): boolean { export function updatePermisson(): void { getPermission().then((resp: any) => { if (resp.code === RespCodeOK) { - userPermissions.value = resp.data + userPermissions.value = resp.data; + updateSidebarItems(); } else { ElMessage.error("failed to get machines overview info: " + resp.msg) } diff --git a/frontend/src/request/audit.ts b/frontend/src/request/audit.ts index b3c4cd9d70f22623ee1bae362b3394a12093fac6..756977d3dc6a52800d80d8455dd1621ce5ccde4f 100644 --- a/frontend/src/request/audit.ts +++ b/frontend/src/request/audit.ts @@ -7,4 +7,14 @@ export function getLogs(data:any) { method: 'get', params: data }) +} + + +// 获取子日志 +export function getLogChildrens(data:{uuid:string}) { + return request({ + url: '/log/log_child', + method: 'get', + params: data + }) } \ No newline at end of file diff --git a/frontend/src/request/batch.ts b/frontend/src/request/batch.ts index e9bd38841ad8ab577d051a7b7bfeaef0bdea242f..f4b28b5b2b4b1a6592b082044a0e54973b0245b9 100644 --- a/frontend/src/request/batch.ts +++ b/frontend/src/request/batch.ts @@ -30,7 +30,7 @@ export function deleteBatch(data: any) { // 创建批次 export function createBatch(data: any) { return request({ - url: 'macList/createbatch', + url: 'batchmanager/createbatch', method: 'post', data }) diff --git a/frontend/src/request/cluster.ts b/frontend/src/request/cluster.ts index ff123127d1c095aded6650337deb9fdd53bcd92d..0b44718311ae8f8fcedc731c310fa17d97d4c500 100644 --- a/frontend/src/request/cluster.ts +++ b/frontend/src/request/cluster.ts @@ -18,6 +18,15 @@ export function getDepartMachines(data: any) { }) } +// 删除机器接口 +export function deleteMachine(data:any) { + return request({ + url: 'macList/deletemachine', + method: 'post', + data + }) +} + // 获取指定部门下的子部门 export function getSubDepartment(data: any) { return request({ @@ -189,6 +198,15 @@ export function installPackage(data: any) { }) } +// 卸载软件包 +export function removePackage(data:any) { + return request({ + url: 'agent/rpm_remove', + method: 'post', + data + }) +} + // 获取给定主机列表的tag标签 export function getMachineTags(data: any) { return request({ diff --git a/frontend/src/request/request.ts b/frontend/src/request/request.ts index 35d411a4762ef89805cc070edef8d20c3df3a96a..68f8ad89dfe46e3f386753b2214b470fd8f725be 100644 --- a/frontend/src/request/request.ts +++ b/frontend/src/request/request.ts @@ -3,6 +3,16 @@ import { directTo } from "@/router/index" // 公共定义 export const RespCodeOK = 200 +export interface RespInterface { + code?: number; + data?: any[]; + msg?: string; + ok?:boolean; + page?:number; + size?: number; + total?: number; +} + // 创建一个axios实例 const instance = axios.create({ diff --git a/frontend/src/request/user.ts b/frontend/src/request/user.ts index 09f65105e9049115d1695b2ebd3b516b53825e97..912ba13d55facf21309a04e81779d4f3f51f7a4a 100644 --- a/frontend/src/request/user.ts +++ b/frontend/src/request/user.ts @@ -17,6 +17,15 @@ export function logout() { }) } +// 用户修改密码 +export function changeUserPwd(data: {email:string,password:string}) { + return request({ + url: '/user/updatepwd', + method: 'post', + data, + }); +} + // 获取全部用户信息 export function getUsers(data: any) { return request({ @@ -86,4 +95,13 @@ export function getPermission() { url: '/user/permission', method: 'post', }) +} + +// 批量导入用户 +export function importUser(data:any) { + return request({ + url: '/user/import', + method: 'post', + data + }) } \ No newline at end of file diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index 853ee1ca0b29959360746f90bafe96483c86c74f..67ddbeceaa06a4cb9f0e7fa940f9802498844955 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -211,6 +211,7 @@ import PluginFrame from "@/views/Plugin/PluginFrame.vue"; import { app } from "@/main"; import { useRouter } from "vue-router"; +import { hasPermisson } from '@/module/permission'; export function updateSidebarItems() { let menus = generateLocalMenus(); @@ -220,6 +221,7 @@ export function updateSidebarItems() { addPluginRoute(item); // 更新侧边菜单 let obj: Menu = { + type:'plugin', path: item.path, title: item.name, hidden: false, @@ -228,7 +230,7 @@ export function updateSidebarItems() { subMenus: null, } let subMenus = [] as any; - if (item.subMenus.length > 0) { + if (item.subMenus && item.subMenus.length > 0) { item.subMenus.forEach((subItem: any) => { subMenus.push({ hidden: false, @@ -245,6 +247,10 @@ export function updateSidebarItems() { // app.component(item.name, PluginFrame); } + menus.map((menu: any) => { + if (menu.type === 'plugin') return; // 插件权限先不做限制 + menu.hidden = !hasPermisson('menu/' + menu.panel); + }) routerStore().menus = menus; } @@ -346,25 +352,31 @@ router.beforeEach((to, from, next) => { } // 解决在插件页面一刷新页面空白问题 if (to.path.includes('plugin-')) { - let paths = [] as any; + /* let paths = [] as any; router.getRoutes().forEach(routeItem => { paths.push(routeItem.path); }) - if (paths.includes(to.path)) { - next(); - } else { + if (paths.includes(to.path)) { */ + if (!router.hasRoute(to.fullPath)) { + console.log('没有这条路径') new Promise(async (resolve, rejection) => { await routerStore().routers.forEach((route: any) => { addPluginRoute(route); }) resolve('addRoute success'); }).then(res => { + console.log(router.getRoutes()) next({ ...to, replace: true }) + // return to.fullPath + }) + /* routerStore().routers.forEach(async (route: any) => { + await addPluginRoute(route); }) + return to.fullPath */ + } - } else { - next(); } + next() }) export function directTo(to: any) { diff --git a/frontend/src/stores/message.ts b/frontend/src/stores/message.ts deleted file mode 100644 index c8de20c1ef135893cd5e30c745bb3c74b0275614..0000000000000000000000000000000000000000 --- a/frontend/src/stores/message.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ref } from 'vue' -import { defineStore } from 'pinia' - -export interface BatchMidifiedMessage { - modified: boolean -} - -export const BatchMidifiedMessageStore = defineStore('batch_modified_message', () => { - const msg = ref({ modified: false }) - - return { msg } -}) - -export function notify_batch_modified() { - BatchMidifiedMessageStore().msg.modified = !BatchMidifiedMessageStore().msg.modified -} \ No newline at end of file diff --git a/frontend/src/stores/router.ts b/frontend/src/stores/router.ts index ef93900114f00b2a47e6456d0260bbed8c6a2327..b40c6426e2816c164f8cbed2722806ccd37926fd 100644 --- a/frontend/src/stores/router.ts +++ b/frontend/src/stores/router.ts @@ -8,6 +8,7 @@ export interface Menu { panel: string icon: string subMenus: Menu[] | null + type?:string // 标识插件,权限到位后可删除 } // 存储的router信息用于sidebar和router动态生成 @@ -18,6 +19,12 @@ export const routerStore = defineStore('router', { routers: [] as any } }, + actions: { + reset(){ + this.menus = []; + this.routers = []; + } + }, persist: true }) diff --git a/frontend/src/styles/base.css b/frontend/src/styles/base.css index 353001c281dbfc59c146739b13fa9077f5ff27fe..119501046c2c32dd6f96a7f54982931481303418 100644 --- a/frontend/src/styles/base.css +++ b/frontend/src/styles/base.css @@ -1,40 +1,8 @@ -/* color palette from */ +/* color */ :root { - --vt-c-white: #ffffff; - --vt-c-white-soft: #f8f8f8; - --vt-c-white-mute: #f2f2f2; - - --vt-c-black: #181818; - --vt-c-black-soft: #222222; - --vt-c-black-mute: #282828; - - --vt-c-indigo: #2c3e50; - - --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); - --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); - --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); - --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); - - --vt-c-text-light-1: var(--vt-c-indigo); - --vt-c-text-light-2: rgba(60, 60, 60, 0.66); - --vt-c-text-dark-1: var(--vt-c-white); - --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); + /* --el-color-primary:#152d80 !important; */ } -/* semantic color variables for this project */ -:root { - --color-background: var(--vt-c-white); - --color-background-soft: var(--vt-c-white-soft); - --color-background-mute: var(--vt-c-white-mute); - - --color-border: var(--vt-c-divider-light-2); - --color-border-hover: var(--vt-c-divider-light-1); - - --color-heading: var(--vt-c-text-light-1); - --color-text: var(--vt-c-text-light-1); - - --section-gap: 160px; -} @media (prefers-color-scheme: dark) { :root { diff --git a/frontend/src/styles/main.css b/frontend/src/styles/main.scss similarity index 65% rename from frontend/src/styles/main.css rename to frontend/src/styles/main.scss index 246ca2f49012d79cb9e56017a65014411cae7605..bdc067fff84893c073838fef475bc076dd44a7b9 100644 --- a/frontend/src/styles/main.css +++ b/frontend/src/styles/main.scss @@ -26,6 +26,9 @@ body { font-weight: normal; } +#main { + padding: 6px; +} .transition3 { transition: all .3s; } @@ -43,3 +46,16 @@ body { .el-tooltip__trigger:focus-visible { outline: unset; } + +/* el-tree */ +.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content { + color: var(--active-color); +} +/* 隐藏无子设备的展开图表 */ +.el-table .row-expand-cover .cell .el-table__expand-icon { + display: none; +} +/* 权限页面 行颜色修改 */ +.el-table .warning-row { + --el-table-tr-bg-color: var(--el-color-info-light-8); +} \ No newline at end of file diff --git a/frontend/src/types/audit.ts b/frontend/src/types/audit.ts new file mode 100644 index 0000000000000000000000000000000000000000..595eb688a6b56c11ccd230f969c70023c52ec22b --- /dev/null +++ b/frontend/src/types/audit.ts @@ -0,0 +1,20 @@ +export interface AuditItem { + CreatedAt: string; + DeletedAt: string; + ID: number; + /* + * @params Isempty + * 0:has children logs + * 1:no children logs + * */ + Isempty: number; + hasChildren?: boolean; + UpdatedAt: string; + action: string; + log_uuid: string; + message: string; + module: string; + parent_uuid: string; + status: string; + user_id: number; +} \ No newline at end of file diff --git a/frontend/src/types/batch.ts b/frontend/src/types/batch.ts new file mode 100644 index 0000000000000000000000000000000000000000..9be3ec0c04f90f354ed3b269a05a04fab1137be8 --- /dev/null +++ b/frontend/src/types/batch.ts @@ -0,0 +1,24 @@ +// 批次列表 +export interface BatchItem { + CreatedAt:String; + DeletedAt:null; + Depart:String; + DepartName: String; + ID: number; + UpdatedAt: String; + description: String; + manager: String; + name: String; +} + +// 批次详情列表 +export interface BatchMachineInfo { + CPU: String; + departid: number; + id:number; + ip: String; + machineuuid: String; + maintstatus: String; + runstatus: String; + sysinfo: String; +} \ No newline at end of file diff --git a/frontend/src/types/cluster.ts b/frontend/src/types/cluster.ts new file mode 100644 index 0000000000000000000000000000000000000000..a7d8a18d5833e84a4e2c2a319b9c411783ced5af --- /dev/null +++ b/frontend/src/types/cluster.ts @@ -0,0 +1,18 @@ +export interface MachineInfo { + cpu: string; + departid: number; + departname: string; + id: number; + ip: string; + maintstatus: string; + runstatus: string; + systeminfo: string; + uuid: string; +} + +export interface DeptTree { + id: number; + pid: number; + label: string; + children?: DeptTree[] +} \ No newline at end of file diff --git a/frontend/src/views/Audit/Audit.vue b/frontend/src/views/Audit/Audit.vue index db7c19dfbc36e3f16a9082530db67799f0f1249c..2fb3d677e488c9888c2ca32a33fac6dfe3c19b57 100644 --- a/frontend/src/views/Audit/Audit.vue +++ b/frontend/src/views/Audit/Audit.vue @@ -1,86 +1,141 @@ \ No newline at end of file diff --git a/frontend/src/views/Audit/AuditDetail.vue b/frontend/src/views/Audit/AuditDetail.vue new file mode 100644 index 0000000000000000000000000000000000000000..6ba22a1a54212b7ddc7a0588696ea77a40b535b1 --- /dev/null +++ b/frontend/src/views/Audit/AuditDetail.vue @@ -0,0 +1,46 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/views/Batch/Batch.vue b/frontend/src/views/Batch/Batch.vue index f971942141191fbfd187eb91f3b003362a12867d..606286c9ce1fc9b59d48498d83dcb4f98c4eb2ae 100644 --- a/frontend/src/views/Batch/Batch.vue +++ b/frontend/src/views/Batch/Batch.vue @@ -1,149 +1,146 @@ \ No newline at end of file diff --git a/frontend/src/views/Batch/Detail.vue b/frontend/src/views/Batch/Detail.vue index 2b024a4ee14d626a948a0539c981a520e260103f..55ac84fb905ea1d57285d02743decf3a2ddbde9f 100644 --- a/frontend/src/views/Batch/Detail.vue +++ b/frontend/src/views/Batch/Detail.vue @@ -1,58 +1,62 @@ diff --git a/frontend/src/views/Batch/components/UpdateRpm.vue b/frontend/src/views/Batch/components/UpdateRpm.vue new file mode 100644 index 0000000000000000000000000000000000000000..07638baa3107f98066c778594f0f271002e6ec1b --- /dev/null +++ b/frontend/src/views/Batch/components/UpdateRpm.vue @@ -0,0 +1,81 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/views/Cluster/Cluster.vue b/frontend/src/views/Cluster/Cluster.vue index f71b12adfa3760b05d3d4aeae34d5334370ac969..4684889ef169d704ea8fd3d8d9e87ff125fcc29e 100644 --- a/frontend/src/views/Cluster/Cluster.vue +++ b/frontend/src/views/Cluster/Cluster.vue @@ -12,7 +12,7 @@ v-model:selectedData="selectedMachines">