发布日期:2024年6月1日
一、系统架构设计
本教程将开发一个完整的企业中台系统,包含以下核心模块:
- RBAC权限系统:基于角色的精细化控制
- 微前端架构:qiankun集成多个子应用
- 数据可视化:ECharts大屏展示
- 工作流引擎:可视化流程设计器
- 消息中心:WebSocket实时通知
技术栈:Vue2.6 + ElementUI + qiankun + ECharts + WebSocket
二、项目初始化与配置
1. 创建主应用
vue create portal-main
cd portal-main
npm install element-ui qiankun echarts socket.io-client
# 添加微前端配置
vue add qiankun
2. 目录结构规划
src/
├── api/ # 接口服务
├── components/ # 公共组件
│ ├── layout/ # 布局组件
│ └── charts/ # 图表组件
├── micro-apps/ # 微应用入口
├── permission/ # 权限控制
├── router/ # 路由配置
├── store/ # Vuex状态
├── utils/ # 工具函数
├── views/ # 页面组件
│ ├── dashboard/ # 数据大屏
│ └── system/ # 系统管理
├── App.vue
└── main.js
三、RBAC权限系统实现
1. 动态路由配置
// permission/index.js
import router from '@/router'
import store from '@/store'
const whiteList = ['/login']
router.beforeEach(async (to, from, next) => {
if (whiteList.includes(to.path)) {
next()
return
}
const hasToken = store.getters.token
if (!hasToken) {
next(`/login?redirect=${to.path}`)
return
}
const hasRoles = store.getters.roles.length > 0
if (hasRoles) {
next()
return
}
try {
const { roles } = await store.dispatch('user/getUserInfo')
const accessRoutes = await store.dispatch('permission/generateRoutes', roles)
router.addRoutes(accessRoutes)
next({ ...to, replace: true })
} catch (error) {
next(`/login?redirect=${to.path}`)
}
})
2. 权限指令实现
// directives/permission.js
import store from '@/store'
function checkPermission(el, binding) {
const { value } = binding
const roles = store.getters.roles
if (value && value instanceof Array) {
if (value.length > 0) {
const hasPermission = roles.some(role => value.includes(role))
if (!hasPermission) {
el.parentNode && el.parentNode.removeChild(el)
}
}
} else {
throw new Error(`需要指定权限数组,如v-permission="['admin']"`)
}
}
export default {
inserted(el, binding) {
checkPermission(el, binding)
},
update(el, binding) {
checkPermission(el, binding)
}
}
四、微前端架构集成
1. 主应用配置
// micro-apps/index.js
import { registerMicroApps, start } from 'qiankun'
const apps = [
{
name: 'app1',
entry: '//localhost:7101',
container: '#subapp-viewport',
activeRule: '/app1',
props: {
token: localStorage.getItem('token'),
baseApi: process.env.VUE_APP_BASE_API
}
}
]
export function registerApps() {
registerMicroApps(apps)
start({
prefetch: 'all',
sandbox: { strictStyleIsolation: true }
})
}
2. 子应用适配
// 子应用入口文件
import './public-path'
import Vue from 'vue'
import App from './App.vue'
let instance = null
function render(props = {}) {
const { container } = props
instance = new Vue({
router,
store,
render: h => h(App)
}).$mount(container ? container.querySelector('#app') : '#app')
}
if (!window.__POWERED_BY_QIANKUN__) {
render()
}
export async function bootstrap() {
console.log('子应用启动')
}
export async function mount(props) {
// 注入主应用传递的props
Vue.prototype.$mainProps = props
render(props)
}
export async function unmount() {
instance.$destroy()
instance.$el.innerHTML = ''
instance = null
}
五、数据可视化大屏
1. ECharts组件封装
<template>
<div ref="chart" :style="{ width, height }"></div>
</template>
<script>
import * as echarts from 'echarts'
import { debounce } from 'lodash'
export default {
props: {
width: { type: String, default: '100%' },
height: { type: String, default: '400px' },
option: { type: Object, required: true },
theme: { type: String, default: 'light' }
},
data() {
return {
chart: null
}
},
watch: {
option: {
deep: true,
handler(newVal) {
this.updateChart(newVal)
}
}
},
mounted() {
this.initChart()
window.addEventListener('resize', this.handleResize)
},
beforeDestroy() {
window.removeEventListener('resize', this.handleResize)
this.chart.dispose()
},
methods: {
initChart() {
this.chart = echarts.init(this.$refs.chart, this.theme)
this.chart.setOption(this.option)
},
updateChart(newOption) {
if (this.chart) {
this.chart.setOption(newOption)
}
},
handleResize: debounce(function() {
this.chart.resize()
}, 300)
}
}
</script>
2. 大屏数据联动
// views/dashboard/index.vue
export default {
data() {
return {
realtimeData: [],
timer: null,
chartOptions: {
xAxis: { type: 'category' },
yAxis: { type: 'value' },
series: [{ type: 'line' }]
}
}
},
created() {
this.fetchData()
this.setupWebSocket()
},
beforeDestroy() {
clearInterval(this.timer)
this.socket.close()
},
methods: {
async fetchData() {
const res = await this.$api.getDashboardData()
this.realtimeData = res.data
this.updateChart()
},
setupWebSocket() {
this.socket = new WebSocket(process.env.VUE_APP_WS_URL)
this.socket.onmessage = (event) => {
const data = JSON.parse(event.data)
this.realtimeData.push(data)
if (this.realtimeData.length > 100) {
this.realtimeData.shift()
}
this.updateChart()
}
},
updateChart() {
this.chartOptions = {
...this.chartOptions,
dataset: {
source: this.realtimeData
}
}
}
}
}
六、工作流引擎实现
1. 可视化流程设计器
<template>
<div class="flow-designer">
<div class="toolbar">
<el-button @click="addNode('approval')">审批节点</el-button>
<el-button @click="addNode('condition')">条件分支</el-button>
</div>
<div ref="canvas" class="canvas"></div>
</div>
</template>
<script>
import G6 from '@antv/g6'
export default {
data() {
return {
graph: null,
data: {
nodes: [],
edges: []
}
}
},
mounted() {
this.initGraph()
},
beforeDestroy() {
this.graph.destroy()
},
methods: {
initGraph() {
this.graph = new G6.Graph({
container: this.$refs.canvas,
width: 800,
height: 600,
modes: { default: ['drag-node', 'drag-canvas'] },
defaultNode: { type: 'rect' },
defaultEdge: { type: 'polyline' }
})
this.graph.data(this.data)
this.graph.render()
this.graph.on('node:click', evt => {
this.showNodeConfig(evt.item)
})
},
addNode(type) {
const id = `node_${Date.now()}`
const node = { id, type, x: 100, y: 100 }
this.data.nodes.push(node)
this.graph.changeData(this.data)
},
showNodeConfig(node) {
this.$emit('node-selected', node)
}
}
}
</script>
2. 流程节点配置
<el-dialog :visible.sync="configVisible">
<el-form :model="currentNode">
<el-form-item label="节点名称">
<el-input v-model="currentNode.name"></el-input>
</el-form-item>
<template v-if="currentNode.type === 'approval'">
<el-form-item label="审批人">
<el-select v-model="currentNode.approvers" multiple>
<el-option
v-for="user in userList"
:key="user.id"
:label="user.name"
:value="user.id">
</el-option>
</el-select>
</el-form-item>
</template>
<el-form-item>
<el-button @click="saveConfig">保存</el-button>
</el-form-item>
</el-form>
</el-dialog>
七、性能优化实践
1. 路由懒加载
// router/index.js
const routes = [
{
path: '/dashboard',
component: () => import(/* webpackChunkName: "dashboard" */ '@/views/dashboard'),
meta: { title: '数据大屏' }
},
{
path: '/workflow',
component: () => import(/* webpackChunkName: "workflow" */ '@/views/workflow'),
meta: { title: '工作流' }
}
]
2. 组件按需加载
// 动态加载重型组件
const HeavyChart = () => ({
component: import('./HeavyChart.vue'),
loading: LoadingComponent,
delay: 200,
timeout: 10000
})
export default {
components: { HeavyChart }
}
八、总结与扩展
通过本教程,您已经掌握了:
- 企业级中台系统架构设计
- RBAC权限模型实现
- 微前端架构集成方案
- 数据可视化大屏开发
- 工作流引擎核心实现
扩展学习方向:
- Web Components跨框架组件
- 低代码平台搭建
- BI商业智能分析
- 微前端状态共享