Vue3.5 企業級管理系統實戰(十九):菜單管理

篇幅原因,本節先探討菜單管理頁面增刪改查相關功能,角色菜單,菜單權限,動態菜單等內容放在后面。

1 菜單 api

在 src/api/menu.ts 中添加菜單 api,代碼如下:

//src/api/menu.ts
import service from "./config/request";
import type { ApiResponse } from "./type";export interface MenuData {id: number;title: string;path: string;icon: string;name: string;sort_id: number;parent_id: number;
}//獲取全部菜單
export const getAllMenus = (): Promise<ApiResponse<MenuData[]>> => {return service.get("/access/menu");
};//刪除指定菜單
export const removeMenuById = (id: number
): Promise<ApiResponse<MenuData[]>> => {return service.delete("/access/menu/" + id);
};//新增菜單
export const addMenu = (data: MenuData): Promise<ApiResponse<MenuData>> => {return service.post("/access/menu", data);
};//更新指定菜單
export const updateMenuById = (id: number,data: Partial<MenuData>
): Promise<ApiResponse<MenuData[]>> => {return service.put("/access/menu/" + id, data);
};//批量更新菜單
export const updateBulkMenu = (data: Partial<MenuData>[]
): Promise<ApiResponse> => {return service.patch("/access/menu/update", { access: data });
};

2 菜單 Store

在 src/store/menu.ts 中添加菜單相關方法,代碼如下:

//src/store/menu.ts
import {getAllMenus,type MenuData,addMenu,removeMenuById,updateMenuById,updateBulkMenu as updateBulkMenuApi
} from "@/api/menu";
import { getRoleAccessByRoles } from "@/api/roleAccess";
import { generateTree, ITreeItemDataWithMenuData } from "@/utils/generateTree";/*** 樹形菜單項數據結構,繼承自MenuData并擴展了子菜單屬性*/
export interface ITreeItemData extends MenuData {children?: ITreeItemData[];
}/*** 菜單狀態管理數據結構*/
export interface IMenuState {menuList: Array<MenuData>; // 原始菜單列表數據menuTreeData: ITreeItemData[]; // 樹形菜單數據(管理界面使用)authMenuList: MenuData[]; // 權限過濾后的菜單列表(側邊欄使用)authMenuTreeData: ITreeItemDataWithMenuData[]; // 權限過濾后的樹形菜單數據(側邊欄使用)
}/*** 菜單管理狀態庫* 使用Pinia實現的菜單狀態管理,包含菜單的增刪改查及權限控制*/
export const useMenuStore = defineStore("menu", () => {// 定義響應式狀態const state = reactive<IMenuState>({menuList: [],menuTreeData: [],authMenuList: [], // 側邊菜單需要的authMenuTreeData: []});/*** 獲取全部菜單列表并轉換為樹形結構* 用于管理界面展示完整菜單樹*/const getAllMenuList = async () => {const res = await getAllMenus();if (res.code == 0) {const { data } = res;state.menuList = data; // 獲取的原始菜單列表數據state.menuTreeData = generateTree(data); // 將原始數據轉換為樹形結構}};/*** 添加新菜單* @param data - 新菜單數據* @returns 添加成功返回true,失敗返回false*/const appendMenu = async (data: ITreeItemData) => {const res = await addMenu(data);if (res.code == 0) {const node = { ...res.data };state.menuList.push(node); // 添加到原始列表state.menuTreeData = generateTree(state.menuList); // 重新生成樹形結構return true;}};/*** 刪除菜單* @param data - 要刪除的菜單數據(需包含id)* @returns 刪除成功返回true,失敗返回false*/const removeMenu = async (data: ITreeItemData) => {const res = await removeMenuById(data.id);if (res.code == 0) {const idx = state.menuList.findIndex((menu) => menu.id === data.id);state.menuList.splice(idx, 1); // 從原始列表中刪除state.menuTreeData = generateTree(state.menuList); // 重新生成樹形結構return true;}};/*** 批量更新菜單(主要用于更新排序)* 1. 更新頂級菜單的sortId為其在數組中的索引位置* 2. 移除菜單對象中的children屬性避免干擾后端數據* @returns 更新成功返回true,失敗返回false*/const updateBulkMenu = async () => {// 1.更新sortIdstate.menuTreeData.forEach((menu, idx) => (menu.sort_id = idx));// 2.刪除子節點(后端存儲不需要children字段)const menus = state.menuTreeData.map((menu) => {const temp = { ...menu };delete temp.children;return temp;});// 批量更新const res = await updateBulkMenuApi(menus);if (res.code == 0) {return true;}};/*** 更新單個菜單* @param data - 要更新的菜單數據(需包含id)* @returns 更新成功返回true,失敗返回false*/const updateMenu = async (data: Partial<MenuData>) => {const res = await updateMenuById(Number(data.id), data);if (res.code === 0) {await getAllMenuList(); // 更新成功后重新獲取完整菜單列表return true;}};/*** 獲取管理員權限的全部菜單* 用于管理員用戶側邊欄顯示*/const getAllMenuListByAdmin = async () => {const res = await getAllMenus();if (res.code == 0) {const { data } = res;state.authMenuList = data; // 側邊欄菜單列表state.authMenuTreeData = generateTree(data, true); // 生成帶權限標識的樹形菜單}};/*** 根據角色獲取對應的菜單權限* @param roles - 角色ID數組*/const getMenuListByRoles = async (roles: number[]) => {const res = await getRoleAccessByRoles(roles);if (res.code == 0) {const { data } = res;const access = data.access;state.authMenuList = access; // 側邊欄菜單列表(權限過濾后)state.authMenuTreeData = generateTree(access, true); // 生成帶權限標識的樹形菜單}};// 導出狀態和方法return {getAllMenuList,state,appendMenu,removeMenu,updateBulkMenu,updateMenu,getAllMenuListByAdmin,getMenuListByRoles};
});

3 封裝生成 Tree 的方法

在 src/utils/generateTree.ts 中封裝生成 Tree 的方法,代碼如下:

//src/utils/generateTree.ts 
import type { MenuData } from "@/api/menu";
import type { ITreeItemData } from "@/stores/menu";/*** 擴展樹形菜單項數據結構,添加可選的meta元數據* 用于側邊欄菜單的路由配置和權限控制*/
export type ITreeItemDataWithMenuData = ITreeItemData & {meta?: { icon: string; title: string; [key: string]: string };
};/*** 映射表類型定義,用于快速查找節點* 鍵為菜單ID,值為樹形菜單項數據*/
export type IMap = Record<number, ITreeItemDataWithMenuData>;/*** 將扁平的菜單列表轉換為樹形結構* @param list - 扁平的菜單數據列表* @param withMeta - 是否添加meta元數據,默認為false* @returns 樹形結構的菜單數據*/
export const generateTree = (list: MenuData[], withMeta: boolean = false) => {// 第一步:構建映射表,快速查找節點const map = list.reduce((memo, current) => {// 復制當前節點數據const temp = { ...current };// 如果需要元數據,添加meta字段if (withMeta) {(temp as ITreeItemDataWithMenuData).meta = {title: current.title, // 菜單標題icon: current.icon // 菜單圖標};}// 將節點添加到映射表中memo[current.id] = temp;return memo;}, {} as IMap);// 第二步:構建樹形結構const tree: ITreeItemDataWithMenuData[] = [];list.forEach((item) => {const pid = item.parent_id; // 當前節點的父IDconst cur = map[item.id]; // 從映射表中獲取當前節點// 如果存在父節點,則將當前節點添加到父節點的children中if (pid !== 0 || pid != null) {const parent = map[pid];if (parent) {const children = parent?.children || [];children.push(cur);parent.children = children;return;}}// 如果沒有父節點或父節點不存在,則作為根節點tree.push(cur);});return tree;
};

4 菜單管理界面

4.1 刷新頁面 hook 函數

在 src/hooks/useReloadPage.ts 中,封裝刷新頁面的鉤子函數,代碼如下:

//src/hooks/useReloadPage.ts
export const useReloadPage = () => {const { proxy } = getCurrentInstance()!;const reloadPage = async ({title = "是否刷新",message = "你確定"} = {}) => {try {await proxy!.$confirm(title, message);window.location.reload();} catch {proxy?.$message.warning("已經取消了刷新");}};return {reloadPage};
};

4.2 菜單管理頁面

在 src/views/system/menu/index.vue 中添加菜單管理頁面,代碼如下:

//src/views/system/menu/index.vue
<template><div class="menu-container"><!-- 菜單樹展示區域 --><el-card><template #header><el-button @click="handleCreateRootMenu">新增頂級菜單</el-button></template><div class="menu-tree"><!-- 可拖拽的樹形菜單組件 --><el-tree:data="menus":props="defaultProps"@node-click="handleNodeClick":expand-on-click-node="false"highlight-currentdraggable:allow-drop="allowDrop":allow-drag="allowDrag"@node-drop="handleNodeDrop"><!-- 自定義樹節點內容,包含操作按鈕 --><template #default="{ node, data }"><p class="custom-item"><span>{{ data.title }} </span><span><el-button link @click="handleCreateChildMenu(data)">添加</el-button><el-button link @click="handleRemoveMenu(data)">刪除</el-button></span></p></template></el-tree></div></el-card><!-- 菜單編輯區域 --><el-card class="edit-card"><template #header> 編輯菜單 </template><!-- 菜單編輯組件,選中節點后顯示 --><editor-menuv-show="editData && editData.id":data="editData!"@updateEdit="handleUpdateEdit"/><span v-if="editData == null">從菜單列表選擇一項后,進行編輯</span></el-card><!-- 右側添加菜單面板 --><right-panel v-model="panelVisible" :title="panelTitle" :size="330"><add-menu @submit="submitMenuForm"></add-menu></right-panel></div>
</template><script lang="ts" setup>
import type { MenuData } from "@/api/menu";
import { useReloadPage } from "@/hooks/useReloadPage";
import { type ITreeItemData, useMenuStore } from "@/stores/menu";
import type Node from "element-plus/es/components/tree/src/model/node";// 處理菜單更新事件
const handleUpdateEdit = async (data: Partial<MenuData>) => {const r = await store.updateMenu(data);if (r) {proxy?.$message.success("菜單編輯成功");reloadPage(); // 刷新頁面數據}
};// 控制節點是否可拖拽
const allowDrag = (draggingNode: Node) => {// 根節點不可拖拽return (draggingNode.data.parent_id !== 0 || draggingNode.data.parent_id != null);
};type DropType = "prev" | "inner" | "next";// 控制節點拖拽放置規則
const allowDrop = (draggingNode: Node, dropNode: Node, type: DropType) => {// 根節點只能作為兄弟節點,不能作為子節點if (draggingNode.data.parent_id === 0 ||draggingNode.data.parent_id == null) {return type !== "inner";}
};// 處理節點拖拽完成事件
const handleNodeDrop = () => {store.updateBulkMenu(); // 更新菜單排序
};// 頁面刷新工具
const { reloadPage } = useReloadPage();
// 獲取菜單狀態管理
const store = useMenuStore();
// 計算屬性:獲取樹形菜單數據
const menus = computed(() => store.state.menuTreeData);
// 初始化加載菜單數據
store.getAllMenuList();// 樹形組件配置
const defaultProps = {children: "children",label: "title"
};// 菜單類型:0-頂級菜單 1-子菜單
const menuType = ref(0);
// 右側面板顯示控制
const panelVisible = ref(false);// 計算屬性:面板標題
const panelTitle = computed(() => {return menuType.value === 0 ? "添加頂級節點" : "添加子節點";
});// 創建頂級菜單
const handleCreateRootMenu = () => {menuType.value = 0;panelVisible.value = true;
};// 父菜單數據
const parentData = ref<ITreeItemData | null>();// 創建子菜單
const handleCreateChildMenu = (data: ITreeItemData) => {menuType.value = 1;panelVisible.value = true;parentData.value = data;
};// 重置狀態
const resetStatus = () => {panelVisible.value = false;parentData.value = null;reloadPage();
};// 生成菜單排序ID
const genMenuSortId = (list: ITreeItemData[]) => {if (list && list.length) {return list[list.length - 1].sort_id + 1;}return 0;
};// 添加頂級菜單
const handleAddRootMenu = async (data: MenuData) => {// 設置父ID和排序IDdata.parent_id = 0;data.sort_id = genMenuSortId(menus.value);let res = await store.appendMenu(data);if (res) {proxy?.$message.success("根菜單添加成功了");}
};const { proxy } = getCurrentInstance()!;// 生成子菜單數據
const genChild = (data: MenuData) => {const parent = parentData.value!;if (!parent.children) {parent.children = [];}data.sort_id = genMenuSortId(parent.children);data.parent_id = parent.id;return data;
};// 添加子菜單
const handleChildRootMenu = async (data: MenuData) => {const child = genChild(data);let res = await store.appendMenu(child);if (res) {proxy?.$message.success("子菜單添加成功了");}
};// 提交菜單表單
const submitMenuForm = async (data: MenuData) => {if (menuType.value === 0) {handleAddRootMenu({ ...data });} else {handleChildRootMenu({ ...data });}resetStatus();
};// 刪除菜單
const handleRemoveMenu = async (data: MenuData) => {try {await proxy?.$confirm("你確定刪除" + data.title + "菜單嗎?", {type: "warning"});await store.removeMenu({...data});proxy?.$message.success("菜單刪除成功");reloadPage();} catch {proxy?.$message.info("取消菜單");}
};// 當前編輯的菜單數據
const editData = ref({} as MenuData);// 處理節點點擊事件
const handleNodeClick = (data: MenuData) => {editData.value = { ...data };
};
</script><style scoped>
.menu-container {@apply flex p-20px; /* 容器布局和內邊距 */
}
.menu-tree {@apply min-w-500px h-400px overflow-y-scroll; /* 菜單樹區域固定高度,溢出滾動 */
}
.custom-item {@apply flex items-center justify-between flex-1; /* 自定義菜單項樣式,兩端對齊 */
}
.edit-card {@apply flex-1 ml-15px; /* 編輯區域自適應寬度 */
}
</style>

4.3 addMenu 組件

在?src/views/system/menu/components/addMenu.vue 中編寫菜單添加組件,代碼如下:

//src/views/system/menu/components/addMenu.vue
<template><div class="editor-container" p-20px><el-form ref="editFormRef" :model="editData" label-width="80px"><el-form-item label="菜單標題"><el-input v-model="editData.title" placeholder="請輸入用戶名" /></el-form-item><el-form-item label="路徑"><el-input v-model="editData.path" placeholder="請輸入郵箱" /></el-form-item><el-form-item label="圖標"><el-input v-model="editData.icon" placeholder="請輸入郵箱" /></el-form-item><el-form-item label="路由name"><el-input v-model="editData.name" placeholder="請輸入郵箱" /></el-form-item><el-form-item><el-button type="primary" @click="submitMenuForm">提交</el-button></el-form-item></el-form></div>
</template><script lang="ts" setup>
import type { FormInstance } from "element-plus";const emit = defineEmits(["submit"]);const editFormRef = ref<FormInstance | null>(null);
const editData = ref({title: "",path: "",icon: "",name: ""
});// 提交編輯菜單
const submitMenuForm = () => {(editFormRef.value as FormInstance).validate((valid) => {if (valid) {emit("submit", editData.value);editData.value = {title: "",path: "",icon: "",name: ""};}});
};
</script>

4.4 editorMenu 組件

在?src/views/system/menu/components/editorMenu.vue 中編寫菜單編輯組件,代碼如下:

//src/views/system/menu/components/editorMenu.vue
<template><div class="editor-container"><el-formref="editFormRef":model="editData":rules="menuFormRules"label-width="100px"><el-form-item label="菜單名稱" prop="title"><el-input v-model="editData.title" placeholder="請輸入菜單名稱" /></el-form-item><el-form-item label="路徑" prop="path"><el-input v-model="editData.path" placeholder="請輸入路由路徑" /></el-form-item><el-form-item label="路由Name" prop="name"><el-input v-model="editData.name" placeholder="請輸入路由名稱" /></el-form-item><el-form-item label="圖標" prop="icon"><el-input v-model="editData.icon" placeholder="請輸入icon名稱" /></el-form-item><el-form-item><el-button type="primary" @click="submitMenuForm">編輯菜單</el-button><el-button @click="submitReset">重置</el-button></el-form-item></el-form></div>
</template><script lang="ts" setup>
import type { MenuData } from "@/api/menu";
import type { FormInstance } from "element-plus";
// 編輯的數據
const editData = ref({id: -1,title: "",name: "",path: "",icon: ""
});
// 驗證規則
const menuFormRules = {title: {required: true,message: "請輸入菜單名稱",trigger: "blur"},path: {required: true,message: "請輸入路由路徑",trigger: "blur"},name: {required: true,message: "請輸入路由名稱",trigger: "blur"}
};
const editFormRef = ref<FormInstance | null>(null);
const loading = ref(false);const resetFormData = (data: MenuData) => {editData.value = { ...editData.value, ...data };
};
const props = defineProps({data: {type: Object as PropType<MenuData>,required: true}
});
watch(() => props.data,(value) => {if (value) {resetFormData(value);}}
);
const submitReset = () => resetFormData(props.data);
const emit = defineEmits(["updateEdit"]);
const submitMenuForm = () => {(editFormRef.value as FormInstance).validate((valid) => {if (valid) {loading.value = true;emit("updateEdit", { ...editData.value });}});
};
</script>

以上,就是菜單管理的相關內容。

下一篇將繼續探討 角色菜單的實現,敬請期待~?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/83806.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/83806.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/83806.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【android bluetooth 協議分析 01】【HCI 層介紹 8】【ReadLocalVersionInformation命令介紹】

1. HCI_Read_Local_Version_Information 命令介紹 1. 功能&#xff08;Description&#xff09; HCI_Read_Local_Version_Information 命令用于讀取本地 Bluetooth Controller 的版本信息&#xff0c;包括 HCI 和 LMP 層的版本&#xff0c;以及廠商 ID 和子版本號。 這類信息用…

React底層架構深度解析:從虛擬DOM到Fiber的演進之路

一、虛擬DOM&#xff1a;性能優化的基石 1.1 核心工作原理 React通過JSX語法將組件轉換為輕量級JavaScript對象&#xff08;即虛擬DOM&#xff09;&#xff0c;而非直接操作真實DOM。這一過程由React.createElement()實現&#xff0c;其結構包含元素類型、屬性和子節點等信息&a…

從AlphaGo到ChatGPT:AI技術如何一步步改變世界?

從AlphaGo到ChatGPT&#xff1a;AI技術如何一步步改變世界&#xff1f; 這里給大家分享一個人工智能學習網站。點擊跳轉到網站。 https://www.captainbed.cn/ccc 前言 在科技發展的歷史長河中&#xff0c;人工智能&#xff08;AI&#xff09;技術無疑是最為璀璨的明珠之一。從…

關于在Unity項目中使用Post Processing插件打包到web端出現的問題

關于在Unity項目中使用Post Processing插件打包到web端出現的問題 解決方法&#xff1a;是不激活攝像機上的Post Processing有關組件&#xff0c;拉低場景中的Directional Light平行光的強度進行web端打包。 &#xff08;烘焙燈光時是可以激活。&#xff09; web端支持這個Pos…

MySQL - 如何突破單庫性能瓶頸

數據庫服務器硬件優化 我們來看看對數據庫所在的服務器是如何進行優化的&#xff0c;服務器是數據庫的宿主&#xff0c;其性能直接影響了數據庫的性能&#xff0c;所以服務器的優化也是數據庫優化的第一步。 數據庫服務器通常是從 CPU、內存、磁盤三個角度進行硬件優化的&…

用 CodeBuddy 搭建「MiniGoal 小目標打卡器」:一次流暢的 UniApp 開發體驗

我正在參加CodeBuddy「首席試玩官」內容創作大賽&#xff0c;本文所使用的 CodeBuddy 免費下載鏈接&#xff1a;騰訊云代碼助手 CodeBuddy - AI 時代的智能編程伙伴 在日常生活中&#xff0c;我們總是希望能夠堅持一些小習慣&#xff0c;比如每天鍛煉十分鐘、讀一頁書、早睡十分…

OpenCV 環境搭建與概述

// //OpenCV-4.11.0 C VS2019 // 一、OpenCV學習路線 1、入門: OpenCV圖像讀寫、視頻讀寫、基本像素處理、基本卷積處理、基本C開發知識。 2、初級: OpenCV自定義卷積操作、圖像梯度、邊緣提取、二值分析、視頻分析、形態學處理、幾何變換與透視變換。 3、中級: 角點查找、BL…

如何快速更換電腦瀏覽器ip:教程與注意事項

無論是為了訪問地域限制內容、保護隱私&#xff0c;還是解決網絡問題&#xff0c;快速更換瀏覽器IP地址的需求日益增多。以下是快速更換電腦瀏覽器IP地址的幾種常用方法及注意事項&#xff0c;結合了多種場景下的解決方案&#xff1a; 一、快速更換瀏覽器IP的方法 1. 代理服務…

【kafka】kafka概念,使用技巧go示例

1. Kafka基礎概念 1.1 什么是Kafka&#xff1f; Kafka是一個分布式流處理平臺&#xff0c;用于構建實時數據管道和流式應用。核心特點&#xff1a; 高吞吐量&#xff1a;每秒可處理百萬級消息持久化存儲&#xff1a;消息按Topic分區存儲在磁盤分布式架構&#xff1a;支持水平…

掌握Git:版本控制與高效協作指南

一、初始Git 提出問題&#xff1a;無論是在工作還是學習&#xff0c;我們在編寫各種文檔的時候&#xff0c;更改失誤&#xff0c;失誤后恢復到原來版本&#xff0c;不得不復制出一個副本。 每個版本由各自的內容&#xff0c;但最終只有一個報告需要被我們使用。 但在此之前的…

【生活相關-日語-日本-東京-搬家后-引越(ひっこし)(3)-踩坑點:國民健康保險】

【生活相關-日語-日本-東京-搬家后-引越&#xff08;ひっこし&#xff09;&#xff08;3&#xff09;-注意點&#xff1a;國民健康保險】 1、前言2、情況說明&#xff08;1&#xff09;問題說明&#xff08;2&#xff09;情況說明&#xff08;1&#xff09;收到情況&#xff08…

linux——mysql故障排查與生產環境優化

目錄 一&#xff0c;mysql數據庫常見的故障 1&#xff0c;故障現象1 2&#xff0c;故障現象2 3&#xff0c;故障現象3 &#xff14;&#xff0c;故障現象&#xff14; &#xff15;&#xff0c;故障現象&#xff15; &#xff16;&#xff0c;故障現象&#xff16; 二&…

【C#】用 DevExpress 創建帶“下拉子表”的參數表格視圖

展示如何用 DevExpress 創建帶“下拉子表”的參數表格視圖。主表為 參數行 ParamRow&#xff0c;子表為 子項 ChildParam。 一、創建模型類 public class ParamRow {public string Pn { get; set; }public string DisplayName { get; set; }public string Value { get; set; }…

【JavaScript】用 Proxy 攔截對象屬性

目錄 一、Proxy 的基本結構&#xff08;打地基&#xff09; 二、最常用的兩個攔截方法&#xff1a;get 和 set 1. get(target, key) 2. set(target, key, value) 三、說到這&#xff0c;那就可以回到題目來 四、什么是 Reflect&#xff1f; 總結不易&#xff0c;本章節對…

[IMX] 02.GPIO 寄存器

目錄 手冊對應章節 1.GPIO 復用&#xff08;引腳功能選擇&#xff09;- IOMUXC_SW_MUX_CTL_PAD_xxx 2.GPIO 電氣特性 - IOMUXC_SW_PAD_CTL_PAD_xxx 3.GPIO 數據與控制寄存器 3.1.數據 - DR 3.2.輸入/輸出選擇 - GDIR 3.3.狀態 - PSR 3.4.中斷觸發控制 - ICR 3.5.中斷使…

Tomcat 配置 HTTPS 訪問全攻略(CentOS 環境)

Tomcat 配置 HTTPS 訪問全攻略&#xff08;CentOS 環境&#xff09; 一、環境說明 操作系統&#xff1a;CentOS Tomcat 版本&#xff1a;Apache Tomcat/9.0.105 服務器 IP&#xff1a;192.168.1.35 目標&#xff1a;將 Tomcat 默認的 HTTP 訪問升級為 HTTPS&#xff0c;提…

Flink 運維監控與指標采集實戰(Prometheus + Grafana 全流程)

一、引言:為什么 Flink 運維監控如此重要? 在實時計算場景中,Flink 作業 724 小時運行,對性能、資源、故障感知、狀態變化的實時監控非常關鍵。沒有有效的運維可觀測體系: 不知道任務是否在穩定運行 發生問題難以快速定位 無法感知背壓、延遲、反壓等狀態 因此,構建完善…

【prometheus+Grafana篇】基于Prometheus+Grafana實現Oracle數據庫的監控與可視化

&#x1f4ab;《博主主頁》&#xff1a; &#x1f50e; CSDN主頁 &#x1f50e; IF Club社區主頁 &#x1f525;《擅長領域》&#xff1a;擅長阿里云AnalyticDB for MySQL(分布式數據倉庫)、Oracle、MySQL、Linux、prometheus監控&#xff1b;并對SQLserver、NoSQL(MongoDB)有了…

【數據倉庫面試題合集③】實時數倉建模思路與實踐詳解

實時數據倉庫已經成為各大企業構建核心指標監控與業務實時洞察的基礎能力。面試中,關于實時建模的題目頻繁出現,尤其聚焦于建模思路、寬表設計、狀態管理、亂序處理等方面。本文整理典型題目及答題思路,幫助你應對相關考察。 一、建模原則與數倉分層認知 1. 實時數倉與離線…

鴻蒙PC操作系統:從Linux到自研微內核的蛻變

鴻蒙PC操作系統是否基于Linux內核,需要結合其技術架構、發展階段和官方聲明綜合分析。以下從多個角度展開論述: 一、鴻蒙操作系統的多內核架構設計 多內核混合架構 根據資料,鴻蒙操作系統(HarmonyOS)采用分層多內核架構,內核層包含Linux內核、LiteOS-m內核、LiteOS-a內核…