diff --git a/frontend/src/router/index.ts b/frontend/src/router/index.ts index 30c13c0677da6679e30d26eee702683c69caa964..b3adc1bb64e2555c67d9cc31863e59dca1ba5040 100644 --- a/frontend/src/router/index.ts +++ b/frontend/src/router/index.ts @@ -281,7 +281,6 @@ function addPluginRoute(item: any) { meta: { title: subItem.name, subRoute: "/plugin/" + item.name.split("-")[1] + subItem.url, - // subRoute: '/plugin/' + item.name.split('plugin-')[1] + subItem.url, breadcrumb: [ { name: item.name, diff --git a/frontend/src/styles/main.scss b/frontend/src/styles/main.scss index 1ba2a4223e6b3bb34cb906bfc16defd06b5987df..bee98878606535150f32b60a2eee1c263d92629c 100644 --- a/frontend/src/styles/main.scss +++ b/frontend/src/styles/main.scss @@ -1,4 +1,5 @@ @import "./base.css"; +@import "./scrollbar.css"; html { // min-width: 1440px; diff --git a/frontend/src/styles/scrollbar.css b/frontend/src/styles/scrollbar.css new file mode 100644 index 0000000000000000000000000000000000000000..535685d0b0c905cdeee5906f1221848da2b68152 --- /dev/null +++ b/frontend/src/styles/scrollbar.css @@ -0,0 +1,33 @@ +/* 整体滚动条 */ +::-webkit-scrollbar { + width: 8px; /* 滚动条的宽度 */ + height: 8px; /* 滚动条的高度 */ +} + +/* 滚动条轨道 */ +::-webkit-scrollbar-track { + background: #f1f1f1; /* 轨道背景颜色 */ + border-radius: 10px; /* 圆角 */ +} + +/* 滚动条滑块 */ +::-webkit-scrollbar-thumb { + background: #c1c1c1; /* 滑块颜色 */ + border-radius: 10px; /* 圆角 */ +} + +/* 滚动条滑块在悬停时的样式 */ +::-webkit-scrollbar-thumb:hover { + background: #a1a1a1; /* 悬停时的颜色 */ +} + +/* 滚动条滑块在活动状态下的样式 */ +::-webkit-scrollbar-thumb:active { + background: #888; /* 点击时的颜色 */ +} + +/* Firefox 滚动条样式 */ +* { + scrollbar-width: thin; /* 设置滚动条宽度为细 */ + scrollbar-color: #c1c1c1 #f1f1f1; /* 滑块颜色和轨道颜色 */ +} diff --git a/frontend/src/utils/index.ts b/frontend/src/utils/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..19c49193a2f6f2c084dd524096eb7a1f9f6ed213 --- /dev/null +++ b/frontend/src/utils/index.ts @@ -0,0 +1,11 @@ +/* 格式化Date */ +export function formatDate(date: Date) { + const year = date.getFullYear(); // 获取年份 + const month = String(date.getMonth() + 1).padStart(2, "0"); // 获取月份,注意要加1,并补零 + const day = String(date.getDate()).padStart(2, "0"); // 获取日期,并补零 + const hours = String(date.getHours()).padStart(2, "0"); // 获取小时,并补零 + const minutes = String(date.getMinutes()).padStart(2, "0"); // 获取分钟,并补零 + const seconds = String(date.getSeconds()).padStart(2, "0"); // 获取秒,并补零 + + return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; // 拼接成所需格式 +} diff --git a/frontend/src/views/Cluster/Cluster.vue b/frontend/src/views/Cluster/Cluster.vue index 913aa6117d648175686c9d45a8163069db94676f..4185a1b48cbbf3c317745069c5257569b198e65b 100644 --- a/frontend/src/views/Cluster/Cluster.vue +++ b/frontend/src/views/Cluster/Cluster.vue @@ -107,6 +107,7 @@ import { getPagedDepartMachines, getMachineTags, deleteMachine } from "@/request import { RespCodeOK, type RespInterface } from "@/request/request"; import { usePluginStore } from "@/stores/plugin"; import { useTerminalStore } from "@/stores/terminal"; +import { updatePlugins } from "@/views/Plugin/plugin"; // 部门树 const departmentID = ref(1); @@ -119,6 +120,7 @@ const showChangeDepartDialog = ref(false); let pluginBtns = ref([] as any); onMounted(() => { + updatePlugins(); updateDepartmentMachines(departmentID.value); pluginBtns.value = usePluginStore().extention; }); diff --git a/frontend/src/views/Home/Home.vue b/frontend/src/views/Home/Home.vue index 4801388745ab8eabf44a9347a70f33690b375e79..004a38478ff897671db57373ea50549a344e1c10 100644 --- a/frontend/src/views/Home/Home.vue +++ b/frontend/src/views/Home/Home.vue @@ -129,7 +129,7 @@ const changeCollapse = () => { watchEffect(() => { user.value = userStore().user; - collapseWidth.value = isCollapse.value ? "3.4%" : "10%"; + collapseWidth.value = isCollapse.value ? "66px" : "160px"; }); watch( diff --git a/frontend/src/views/Home/components/BreadCrumb.vue b/frontend/src/views/Home/components/BreadCrumb.vue index 87fb17dd6600b7a1e86dc328e7165aaddfdc1529..1627d1b1dd969dff691eeedcc3f173a0a8bbf77c 100644 --- a/frontend/src/views/Home/components/BreadCrumb.vue +++ b/frontend/src/views/Home/components/BreadCrumb.vue @@ -7,17 +7,15 @@ --> diff --git a/frontend/src/views/Overview/Overview.vue b/frontend/src/views/Overview/Overview.vue index 722d893f0f02783cad5b881d0ab325b35e13165a..cc64170657e0943eb390dc0b483861cd5cfeeb5b 100644 --- a/frontend/src/views/Overview/Overview.vue +++ b/frontend/src/views/Overview/Overview.vue @@ -7,141 +7,111 @@ --> \ No newline at end of file + diff --git a/frontend/src/views/Overview/components/Chart.vue b/frontend/src/views/Overview/components/Chart.vue new file mode 100644 index 0000000000000000000000000000000000000000..d55f988de66e24e55bd5867065aade02598b9266 --- /dev/null +++ b/frontend/src/views/Overview/components/Chart.vue @@ -0,0 +1,55 @@ + + + + + + diff --git a/frontend/src/views/Overview/components/DepartChart.vue b/frontend/src/views/Overview/components/DepartChart.vue deleted file mode 100644 index 8724bcb4873a35d0a10e09592cd99a83c6aa54db..0000000000000000000000000000000000000000 --- a/frontend/src/views/Overview/components/DepartChart.vue +++ /dev/null @@ -1,118 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/frontend/src/views/Overview/components/chart.ts b/frontend/src/views/Overview/components/chart.ts new file mode 100644 index 0000000000000000000000000000000000000000..176b71a304b5741963a332273da3e774e17a62f8 --- /dev/null +++ b/frontend/src/views/Overview/components/chart.ts @@ -0,0 +1,31 @@ +import { formatDate } from "@/utils"; +export const baseOptions_pie = { + title: { + text: "主机状态概览", + subtext: "更新时间:" + formatDate(new Date()), + left: 20, + top: 20, + }, + tooltip: { + trigger: "item", + }, + series: [ + { + name: "主机状态", + type: "pie", + radius: "76%", + data: [ + { value: 0, name: "在线" }, + { value: 0, name: "离线" }, + { value: 0, name: "未分配" }, + ], + emphasis: { + itemStyle: { + shadowBlur: 10, + shadowOffsetX: 0, + shadowColor: "rgba(0, 0, 0, 0.5)", + }, + }, + }, + ], +}; diff --git a/frontend/src/views/Overview/socket.ts b/frontend/src/views/Overview/socket.ts new file mode 100644 index 0000000000000000000000000000000000000000..0f3ca045d76011142e3346088c80395762e58dd9 --- /dev/null +++ b/frontend/src/views/Overview/socket.ts @@ -0,0 +1,159 @@ +/* + * Copyright (c) KylinSoft Co., Ltd. 2024.All rights reserved. + * PilotGo-plugin-topology licensed under the Mulan Permissive Software License, Version 2. + * See LICENSE file for more details. + * Author: fairy + * Date: Tue Nov 5 17:13:22 2024 +0800 + */ +import { ElMessage } from "element-plus"; +interface socket { + websocket: any; + connectURL: string; + socket_open: boolean; + hearbeat_timer: any; + hearbeat_interval: number; + is_reonnect: boolean; + reconnect_count: number; + reconnect_current: number; + ronnect_number: number; + reconnect_timer: any; + reconnect_interval: number; + init: (receiveMessage: Function | null, socketUrl: string) => any; + receive: (message: any) => void; + heartbeat: () => void; + send: (data: any, callback?: any) => void; + close: () => void; + reconnect: (url: string) => void; +} +let protocol = window.location.protocol === "http:" ? "ws://" : "wss://"; +const socket: socket = { + websocket: null, + connectURL: "wss://" + "10.41.107.29:8888", + // connectURL: protocol+window.location.host+"/plugin/ws/logs", + // 开启标识 + socket_open: false, + // 心跳timer + hearbeat_timer: null, + // 心跳发送频率 + hearbeat_interval: 45000, + // 是否自动重连 + is_reonnect: true, + // 重连次数 + reconnect_count: 100, + // 已发起重连次数 + reconnect_current: 1, + // 网络错误提示此时 + ronnect_number: 0, + // 重连timer + reconnect_timer: null, + // 重连频率 + reconnect_interval: 5000, + + init: (receiveMessage: Function | null, socketUrl: string) => { + if (!("WebSocket" in window)) { + ElMessage.warning("浏览器不支持WebSocket"); + return null; + } + + socket.websocket = new WebSocket(socket.connectURL + socketUrl); + socket.websocket.onmessage = (e: any) => { + if (receiveMessage) { + receiveMessage(e); + } + }; + + socket.websocket.onclose = (e: any) => { + console.log("检测到关闭", e); + clearInterval(socket.hearbeat_interval); + socket.socket_open = false; + + // 需要重新连接 + if (socket.is_reonnect) { + socket.reconnect_timer = setTimeout(() => { + // 超过重连次数 + if (socket.reconnect_current > socket.reconnect_count) { + clearTimeout(socket.reconnect_timer); + socket.is_reonnect = false; + return; + } + + // 记录重连次数 + socket.reconnect_current++; + console.log("重连次数:", socket.reconnect_current); + socket.reconnect(socketUrl); + }, socket.reconnect_interval); + } + }; + + // 连接成功 + socket.websocket.onopen = function () { + console.log("ws连接成功,当前连接地址:", socket.connectURL + socketUrl); + socket.socket_open = true; + socket.is_reonnect = false; + // 开启心跳 + // socket.heartbeat() + }; + + // 连接发生错误 + socket.websocket.onerror = function (e: any) { + console.log("连接发生错误", e); + }; + }, + + send: (data, callback = null) => { + // 开启状态直接发送 + if (socket.websocket.readyState === socket.websocket.OPEN) { + socket.websocket.send(JSON.stringify(data)); + if (callback) { + callback(); + } + + // 正在开启状态,则等待1s后重新调用 + } else { + clearInterval(socket.hearbeat_timer); + socket.ronnect_number++; + } + }, + + receive: (message: any) => { + let params = JSON.parse(message.data).data; + return params; + }, + + heartbeat: () => { + if (socket.hearbeat_timer) { + clearInterval(socket.hearbeat_timer); + } + + socket.hearbeat_timer = setInterval(() => { + let data = { + content: "ping", + }; + var sendDara = { + encryption_type: "base64", + data: data, + }; + socket.send(sendDara); + }, socket.hearbeat_interval); + }, + + close: () => { + clearInterval(socket.hearbeat_interval); + socket.is_reonnect = false; + socket.websocket.close(); + }, + + /** + * 重新连接 + */ + reconnect: (url: string) => { + console.log("重新连接"); + if (socket.websocket && !socket.is_reonnect) { + socket.close(); + } + + socket.init(null, url); + }, +}; + +export default socket; diff --git a/frontend/src/views/Plugin/Plugin.vue b/frontend/src/views/Plugin/Plugin.vue index 7c9132eaf7981aa1aca04fdfe43979c30d33d465..b46a0fb0e6fc10c2ee42f9bfcee5396938a086ba 100644 --- a/frontend/src/views/Plugin/Plugin.vue +++ b/frontend/src/views/Plugin/Plugin.vue @@ -102,14 +102,6 @@ function togglePluginState(item: any) { updatePluginList(); // 更新页面插件路由、sidebar等 updatePlugins(); - // 删除插件tagview、增删全局扩展点 - let pluginExt = res.data.filter((item: Extention) => item.type === "machine"); - if (targetEnabled === 0) { - clearTagview(item); - usePluginStore().delExtention(pluginExt); - } else { - usePluginStore().addExtention(pluginExt); - } } else { ElMessage.error(res.msg); } @@ -124,25 +116,11 @@ function onDeletePlugin(item: any) { updatePluginList(); // 更新页面插件路由、sidebar等 updatePlugins(); - // 删除插件tagview - clearTagview(item); - // 删除插件扩展点 - let pluginExt = item.extentions && item.extentions.filter((item: Extention) => item.type === "machine"); - usePluginStore().delExtention(pluginExt); } else { ElMessage.error(res.msg); } }); } - -import { tagviewStore } from "@/stores/tagview"; -function clearTagview(item: any) { - for (let i = 0; i < tagviewStore().taginfos.length; i++) { - if (tagviewStore().taginfos[i].path === "/plugin-" + item.name) { - tagviewStore().taginfos.splice(i, 1); - } - } -} \ No newline at end of file + diff --git a/frontend/src/views/Role/components/authData.ts b/frontend/src/views/Role/components/authData.ts index e6326592f4af1079f33e6fcf3113094848be7d1c..dd6fbebd4ea90aeae6f03863f6e4a18bcfedcb17 100644 --- a/frontend/src/views/Role/components/authData.ts +++ b/frontend/src/views/Role/components/authData.ts @@ -1,6 +1,6 @@ -/* +/* * Copyright (c) KylinSoft Co., Ltd. 2024.All rights reserved. - * PilotGo licensed under the Mulan Permissive Software License, Version 2. + * PilotGo licensed under the Mulan Permissive Software License, Version 2. * See LICENSE file for more details. * Author: Gzx1999 * Date: Wed Jan 3 18:00:12 2024 +0800 @@ -9,137 +9,169 @@ // 需要做动态添加插件权限逻辑 -export let authData = [{ - id: '1', - label: '概览', +export let authData = [ + { + id: "1", + label: "概览", isMenu: true, - menuName: 'overview', - operations: [] -}, { - id: '2', - label: '系统', + display: true, + menuName: "overview", + operations: [], + }, + { + id: "2", + label: "系统", isMenu: true, - menuName: 'cluster', - operations: [{ - id: '8', - btnId: '1', - label: 'rpm下发', - menuName: 'rpm_install', - }, { - id: '9', - btnId: '2', - label: 'rpm卸载', - menuName: 'rpm_uninstall', - }, { - id: '22', - btnId: '15', - label: '变更部门', - menuName: 'dept_change', - },{ - id: '23', - btnId: '16', - label: '机器删除', - menuName: 'machine_delete', - },{ - id: '24', - btnId: '17', - label: '创建批次', - menuName: 'batch_create', - },{ - id: '25', - btnId: '18', - label: '添加部门', - menuName: 'dept_add', - },{ - id: '26', - btnId: '19', - label: '删除部门', - menuName: 'dept_delete', - },{ - id: '27', - btnId: '20', - label: '编辑部门', - menuName: 'dept_update', - },] -}, { - id: '3', - label: '批次', + display: true, + menuName: "cluster", + operations: [ + { + id: "8", + btnId: "1", + label: "rpm下发", + menuName: "rpm_install", + }, + { + id: "9", + btnId: "2", + label: "rpm卸载", + menuName: "rpm_uninstall", + }, + { + id: "22", + btnId: "15", + label: "变更部门", + menuName: "dept_change", + }, + { + id: "23", + btnId: "16", + label: "机器删除", + menuName: "machine_delete", + }, + { + id: "24", + btnId: "17", + label: "创建批次", + menuName: "batch_create", + }, + { + id: "25", + btnId: "18", + label: "添加部门", + menuName: "dept_add", + }, + { + id: "26", + btnId: "19", + label: "删除部门", + menuName: "dept_delete", + }, + { + id: "27", + btnId: "20", + label: "编辑部门", + menuName: "dept_update", + }, + ], + }, + { + id: "3", + label: "批次", isMenu: true, - menuName: 'batch', - operations: [{ - id: '10', - btnId: '3', - label: '编辑批次', - menuName: 'batch_update', - }, { - id: '11', - btnId: '4', - label: '删除批次', - menuName: 'batch_delete', - }] -}, { - id: '4', - label: '用户管理', + display: true, + menuName: "batch", + operations: [ + { + id: "10", + btnId: "3", + label: "编辑批次", + menuName: "batch_update", + }, + { + id: "11", + btnId: "4", + label: "删除批次", + menuName: "batch_delete", + }, + ], + }, + { + id: "4", + label: "用户管理", isMenu: true, - menuName: 'usermanager', - operations: [{ - id: '12', - btnId: '5', - label: '添加用户', - menuName: 'user_add', - }, { - id: '13', - btnId: '6', - label: '导入用户', - menuName: 'user_import', - }, { - id: '14', - btnId: '7', - label: '编辑用户', - menuName: 'user_edit', - }, { - id: '15', - btnId: '8', - label: '重置密码', - menuName: 'user_reset', - }, { - id: '16', - btnId: '9', - label: '删除用户', - menuName: 'user_del', - }] -}, { - id: '5', - label: '角色管理', + display: true, + menuName: "usermanager", + operations: [ + { + id: "12", + btnId: "5", + label: "添加用户", + menuName: "user_add", + }, + { + id: "13", + btnId: "6", + label: "导入用户", + menuName: "user_import", + }, + { + id: "14", + btnId: "7", + label: "编辑用户", + menuName: "user_edit", + }, + { + id: "15", + btnId: "8", + label: "重置密码", + menuName: "user_reset", + }, + { + id: "16", + btnId: "9", + label: "删除用户", + menuName: "user_del", + }, + ], + }, + { + id: "5", + label: "角色管理", isMenu: true, - menuName: 'rolemanager', + display: true, + menuName: "rolemanager", operations: [ - { - id: '17', - btnId: '10', - label: '添加角色', - menuName: 'role_add', - }, { - id: '18', - btnId: '11', - label: '编辑角色', - menuName: 'role_update', - }, { - id: '19', - btnId: '12', - label: '删除角色', - menuName: 'role_delete', - }, { - id: '20', - btnId: '13', - label: '角色授权', - menuName: 'role_modify', - }] -}, -/* { + { + id: "17", + btnId: "10", + label: "添加角色", + menuName: "role_add", + }, + { + id: "18", + btnId: "11", + label: "编辑角色", + menuName: "role_update", + }, + { + id: "19", + btnId: "12", + label: "删除角色", + menuName: "role_delete", + }, + { + id: "20", + btnId: "13", + label: "角色授权", + menuName: "role_modify", + }, + ], + }, + /* { id: '6', label: '配置管理', - isMenu: true, + isMenu: true,display:true, menuName: 'config', operations: [{ id: '21', @@ -148,17 +180,41 @@ export let authData = [{ menuName: 'config_install', }] }, */ -{ - id: '7', - label: '日志管理', + { + id: "7", + label: "日志管理", isMenu: true, - menuName: 'log', - operations: [] -}, -{ - id: '8', - label: '插件管理', + display: true, + menuName: "log", + operations: [], + }, + { + id: "8", + label: "插件管理", isMenu: true, - menuName: 'plugin', - operations: [] -}]; \ No newline at end of file + display: true, + menuName: "plugin", + operations: [], + }, + { + id: "9", + label: "监控告警", + isMenu: true, + display: false, + menuName: "monitor", + operations: [ + { + id: "22", + btnId: "15", + label: "安装expoter", + menuName: "expoter_install", + }, + { + id: "23", + btnId: "16", + label: "卸载expoter", + menuName: "expoter_uninstall", + }, + ], + }, +];