first commit
This commit is contained in:
commit
eb2f504652
32490 changed files with 5731109 additions and 0 deletions
23
node_modules/bma-org-chart/README.md
generated
vendored
Normal file
23
node_modules/bma-org-chart/README.md
generated
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# Org Chart
|
||||
|
||||
## วิธีใช้
|
||||
|
||||
```
|
||||
// import Org Chart Component
|
||||
import { OrgChart } from 'org-chart'
|
||||
import 'org-chart/org-chart.css' // or import 'org-chart/dist/style.css'
|
||||
|
||||
// import Data from static file or API
|
||||
import chartData from '@/assets/orgChartData'
|
||||
const dataSource = ref(chartData)
|
||||
|
||||
// onClick Event
|
||||
const chartClick = (data: any) => {
|
||||
console.log(data.value)
|
||||
}
|
||||
|
||||
<OrgChart
|
||||
:dataSource="data"
|
||||
@onElementClick="chartClick"
|
||||
/>
|
||||
```
|
||||
11
node_modules/bma-org-chart/dist/components/OrgChart.vue.d.ts
generated
vendored
Normal file
11
node_modules/bma-org-chart/dist/components/OrgChart.vue.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
declare const _sfc_main: import("vue").DefineComponent<{
|
||||
dataSource: ObjectConstructor;
|
||||
}, {
|
||||
savePNG: (scale?: number) => Promise<void>;
|
||||
savePDF: (scale?: number) => Promise<void>;
|
||||
}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, "onElementClick"[], "onElementClick", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
|
||||
dataSource: ObjectConstructor;
|
||||
}>> & {
|
||||
onOnElementClick?: ((...args: any[]) => any) | undefined;
|
||||
}, {}>;
|
||||
export default _sfc_main;
|
||||
6
node_modules/bma-org-chart/dist/components/OrgChartNode.vue.d.ts
generated
vendored
Normal file
6
node_modules/bma-org-chart/dist/components/OrgChartNode.vue.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
declare const _sfc_main: import("vue").DefineComponent<{
|
||||
dataSource: ObjectConstructor;
|
||||
}, {}, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
|
||||
dataSource: ObjectConstructor;
|
||||
}>>, {}>;
|
||||
export default _sfc_main;
|
||||
13898
node_modules/bma-org-chart/dist/index-02b08cd7.js
generated
vendored
Normal file
13898
node_modules/bma-org-chart/dist/index-02b08cd7.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
2
node_modules/bma-org-chart/dist/index.d.ts
generated
vendored
Normal file
2
node_modules/bma-org-chart/dist/index.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
import OrgChart from './components/OrgChart.vue';
|
||||
export { OrgChart };
|
||||
5768
node_modules/bma-org-chart/dist/index.es-19c70e5e.js
generated
vendored
Normal file
5768
node_modules/bma-org-chart/dist/index.es-19c70e5e.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
6
node_modules/bma-org-chart/dist/org-chart.js
generated
vendored
Normal file
6
node_modules/bma-org-chart/dist/org-chart.js
generated
vendored
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
import { O as p } from "./index-02b08cd7.js";
|
||||
import "vue";
|
||||
import "pinia";
|
||||
export {
|
||||
p as OrgChart
|
||||
};
|
||||
283
node_modules/bma-org-chart/dist/org-chart.umd.cjs
generated
vendored
Normal file
283
node_modules/bma-org-chart/dist/org-chart.umd.cjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
470
node_modules/bma-org-chart/dist/purify.es-4f9a0368.js
generated
vendored
Normal file
470
node_modules/bma-org-chart/dist/purify.es-4f9a0368.js
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
10
node_modules/bma-org-chart/dist/stores/OrgStore.d.ts
generated
vendored
Normal file
10
node_modules/bma-org-chart/dist/stores/OrgStore.d.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
export declare const useOrgStore: import("pinia").StoreDefinition<"StructStore", import("pinia")._UnwrapAll<Pick<{
|
||||
dataSource: import("vue").Ref<any>;
|
||||
selectedElement: import("vue").Ref<any>;
|
||||
}, "dataSource" | "selectedElement">>, Pick<{
|
||||
dataSource: import("vue").Ref<any>;
|
||||
selectedElement: import("vue").Ref<any>;
|
||||
}, never>, Pick<{
|
||||
dataSource: import("vue").Ref<any>;
|
||||
selectedElement: import("vue").Ref<any>;
|
||||
}, never>>;
|
||||
1
node_modules/bma-org-chart/dist/style.css
generated
vendored
Normal file
1
node_modules/bma-org-chart/dist/style.css
generated
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
.node-container[data-v-83904042]{border-collapse:collapse;margin:0 auto}.root-node td[data-v-83904042]{text-align:center;width:100%}.element-container[data-v-83904042]{background:white;border:1px solid #f0efef;border-radius:5px;box-sizing:border-box;box-shadow:0 20px 20px -20px #a3a5ae36;display:inline-flex;flex-direction:column;position:relative;margin:0 1px 2px;min-width:9rem;text-align:left;transition-duration:.25s}.root-element[data-v-83904042]{border-top:3px solid hsl(212,86%,64%)}.child-element[data-v-83904042]{border-top:3px solid hsl(180,62%,55%)}.section-list[data-v-83904042]{font-family:sans-serif;display:flex;align-items:center;padding:15px 20px;bottom:0}.section-list .column-content[data-v-83904042]{min-width:120px}.section-list .column-content .header[data-v-83904042]{color:#334454;font-size:1.1rem;font-weight:700!important;line-height:1.5rem;margin:0}.section-list .column-content .subheader[data-v-83904042],.section-list .column-content .caption[data-v-83904042]{color:#7a7d89;font-size:.9rem;padding-top:5px;margin:0}.section-list .column-content .caption[data-v-83904042]{font-size:1rem;font-weight:600!important}.section-list .column-avatar img[data-v-83904042]{background-color:#efefef;width:50px;height:50px;border-radius:50%;object-position:center;object-fit:cover;margin-right:10px}.section-list .column-side[data-v-83904042]{margin-left:20px}.section-list .column-side .side-button[data-v-83904042]{background-image:url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IS0tIFVwbG9hZGVkIHRvOiBTVkcgUmVwbywgd3d3LnN2Z3JlcG8uY29tLCBHZW5lcmF0b3I6IFNWRyBSZXBvIE1peGVyIFRvb2xzIC0tPgo8c3ZnIHdpZHRoPSI4MDBweCIgaGVpZ2h0PSI4MDBweCIgdmlld0JveD0iMCAwIDE2IDE2IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiMwMDAwMDAiIGNsYXNzPSJiaSBiaS1jYXJldC1kb3duLWZpbGwiPgogIDxwYXRoIGQ9Ik03LjI0NyAxMS4xNCAyLjQ1MSA1LjY1OEMxLjg4NSA1LjAxMyAyLjM0NSA0IDMuMjA0IDRoOS41OTJhMSAxIDAgMCAxIC43NTMgMS42NTlsLTQuNzk2IDUuNDhhMSAxIDAgMCAxLTEuNTA2IDB6Ii8+Cjwvc3ZnPg==);background-position:center center;background-repeat:no-repeat;background-size:16px;border:1px solid white;border-radius:50%;cursor:pointer;color:#717171;width:32px;height:32px;text-align:center}.section-list .column-side .oncollapse[data-v-83904042]{transform:rotate(90deg);transition:all .3s ease-out}.section-list .column-side .onexpand[data-v-83904042]{transform:rotate(0);transition:all .3s ease-out}.node-children[data-v-83904042]{vertical-align:top}.nodeline[data-v-83904042]{height:1.75rem}.nodeline-down[data-v-83904042]{background:#D2D6DB;margin-left:auto;margin-right:auto;margin-top:-1rem;margin-bottom:-1rem;height:1.9rem;width:.125rem;float:none}.nodeline-top[data-v-83904042]{border-top-color:#d2d6db;border-top-style:solid;border-top-width:2px}.nodeline-right[data-v-83904042]{border-right-color:#d2d6db;border-right-style:solid;border-right-width:2px}.nodeline-left[data-v-83904042]{border-left-color:#d2d6db;border-left-style:solid;border-left-width:2px}.slide-fade-enter-active[data-v-83904042],.slide-fade-leave-active[data-v-83904042]{transition:all .3s ease-out}.slide-fade-enter-from[data-v-83904042],.slide-fade-leave-to[data-v-83904042]{transform:translateY(-20px);opacity:0}.org-chart[data-v-22da8111]{width:100vw;height:100vh;background-color:#fff;user-select:none}.org-chart-container[data-v-22da8111]{width:auto;height:auto}
|
||||
59
node_modules/bma-org-chart/package.json
generated
vendored
Normal file
59
node_modules/bma-org-chart/package.json
generated
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
{
|
||||
"name": "bma-org-chart",
|
||||
"version": "0.0.8",
|
||||
"description": "Organization Chart",
|
||||
"keywords": [
|
||||
"vue",
|
||||
"vue3",
|
||||
"organization",
|
||||
"chart",
|
||||
"org"
|
||||
],
|
||||
"author": "Suchin Prasongbundit",
|
||||
"type": "module",
|
||||
"main": "./dist/org-chart.umd.js",
|
||||
"module": "./dist/org-chart.js",
|
||||
"types": "./dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/org-chart.js",
|
||||
"require": "./dist/org-chart.umd.js"
|
||||
},
|
||||
"./org-chart.css": "./dist/style.css",
|
||||
"./dist/*": "./dist/*"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"src"
|
||||
],
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "run-p type-check build-only",
|
||||
"build-npm": "vue-tsc && vite build",
|
||||
"preview": "vite preview",
|
||||
"build-only": "vite build",
|
||||
"type-check": "vue-tsc --noEmit",
|
||||
"lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs,.ts,.tsx,.cts,.mts --fix --ignore-path .gitignore"
|
||||
},
|
||||
"dependencies": {
|
||||
"html2canvas": "^1.4.1",
|
||||
"jspdf": "^2.5.1",
|
||||
"pinia": "^2.0.32",
|
||||
"vue": "^3.2.47"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rushstack/eslint-patch": "^1.2.0",
|
||||
"@types/node": "^18.14.2",
|
||||
"@vitejs/plugin-vue": "^4.0.0",
|
||||
"@vue/eslint-config-typescript": "^11.0.2",
|
||||
"@vue/tsconfig": "^0.1.3",
|
||||
"eslint": "^8.34.0",
|
||||
"eslint-plugin-vue": "^9.9.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"sass": "^1.61.0",
|
||||
"typescript": "~4.8.4",
|
||||
"vite": "^4.1.4",
|
||||
"vite-plugin-dts": "^2.2.0",
|
||||
"vue-tsc": "^1.2.0"
|
||||
}
|
||||
}
|
||||
26
node_modules/bma-org-chart/src/App.vue
generated
vendored
Normal file
26
node_modules/bma-org-chart/src/App.vue
generated
vendored
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<script setup lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import OrgChart from './components/OrgChart.vue'
|
||||
import chartData from './assets/orgChartData'
|
||||
const dataSource = ref(chartData)
|
||||
// const dataSource = ref()
|
||||
|
||||
const chartRef = ref()
|
||||
const savePNG = () => {
|
||||
chartRef.value.savePNG()
|
||||
}
|
||||
const savePDF = () => {
|
||||
chartRef.value.savePDF()
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<button @click="savePNG()">Save PNG</button>
|
||||
<button @click="savePDF()">Save PDF</button>
|
||||
<OrgChart ref="chartRef" :dataSource="dataSource"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
</style>
|
||||
160
node_modules/bma-org-chart/src/assets/orgChartData.ts
generated
vendored
Normal file
160
node_modules/bma-org-chart/src/assets/orgChartData.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,160 @@
|
|||
const chartData = {
|
||||
personID: "1", // Unique ID เป็นเลข ID ที่อ้างอิงไปที่ตัวบุคคล
|
||||
name: "นายชัชชาติ สิทธิพันธุ์", // ขื่อบุคคล
|
||||
positionName: "ผู้ว่าราชการกรุงเทพมหานคร", // ชื่อตำแหน่ง
|
||||
positionNum: "กทข.1", // เลขที่ประจำตำแหน่งในโครงสร้าง
|
||||
departmentName: "กรุงเทพมหานคร", // ชื่อหน่วยงานที่สังกัด
|
||||
avatar: "", // ภาพถ่าย
|
||||
children: [ // บุคคลอื่น ๆ ที่อยู่ภายใต้คนนี้ มีโครงสร้างเหมือนกัน
|
||||
{
|
||||
personID: "2",
|
||||
name: "นายเอกภพ พัฒน์ธนโกศล",
|
||||
positionName: "ผอ.สูง(เลขานุการสภากรุงเทพมหานคร)",
|
||||
positionNum: "กทข.2",
|
||||
departmentName: "สำนักงานเลขานุการสภากรุงเทพมหานคร",
|
||||
avatar: "",
|
||||
children: [
|
||||
{
|
||||
personID: "3",
|
||||
name: "นางชญานี ไกรภพ",
|
||||
positionName: "ผอ.ต้น(ผช.เลขานุการสภากรุงเทพมหานคร)",
|
||||
positionNum: "กทข.3",
|
||||
departmentName: "สำนักงานเลขานุการสภากรุงเทพมหานคร",
|
||||
avatar: "",
|
||||
},
|
||||
{
|
||||
personID: "4",
|
||||
name: "นางสาวปิยะดา ศิริพัฒน์",
|
||||
positionName: "ผอ.ต้น(ผช.เลขานุการสภากรุงเทพมหานคร)",
|
||||
positionNum: "กทข.4",
|
||||
departmentName: "สำนักงานเลขานุการสภากรุงเทพมหานคร",
|
||||
avatar: "",
|
||||
children: [
|
||||
{
|
||||
personID: "12",
|
||||
name: "นายทดสอบ สกุลทดสอบ",
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "กทข.5",
|
||||
departmentName: "สำนักงานเลขานุการสภากรุงเทพมหานคร",
|
||||
avatar: "",
|
||||
},
|
||||
{
|
||||
personID: "13",
|
||||
name: "นายทดสอบ สกุลทดสอบ",
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "กทข.5",
|
||||
departmentName: "สำนักงานเลขานุการสภากรุงเทพมหานคร",
|
||||
avatar: "",
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
personID: "5",
|
||||
name: "นายวันชัย ปานประกอบ",
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "กทข.5",
|
||||
departmentName: "สำนักงานเลขานุการสภากรุงเทพมหานคร",
|
||||
avatar: "",
|
||||
children: [
|
||||
{
|
||||
personID: "10",
|
||||
name: "นายทดสอบ สกุลทดสอบ",
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "กทข.5",
|
||||
departmentName: "สำนักงานเลขานุการสภากรุงเทพมหานคร",
|
||||
avatar: "",
|
||||
},
|
||||
{
|
||||
personID: "11",
|
||||
name: "นายทดสอบ สกุลทดสอบ",
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "กทข.5",
|
||||
departmentName: "สำนักงานเลขานุการสภากรุงเทพมหานคร",
|
||||
avatar: "",
|
||||
},
|
||||
{
|
||||
personID: "14",
|
||||
name: "นายทดสอบ สกุลทดสอบ",
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "กทข.5",
|
||||
departmentName: "สำนักงานเลขานุการสภากรุงเทพมหานคร",
|
||||
avatar: "",
|
||||
children: [
|
||||
{
|
||||
personID: "15",
|
||||
name: "นายทดสอบ สกุลทดสอบ",
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "กทข.5",
|
||||
departmentName: "สำนักงานเลขานุการสภากรุงเทพมหานคร",
|
||||
avatar: "",
|
||||
},
|
||||
{
|
||||
personID: "16",
|
||||
name: "นายทดสอบ สกุลทดสอบ",
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "กทข.5",
|
||||
departmentName: "สำนักงานเลขานุการสภากรุงเทพมหานคร",
|
||||
avatar: "",
|
||||
children: [
|
||||
{
|
||||
personID: "18",
|
||||
name: "นายทดสอบ สกุลทดสอบ",
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "กทข.5",
|
||||
departmentName: "สำนักงานเลขานุการสภากรุงเทพมหานคร",
|
||||
avatar: "",
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
personID: "17",
|
||||
name: "นายทดสอบ สกุลทดสอบ",
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "กทข.5",
|
||||
departmentName: "สำนักงานเลขานุการสภากรุงเทพมหานคร",
|
||||
avatar: "",
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
personID: "6",
|
||||
name: "นายนที ขจรเกียรติสกุล",
|
||||
positionName: "นักบริหารสูง(ผอ.สำนัก)",
|
||||
positionNum: "สรน.1",
|
||||
departmentName: "สำนักการระบายน้ำ",
|
||||
avatar: "",
|
||||
},
|
||||
{
|
||||
personID: "7",
|
||||
name: "นายทดสอบ สกุลทดสอบ",
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "กทข.5",
|
||||
departmentName: "สำนักงานเลขานุการสภากรุงเทพมหานคร",
|
||||
avatar: "",
|
||||
children: [
|
||||
{
|
||||
personID: "9",
|
||||
name: "นายทดสอบ สกุลทดสอบ",
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "กทข.5",
|
||||
departmentName: "สำนักงานเลขานุการสภากรุงเทพมหานคร",
|
||||
avatar: "",
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
personID: "8",
|
||||
name: "นายทดสอบ สกุลทดสอบ",
|
||||
positionName: "นักจัดการงานทั่วไป",
|
||||
positionNum: "กทข.5",
|
||||
departmentName: "สำนักงานเลขานุการสภากรุงเทพมหานคร",
|
||||
avatar: "",
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export default chartData;
|
||||
173
node_modules/bma-org-chart/src/components/OrgChart.vue
generated
vendored
Normal file
173
node_modules/bma-org-chart/src/components/OrgChart.vue
generated
vendored
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
<script setup lang="ts">
|
||||
/**
|
||||
* import Vue's Stuff
|
||||
*/
|
||||
import { watch, onMounted } from 'vue'
|
||||
import html2canvas from 'html2canvas'
|
||||
import { jsPDF } from "jspdf"
|
||||
|
||||
/**
|
||||
* import Chart Node component
|
||||
*/
|
||||
import OrgChartNode from './OrgChartNode.vue'
|
||||
|
||||
/**
|
||||
* import Pinia Store
|
||||
*/
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useOrgStore } from '../stores/OrgStore'
|
||||
const { dataSource, selectedElement } = storeToRefs(useOrgStore())
|
||||
|
||||
/**
|
||||
* define Prop (Pass down value)
|
||||
*/
|
||||
const props = defineProps({
|
||||
dataSource: Object, // Data Source
|
||||
})
|
||||
|
||||
/**
|
||||
* define Emit (Child to Parent value)
|
||||
*/
|
||||
const emit = defineEmits([
|
||||
'onElementClick', // Event call when user click each element
|
||||
])
|
||||
|
||||
/**
|
||||
* จับภาพหน้าจอออกมาเป็น canvas object ส่งให้ฟังก์ชันอื่น ๆ นำไปประมวลผลต่อ
|
||||
* @param scale ขนาดของภาพที่ต้องการ ค่าพื้นฐานคือ 3 เท่าของหน้าจอ
|
||||
*/
|
||||
const captureChart = async (scale: number = 3) => {
|
||||
return await html2canvas(document.querySelector('.org-chart-container') as HTMLElement, {
|
||||
scale: scale,
|
||||
width: (document.querySelector('.org-chart-container') as HTMLElement).scrollWidth,
|
||||
height: (document.querySelector('.org-chart-container') as HTMLElement).scrollHeight,
|
||||
useCORS: true,
|
||||
allowTaint: true
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* จับภาพหน้าจอออกมาเป็น PNG แล้วดาวน์โหลด
|
||||
* @param scale ขนาดของภาพที่ต้องการ ค่าพื้นฐานคือ 3 เท่าของหน้าจอ
|
||||
*/
|
||||
const savePNG = async (scale: number = 3) => {
|
||||
let canvas = await captureChart(scale)
|
||||
let anchor = document.createElement('a')
|
||||
anchor.href = canvas.toDataURL('image/png')
|
||||
anchor.download = 'org-chart.png'
|
||||
anchor.click()
|
||||
anchor.remove()
|
||||
}
|
||||
|
||||
/**
|
||||
* savePDF - save canvas to PNG format and embed in PDF file then download.
|
||||
*/
|
||||
const savePDF = async (scale: number = 3) => {
|
||||
let canvas = await captureChart(scale)
|
||||
const doc = new jsPDF('l', 'px', 'a4')
|
||||
// const doc = new jsPDF('p', 'px', 'a4')
|
||||
let pageWidth = doc.internal.pageSize.getWidth()
|
||||
let pageHeight = doc.internal.pageSize.getHeight()
|
||||
|
||||
let widthRatio = pageWidth / canvas.width
|
||||
let heightRatio = pageHeight / canvas.height
|
||||
let canvasRatio = widthRatio > heightRatio ? heightRatio : widthRatio
|
||||
|
||||
let canvasWidth = canvas.width * canvasRatio;
|
||||
let canvasHeight = canvas.height * canvasRatio;
|
||||
|
||||
let marginX = (pageWidth - canvasWidth) / 2
|
||||
let marginY = (pageHeight - canvasHeight) / 2
|
||||
doc.addImage(canvas.toDataURL('image/png'), 'PNG', marginX, marginY, canvasWidth, canvasHeight);
|
||||
doc.save('org-chart.pdf');
|
||||
}
|
||||
|
||||
// export method to public
|
||||
defineExpose({ savePNG, savePDF })
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* onMounted:
|
||||
* - assign dataSource to internal Store
|
||||
* - init panzoom
|
||||
*/
|
||||
onMounted(() => {
|
||||
// dataSource.value = props.dataSource
|
||||
// depthGenerator()
|
||||
|
||||
// PanZoom
|
||||
// let element = document.querySelector('.struct-chart-container')
|
||||
// panzoom(element as HTMLElement, { // or let instance = panzoom(...)
|
||||
// smoothScroll: true,
|
||||
// minZoom: minZoom.value,
|
||||
// maxZoom: maxZoom.value
|
||||
// })
|
||||
})
|
||||
|
||||
/**
|
||||
* watch if dataSource change -> update internal Store
|
||||
*/
|
||||
watch(() => props.dataSource, (newVal) => {
|
||||
dataSource.value = newVal
|
||||
depthGenerator()
|
||||
})
|
||||
|
||||
/**
|
||||
* watch if user click element (selectedElement in internal Store change value)
|
||||
*/
|
||||
watch(selectedElement, () => {
|
||||
// emit onElementClick when user select element
|
||||
emit('onElementClick', selectedElement)
|
||||
})
|
||||
|
||||
|
||||
const chartTraverse = async (chart: any, depth: number) => {
|
||||
for (const child of chart) {
|
||||
// if (typeof child.personID !== 'undefined' && child.personID !== null) {
|
||||
child.depth = depth
|
||||
// }
|
||||
}
|
||||
for (const child of chart) {
|
||||
if (typeof child.children !== 'undefined' &&
|
||||
child.children !== null &&
|
||||
child.children.length > 0) {
|
||||
chartTraverse(child.children, depth + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const depthGenerator = async() => {
|
||||
// if (typeof dataSource.value.personID !== 'undefined' && dataSource.value.personID !== null) {
|
||||
dataSource.value.depth = 0
|
||||
// console.log(dataSource.value)
|
||||
// dataSource.value.show = true
|
||||
// }
|
||||
if (dataSource.value.children.length > 0) {
|
||||
await chartTraverse(dataSource.value.children, 1)
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="org-chart">
|
||||
<div class="org-chart-container">
|
||||
<OrgChartNode :dataSource="dataSource" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.org-chart {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-color: white;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.org-chart-container {
|
||||
width: auto;
|
||||
height: auto;
|
||||
}
|
||||
</style>
|
||||
327
node_modules/bma-org-chart/src/components/OrgChartNode.vue
generated
vendored
Normal file
327
node_modules/bma-org-chart/src/components/OrgChartNode.vue
generated
vendored
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
<script setup lang="ts">
|
||||
/**
|
||||
* Inspiration from : https://github.com/AugustinRibreau/vue3-organization-chart
|
||||
*/
|
||||
|
||||
import { toRefs, ref, watch, onMounted, onBeforeMount, onBeforeUpdate, watchEffect } from 'vue'
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { useOrgStore } from '../stores/OrgStore'
|
||||
|
||||
const { selectedElement } = storeToRefs(useOrgStore())
|
||||
|
||||
const props = defineProps({
|
||||
dataSource: Object
|
||||
})
|
||||
|
||||
const propDataSource = toRefs(props).dataSource
|
||||
|
||||
const isShowChild = ref(false)
|
||||
|
||||
onBeforeMount(() => {
|
||||
if (props.dataSource?.depth < 1) isShowChild.value = true
|
||||
else isShowChild.value = false
|
||||
})
|
||||
|
||||
onBeforeUpdate(() => {
|
||||
if (props.dataSource?.depth < 1) isShowChild.value = true
|
||||
else isShowChild.value = false
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
})
|
||||
|
||||
watch(() => props.dataSource, (newVal) => {
|
||||
// console.log(newVal)
|
||||
})
|
||||
|
||||
const sideButton = ref()
|
||||
watch(() => isShowChild, (newVal) => {
|
||||
// if (newVal.value) {
|
||||
// (sideButton.value as HTMLDivElement).classList.remove('oncollapse');
|
||||
// (sideButton.value as HTMLDivElement).classList.add('onexpand');
|
||||
// } else {
|
||||
// (sideButton.value as HTMLDivElement).classList.remove('onexpand');
|
||||
// (sideButton.value as HTMLDivElement).classList.add('oncollapse');
|
||||
// }
|
||||
})
|
||||
|
||||
watchEffect(() => {
|
||||
if (isShowChild.value) {
|
||||
(sideButton.value as HTMLDivElement)?.classList.remove('oncollapse');
|
||||
(sideButton.value as HTMLDivElement)?.classList.add('onexpand');
|
||||
} else {
|
||||
(sideButton.value as HTMLDivElement)?.classList.remove('onexpand');
|
||||
(sideButton.value as HTMLDivElement)?.classList.add('oncollapse');
|
||||
}
|
||||
})
|
||||
|
||||
const onElementSelected = (data: any) => {
|
||||
selectedElement.value = data
|
||||
}
|
||||
|
||||
const toggleChildView = () => {
|
||||
isShowChild.value = !isShowChild.value
|
||||
}
|
||||
const isShowChildNode = (): boolean => {
|
||||
// const isShowChildNode = (dataSource: any): boolean => {
|
||||
// return !(dataSource?.depth % 2 == 0 && dataSource?.depth !== 0 && !isShowChild.value)
|
||||
// return !(dataSource?.depth % 2 == 0 && dataSource?.depth > 1 && !isShowChild.value)
|
||||
return isShowChild.value
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<table class="node-container">
|
||||
<tbody>
|
||||
<tr class="root-node">
|
||||
<td :colspan="propDataSource?.children && propDataSource?.children.length ? propDataSource?.children.length * 2 : 0">
|
||||
<div :class="propDataSource?.personID == 1 ? 'element-container root-element' : 'element-container child-element'" :id="propDataSource?.personID" @clik="onElementSelected(propDataSource?.persosnID)">
|
||||
<div class="section-list">
|
||||
<div class="column-avatar">
|
||||
<img :src="propDataSource?.avatar && propDataSource?.avatar !== '' ? propDataSource?.avatar : 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4NCjwhLS0gVXBsb2FkZWQgdG86IFNWRyBSZXBvLCB3d3cuc3ZncmVwby5jb20sIEdlbmVyYXRvcjogU1ZHIFJlcG8gTWl4ZXIgVG9vbHMgLS0+Cjxzdmcgd2lkdGg9IjgwMHB4IiBoZWlnaHQ9IjgwMHB4IiB2aWV3Qm94PSIwIDAgMTYgMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+DQogICAgPHBhdGggZD0ibSA4IDEgYyAtMS42NTYyNSAwIC0zIDEuMzQzNzUgLTMgMyBzIDEuMzQzNzUgMyAzIDMgcyAzIC0xLjM0Mzc1IDMgLTMgcyAtMS4zNDM3NSAtMyAtMyAtMyB6IG0gLTEuNSA3IGMgLTIuNDkyMTg4IDAgLTQuNSAyLjAwNzgxMiAtNC41IDQuNSB2IDAuNSBjIDAgMS4xMDkzNzUgMC44OTA2MjUgMiAyIDIgaCA4IGMgMS4xMDkzNzUgMCAyIC0wLjg5MDYyNSAyIC0yIHYgLTAuNSBjIDAgLTIuNDkyMTg4IC0yLjAwNzgxMiAtNC41IC00LjUgLTQuNSB6IG0gMCAwIiBmaWxsPSIjMmUzNDM2Ii8+DQo8L3N2Zz4='" alt="{{ propDataSource?.name }}"/>
|
||||
</div>
|
||||
<div class="column-content">
|
||||
<div class="header">
|
||||
<template v-if="propDataSource?.name.trim() !== ''">
|
||||
{{ propDataSource?.name }}
|
||||
</template>
|
||||
<template v-else>
|
||||
{{ propDataSource?.depth > 0 ? 'ว่าง' : '' }}
|
||||
<!-- {{ propDataSource?.depth > 0 ? 'ว่าง' : '' }} -->
|
||||
</template>
|
||||
<!-- {{ propDataSource?.name ? propDataSource?.name : '' }} -->
|
||||
</div>
|
||||
<div class="subheader">{{ propDataSource?.positionName ? propDataSource?.positionName : '' }}</div>
|
||||
<div class="caption">
|
||||
{{ propDataSource?.departmentName ? propDataSource?.departmentName : '' }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="column-side">
|
||||
<!-- <template v-if="propDataSource?.children && propDataSource?.depth % 2 == 0 && propDataSource?.depth !== 0"> -->
|
||||
<!-- <button class="side-button" @click="toggleChildView" /> -->
|
||||
<!-- </template> -->
|
||||
<template v-if="propDataSource?.children && propDataSource?.children.length > 0">
|
||||
<button
|
||||
ref="sideButton"
|
||||
class="side-button"
|
||||
@click="toggleChildView()"
|
||||
>
|
||||
</button>
|
||||
<!-- <button
|
||||
@click="toggleChildView"
|
||||
class="side-button"
|
||||
:class="[
|
||||
isShowChild ? 'onexpand' : 'oncollapse',
|
||||
]"
|
||||
/> -->
|
||||
<!-- <button :class="isShowChild ? 'side-button onexpand' : 'side-button oncollapse'" @click="toggleChildView" /> -->
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<template v-if="propDataSource?.children && propDataSource?.children.length">
|
||||
<tr>
|
||||
<td :colspan="propDataSource?.children && propDataSource?.children.length ? propDataSource?.children.length * 2 : 0">
|
||||
<Transition name="slide-fade">
|
||||
<table class="node-container" v-show="isShowChildNode()">
|
||||
<tr class="nodeline">
|
||||
<td :colspan="propDataSource?.children.length * 2">
|
||||
<div class="nodeline-down"></div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="nodeline">
|
||||
<td class="nodeline-right"></td>
|
||||
<template v-for="n in propDataSource?.children.length - 1" v-bind:key="n">
|
||||
<td class="nodeline-left nodeline-top"></td>
|
||||
<td class="nodeline-right nodeline-top"></td>
|
||||
</template>
|
||||
<td class="nodeline-left"></td>
|
||||
</tr>
|
||||
<tr class="node-children">
|
||||
<td colspan="2" v-for="child in propDataSource?.children" :key="child.id">
|
||||
<OrgChartNode :dataSource="child"></OrgChartNode>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</Transition>
|
||||
</td>
|
||||
</tr>
|
||||
</template>
|
||||
</tbody>
|
||||
</table>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
// container ของทั้ง node
|
||||
.node-container {
|
||||
border-collapse: collapse;
|
||||
margin: 0 auto 0 auto;
|
||||
}
|
||||
// root node element
|
||||
.root-node {
|
||||
td {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
// container ของ element
|
||||
.element-container {
|
||||
background: white;
|
||||
border: 1px solid #f0efef;
|
||||
border-radius: 5px;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0px 20px 20px -20px hsla(229, 6%, 66%, 0.212);
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
margin: 0 1px 2px 1px;
|
||||
min-width: 9rem;
|
||||
text-align: left;
|
||||
transition-duration: 250ms;
|
||||
|
||||
// &:hover {
|
||||
// box-shadow: 0 6px 10px #7c7c7c;
|
||||
// cursor: pointer;
|
||||
// transform: scale(1.05);
|
||||
// z-index: 20;
|
||||
// }
|
||||
}
|
||||
|
||||
// กรณีเป็น root element ใช้สีฟ้า
|
||||
.root-element {
|
||||
border-top: 3px solid hsl(212, 86%, 64%);
|
||||
}
|
||||
|
||||
// กรณีเป็น child element ใช้สีเขียว
|
||||
.child-element {
|
||||
border-top: 3px solid hsl(180, 62%, 55%);
|
||||
}
|
||||
|
||||
.section-list {
|
||||
font-family: sans-serif;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 15px 20px 15px 20px;
|
||||
bottom: 0;
|
||||
|
||||
.column-content {
|
||||
min-width: 120px;
|
||||
|
||||
.header {
|
||||
color: #334454;
|
||||
font-size: 1.1rem;
|
||||
font-weight: 700 !important;
|
||||
line-height: 1.5rem;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.subheader, .caption {
|
||||
color: #7a7d89;
|
||||
font-size: 0.9rem;
|
||||
padding-top: 5px;
|
||||
margin: 0;
|
||||
}
|
||||
.caption {
|
||||
font-size: 1.0rem;
|
||||
font-weight: 600 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.column-avatar {
|
||||
img {
|
||||
background-color: #efefef;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
object-position: center;
|
||||
object-fit: cover;
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.column-side {
|
||||
margin-left: 20px;
|
||||
.side-button {
|
||||
background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz48IS0tIFVwbG9hZGVkIHRvOiBTVkcgUmVwbywgd3d3LnN2Z3JlcG8uY29tLCBHZW5lcmF0b3I6IFNWRyBSZXBvIE1peGVyIFRvb2xzIC0tPgo8c3ZnIHdpZHRoPSI4MDBweCIgaGVpZ2h0PSI4MDBweCIgdmlld0JveD0iMCAwIDE2IDE2IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9IiMwMDAwMDAiIGNsYXNzPSJiaSBiaS1jYXJldC1kb3duLWZpbGwiPgogIDxwYXRoIGQ9Ik03LjI0NyAxMS4xNCAyLjQ1MSA1LjY1OEMxLjg4NSA1LjAxMyAyLjM0NSA0IDMuMjA0IDRoOS41OTJhMSAxIDAgMCAxIC43NTMgMS42NTlsLTQuNzk2IDUuNDhhMSAxIDAgMCAxLTEuNTA2IDB6Ii8+Cjwvc3ZnPg==);
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 16px;
|
||||
border: 1px solid white;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
// padding: 5px 10px;
|
||||
color: #717171;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
text-align: center;
|
||||
// div {
|
||||
// margin-top: -10px;
|
||||
// }
|
||||
}
|
||||
|
||||
.oncollapse {
|
||||
transform: rotate(90deg);
|
||||
transition: all 0.3s ease-out;
|
||||
}
|
||||
.onexpand {
|
||||
transform: rotate(0deg);
|
||||
transition: all 0.3s ease-out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.node-children {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.nodeline {
|
||||
height: 1.75rem;
|
||||
}
|
||||
|
||||
.nodeline-down {
|
||||
background: #D2D6DB;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: -1rem;
|
||||
margin-bottom: -1rem;
|
||||
height: 1.9rem;
|
||||
width: 0.125rem;
|
||||
float: none;
|
||||
}
|
||||
|
||||
.nodeline-top {
|
||||
border-top-color: #D2D6DB;
|
||||
border-top-style: solid;
|
||||
border-top-width: 2px;
|
||||
}
|
||||
|
||||
.nodeline-right {
|
||||
border-right-color: #D2D6DB;
|
||||
border-right-style: solid;
|
||||
border-right-width: 2px;
|
||||
}
|
||||
|
||||
.nodeline-left {
|
||||
border-left-color: #D2D6DB;
|
||||
border-left-style: solid;
|
||||
border-left-width: 2px;
|
||||
}
|
||||
|
||||
.slide-fade-enter-active {
|
||||
transition: all 0.3s ease-out;
|
||||
}
|
||||
.slide-fade-leave-active {
|
||||
transition: all 0.3s ease-out;
|
||||
// cubic-bezier(1, 0.5, 0.8, 1);
|
||||
}
|
||||
.slide-fade-enter-from,
|
||||
.slide-fade-leave-to {
|
||||
transform: translateY(-20px);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
</style>
|
||||
3
node_modules/bma-org-chart/src/index.ts
generated
vendored
Normal file
3
node_modules/bma-org-chart/src/index.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
import OrgChart from './components/OrgChart.vue'
|
||||
|
||||
export { OrgChart }
|
||||
7
node_modules/bma-org-chart/src/main.ts
generated
vendored
Normal file
7
node_modules/bma-org-chart/src/main.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import { createApp } from 'vue'
|
||||
import { createPinia } from 'pinia'
|
||||
import App from './App.vue'
|
||||
|
||||
const app = createApp(App)
|
||||
app.use(createPinia())
|
||||
app.mount('#app')
|
||||
16
node_modules/bma-org-chart/src/stores/OrgStore.ts
generated
vendored
Normal file
16
node_modules/bma-org-chart/src/stores/OrgStore.ts
generated
vendored
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import { ref } from 'vue'
|
||||
import { defineStore } from 'pinia'
|
||||
|
||||
export const useOrgStore = defineStore('StructStore', () => {
|
||||
|
||||
// ข้อมูลที่กำลังแสดงอยู่
|
||||
const dataSource = ref()
|
||||
|
||||
// Current (Active) Node
|
||||
const selectedElement = ref()
|
||||
|
||||
return {
|
||||
dataSource,
|
||||
selectedElement
|
||||
}
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue