first commit

This commit is contained in:
Warunee Tamkoo 2023-09-06 14:51:44 +07:00
commit eb2f504652
32490 changed files with 5731109 additions and 0 deletions

23
node_modules/bma-org-chart/README.md generated vendored Normal file
View 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"
/>
```

View 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;

View 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

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
View 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

File diff suppressed because it is too large Load diff

6
node_modules/bma-org-chart/dist/org-chart.js generated vendored Normal file
View 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

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

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
View 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
View 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
View 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
View 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
View 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
View 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>

View 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
View 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
View 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
View 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
}
})