Skip to content

Commit e78f77f

Browse files
committed
新增组织结构树页面
1 parent 5e345e0 commit e78f77f

File tree

16 files changed

+498
-5
lines changed

16 files changed

+498
-5
lines changed

.eslintrc.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ module.exports = {
99
'generator-star-spacing': 'off',
1010
// allow debugger during development
1111
'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off',
12-
'vue/no-parsing-error': [2, { 'x-invalid-end-tag': false }],
12+
'vue/no-parsing-error': [2, {
13+
'x-invalid-end-tag': false
14+
}],
1315
'no-undef': 'off',
1416
'camelcase': 'off'
1517
},

package-lock.json

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"simplemde": "^1.11.2",
2626
"sortablejs": "^1.7.0",
2727
"tree-table-vue": "^1.1.0",
28+
"v-org-tree": "^1.0.6",
2829
"vue": "^2.5.10",
2930
"vue-i18n": "^7.8.0",
3031
"vue-router": "^3.0.1",

src/api/data.js

+7
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,10 @@ export const uploadImg = formData => {
3535
data: formData
3636
})
3737
}
38+
39+
export const getOrgData = () => {
40+
return axios.request({
41+
url: 'get_org_data',
42+
method: 'get'
43+
})
44+
}

src/locale/lang/en-US.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,6 @@ export default {
3838
params: 'Params',
3939
cropper_page: 'Cropper',
4040
message_page: 'Message Center',
41-
tree_table_page: 'Tree Table'
41+
tree_table_page: 'Tree Table',
42+
org_tree_page: 'Org Tree'
4243
}

src/locale/lang/zh-CN.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,6 @@ export default {
3838
params: '动态路由',
3939
cropper_page: '图片裁剪',
4040
message_page: '消息中心',
41-
tree_table_page: '树状表格'
41+
tree_table_page: '树状表格',
42+
org_tree_page: '组织结构树'
4243
}

src/locale/lang/zh-TW.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -38,5 +38,6 @@ export default {
3838
params: '動態路由',
3939
cropper_page: '圖片裁剪',
4040
message_page: '消息中心',
41-
tree_table_page: '樹狀表格'
41+
tree_table_page: '樹狀表格',
42+
org_tree_page: '組織結構樹'
4243
}

src/main.js

+5
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,13 @@ import iView from 'iview'
88
import i18n from '@/locale'
99
import config from '@/config'
1010
import importDirective from '@/directive'
11+
import { directive as clickOutside } from 'v-click-outside-x'
1112
import installPlugin from '@/plugin'
1213
import './index.less'
1314
import '@/assets/icons/iconfont.css'
1415
import TreeTable from 'tree-table-vue'
16+
import VOrgTree from 'v-org-tree'
17+
import 'v-org-tree/dist/v-org-tree.css'
1518
// 实际打包时应该不引入mock
1619
/* eslint-disable */
1720
if (process.env.NODE_ENV !== 'production') require('@/mock')
@@ -20,6 +23,7 @@ Vue.use(iView, {
2023
i18n: (key, value) => i18n.t(key, value)
2124
})
2225
Vue.use(TreeTable)
26+
Vue.use(VOrgTree)
2327
/**
2428
* @description 注册admin内置插件
2529
*/
@@ -36,6 +40,7 @@ Vue.prototype.$config = config
3640
* 注册指令
3741
*/
3842
importDirective(Vue)
43+
Vue.directive('clickOutside', clickOutside)
3944

4045
/* eslint-disable no-new */
4146
new Vue({

src/mock/data.js

+5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Mock from 'mockjs'
22
import { doCustomTimes } from '@/libs/util'
3+
import orgData from './data/org-data'
34
const Random = Mock.Random
45

56
export const getTableData = req => {
@@ -28,3 +29,7 @@ export const getDragList = req => {
2829
export const uploadImage = req => {
2930
return Promise.resolve()
3031
}
32+
33+
export const getOrgData = req => {
34+
return orgData
35+
}

src/mock/data/org-data.js

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
export default {
2+
id: 0,
3+
label: 'XXX科技有限公司',
4+
children: [
5+
{
6+
id: 2,
7+
label: '产品研发部',
8+
children: [
9+
{
10+
id: 5,
11+
label: '研发-前端'
12+
}, {
13+
id: 6,
14+
label: '研发-后端'
15+
}, {
16+
id: 9,
17+
label: 'UI设计'
18+
}, {
19+
id: 10,
20+
label: '产品经理'
21+
}
22+
]
23+
},
24+
{
25+
id: 3,
26+
label: '销售部',
27+
children: [
28+
{
29+
id: 7,
30+
label: '销售一部'
31+
}, {
32+
id: 8,
33+
label: '销售二部'
34+
}
35+
]
36+
},
37+
{
38+
id: 4,
39+
label: '财务部'
40+
}, {
41+
id: 11,
42+
label: 'HR人事'
43+
}
44+
]
45+
}

src/mock/index.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import Mock from 'mockjs'
22
import { login, logout, getUserInfo } from './login'
3-
import { getTableData, getDragList, uploadImage } from './data'
3+
import { getTableData, getDragList, uploadImage, getOrgData } from './data'
44
import { getMessageInit, getContentByMsgId, hasRead, removeReaded, restoreTrash, messageCount } from './user'
55

66
// 配置Ajax请求延时,可用来测试网络延迟大时项目中一些效果
@@ -22,5 +22,6 @@ Mock.mock(/\/message\/has_read/, hasRead)
2222
Mock.mock(/\/message\/remove_readed/, removeReaded)
2323
Mock.mock(/\/message\/restore/, restoreTrash)
2424
Mock.mock(/\/message\/count/, messageCount)
25+
Mock.mock(/\/get_org_data/, getOrgData)
2526

2627
export default Mock

src/router/routers.js

+9
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,15 @@ export default [
125125
},
126126
component: () => import('@/view/components/drag-list/drag-list.vue')
127127
},
128+
{
129+
path: 'org_tree_page',
130+
name: 'org_tree_page',
131+
meta: {
132+
icon: 'ios-people',
133+
title: '组织结构树'
134+
},
135+
component: () => import('@/view/components/org-tree')
136+
},
128137
{
129138
path: 'tree_table_page',
130139
name: 'tree_table_page',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
<template>
2+
<div
3+
ref="dragWrapper"
4+
class="org-tree-drag-wrapper"
5+
@mousedown="mousedownView"
6+
@contextmenu="handleDocumentContextmenu"
7+
>
8+
<div class="org-tree-wrapper" :style="orgTreeStyle">
9+
<v-org-tree
10+
v-if="data"
11+
:data="data"
12+
:node-render="nodeRender"
13+
:expand-all="true"
14+
@on-node-click="handleNodeClick"
15+
collapsable
16+
></v-org-tree>
17+
</div>
18+
</div>
19+
</template>
20+
21+
<script>
22+
import { on, off } from '@/libs/tools'
23+
const menuList = [
24+
{
25+
key: 'edit',
26+
label: '编辑部门'
27+
},
28+
{
29+
key: 'detail',
30+
label: '查看部门'
31+
},
32+
{
33+
key: 'new',
34+
label: '新增子部门'
35+
},
36+
{
37+
key: 'delete',
38+
label: '删除部门'
39+
}
40+
]
41+
export default {
42+
name: 'OrgView',
43+
props: {
44+
zoomHandled: {
45+
type: Number,
46+
default: 1
47+
},
48+
data: Object
49+
},
50+
data () {
51+
return {
52+
currentContextMenuId: '',
53+
orgTreeOffsetLeft: 0,
54+
orgTreeOffsetTop: 0,
55+
initPageX: 0,
56+
initPageY: 0,
57+
oldMarginLeft: 0,
58+
oldMarginTop: 0,
59+
canMove: false
60+
}
61+
},
62+
computed: {
63+
orgTreeStyle () {
64+
return {
65+
transform: `translate(-50%, -50%) scale(${this.zoomHandled}, ${
66+
this.zoomHandled
67+
})`,
68+
marginLeft: `${this.orgTreeOffsetLeft}px`,
69+
marginTop: `${this.orgTreeOffsetTop}px`
70+
}
71+
}
72+
},
73+
methods: {
74+
handleNodeClick (e, data, expand) {
75+
expand()
76+
},
77+
closeMenu () {
78+
this.currentContextMenuId = ''
79+
},
80+
getBgColor (data) {
81+
return this.currentContextMenuId === data.id
82+
? data.isRoot
83+
? '#0d7fe8'
84+
: '#5d6c7b'
85+
: ''
86+
},
87+
nodeRender (h, data) {
88+
return (
89+
<div
90+
class={[
91+
'custom-org-node',
92+
data.children && data.children.length ? 'has-children-label' : ''
93+
]}
94+
on-mousedown={event => event.stopPropagation()}
95+
on-contextmenu={this.contextmenu.bind(this, data)}
96+
>
97+
{data.label}
98+
<dropdown
99+
trigger="custom"
100+
class="context-menu"
101+
visible={this.currentContextMenuId === data.id}
102+
nativeOn-click={this.handleDropdownClick}
103+
on-on-click={this.handleContextMenuClick.bind(this, data)}
104+
style={{
105+
transform: `scale(${1 / this.zoomHandled}, ${1 /
106+
this.zoomHandled})`
107+
}}
108+
v-click-outside={this.closeMenu}
109+
>
110+
<dropdown-menu slot="list">
111+
{menuList.map(item => {
112+
return (
113+
<dropdown-item name={item.key}>{item.label}</dropdown-item>
114+
)
115+
})}
116+
</dropdown-menu>
117+
</dropdown>
118+
</div>
119+
)
120+
},
121+
contextmenu (data, $event) {
122+
let event = $event || window.event
123+
event.preventDefault
124+
? event.preventDefault()
125+
: (event.returnValue = false)
126+
this.currentContextMenuId = data.id
127+
},
128+
setDepartmentData (data) {
129+
data.isRoot = true
130+
this.departmentData = data
131+
},
132+
mousedownView (event) {
133+
this.canMove = true
134+
this.initPageX = event.pageX
135+
this.initPageY = event.pageY
136+
this.oldMarginLeft = this.orgTreeOffsetLeft
137+
this.oldMarginTop = this.orgTreeOffsetTop
138+
on(document, 'mousemove', this.mousemoveView)
139+
on(document, 'mouseup', this.mouseupView)
140+
},
141+
mousemoveView (event) {
142+
if (!this.canMove) return
143+
const { pageX, pageY } = event
144+
this.orgTreeOffsetLeft = this.oldMarginLeft + pageX - this.initPageX
145+
this.orgTreeOffsetTop = this.oldMarginTop + pageY - this.initPageY
146+
},
147+
mouseupView () {
148+
this.canMove = false
149+
off(document, 'mousemove', this.mousemoveView)
150+
off(document, 'mouseup', this.mouseupView)
151+
},
152+
handleDropdownClick (event) {
153+
event.stopPropagation()
154+
},
155+
handleDocumentContextmenu () {
156+
this.canMove = false
157+
},
158+
handleContextMenuClick (data, key) {
159+
this.$emit('on-menu-click', { data, key })
160+
}
161+
},
162+
mounted () {
163+
on(document, 'mousedown', this.mousedownView)
164+
on(document, 'contextmenu', this.handleDocumentContextmenu)
165+
},
166+
beforeDestroy () {
167+
off(document, 'mousedown', this.mousedownView)
168+
off(document, 'contextmenu', this.handleDocumentContextmenu)
169+
}
170+
}
171+
</script>
172+
173+
<style>
174+
</style>

0 commit comments

Comments
 (0)