238 lines
7 KiB
Vue
238 lines
7 KiB
Vue
<script setup lang="ts">
|
||
import { defineAsyncComponent } from "@vue/runtime-core";
|
||
import { ref, onMounted } from "vue";
|
||
|
||
import http from "@/plugins/http";
|
||
import config from "@/app.config";
|
||
|
||
import { StructChart } from "structure-chart";
|
||
import "structure-chart/structure-chart.css";
|
||
import { useCounterMixin } from "@/stores/mixin";
|
||
|
||
const mixin = useCounterMixin();
|
||
const { showLoader, hideLoader } = mixin;
|
||
|
||
// import chartData from '@/assets/structChartData'
|
||
// const dataSource = ref(chartData)
|
||
const dataSource = ref(); // ข้อมูล Chart
|
||
const rootOrgID = ref(); // org id ของ root ตัวปัจจุบันที่เลือกอยู่
|
||
const dataSourceLock = ref(); // ข้อมูลตั้งต้นของ Chart ใช้ให้กดกลับไปที่ home
|
||
const chartRef = ref(); // อ้างอิงไปที่ตัว chart
|
||
const savePNG = () => {
|
||
chartRef.value.savePNG();
|
||
};
|
||
const savePDF = () => {
|
||
chartRef.value.savePDF();
|
||
};
|
||
|
||
const loader = ref<boolean>(false); // Loader
|
||
|
||
onMounted(async () => {
|
||
await fetchTreeRoot();
|
||
await fetchStructChart();
|
||
});
|
||
|
||
/**
|
||
* อ่าน Root ของข้อมูลทั้งหมดจาก API ต้องทำเป็นอันดับแรก เพื่อจะได้รู้รากของข้อมูล
|
||
*/
|
||
const fetchTreeRoot = async () => {
|
||
showLoader();
|
||
let urlRequest = config.API.chartGetTreeRoot;
|
||
await http
|
||
.get(urlRequest)
|
||
.then((response) => {
|
||
if (response.data.result.length > 0) {
|
||
rootOrgID.value = response.data.result[0].organizationId;
|
||
}
|
||
})
|
||
.catch((e) => {
|
||
console.log(e);
|
||
})
|
||
.finally(() => {
|
||
hideLoader();
|
||
});
|
||
};
|
||
|
||
/**
|
||
* อ่านข้อมูล organization id ปัจจุบันจาก API ข้อมูลที่ได้เอามาสร้าง Structure Chart
|
||
*/
|
||
const fetchStructChart = async () => {
|
||
showLoader();
|
||
let urlRequest = config.API.chartGetStructure(rootOrgID.value);
|
||
await http
|
||
.get(urlRequest)
|
||
.then((response) => {
|
||
if (response.data.result.length > 0) {
|
||
dataSource.value = response.data.result[0];
|
||
if (dataSourceLock.value === undefined)
|
||
dataSourceLock.value = dataSource.value;
|
||
breadcrumbsGen();
|
||
}
|
||
})
|
||
.catch((e) => {
|
||
console.log(e);
|
||
})
|
||
.finally(() => {
|
||
hideLoader();
|
||
});
|
||
};
|
||
|
||
/**
|
||
* เมื่อมีการคลิกที่ Chart ให้อ่าน ID ของหน่วยงานที่ถูกคลิก แล้วดึงข้อมูล Chart ของหน่วยงานนั้น ๆ จาก API
|
||
* @param data
|
||
*/
|
||
const refreshChart = async (data: any) => {
|
||
if (data.value !== undefined) rootOrgID.value = data.value;
|
||
else rootOrgID.value = data;
|
||
if (rootOrgID.value !== 0) await fetchStructChart();
|
||
if (data.value !== undefined) data.value = 0;
|
||
};
|
||
|
||
/**
|
||
* === กระบวนการสร้าง Path ===
|
||
*/
|
||
/**
|
||
* Recursive เพื่อหา Path ที่ผู้ใช้คลิก
|
||
* @param id OrgID ของหน่วยงานที่ต้องการหา
|
||
* @param chart Array ของ Object ของหน่วยงานย่อยใน Tree นั้น ๆ
|
||
*/
|
||
const chartTraverse = (id: any, chart: any): any => {
|
||
let _returnPath = [];
|
||
for (const child of chart) {
|
||
if (child.deptID === id) {
|
||
_returnPath.push({
|
||
label: child.departmentName,
|
||
id: child.deptID,
|
||
});
|
||
return _returnPath;
|
||
} else {
|
||
if (
|
||
typeof child.children !== "undefined" &&
|
||
child.children !== null &&
|
||
child.children.length > 0
|
||
) {
|
||
let _result = chartTraverse(id, child.children);
|
||
if (typeof _result !== "undefined" && _result !== null) {
|
||
_returnPath.push({
|
||
label: child.departmentName,
|
||
id: child.deptID,
|
||
});
|
||
return [..._returnPath, ...(_result ?? [])];
|
||
}
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
const findPath = (id: any) => {
|
||
let _path = [];
|
||
_path.push({
|
||
label: dataSourceLock.value.departmentName,
|
||
id: dataSourceLock.value.deptID,
|
||
});
|
||
if (dataSourceLock.value.deptID === id) return _path;
|
||
if (dataSourceLock.value.children.length > 0) {
|
||
let _returnPath = chartTraverse(id, dataSourceLock.value.children);
|
||
return [..._path, ...(_returnPath ?? [])];
|
||
}
|
||
};
|
||
|
||
const theBreadcrumb = ref();
|
||
/**
|
||
* สร้าง Path Breadcrumbs
|
||
*/
|
||
const breadcrumbsGen = () => {
|
||
if (rootOrgID.value !== 0) {
|
||
theBreadcrumb.value = [];
|
||
const newPath = findPath(rootOrgID.value);
|
||
theBreadcrumb.value = newPath;
|
||
}
|
||
};
|
||
</script>
|
||
|
||
<template>
|
||
<div class="toptitle text-dark col-12 row items-center">แผนภูมิโครงสร้าง</div>
|
||
<div class="text-dark">
|
||
<q-card flat bordered class="col-12 q-mt-sm">
|
||
<div class="q-pa-sm row wrap items-center">
|
||
<q-btn flat round color="primary" @click="savePNG()" icon="mdi-image">
|
||
<q-tooltip> ดาวน์โหลด PNG </q-tooltip>
|
||
</q-btn>
|
||
<q-btn
|
||
flat
|
||
round
|
||
color="red-7"
|
||
@click="savePDF()"
|
||
icon="mdi-file-pdf-box"
|
||
>
|
||
<q-tooltip> ดาวน์โหลด PDF </q-tooltip>
|
||
</q-btn>
|
||
<div class="bg-grey-2 q-py-xs q-px-sm rounded-borders">
|
||
<q-breadcrumbs>
|
||
<template v-slot:separator>
|
||
<q-icon size="1.5em" name="chevron_right" color="primary" />
|
||
</template>
|
||
<template v-for="link in theBreadcrumb" :key="link.id">
|
||
<q-breadcrumbs-el
|
||
:label="link.label"
|
||
@click="refreshChart(link.id)"
|
||
class="breadcrumbs-link"
|
||
/>
|
||
</template>
|
||
</q-breadcrumbs>
|
||
</div>
|
||
</div>
|
||
<q-separator />
|
||
<div style="overflow-x: auto; overflow-y: auto" class="q-pt-md">
|
||
<StructChart
|
||
style="height: 70vh"
|
||
ref="chartRef"
|
||
class="struct"
|
||
:dataSource="dataSource"
|
||
@onElementClick="refreshChart"
|
||
/>
|
||
</div>
|
||
</q-card>
|
||
</div>
|
||
<full-loader :visibility="loader"></full-loader>
|
||
</template>
|
||
|
||
<style>
|
||
.breadcrumbs-link {
|
||
cursor: pointer;
|
||
}
|
||
.struct .section-primary .header,
|
||
.struct .section-secondary .header,
|
||
.struct .section-tertiary .header {
|
||
font-size: 1rem !important;
|
||
}
|
||
|
||
.struct .section-primary .column-side .side-button,
|
||
.struct .section-secondary .column-side .side-button,
|
||
.struct .section-list .column-side .side-button {
|
||
background-color: #d9d9d96b !important;
|
||
color: #545459 !important;
|
||
width: 25px !important;
|
||
height: 25px !important;
|
||
font-size: 11px !important;
|
||
padding: 0px;
|
||
}
|
||
|
||
.struct .section-primary,
|
||
.section-secondary,
|
||
.struct .section-list {
|
||
padding: 6px 15px 6px 15px;
|
||
}
|
||
.struct .section-primary .header {
|
||
font-weight: 600 !important;
|
||
}
|
||
|
||
.struct .section-secondary .header {
|
||
font-weight: 400 !important;
|
||
}
|
||
|
||
.struct .subchild-more {
|
||
background-position: center !important;
|
||
background-size: 14px !important;
|
||
}
|
||
</style>
|