pull/1/head
z 2024-01-05 18:02:22 +08:00
parent 1fc7e96f0d
commit b5861440f2
4 changed files with 187 additions and 1 deletions

62
package-lock.json generated
View File

@ -23,6 +23,7 @@
"pinia-plugin-persistedstate": "^3.2.1",
"qrcode": "^1.5.3",
"qs": "^6.11.2",
"relation-graph": "^2.1.24",
"throttle-debounce": "^5.0.0",
"v-viewer": "^3.0.11",
"vue": "^3.4.3",
@ -1936,6 +1937,14 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"node_modules/base64-arraybuffer": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
"integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
"engines": {
"node": ">= 0.6.0"
}
},
"node_modules/binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
@ -2216,6 +2225,14 @@
"node": ">= 8"
}
},
"node_modules/css-line-break": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/css-line-break/-/css-line-break-2.1.0.tgz",
"integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
@ -3473,6 +3490,18 @@
"node": ">= 0.4"
}
},
"node_modules/html2canvas": {
"version": "1.4.1",
"resolved": "https://registry.npmmirror.com/html2canvas/-/html2canvas-1.4.1.tgz",
"integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
"dependencies": {
"css-line-break": "^2.1.0",
"text-segmentation": "^1.0.3"
},
"engines": {
"node": ">=8.0.0"
}
},
"node_modules/ignore": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.0.tgz",
@ -4632,6 +4661,15 @@
"url": "https://github.com/sponsors/mysticatea"
}
},
"node_modules/relation-graph": {
"version": "2.1.24",
"resolved": "https://registry.npmmirror.com/relation-graph/-/relation-graph-2.1.24.tgz",
"integrity": "sha512-W9eM2Ph8libTN1GeFrmVW8lYFW5wEZdeXrfliT+l1Mc6nBdGEojT+qXeiUSK0yhjhmilrD+yW1hx5d607/15Hw==",
"dependencies": {
"html2canvas": "^1.4.1",
"screenfull": "^5.1.0"
}
},
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
@ -4784,6 +4822,14 @@
"node": ">=14.0.0"
}
},
"node_modules/screenfull": {
"version": "5.2.0",
"resolved": "https://registry.npmmirror.com/screenfull/-/screenfull-5.2.0.tgz",
"integrity": "sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/scule": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/scule/-/scule-1.1.1.tgz",
@ -5009,6 +5055,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/text-segmentation": {
"version": "1.0.3",
"resolved": "https://registry.npmmirror.com/text-segmentation/-/text-segmentation-1.0.3.tgz",
"integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
"dependencies": {
"utrie": "^1.0.2"
}
},
"node_modules/text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@ -5342,6 +5396,14 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"dev": true
},
"node_modules/utrie": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/utrie/-/utrie-1.0.2.tgz",
"integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
"dependencies": {
"base64-arraybuffer": "^1.0.2"
}
},
"node_modules/v-viewer": {
"version": "3.0.11",
"resolved": "https://registry.npmjs.org/v-viewer/-/v-viewer-3.0.11.tgz",

View File

@ -25,6 +25,7 @@
"pinia-plugin-persistedstate": "^3.2.1",
"qrcode": "^1.5.3",
"qs": "^6.11.2",
"relation-graph": "^2.1.24",
"throttle-debounce": "^5.0.0",
"v-viewer": "^3.0.11",
"vue": "^3.4.3",

View File

@ -0,0 +1,112 @@
<template>
<el-dialog v-model="visible" title="组织机构结构图" width="80%">
<div style="height: calc(100vh - 200px)">
<RelationGraph ref="relationGraphRef" :options="graphOptions" />
</div>
</el-dialog>
</template>
<script setup>
import { useVModel } from "@vueuse/core";
import RelationGraph from "relation-graph/vue3";
import { nextTick, ref, watchEffect } from "vue";
const props = defineProps({
visible: {
type: Boolean,
required: true,
default: false,
},
treeData: {
type: Array,
required: true,
default: () => [],
},
});
const emits = defineEmits(["update:visible"]);
const visible = useVModel(props, "visible", emits);
const relationGraphRef = ref(null);
const graphOptions = ref({
disableDragNode: "false",
layouts: [
{
label: "中心",
layoutName: "tree",
layoutClassName: "seeks-layout-center",
defaultJunctionPoint: "border",
defaultNodeShape: 0,
defaultLineShape: 1,
min_per_width: 40,
max_per_width: 70,
min_per_height: 200,
},
],
buttonloading: false,
defaultLineMarker: {
markerWidth: 12,
markerHeight: 12,
refX: 6,
refY: 6,
data: "M2,2 L10,6 L2,10 L6,6 L2,2",
},
defaultNodeShape: 1,
defaultLineShape: 2,
defaultJunctionPoint: "tb",
defaultNodeBorderWidth: 0,
backgroundColor: "#08163b",
defaultLineColor: "rgba(0, 186, 189, 1)",
defaultNodeColor: "rgba(0, 206, 209, 1)",
defaultNodeHeight: 150,
defaultNodeWidth: 60,
});
const fnRecursion = (data) => {
let arr = [];
for (let i = 0; i < data.length; i++) {
if (data[i].nodes && data[i].nodes.length > 0) {
arr.push(data[i]);
arr = arr.concat(fnRecursion(data[i].nodes));
} else {
arr.push(data[i]);
}
}
return arr;
};
const fnSeeksGraph = async () => {
await nextTick();
const treeData = fnRecursion(props.treeData);
const __graph_json_data = {
rootId: props.treeData[0].name,
nodes: [],
links: [],
};
for (let i = 0; i < treeData.length; i++) {
if (i === 0) {
__graph_json_data.nodes.push({
id: treeData[i].name,
text: treeData[i].name,
width: 150,
height: 60,
});
} else {
__graph_json_data.nodes.push({
id: treeData[i].name,
text: treeData[i].name,
});
}
for (let j = 0; j < treeData.length; j++) {
if (treeData[i].id === treeData[j].pId) {
__graph_json_data.links.push({
from: treeData[i].name,
to: treeData[j].name,
});
}
}
}
relationGraphRef.value.setJsonData(__graph_json_data, () => {});
};
watchEffect(() => {
if (visible.value) fnSeeksGraph();
});
</script>
<style scoped lang="scss"></style>

View File

@ -21,7 +21,12 @@
/>
</el-col>
<el-col :span="19">
<el-button class="mb-10">结构图</el-button>
<el-button
class="mb-10"
@click="data.structuralDiagramVisible = true"
>
结构图
</el-button>
<layout-table
:data="list"
v-model:pagination="pagination"
@ -86,6 +91,10 @@
</el-col>
</el-row>
</layout-card>
<structural-diagram
v-model:visible="data.structuralDiagramVisible"
:tree-data="data.treeData"
/>
</div>
</template>
@ -102,6 +111,7 @@ import { onBeforeRouteUpdate, useRoute, useRouter } from "vue-router";
import { ArrowRight } from "@element-plus/icons-vue";
import { debounce } from "throttle-debounce";
import { ElMessage, ElMessageBox } from "element-plus";
import StructuralDiagram from "./components/structural_diagram.vue";
const router = useRouter();
const route = useRoute();
@ -121,6 +131,7 @@ const { list, pagination, fnGetData, fnResetPagination } = useListData(
);
const data = reactive({
treeData: [],
structuralDiagramVisible: false,
});
watch(filterText, (val) => {
treeRef.value.filter(val);