diff --git a/.eslintrc.js b/.eslintrc.js index 2005c1a4..4ca177e4 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -9,7 +9,9 @@ module.exports = { 'generator-star-spacing': 'off', // allow debugger during development 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off', - 'vue/no-parsing-error': [2, { 'x-invalid-end-tag': false }], + 'vue/no-parsing-error': [2, { + 'x-invalid-end-tag': false + }], 'no-undef': 'off', 'camelcase': 'off' }, diff --git a/package-lock.json b/package-lock.json index eb2c3e76..42cc71f1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11973,6 +11973,14 @@ "resolved": "https://registry.npmjs.org/v-click-outside-x/-/v-click-outside-x-3.5.6.tgz", "integrity": "sha512-41j5mdZ8NzGJM5Or0BTADKU1B0vBi5a29g9ieVNTorg3FTiep6zOXjZeLpMmSH/koon1JP6S5uvwI2OfSVCgSA==" }, + "v-org-tree": { + "version": "1.0.6", + "resolved": "http://registry.npm.taobao.org/v-org-tree/download/v-org-tree-1.0.6.tgz", + "integrity": "sha1-uh4EL9bExFb9/FmFtlvClFpAaWc=", + "requires": { + "clonedeep": "2.0.0" + } + }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", diff --git a/package.json b/package.json index 1dbe78c6..cbf3e6bc 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,7 @@ "simplemde": "^1.11.2", "sortablejs": "^1.7.0", "tree-table-vue": "^1.1.0", + "v-org-tree": "^1.0.6", "vue": "^2.5.10", "vue-i18n": "^7.8.0", "vue-router": "^3.0.1", diff --git a/src/api/data.js b/src/api/data.js index ca4286ab..fce9771c 100644 --- a/src/api/data.js +++ b/src/api/data.js @@ -35,3 +35,10 @@ export const uploadImg = formData => { data: formData }) } + +export const getOrgData = () => { + return axios.request({ + url: 'get_org_data', + method: 'get' + }) +} diff --git a/src/locale/lang/en-US.js b/src/locale/lang/en-US.js index d9153727..c6a0aa1c 100644 --- a/src/locale/lang/en-US.js +++ b/src/locale/lang/en-US.js @@ -38,5 +38,6 @@ export default { params: 'Params', cropper_page: 'Cropper', message_page: 'Message Center', - tree_table_page: 'Tree Table' + tree_table_page: 'Tree Table', + org_tree_page: 'Org Tree' } diff --git a/src/locale/lang/zh-CN.js b/src/locale/lang/zh-CN.js index 43937384..e6a9079b 100644 --- a/src/locale/lang/zh-CN.js +++ b/src/locale/lang/zh-CN.js @@ -38,5 +38,6 @@ export default { params: '动态路由', cropper_page: '图片裁剪', message_page: '消息中心', - tree_table_page: '树状表格' + tree_table_page: '树状表格', + org_tree_page: '组织结构树' } diff --git a/src/locale/lang/zh-TW.js b/src/locale/lang/zh-TW.js index fed4b1dd..70386743 100644 --- a/src/locale/lang/zh-TW.js +++ b/src/locale/lang/zh-TW.js @@ -38,5 +38,6 @@ export default { params: '動態路由', cropper_page: '圖片裁剪', message_page: '消息中心', - tree_table_page: '樹狀表格' + tree_table_page: '樹狀表格', + org_tree_page: '組織結構樹' } diff --git a/src/main.js b/src/main.js index 37180aaf..8da5b6ea 100644 --- a/src/main.js +++ b/src/main.js @@ -8,10 +8,13 @@ import iView from 'iview' import i18n from '@/locale' import config from '@/config' import importDirective from '@/directive' +import { directive as clickOutside } from 'v-click-outside-x' import installPlugin from '@/plugin' import './index.less' import '@/assets/icons/iconfont.css' import TreeTable from 'tree-table-vue' +import VOrgTree from 'v-org-tree' +import 'v-org-tree/dist/v-org-tree.css' // 实际打包时应该不引入mock /* eslint-disable */ if (process.env.NODE_ENV !== 'production') require('@/mock') @@ -20,6 +23,7 @@ Vue.use(iView, { i18n: (key, value) => i18n.t(key, value) }) Vue.use(TreeTable) +Vue.use(VOrgTree) /** * @description 注册admin内置插件 */ @@ -36,6 +40,7 @@ Vue.prototype.$config = config * 注册指令 */ importDirective(Vue) +Vue.directive('clickOutside', clickOutside) /* eslint-disable no-new */ new Vue({ diff --git a/src/mock/data.js b/src/mock/data.js index e0d36ae9..e2ee4400 100644 --- a/src/mock/data.js +++ b/src/mock/data.js @@ -1,5 +1,6 @@ import Mock from 'mockjs' import { doCustomTimes } from '@/libs/util' +import orgData from './data/org-data' const Random = Mock.Random export const getTableData = req => { @@ -28,3 +29,7 @@ export const getDragList = req => { export const uploadImage = req => { return Promise.resolve() } + +export const getOrgData = req => { + return orgData +} diff --git a/src/mock/data/org-data.js b/src/mock/data/org-data.js new file mode 100644 index 00000000..c2588ae9 --- /dev/null +++ b/src/mock/data/org-data.js @@ -0,0 +1,45 @@ +export default { + id: 0, + label: 'XXX科技有限公司', + children: [ + { + id: 2, + label: '产品研发部', + children: [ + { + id: 5, + label: '研发-前端' + }, { + id: 6, + label: '研发-后端' + }, { + id: 9, + label: 'UI设计' + }, { + id: 10, + label: '产品经理' + } + ] + }, + { + id: 3, + label: '销售部', + children: [ + { + id: 7, + label: '销售一部' + }, { + id: 8, + label: '销售二部' + } + ] + }, + { + id: 4, + label: '财务部' + }, { + id: 11, + label: 'HR人事' + } + ] +} diff --git a/src/mock/index.js b/src/mock/index.js index 5c1f32ed..503e3cdb 100644 --- a/src/mock/index.js +++ b/src/mock/index.js @@ -1,6 +1,6 @@ import Mock from 'mockjs' import { login, logout, getUserInfo } from './login' -import { getTableData, getDragList, uploadImage } from './data' +import { getTableData, getDragList, uploadImage, getOrgData } from './data' import { getMessageInit, getContentByMsgId, hasRead, removeReaded, restoreTrash, messageCount } from './user' // 配置Ajax请求延时,可用来测试网络延迟大时项目中一些效果 @@ -22,5 +22,6 @@ Mock.mock(/\/message\/has_read/, hasRead) Mock.mock(/\/message\/remove_readed/, removeReaded) Mock.mock(/\/message\/restore/, restoreTrash) Mock.mock(/\/message\/count/, messageCount) +Mock.mock(/\/get_org_data/, getOrgData) export default Mock diff --git a/src/router/routers.js b/src/router/routers.js index a73ae86c..325a7493 100644 --- a/src/router/routers.js +++ b/src/router/routers.js @@ -125,6 +125,15 @@ export default [ }, component: () => import('@/view/components/drag-list/drag-list.vue') }, + { + path: 'org_tree_page', + name: 'org_tree_page', + meta: { + icon: 'ios-people', + title: '组织结构树' + }, + component: () => import('@/view/components/org-tree') + }, { path: 'tree_table_page', name: 'tree_table_page', diff --git a/src/view/components/org-tree/components/org-view.vue b/src/view/components/org-tree/components/org-view.vue new file mode 100644 index 00000000..4b255788 --- /dev/null +++ b/src/view/components/org-tree/components/org-view.vue @@ -0,0 +1,174 @@ + + + + + diff --git a/src/view/components/org-tree/components/zoom-controller.vue b/src/view/components/org-tree/components/zoom-controller.vue new file mode 100644 index 00000000..e7654a8d --- /dev/null +++ b/src/view/components/org-tree/components/zoom-controller.vue @@ -0,0 +1,81 @@ + + + + + diff --git a/src/view/components/org-tree/index.less b/src/view/components/org-tree/index.less new file mode 100644 index 00000000..1a7f4761 --- /dev/null +++ b/src/view/components/org-tree/index.less @@ -0,0 +1,75 @@ +@wrapper: ~'department'; +.percent-100 { + width: 100%; + height: 100%; +} +.@{wrapper}-outer { + .percent-100; + overflow: hidden; + .tip-box{ + position: absolute; + left: 20px; + top: 20px; + z-index: 12; + } + .zoom-box { + position: absolute; + right: 30px; + bottom: 30px; + z-index: 2; + } + .view-box { + position: absolute; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 1; + cursor: move; + .org-tree-drag-wrapper { + width: 100%; + height: 100%; + } + .org-tree-wrapper { + display: inline-block; + position: absolute; + left: 50%; + top: 50%; + transition: transform 0.2s ease-out; + .org-tree-node-label { + box-shadow: 0px 2px 12px 0px rgba(143, 154, 165, 0.4); + border-radius: 4px; + .org-tree-node-label-inner { + padding: 0; + .custom-org-node { + padding: 14px 41px; + background: #738699; + user-select: none; + word-wrap: none; + white-space: nowrap; + border-radius: 4px; + color: #ffffff; + font-size: 14px; + font-weight: 500; + line-height: 20px; + transition: background 0.1s ease-in; + cursor: default; + &:hover { + background: #5d6c7b; + transition: background 0.1s ease-in; + } + &.has-children-label { + cursor: pointer; + } + .context-menu{ + position: absolute; + right: -10px; + bottom: 20px; + z-index: 10; + } + } + } + } + } + } +} diff --git a/src/view/components/org-tree/index.vue b/src/view/components/org-tree/index.vue new file mode 100644 index 00000000..8e6c61a4 --- /dev/null +++ b/src/view/components/org-tree/index.vue @@ -0,0 +1,77 @@ + + + + +