初版完成

master
Chengliang 1 year ago
parent 55ca09d4f0
commit adc2e374dc

@ -9,9 +9,11 @@
"preview": "vite preview"
},
"dependencies": {
"axios": "^1.6.4",
"dom-to-image": "^2.6.0",
"element-plus": "^2.4.4",
"html2pdf.js": "^0.10.1",
"js-cookie": "^3.0.5",
"vue": "^3.3.11",
"vue-router": "^4.2.5",
"vue3-tree-org": "^4.2.2"

@ -0,0 +1,16 @@
import request from "@/axios";
//人员组织架构图
export function selectResourceChart(){
return request.get('/sship/organization/chart/resource-tree')
}
//人员信息
export function selectPerson(params){
return request.get('/sship/organization/chart/person',{
params
})
}
//机能组织

@ -0,0 +1,33 @@
import axios from 'axios'
import Cookies from 'js-cookie'
import { tansParams } from "@/utils/custom"
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
const TokenKey = 'ecology_JSessionid=aaaTjPF0rg2oWfJEKdiZy; JSESSIONID=aaaTjPF0rg2oWfJEKdiZy; Systemlanguid=7; languageidweaver=7; loginuuids=1; loginidweaver=sysadmin;'
// 创建axios实例
const service = axios.create({
baseURL: '/api',
// 超时
timeout: 10000
})
// request拦截器
service.interceptors.request.use(config => {
// 是否需要设置 token
const isToken = (config.headers || {}).isToken === false
if (!isToken) {
//config.headers['Cookie'] = TokenKey // 让每个请求携带自定义token 请根据实际情况自行修改
}
// get请求映射params参数
if (config.method === 'get' && config.params) {
let url = config.url + '?' + tansParams(config.params);
url = url.slice(0, -1);
config.params = {};
config.url = url;
}
return config
}, error => {
Promise.reject(error)
})
export default service

@ -0,0 +1,72 @@
<template>
<el-dialog
v-model="centerDialogVisible"
title="人员信息"
width="60%"
align-center
>
<el-table :data="tableData" stripe style="width: 100%" height="300">
<el-table-column prop="lastname" label="姓名" />
<el-table-column prop="workcode" label="编号" />
<el-table-column prop="sex" label="性别" />
<el-table-column prop="manager" label="直接上级" />
<el-table-column prop="loginid" label="登录名" />
</el-table>
<template #footer>
<span class="dialog-footer">
<el-button type="primary" @click="centerDialogVisible = false">
关闭
</el-button>
</span>
</template>
</el-dialog>
</template>
<script>
import { ElDialog,ElButton,ElTable,ElMessage } from 'element-plus'
import {selectPerson} from '@/api/chart'
export default {
name: 'ViewDialog',
components: {
ElDialog,
ElButton,
ElTable
},
data() {
return {
centerDialogVisible:false,
tableData:[],
params:{
pid:'',
id:''
}
};
},
created() {
},
methods: {
openDialog(data){
this.params.id = data.id;
this.tableList();
},
tableList() {
selectPerson(this.params).then(res=>{
this.tableData = res.data.data;
this.centerDialogVisible = true;
})
.catch(err=>{
ElMessage.error(err.msg);
})
},
}
}
</script>
<style scoped>
.dialog-footer button:first-child {
margin-right: 10px;
}
</style>

@ -9,6 +9,7 @@ import 'element-plus/dist/index.css'
//document.title = 'org-chart';
const app = createApp(App)
app.use(router);
app.use(vue3TreeOrg);

@ -1,7 +1,10 @@
import { createRouter, createWebHashHistory } from "vue-router";
import ResourceChart from "../views/resource-chart.vue";
import OrganizationChart from "../views/organization-chart.vue";
const routes = [
{ name: 'resource-chart', path: "/resource-chart", component: ResourceChart },
{ name: 'organization-chart', path: "/organization-chart", component: OrganizationChart }
];
// 初始化路由

@ -0,0 +1,25 @@
/**
* 参数处理
* @param {*} params 参数
*/
export function tansParams(params) {
let result = ''
for (const propName of Object.keys(params)) {
const value = params[propName];
var part = encodeURIComponent(propName) + "=";
if (value !== null && typeof (value) !== "undefined") {
if (typeof value === 'object') {
for (const key of Object.keys(value)) {
if (value[key] !== null && typeof (value[key]) !== 'undefined') {
let params = propName + '[' + key + ']';
var subPart = encodeURIComponent(params) + "=";
result += subPart + encodeURIComponent(value[key]) + "&";
}
}
} else {
result += part + encodeURIComponent(value) + "&";
}
}
}
return result
}

@ -0,0 +1,128 @@
<template>
<div style="display: flex; padding: 10px;">
<div style="margin-right: 10px"><el-switch v-model="horizontal"></el-switch> 横向</div>
<div style="margin-right: 10px"><el-button @click="exportToPDF" type="primary">导出PDF</el-button></div>
<div style="margin-right: 10px"><el-button @click="exportImage" type="primary">导出图片</el-button></div>
</div>
<div id="tree-container" style="height: 800px;">
<vue3-tree-org
ref="treeChart"
:data="treeData"
center
:props="{children: 'childrens'}"
:horizontal="horizontal"
:collapsable="collapsable"
:label-style="style"
@on-expand="onExpand"
/>
</div>
</template>
<script>
import { ElSwitch, ElColorPicker, ElMessage } from 'element-plus'
import html2pdf from 'html2pdf.js'
import { ref } from 'vue'
import domToImage from 'dom-to-image';
export default {
name: "organization-chart",
components: {
ElSwitch,
ElColorPicker
},
setup() {
},
data() {
return {
treeData: {
"id":1,"label":"xxx科技有限公司",
"childrens":[
{
"id":2,"pid":1,"label":"产品研发部",
"childrens":[
{"id":6,"pid":2,"label":"禁止编辑节点"},
{"id":8,"pid":2,"label":"禁止拖拽节点"},
{"id":10,"pid":2,"label":"测试"}
]
},
{
"id":3,"pid":1,"label":"客服部",
"childrens":[
{"id":11,"pid":3,"label":"客服一部"},
{"id":12,"pid":3,"label":"客服二部"}
]
},
{"id":4,"pid":1,"label":"业务部"}
]
},
horizontal: false,
collapsable: true,
onlyOneNode: false,
expandAll: true,
disaled: false,
style: {
background: "#fff",
color: "#5e6d82",
},
};
},
created() {
this.toggleExpand(this.treeData, this.expandAll);
},
methods: {
exportImage() {
const treeOrgEl = this.$refs.treeChart.$el;
domToImage.toPng(treeOrgEl) // PNG
.then(function (dataURL) {
const link = document.createElement('a');
link.href = dataURL;
link.download = 'tree_image.png';
link.click();
link.remove();
})
.catch(function (error) {
console.error('导出图片出错:', error);
});
},
exportToPDF() {
debugger
const element = document.getElementById('tree-container') // TreeOrg
const options = {
filename: 'tree-structure.pdf', //
jsPDF: { format: 'letter' }
}
html2pdf().set(options).from(element).save();
},
onExpand(e, data) {
console.log(e, data);
},
onExpandAll(b) {
console.log(b)
},
expandChange() {
// this.toggleExpand(this.data, this.expandAll);
},
toggleExpand(data, val) {
if (Array.isArray(data)) {
data.forEach((item) => {
item.expand = val
if (item.childrens) {
this.toggleExpand(item.childrens, val);
}
});
} else {
data.expand = val
if (data.childrens) {
this.toggleExpand(data.childrens, val);
}
}
},
},
};
</script>

@ -4,65 +4,52 @@
<div style="margin-right: 10px"><el-button @click="exportToPDF" type="primary">导出PDF</el-button></div>
<div style="margin-right: 10px"><el-button @click="exportImage" type="primary">导出图片</el-button></div>
</div>
<div id="tree-container" style="height: 800px;">
<div id="tree-container" style="height: 600px;">
<vue3-tree-org
ref="treeChart"
:data="treeData"
center
:props="{children: 'childrens'}"
:define-menus="defineMenus"
:horizontal="horizontal"
:collapsable="collapsable"
:label-style="style"
@on-expand="onExpand"
@on-node-click="onNodeClick"
/>
</div>
<view-dialog ref="viewDialog"/>
</template>
<script>
import { ElSwitch, ElColorPicker, ElMessage } from 'element-plus'
import { ElSwitch, ElButton, ElMessage } from 'element-plus'
import html2pdf from 'html2pdf.js'
import { ref } from 'vue'
import domToImage from 'dom-to-image';
import {selectResourceChart} from '@/api/chart'
import ViewDialog from '@/components/ViewDialog.vue'
export default {
name: "resource-chart",
components: {
ElSwitch,
ElColorPicker
ViewDialog,
ElButton
},
setup() {
},
data() {
return {
treeData: {
"id":1,"label":"xxx科技有限公司",
"childrens":[
{
"id":2,"pid":1,"label":"产品研发部",
"childrens":[
{"id":6,"pid":2,"label":"禁止编辑节点"},
{"id":8,"pid":2,"label":"禁止拖拽节点"},
{"id":10,"pid":2,"label":"测试"}
]
},
{
"id":3,"pid":1,"label":"客服部",
"childrens":[
{"id":11,"pid":3,"label":"客服一部"},
{"id":12,"pid":3,"label":"客服二部"}
]
},
{"id":4,"pid":1,"label":"业务部"}
]
},
treeData:{},
horizontal: false,
collapsable: true,
onlyOneNode: false,
expandAll: true,
disaled: false,
defineMenus:[],
style: {
background: "#fff",
color: "#5e6d82",
@ -70,20 +57,23 @@
};
},
created() {
this.toggleExpand(this.treeData, this.expandAll);
selectResourceChart().then(res=>{
this.treeData = res.data.data;
this.toggleExpand(res.data.data, this.expandAll);
})
.catch(err=>{
ElMessage.error(err.msg);
})
},
methods: {
exportImage() {
const treeOrgEl = this.$refs.treeChart.$el; // vue3-tree-org
const treeOrgEl = this.$refs.treeChart.$el;
domToImage.toPng(treeOrgEl) // PNG
.then(function (dataURL) {
//
const link = document.createElement('a');
link.href = dataURL;
link.download = 'tree_image.png';
//
link.click();
//
link.remove();
})
.catch(function (error) {
@ -91,7 +81,6 @@
});
},
exportToPDF() {
debugger
const element = document.getElementById('tree-container') // TreeOrg
const options = {
filename: 'tree-structure.pdf', //
@ -106,7 +95,9 @@
onExpandAll(b) {
console.log(b)
},
onNodeClick(e, data) {
this.$refs.viewDialog.openDialog(data);
},
expandChange() {
// this.toggleExpand(this.data, this.expandAll);
},

@ -1,7 +1,24 @@
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path';
// https://vitejs.dev/config/
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
// 配置别名路径
'@': path.resolve(__dirname, './src'),
},
},
server: {
proxy: {
'/api': {
target: 'http://127.0.0.1:8089',
changeOrigin: true,
//rewrite: (path) => path.replace(/^\/api/, ''),
},
}
}
})

@ -372,11 +372,25 @@ async-validator@^4.2.5:
resolved "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz#c96ea3332a521699d0afaaceed510a54656c6339"
integrity sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
atob@^2.1.2:
version "2.1.2"
resolved "https://registry.npmmirror.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
axios@^1.6.4:
version "1.6.4"
resolved "https://registry.npmmirror.com/axios/-/axios-1.6.4.tgz#184ee1f63d412caffcf30d2c50982253c3ee86e0"
integrity sha512-heJnIs6N4aa1eSthhN9M5ioILu8Wi8vmQW9iHQ9NUvfkJb0lEEDUiIdQNAuBtfUt3FxReaKdpQA5DbmMOqzF/A==
dependencies:
follow-redirects "^1.15.4"
form-data "^4.0.0"
proxy-from-env "^1.1.0"
base64-arraybuffer@^1.0.2:
version "1.0.2"
resolved "https://registry.npmmirror.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz#1c37589a7c4b0746e34bd1feb951da2df01c1bdc"
@ -401,6 +415,13 @@ canvg@^3.0.6:
stackblur-canvas "^2.0.0"
svg-pathdata "^6.0.3"
combined-stream@^1.0.8:
version "1.0.8"
resolved "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
dependencies:
delayed-stream "~1.0.0"
core-js@^3.6.0, core-js@^3.6.5, core-js@^3.8.3:
version "3.35.0"
resolved "https://registry.npmmirror.com/core-js/-/core-js-3.35.0.tgz#58e651688484f83c34196ca13f099574ee53d6b4"
@ -423,6 +444,11 @@ dayjs@^1.11.3:
resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0"
integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
dom-to-image@^2.6.0:
version "2.6.0"
resolved "https://registry.npmmirror.com/dom-to-image/-/dom-to-image-2.6.0.tgz#8a503608088c87b1c22f9034ae032e1898955867"
@ -508,6 +534,20 @@ fflate@^0.4.8:
resolved "https://registry.npmmirror.com/fflate/-/fflate-0.4.8.tgz#f90b82aefbd8ac174213abb338bd7ef848f0f5ae"
integrity sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==
follow-redirects@^1.15.4:
version "1.15.4"
resolved "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.4.tgz#cdc7d308bf6493126b17ea2191ea0ccf3e535adf"
integrity sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==
form-data@^4.0.0:
version "4.0.0"
resolved "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
dependencies:
asynckit "^0.4.0"
combined-stream "^1.0.8"
mime-types "^2.1.12"
fsevents@~2.3.2, fsevents@~2.3.3:
version "2.3.3"
resolved "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6"
@ -530,6 +570,11 @@ html2pdf.js@^0.10.1:
html2canvas "^1.0.0"
jspdf "^2.3.1"
js-cookie@^3.0.5:
version "3.0.5"
resolved "https://registry.npmmirror.com/js-cookie/-/js-cookie-3.0.5.tgz#0b7e2fd0c01552c58ba86e0841f94dc2557dcdbc"
integrity sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==
jspdf@^2.3.1:
version "2.5.1"
resolved "https://registry.npmmirror.com/jspdf/-/jspdf-2.5.1.tgz#00c85250abf5447a05f3b32ab9935ab4a56592cc"
@ -572,6 +617,18 @@ memoize-one@^6.0.0:
resolved "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045"
integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==
mime-db@1.52.0:
version "1.52.0"
resolved "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
mime-types@^2.1.12:
version "2.1.35"
resolved "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
dependencies:
mime-db "1.52.0"
nanoid@^3.3.7:
version "3.3.7"
resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8"
@ -601,6 +658,11 @@ postcss@^8.4.32:
picocolors "^1.0.0"
source-map-js "^1.0.2"
proxy-from-env@^1.1.0:
version "1.1.0"
resolved "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==
raf@^3.4.1:
version "3.4.1"
resolved "https://registry.npmmirror.com/raf/-/raf-3.4.1.tgz#0742e99a4a6552f445d73e3ee0328af0ff1ede39"

Loading…
Cancel
Save