3b1ebb39 by 任超

style:权限处理

1 parent 9724faa4
...@@ -19,7 +19,9 @@ ...@@ -19,7 +19,9 @@
19 "nprogress": "0.2.0", 19 "nprogress": "0.2.0",
20 "vue": "2.6.10", 20 "vue": "2.6.10",
21 "vue-router": "3.0.2", 21 "vue-router": "3.0.2",
22 "vuex": "3.1.0" 22 "vuex": "3.1.0",
23 "bpmn-js": "^7.4.0",
24 "diagram-js": "^6.8.2"
23 }, 25 },
24 "devDependencies": { 26 "devDependencies": {
25 "@vue/cli-plugin-babel": "4.4.4", 27 "@vue/cli-plugin-babel": "4.4.4",
......
1 <template>
2 <div class="process-viewer">
3 <div v-show="!isLoading" ref="processCanvas" class="process-canvas" style="height: 100%;" />
4 <!-- 自定义箭头样式,用于成功状态下流程连线箭头 -->
5 <defs ref="customSuccessDefs">
6 <marker id="sequenceflow-end-white-success" view-box="0 0 20 20" ref-x="11" ref-y="10" marker-width="10"
7 marker-height="10" orient="auto">
8 <path class="success-arrow" d="M 1 5 L 11 10 L 1 15 Z"
9 style="stroke-width: 1px; stroke-linecap: round; stroke-dasharray: 10000, 1;" />
10 </marker>
11 <marker id="conditional-flow-marker-white-success" view-box="0 0 20 20" ref-x="-1" ref-y="10" marker-width="10"
12 marker-height="10" orient="auto">
13 <path class="success-conditional" d="M 0 10 L 8 6 L 16 10 L 8 14 Z"
14 style="stroke-width: 1px; stroke-linecap: round; stroke-dasharray: 10000, 1;" />
15 </marker>
16 </defs>
17 <!-- 自定义箭头样式,用于失败状态下流程连线箭头 -->
18 <defs ref="customFailDefs">
19 <marker id="sequenceflow-end-white-fail" view-box="0 0 20 20" ref-x="11" ref-y="10" marker-width="10"
20 marker-height="10" orient="auto">
21 <path class="fail-arrow" d="M 1 5 L 11 10 L 1 15 Z"
22 style="stroke-width: 1px; stroke-linecap: round; stroke-dasharray: 10000, 1;" />
23 </marker>
24 <marker id="conditional-flow-marker-white-fail" view-box="0 0 20 20" ref-x="-1" ref-y="10" marker-width="10"
25 marker-height="10" orient="auto">
26 <path class="fail-conditional" d="M 0 10 L 8 6 L 16 10 L 8 14 Z"
27 style="stroke-width: 1px; stroke-linecap: round; stroke-dasharray: 10000, 1;" />
28 </marker>
29 </defs>
30 <!-- 已完成节点悬浮弹窗 -->
31 <el-dialog class="comment-dialog" :title="dlgTitle || '审批记录'" :visible.sync="dialogVisible" append-to-body>
32 <el-row>
33 <el-table :data="taskCommentList" size="mini" border header-cell-class-name="table-header-gray">
34 <el-table-column label="序号" header-align="center" align="center" type="index" width="55px" />
35 <el-table-column label="候选办理" prop="candidate" width="150px" align="center" />
36 <el-table-column label="实际办理" prop="assigneeName" width="100px" align="center" />
37 <el-table-column label="处理时间" prop="createTime" width="140px" align="center" />
38 <el-table-column label="办结时间" prop="finishTime" width="140px" align="center" />
39 <el-table-column label="耗时" prop="duration" width="100px" align="center" />
40 <el-table-column label="审批意见" align="center">
41 <template slot-scope="scope">
42 {{ scope.row.commentList&&scope.row.commentList[0]?scope.row.commentList[0].fullMessage:'' }}
43 </template>
44 </el-table-column>
45 </el-table>
46 </el-row>
47 </el-dialog>
48 <div style="position: absolute; top: 0px; left: 0px; width: 100%;">
49 <el-row type="flex" justify="end">
50 <el-button-group key="scale-control" size="medium">
51 <el-button size="medium" type="default" :plain="true" :disabled="defaultZoom <= 0.3" icon="el-icon-zoom-out"
52 @click="processZoomOut()" />
53 <el-button size="medium" type="default" style="width: 90px;">{{ Math.floor(this.defaultZoom * 10 * 10) + "%"
54 }}</el-button>
55 <el-button size="medium" type="default" :plain="true" :disabled="defaultZoom >= 3.9" icon="el-icon-zoom-in"
56 @click="processZoomIn()" />
57 <el-button size="medium" type="default" icon="el-icon-c-scale-to-original" @click="processReZoom()" />
58 <slot />
59 </el-button-group>
60 </el-row>
61 </div>
62 </div>
63 </template>
64
65 <script>
66 import BpmnViewer from 'bpmn-js/lib/Viewer'
67 import MoveCanvasModule from 'diagram-js/lib/navigation/movecanvas'
68
69 export default {
70 props: {
71 // eslint-disable-next-line vue/require-default-prop
72 xml: {
73 type: String
74 },
75 // eslint-disable-next-line vue/require-default-prop
76 finishedInfo: {
77 type: Object
78 },
79 // 所有节点审批记录
80 // eslint-disable-next-line vue/require-default-prop
81 allCommentList: {
82 type: Array
83 }
84 },
85 data () {
86 return {
87 dialogVisible: false,
88 dlgTitle: undefined,
89 defaultZoom: 1,
90 // 是否正在加载流程图
91 isLoading: false,
92 bpmnViewer: undefined,
93 // 已完成流程元素
94 processNodeInfo: undefined,
95 // 当前任务id
96 selectTaskId: undefined,
97 // 任务节点审批记录
98 taskCommentList: [],
99 // 已完成任务悬浮延迟Timer
100 hoverTimer: null
101 }
102 },
103 watch: {
104 xml: {
105 handler (newXml) {
106 this.importXML(newXml)
107 },
108 immediate: true
109 },
110 finishedInfo: {
111 handler (newInfo) {
112 this.setProcessStatus(newInfo)
113 },
114 immediate: true
115 }
116 },
117 created () {
118 this.$nextTick(() => {
119 this.importXML(this.xml)
120 this.setProcessStatus(this.finishedInfo)
121 })
122 },
123 destroyed () {
124 this.clearViewer()
125 },
126 methods: {
127 processReZoom () {
128 this.defaultZoom = 1
129 this.bpmnViewer.get('canvas').zoom('fit-viewport', 'auto')
130 },
131 processZoomIn (zoomStep = 0.1) {
132 const newZoom = Math.floor(this.defaultZoom * 100 + zoomStep * 100) / 100
133 if (newZoom > 4) {
134 throw new Error('[Process Designer Warn ]: The zoom ratio cannot be greater than 4')
135 }
136 this.defaultZoom = newZoom
137 this.bpmnViewer.get('canvas').zoom(this.defaultZoom)
138 },
139 processZoomOut (zoomStep = 0.1) {
140 const newZoom = Math.floor(this.defaultZoom * 100 - zoomStep * 100) / 100
141 if (newZoom < 0.2) {
142 throw new Error('[Process Designer Warn ]: The zoom ratio cannot be less than 0.2')
143 }
144 this.defaultZoom = newZoom
145 this.bpmnViewer.get('canvas').zoom(this.defaultZoom)
146 },
147 getOperationTagType (type) {
148 return 'success'
149 // switch (type) {
150 // case this.SysFlowTaskOperationType.AGREE:
151 // case this.SysFlowTaskOperationType.MULTI_AGREE:
152 // return 'success';
153 // case this.SysFlowTaskOperationType.REFUSE:
154 // case this.SysFlowTaskOperationType.PARALLEL_REFUSE:
155 // case this.SysFlowTaskOperationType.MULTI_REFUSE:
156 // return 'warning';
157 // case this.SysFlowTaskOperationType.STOP:
158 // return 'danger'
159 // default:
160 // return 'primary';
161 // }
162 },
163 // 流程图预览清空
164 clearViewer (a) {
165 if (this.$refs.processCanvas) {
166 this.$refs.processCanvas.innerHTML = ''
167 }
168 if (this.bpmnViewer) {
169 this.bpmnViewer.destroy()
170 }
171 this.bpmnViewer = null
172 },
173 // 添加自定义箭头
174 addCustomDefs () {
175 const canvas = this.bpmnViewer.get('canvas')
176 const svg = canvas._svg
177 const customSuccessDefs = this.$refs.customSuccessDefs
178 const customFailDefs = this.$refs.customFailDefs
179 svg.appendChild(customSuccessDefs)
180 svg.appendChild(customFailDefs)
181 },
182 // 任务悬浮弹窗
183 onSelectElement (element) {
184 this.selectTaskId = undefined
185 this.dlgTitle = undefined
186
187 if (this.processNodeInfo == null || this.processNodeInfo.finishedTaskSet == null) return
188
189 if (element == null || this.processNodeInfo.finishedTaskSet.indexOf(element.id) === -1) {
190 return
191 }
192
193 this.selectTaskId = element.id
194 this.dlgTitle = element.businessObject ? element.businessObject.name : undefined
195 // 计算当前悬浮任务审批记录,如果记录为空不显示弹窗
196 this.taskCommentList = (this.allCommentList || []).filter(item => {
197 return item.taskDefKey === this.selectTaskId
198 })
199 this.dialogVisible = true
200 },
201 // 显示流程图
202 async importXML (xml) {
203 this.clearViewer('a')
204 if (xml != null && xml !== '') {
205 try {
206 this.bpmnViewer = new BpmnViewer({
207 additionalModules: [
208 // 移动整个画布
209 MoveCanvasModule
210 ],
211 container: this.$refs.processCanvas
212 })
213 // 任务节点悬浮事件
214 this.bpmnViewer.on('element.click', ({ element }) => {
215 this.onSelectElement(element)
216 })
217
218 this.isLoading = true
219 const c = await this.bpmnViewer.importXML(xml)
220 this.addCustomDefs()
221 } catch (e) {
222 // this.clearViewer('b')
223 } finally {
224 this.isLoading = false
225 this.setProcessStatus(this.processNodeInfo)
226 this.$nextTick(() => {
227 this.processReZoom()
228 })
229 }
230 }
231 },
232 // 设置流程图元素状态
233 setProcessStatus (processNodeInfo) {
234 this.processNodeInfo = processNodeInfo
235 if (this.isLoading || this.processNodeInfo == null || this.bpmnViewer == null) return
236 const { finishedTaskSet, rejectedTaskSet, unfinishedTaskSet, finishedSequenceFlowSet } = this.processNodeInfo
237 const canvas = this.bpmnViewer.get('canvas')
238 const elementRegistry = this.bpmnViewer.get('elementRegistry')
239 if (Array.isArray(finishedSequenceFlowSet)) {
240 finishedSequenceFlowSet.forEach(item => {
241 if (item != null) {
242 canvas.addMarker(item, 'success')
243 const element = elementRegistry.get(item)
244 const conditionExpression = element.businessObject.conditionExpression
245 if (conditionExpression) {
246 canvas.addMarker(item, 'condition-expression')
247 }
248 }
249 })
250 }
251 if (Array.isArray(finishedTaskSet)) {
252 finishedTaskSet.forEach(item => canvas.addMarker(item, 'success'))
253 }
254 if (Array.isArray(unfinishedTaskSet)) {
255 unfinishedTaskSet.forEach(item => canvas.addMarker(item, 'primary'))
256 }
257 if (Array.isArray(rejectedTaskSet)) {
258 rejectedTaskSet.forEach(item => {
259 if (item != null) {
260 const element = elementRegistry.get(item)
261 if (element.type.includes('Task')) {
262 canvas.addMarker(item, 'danger')
263 } else {
264 canvas.addMarker(item, 'warning')
265 }
266 }
267 })
268 }
269 }
270 }
271 }
272 </script>
...\ No newline at end of file ...\ No newline at end of file
1 <template> 1 <template>
2 <div v-if="!item.hidden"> 2 <div v-if="!item.hidden">
3 <template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow"> 3 <template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)">
4 <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)"> 4 <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
5 <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}"> 5 <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
6 <item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" class="menu-icon" /> 6 <item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title"
7 class="menu-icon" />
7 </el-menu-item> 8 </el-menu-item>
8 </app-link> 9 </app-link>
9 </template> 10 </template>
...@@ -12,14 +13,8 @@ ...@@ -12,14 +13,8 @@
12 <template slot="title"> 13 <template slot="title">
13 <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" /> 14 <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
14 </template> 15 </template>
15 <sidebar-item 16 <sidebar-item v-for="child in item.children" :key="child.path" :is-nest="true" :item="child"
16 v-for="child in item.children" 17 :base-path="resolvePath(child.path)" class="nest-menu" />
17 :key="child.path"
18 :is-nest="true"
19 :item="child"
20 :base-path="resolvePath(child.path)"
21 class="nest-menu"
22 />
23 </el-submenu> 18 </el-submenu>
24 </div> 19 </div>
25 </template> 20 </template>
...@@ -50,14 +45,14 @@ export default { ...@@ -50,14 +45,14 @@ export default {
50 default: '' 45 default: ''
51 } 46 }
52 }, 47 },
53 data() { 48 data () {
54 // To fix https://github.com/PanJiaChen/vue-admin-template/issues/237 49 // To fix https://github.com/PanJiaChen/vue-admin-template/issues/237
55 // TODO: refactor with render function 50 // TODO: refactor with render function
56 this.onlyOneChild = null 51 this.onlyOneChild = null
57 return {} 52 return {}
58 }, 53 },
59 methods: { 54 methods: {
60 hasOneShowingChild(children = [], parent) { 55 hasOneShowingChild (children = [], parent) {
61 const showingChildren = children.filter(item => { 56 const showingChildren = children.filter(item => {
62 if (item.hidden) { 57 if (item.hidden) {
63 return false 58 return false
...@@ -75,13 +70,13 @@ export default { ...@@ -75,13 +70,13 @@ export default {
75 70
76 // Show parent if there are no child router to display 71 // Show parent if there are no child router to display
77 if (showingChildren.length === 0) { 72 if (showingChildren.length === 0) {
78 this.onlyOneChild = { ... parent, path: '', noShowingChildren: true } 73 this.onlyOneChild = { ...parent, path: '', noShowingChildren: true }
79 return true 74 return true
80 } 75 }
81 76
82 return false 77 return false
83 }, 78 },
84 resolvePath(routePath) { 79 resolvePath (routePath) {
85 if (isExternal(routePath)) { 80 if (isExternal(routePath)) {
86 return routePath 81 return routePath
87 } 82 }
......
...@@ -5,9 +5,9 @@ ...@@ -5,9 +5,9 @@
5 :unique-opened="true" :active-text-color="variables.menuActiveText" :collapse-transition="false" 5 :unique-opened="true" :active-text-color="variables.menuActiveText" :collapse-transition="false"
6 mode="vertical"> 6 mode="vertical">
7 <!-- 权限菜单 --> 7 <!-- 权限菜单 -->
8 <!-- <sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" /> --> 8 <sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />
9 <!-- 菜单全部展示 --> 9 <!-- 菜单全部展示 -->
10 <sidebar-item v-for="route in asyncRoutes" :key="route.path" :item="route" :base-path="route.path" /> 10 <!-- <sidebar-item v-for="route in asyncRoutes" :key="route.path" :item="route" :base-path="route.path" /> -->
11 </el-menu> 11 </el-menu>
12 </el-scrollbar> 12 </el-scrollbar>
13 </div> 13 </div>
......
...@@ -20,17 +20,16 @@ router.beforeEach(async (to, from, next) => { ...@@ -20,17 +20,16 @@ router.beforeEach(async (to, from, next) => {
20 next() 20 next()
21 } else { 21 } else {
22 const { result: getMenuData } = await getMenuInfo() 22 const { result: getMenuData } = await getMenuInfo()
23 console.log(getMenuData); 23 const accessRoutes = await store.dispatch('permission/generateRoutes', getMenuData)
24 // const accessRoutes = await store.dispatch('permission/generateRoutes', getMenuData) 24 router.addRoutes(accessRoutes)
25 // router.addRoutes(accessRoutes) 25 console.log(router);
26 next() 26 next({ ...to, replace: true })
27 } 27 }
28 NProgress.done() 28 NProgress.done()
29 29
30 }) 30 })
31 router.afterEach(to => { 31 router.afterEach(to => {
32 // 解决刷新页面报404问题 32 // 解决刷新页面报404问题
33 sessionStorage.setItem('routerTo', to.fullPath)
34 Cookies.set("routerTo", to.fullPath) 33 Cookies.set("routerTo", to.fullPath)
35 NProgress.done() 34 NProgress.done()
36 }) 35 })
......
...@@ -25,7 +25,6 @@ export const constantRoutes = [ ...@@ -25,7 +25,6 @@ export const constantRoutes = [
25 component: () => import('@/views/error-page/404'), 25 component: () => import('@/views/error-page/404'),
26 hidden: true 26 hidden: true
27 }, 27 },
28 { path: '*', redirect: '/404', hidden: true },
29 // 业务流程框架 28 // 业务流程框架
30 { 29 {
31 path: '/workFrame', 30 path: '/workFrame',
...@@ -58,7 +57,7 @@ export const asyncRoutes = [ ...@@ -58,7 +57,7 @@ export const asyncRoutes = [
58 { 57 {
59 path: 'home', 58 path: 'home',
60 component: () => import('@/views/home/index'), 59 component: () => import('@/views/home/index'),
61 name: 'Dashboard', 60 name: 'home',
62 meta: { title: '工作台', icon: 'workbench', affix: true } 61 meta: { title: '工作台', icon: 'workbench', affix: true }
63 } 62 }
64 ] 63 ]
...@@ -273,7 +272,7 @@ export const asyncRoutes = [ ...@@ -273,7 +272,7 @@ export const asyncRoutes = [
273 const createRouter = () => 272 const createRouter = () =>
274 new Router({ 273 new Router({
275 scrollBehavior: () => ({ y: 0 }), 274 scrollBehavior: () => ({ y: 0 }),
276 routes: [...constantRoutes, ...asyncRoutes] 275 routes: [...constantRoutes]
277 }) 276 })
278 277
279 const router = createRouter() 278 const router = createRouter()
......
1 import { asyncRoutes, constantRoutes, resetRouter } from '@/router' 1 import { asyncRoutes, constantRoutes, resetRouter } from '@/router'
2 2 import asyncRouter from '@/utils/asyncRouter.js'
3 const state = { 3 const state = {
4 routes: [], 4 routes: [],
5 addRoutes: false, 5 addRoutes: false,
...@@ -8,26 +8,18 @@ const state = { ...@@ -8,26 +8,18 @@ const state = {
8 const mutations = { 8 const mutations = {
9 SET_ROUTES: (state, routes) => { 9 SET_ROUTES: (state, routes) => {
10 state.addRoutes = true 10 state.addRoutes = true
11 state.routes = constantRoutes.concat(routes) 11 state.routes = routes
12 }, 12 },
13 RESET_ROUTE: (state) => { 13 RESET_ROUTE: (state) => {
14 state.addRoutes = false 14 state.addRoutes = false
15 } 15 }
16 } 16 }
17
18 const actions = { 17 const actions = {
19 // 添加全部菜单 18 // 添加全部菜单
20 generateRoutes ({ commit }, getMenuInfo) { 19 generateRoutes ({ commit }, getMenuInfo) {
21 return new Promise(resolve => { 20 return new Promise(resolve => {
22 // 将路由树数据转成数组结构
23 let arr1 = []
24 dfs(_.cloneDeep(asyncRoutes), node => arr1.push(node))
25 _.each(arr1, i => {
26 i.parentId = i.parentId ? i.parentId : null
27 })
28 let permission_arr = _.intersectionBy(arr1, getMenuInfo, 'name')
29 // 将权限菜单数组转成路由树数据结构 21 // 将权限菜单数组转成路由树数据结构
30 let permission_tree = array2Tree(permission_arr, null) 22 let permission_tree = asyncRouter(getMenuInfo)
31 commit('SET_ROUTES', permission_tree) 23 commit('SET_ROUTES', permission_tree)
32 resolve(permission_tree) 24 resolve(permission_tree)
33 }) 25 })
......
1 import Layout from '@/layout'
2 export default function filterAsyncRouter (routers) {
3 routers.forEach(item => {
4 if (!item.children) {
5 delete item.children
6 delete item.redirect
7 }
8 if (!item.parentId) {
9 item.component = Layout
10 } else {
11 item.component = loadView(item.uri)
12 }
13 item.meta.icon = item.icon
14 if (item.children) {
15 item.children = filterAsyncRouter(item.children)
16 }
17 })
18 return routers
19 }
20 function loadView (view) {
21 return r => require.ensure([], () => r(require(`@/views${view}.vue`)))
22 }
...\ No newline at end of file ...\ No newline at end of file
...@@ -11,9 +11,9 @@ const service = axios.create({ ...@@ -11,9 +11,9 @@ const service = axios.create({
11 withCredentials: true, //是否允许跨域 11 withCredentials: true, //是否允许跨域
12 headers: { 12 headers: {
13 'Content-Type': 'application/json; charset=utf-8', 13 'Content-Type': 'application/json; charset=utf-8',
14 // 'Authorization': 'bearer AT-16-oqkOHiUSsDdFA-eAZ49k2rJQDTzQpClO' 14 'Authorization': 'bearer AT-16-oqkOHiUSsDdFA-eAZ49k2rJQDTzQpClO'
15 //token列表 15 //token列表
16 'Authorization': 'bearer AT-12-eRKHta5I8ZWftIU86sSyJ8rUkPhMvMJU' 16 // 'Authorization': 'bearer AT-12-eRKHta5I8ZWftIU86sSyJ8rUkPhMvMJU'
17 //renc:bearer AT-30-KHB4LXc8-CZXwBEyaFJa9lRmMTc5sHVI 17 //renc:bearer AT-30-KHB4LXc8-CZXwBEyaFJa9lRmMTc5sHVI
18 //tianh:bearer AT-33-3zFTGkhQ4eUv4nXvzAmbgN5RPZppzEY6 18 //tianh:bearer AT-33-3zFTGkhQ4eUv4nXvzAmbgN5RPZppzEY6
19 //zhangh:bearer AT-7-Tx8dlZH0LNRc33UjD1CX1xwa-1D7kQmQ 19 //zhangh:bearer AT-7-Tx8dlZH0LNRc33UjD1CX1xwa-1D7kQmQ
......