Vue 3 + TypeScript 构建大型电信运维平台的前端架构设计

电信网络运维平台(OSS)通常具有业务模块繁多、数据可视化要求高、交互逻辑复杂等特点。如何构建一个既具备高性能,又易于维护、支持多主题切换和细粒度权限控制的前端架构,是工程化落地的核心挑战。

本文将分享如何基于 Vue 3 + TypeScript + Vite 技术栈,结合 Spring Cloud Alibaba 后端生态,构建一个模块化、可扩展的大型前端应用。我们将重点探讨如何利用 CSS Variables 实现动态主题切换,以及如何设计基于 RBAC 模型的菜单与按钮权限控制系统。

一、 总体架构设计

1. 技术选型

  • 核心框架:Vue 3 (Composition API) + TypeScript。TS 的类型系统能有效约束复杂的业务数据结构(如基站信息、告警对象),提升代码健壮性。
  • 构建工具:Vite。利用其原生 ESM 特性,实现秒级冷启动和热更新,显著提升开发体验。
  • 状态管理:Pinia。替代 Vuex,提供更简洁的 API 和完美的 TS 支持,用于管理用户信息、主题配置、全局字典等。
  • UI 组件库:Element Plus。提供丰富的基础组件,满足后台管理系统的基本需求。
  • 路由管理:Vue Router 4。支持动态路由添加,是实现权限控制的关键。

2. 目录结构规范

采用功能模块化的目录结构,便于大型团队协作:

复制代码
src/
├── api/          # 接口请求封装(按微服务模块划分:perf, jom, netmgr...)
├── assets/       # 静态资源
├── components/   # 公共组件(BusinessChart, MapContainer...)
├── layout/       # 布局组件(Sidebar, Navbar, AppMain)
├── router/       # 路由配置(静态路由 + 动态路由逻辑)
├── stores/       # Pinia Store(user, theme, permission)
├── styles/       # 全局样式与主题变量
├── utils/        # 工具函数(auth, request, validate)
├── views/        # 页面视图(按业务域划分:PerfAnalysis, WorkOrder...)
└── App.vue

二、 动态主题切换实现

借鉴原系统中 Content/Theme/Blue 和 Red 的多主题设计理念,我们在 Vue 3 中通过 CSS Variables (CSS 自定义属性) 实现无刷新动态换肤。

1. 定义主题变量

src/styles/variables.css 中定义两套主题的核心色值:

css 复制代码
:root {
  /* 默认蓝色主题 */
  --primary-color: #409eff;
  --bg-color: #f0f2f5;
  --sidebar-bg: #304156;
  --text-color: #303133;
}

[data-theme='red'] {
  /* 红色主题 */
  --primary-color: #f56c6c;
  --bg-color: #fff0f0;
  --sidebar-bg: #5e3030;
  --text-color: #2c3e50;
}

2. Pinia 管理主题状态

创建 themeStore.ts

css 复制代码
import { defineStore } from 'pinia';
import { ref } from 'vue';

export const useThemeStore = defineStore('theme', () => {
  const currentTheme = ref<'blue' | 'red'>('blue');

  function setTheme(theme: 'blue' | 'red') {
    currentTheme.value = theme;
    // 动态修改 html 标签的 data-theme 属性
    document.documentElement.setAttribute('data-theme', theme);
    // 持久化到 localStorage
    localStorage.setItem('app-theme', theme);
  }

  // 初始化时读取本地存储
  function initTheme() {
    const savedTheme = localStorage.getItem('app-theme') as 'blue' | 'red' || 'blue';
    setTheme(savedTheme);
  }

  return { currentTheme, setTheme, initTheme };
});

3. 组件中使用变量

在 Vue 组件的 <style> 中直接使用变量,确保样式随主题自动切换:

css 复制代码
.sidebar {
  background-color: var(--sidebar-bg);
  color: #fff;
}

.el-button--primary {
  background-color: var(--primary-color);
  border-color: var(--primary-color);
}

三、 基于角色的权限控制 (RBAC)

电信运维系统涉及不同角色(如:监控员、优化专家、管理员),需要精确控制菜单可见性和按钮操作权限。

1. 后端接口设计

Spring Cloud Gateway 配合 SSO 服务,在用户登录成功后返回该用户的权限标识列表(Permission Codes)和菜单树(Menu Tree)。

css 复制代码
// /api/user/info 响应示例
{
  "roles": ["OPTIMIZER"],
  "permissions": [
    "perf:view",
    "perf:export",
    "jom:create_order",
    "netmgr:edit_cell"
  ],
  "menus": [
    {
      "path": "/perf",
      "name": "PerfAnalysis",
      "component": "Layout",
      "children": [...]
    }
  ]
}

2. 动态路由生成

permissionStore.ts 中,根据后端返回的菜单树,利用 router.addRoute 动态挂载路由。

TypeScript 复制代码
import { useRouter } from 'vue-router';
import Layout from '@/layout/index.vue';

// 映射组件路径
const modules = import.meta.glob('@/views/**/*.vue');

function generateRoutes(menuList: any[]) {
  return menuList.map(menu => {
    const route: any = {
      path: menu.path,
      name: menu.name,
      meta: { title: menu.title, icon: menu.icon }
    };
    
    if (menu.component === 'Layout') {
      route.component = Layout;
    } else {
      // 动态导入组件
      const componentPath = `./views/${menu.component}.vue`;
      route.component = modules[componentPath];
    }
    
    if (menu.children && menu.children.length > 0) {
      route.children = generateRoutes(menu.children);
    }
    return route;
  });
}

3. 按钮级权限指令

为了控制页面内具体按钮(如"导出"、"派单")的显隐,我们自定义一个 Vue 指令 v-auth

注册指令 (directives/auth.ts):

TypeScript 复制代码
import { DirectiveBinding } from 'vue';
import { useUserStore } from '@/stores/user';

export const auth = {
  mounted(el: HTMLElement, binding: DirectiveBinding) {
    const { value } = binding;
    const userStore = useUserStore();
    const permissions = userStore.permissions;

    if (value && !permissions.includes(value)) {
      el.parentNode?.removeChild(el);
    }
  }
};

在模板中使用:

html 复制代码
<template>
  <!-- 只有拥有 perf:export 权限的用户才能看到导出按钮 -->
  <el-button v-auth="'perf:export'" type="primary">导出数据</el-button>
  
  <!-- 只有拥有 jom:create_order 权限的用户才能看到派单按钮 -->
  <el-button v-auth="'jom:create_order'" @click="handleDispatch">一键派单</el-button>
</template>

四、 网络请求与微服务适配

前端通过 Axios 拦截器统一处理请求,适配 Spring Cloud Gateway 的路由规则。

TypeScript 复制代码
// utils/request.ts
import axios from 'axios';
import { useUserStore } from '@/stores/user';

const service = axios.create({
  baseURL: import.meta.env.VITE_APP_BASE_API, // 网关地址
  timeout: 15000
});

// 请求拦截器:携带 Token
service.interceptors.request.use(config => {
  const userStore = useUserStore();
  if (userStore.token) {
    config.headers['Authorization'] = `Bearer ${userStore.token}`;
  }
  return config;
});

// 响应拦截器:统一错误处理
service.interceptors.response.use(
  response => response.data,
  error => {
    if (error.response?.status === 401) {
      // Token 过期,跳转登录页
      window.location.href = '/login';
    }
    return Promise.reject(error);
  }
);

export default service;

五、 总结

通过 Vue 3 + TypeScript 的现代化架构,我们成功构建了一个灵活、高效的电信运维前端平台:

  1. 动态主题:利用 CSS Variables 和 Pinia,实现了蓝/红主题的无缝切换,满足了不同运维场景下的视觉偏好。
  2. 精细权限:通过动态路由和自定义指令,实现了从菜单到按钮的全链路权限控制,保障了系统数据的安全性。
  3. 工程化规范:TypeScript 的类型约束和 Vite 的快速构建,显著提升了代码质量和开发效率。

这种架构不仅适用于当前的运维业务,也为未来引入 GIS 可视化、实时信令追踪等复杂功能奠定了坚实的基础。

互动环节

💬 你们公司的动态指标计算引擎是怎么实现的?遇到过哪些难题?欢迎在评论区分享!

⭐ 如果觉得这篇文章有帮助,欢迎点赞、收藏、转发!

🔔 关注我,下一篇将分享《Web GIS 最佳实践:Vue 集成 Leaflet/OpenLayers 实现基站海量点位渲染》

版权声明:本文为原创文章,转载请注明出处。商业转载请联系作者获得授权。

作者简介:系统架构 师,专注于电信大数据平台架构设计与运维。目前负责日均处理2亿条消息的ucp平台,擅长分布式系统设计、消息中间件运维和高可用架构

相关推荐
xiaofeichaichai2 小时前
Map / Set / WeakMap / WeakSet
前端·javascript
李可以量化2 小时前
成交量的终极量化策略:价量共振指标完整实现(下篇)
前端·数据库·人工智能
copyer_xyf3 小时前
Python 如何同时做很多事:进程、线程、协程
前端·后端·python
gqk013 小时前
Delegate.Target/ Method
前端·ui·xhtml
有梦想的程序星空4 小时前
【环境配置】Vue3项目离线化本地部署echarts全攻略
前端·javascript·vue·echarts
IT_陈寒4 小时前
被Vite的动态导入坑了一整天,原来问题出在这
前端·人工智能·后端
薛先生_0994 小时前
vue-路由重定向
前端·javascript·vue.js
橘子星5 小时前
基于 ES6 语法的 NLP 任务模块化开发实践
前端·javascript
玉宇夕落5 小时前
Props的传递学习
前端