clone code

This commit is contained in:
Kittapath 2023-06-01 12:54:58 +07:00
parent c9597d1e38
commit d57bcd1719
362 changed files with 104804 additions and 0 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,90 @@
<template>
<q-card-actions class="text-primary">
<q-space />
<q-btn
v-if="!editvisible"
flat
round
:disabled="editvisible"
:color="editvisible ? 'grey-7' : 'primary'"
@click="edit"
icon="mdi-pencil-outline"
>
<q-tooltip>แกไขขอม</q-tooltip>
</q-btn>
<div v-else>
<!-- <q-btn
flat
round
:disabled="!editvisible"
:outline="!editvisible"
:color="!editvisible ? 'grey-7' : 'red'"
@click="cancel()"
icon="mdi-undo"
v-if="modalEdit == true"
>
<q-tooltip>ยกเล</q-tooltip>
</q-btn> -->
<q-btn
flat
round
:disabled="!editvisible"
:color="!editvisible ? 'grey-7' : 'public'"
@click="checkSave"
icon="mdi-content-save-outline"
>
<q-tooltip>นท</q-tooltip>
</q-btn>
</div>
</q-card-actions>
</template>
<script setup lang="ts">
import { ref, useAttrs } from "vue";
const props = defineProps({
editvisible: Boolean,
modalEdit: Boolean,
cancel: {
type: Function,
default: () => console.log("not function"),
},
edit: {
type: Function,
default: () => console.log("not function"),
},
save: {
type: Function,
default: () => console.log("not function"),
},
validate: {
type: Function,
default: () => console.log("not function"),
},
});
const emit = defineEmits([
"update:editvisible",
"update:next",
"update:previous",
]);
const updateEdit = (value: Boolean) => {
emit("update:editvisible", value);
};
const cancel = async () => {
props.cancel();
};
const edit = async () => {
updateEdit(!props.editvisible);
props.edit();
};
const checkSave = () => {
props.validate();
props.save();
// if (myForm.value !== null) {
// myForm.value.validate().then((success) => {
// if (success) {
// }
// });
// }
};
</script>

View file

@ -0,0 +1,27 @@
<template>
<q-toolbar>
<q-toolbar-title class="text-subtitle2 text-bold">{{ tittle }}</q-toolbar-title>
<q-btn
icon="close"
unelevated
round
dense
@click="close"
style="color: #ff8080; background-color: #ffdede"
/>
</q-toolbar>
</template>
<script setup lang="ts">
import { ref, useAttrs } from "vue";
const props = defineProps({
tittle: String,
close: {
type: Function,
default: () => console.log("not function"),
},
});
const close = async () => {
props.close();
};
</script>

View file

@ -0,0 +1,221 @@
<template>
<div class="q-pb-sm row">
<div class="flex items-center">
<q-btn
size="12px"
v-if="!editvisible"
flat
round
:disabled="editvisible"
:color="editvisible ? 'grey-7' : 'primary'"
@click="clickEdit"
icon="mdi-pencil-outline"
>
<q-tooltip>แกไขขอม</q-tooltip>
</q-btn>
<q-btn
size="12px"
flat
round
v-if="editvisible"
:disabled="!editvisible"
:color="!editvisible ? 'grey-7' : 'add'"
@click="checkAdd"
icon="mdi-plus"
>
<q-tooltip>เพมขอม</q-tooltip>
</q-btn>
<q-btn
size="12px"
flat
round
v-if="editvisible"
:disabled="!editvisible"
:color="!editvisible ? 'grey-7' : 'red'"
@click="clickCancel"
icon="mdi-undo"
>
<q-tooltip>ยกเล</q-tooltip>
</q-btn>
<q-space />
</div>
<q-space />
<div class="items-center" style="display: flex">
<!-- นหาขอความใน table -->
<q-input
standout
dense
:model-value="inputfilter"
ref="filterRef"
@update:model-value="updateInput"
outlined
debounce="300"
placeholder="ค้นหา"
style="max-width: 200px"
class="q-ml-sm"
>
<template v-slot:append>
<q-icon v-if="inputfilter == ''" name="search" />
<q-icon
v-if="inputfilter !== ''"
name="clear"
class="cursor-pointer"
@click="resetFilter"
/>
</template>
</q-input>
<!-- แสดงคอลมนใน table -->
<q-select
:model-value="inputvisible"
@update:model-value="updateVisible"
:display-value="$q.lang.table.columns"
multiple
outlined
dense
:options="attrs.columns"
options-dense
option-value="name"
map-options
emit-value
style="min-width: 150px"
class="gt-xs q-ml-sm"
/>
</div>
</div>
<q-table
ref="table"
flat
bordered
class="custom-header-table"
v-bind="attrs"
virtual-scroll
:virtual-scroll-sticky-size-start="48"
dense
:pagination-label="paginationLabel"
:pagination="initialPagination"
:rows-per-page-options="[0]"
>
<template v-slot:header="props">
<q-tr :props="props">
<q-th auto-width />
<q-th v-for="col in props.cols" :key="col.name" :props="props">
<span class="text-weight-medium">{{ col.label }}</span>
</q-th>
<q-th auto-width v-if="history == true" />
</q-tr>
</template>
<template #body="props">
<slot v-bind="props" name="columns"></slot>
</template>
</q-table>
</template>
<script setup lang="ts">
import { ref, useAttrs } from "vue";
import type { Pagination } from "@/modules/04_registry/interface/index/Main";
const attrs = ref<any>(useAttrs());
const table = ref<any>(null);
const filterRef = ref<any>(null);
const editvisible = ref<boolean>(false);
const initialPagination = ref<Pagination>({
// descending: false,
rowsPerPage: 0,
});
const props = defineProps({
inputfilter: String,
inputvisible: Array,
editvisible: Boolean,
history: Boolean,
edit: {
type: Function,
default: () => console.log("not function"),
},
add: {
type: Function,
default: () => console.log("not function"),
},
cancel: {
type: Function,
default: () => console.log("not function"),
},
});
const emit = defineEmits([
"update:inputfilter",
"update:inputvisible",
"update:editvisible",
]);
const updateEdit = (value: Boolean) => {
emit("update:editvisible", value);
};
const updateInput = (value: string | number | null) => {
emit("update:inputfilter", value);
};
const updateVisible = (value: []) => {
emit("update:inputvisible", value);
};
const paginationLabel = (start: string, end: string, total: string) => {
return start + "-" + end + " ใน " + total;
};
const checkAdd = () => {
props.add();
};
const clickEdit = () => {
updateEdit(!props.editvisible);
editvisible.value = !editvisible.value;
props.edit();
};
const clickCancel = () => {
updateEdit(!props.editvisible);
editvisible.value = !editvisible.value;
props.cancel();
};
const resetFilter = () => {
// reset X
emit("update:inputfilter", "");
filterRef.value.focus();
};
</script>
<style lang="scss">
.icon-color {
color: #4154b3;
}
.custom-header-table {
max-height: 64vh;
.q-table tr:nth-child(odd) td {
background: white;
}
.q-table tr:nth-child(even) td {
background: #f8f8f8;
}
.q-table thead tr {
background: #ecebeb;
}
.q-table thead tr th {
position: sticky;
z-index: 1;
}
/* this will be the loading indicator */
.q-table thead tr:last-child th {
/* height of all previous header rows */
top: 48px;
}
.q-table thead tr:first-child th {
top: 0;
}
}
</style>

View file

@ -0,0 +1,215 @@
<template>
<div class="q-px-md q-pb-md">
<div class="col-12 row q-pb-sm items-center q-col-gutter-sm">
<q-btn
size="14px"
color="grey-7"
dense
flat
round
@click="onTab"
class="shadow-1"
icon="chevron_right"
v-if="!isTab"
>
<q-tooltip>เป</q-tooltip>
</q-btn>
<q-btn
size="14px"
dense
flat
round
color="primary"
@click="onConfirm"
icon="assignment_turned_in"
>
<q-tooltip>นยนเพอเอาไปออกคำส</q-tooltip>
</q-btn>
<q-btn
size="14px"
dense
flat
round
color="info"
icon="mdi-history"
@click="onHistory"
>
<q-tooltip>ประว</q-tooltip>
</q-btn>
<q-space />
<!-- นหาขอความใน table -->
<q-input
standout
dense
:model-value="inputfilter"
ref="filterRef"
@update:model-value="updateInput"
outlined
debounce="300"
placeholder="ค้นหา"
style="max-width: 200px"
>
<template v-slot:append>
<q-icon v-if="inputfilter == ''" name="search" />
<q-icon
v-if="inputfilter !== ''"
name="clear"
class="cursor-pointer"
@click="resetFilter"
/>
</template>
</q-input>
<!-- แสดงคอลมนใน table -->
<q-select
:model-value="inputvisible"
@update:model-value="updateVisible"
:display-value="$q.lang.table.columns"
multiple
outlined
dense
:options="attrs.columns"
options-dense
option-value="name"
map-options
emit-value
style="min-width: 150px"
class="gt-xs"
/>
</div>
<q-table
ref="table"
flat
bordered
class="custom-header-table"
v-bind="attrs"
virtual-scroll
:virtual-scroll-sticky-size-start="48"
dense
:pagination-label="paginationLabel"
:pagination="initialPagination"
:rows-per-page-options="paging == true ? [25, 50, 100, 500] : []"
>
<template v-slot:header="props">
<q-tr :props="props">
<q-th v-for="col in props.cols" :key="col.name" :props="props">
<span class="text-weight-medium">{{ col.label }}</span>
</q-th>
<q-th auto-width v-if="delect == true" />
</q-tr>
</template>
<template #body="props">
<slot v-bind="props" name="columns"></slot>
</template>
</q-table>
</div>
</template>
<script setup lang="ts">
import { ref, useAttrs } from "vue";
const attrs = ref<any>(useAttrs());
const table = ref<any>(null);
const filterRef = ref<any>(null);
const props = defineProps({
inputfilter: String,
inputvisible: Array,
addvisible: Boolean,
delect: {
type: Boolean,
defualt: false,
},
paging: {
type: Boolean,
defualt: false,
},
isTab: {
type: Boolean,
default: true,
},
onTab: {
type: Function,
default: () => console.log("not function"),
},
onConfirm: {
type: Function,
default: () => console.log("not function"),
},
onHistory: {
type: Function,
default: () => console.log("not function"),
},
add: {
type: Function,
default: () => console.log("not function"),
},
});
const emit = defineEmits(["update:inputfilter", "update:inputvisible"]);
const updateVisible = (value: any) => {
emit("update:inputvisible", value);
};
const updateInput = (value: any) => {
emit("update:inputfilter", value);
};
const onConfirm = () => {
props.onConfirm();
};
const onHistory = () => {
props.onHistory();
};
const onTab = () => {
props.onTab();
};
const checkAdd = () => {
props.add();
};
const initialPagination = ref<any>({
// descending: false,
rowsPerPage: props.paging == true ? 25 : 0,
});
const paginationLabel = (start: string, end: string, total: string) => {
if (props.paging == true)
return " " + start + " ใน " + end + " จากจำนวน " + total + " รายการ";
else return start + "-" + end + " ใน " + total;
};
const resetFilter = () => {
emit("update:inputfilter", "");
filterRef.value.focus();
};
</script>
<style lang="scss">
.icon-color {
color: #4154b3;
}
.custom-header-table {
max-height: 80vh;
.q-table tr:nth-child(odd) td {
background: white;
}
.q-table tr:nth-child(even) td {
background: #f8f8f8;
}
.q-table thead tr {
background: #ecebeb;
}
.q-table thead tr th {
position: sticky;
z-index: 1;
}
/* this will be the loading indicator */
.q-table thead tr:last-child th {
/* height of all previous header rows */
top: 48px;
}
.q-table thead tr:first-child th {
top: 0;
}
}
</style>

View file

@ -0,0 +1,444 @@
<!-- =============================== -->
<!-- component เพ/แกไข ตำแหน ของ โครงสรางอตรากำล -->
<!-- เปนช q-select(dropdown) ใชในการ mapping ตำแหนงกบโครงสราง -->
<!-- เพอสราง โครงสรางตำแหน ใหมใน DB -->
<!-- Call API to fill all dropdown list -->
<!-- แกไขไมองมจำนวน จะแก 1:1 check เรองการสงคาด -->
<!-- =============================== -->
<template>
<div v-if="isAddNew" class="row col-12 items-center q-pt-md">
<div class="bg-white q-px-sm topCard">
<span class="text-weight-medium">เพมตำแหน</span>
<q-btn
flat
color="primary"
size="12px"
icon="mdi-plus"
dense
class="q-mx-sm"
@click="addPositionItem()"
>
<q-tooltip>เพมตำแหน</q-tooltip>
</q-btn>
</div>
</div>
<!-- การดเพมตำแหน-->
<q-form ref="myForm">
<div v-if="!isAddNew">
<div v-for="(item, index) in positions" :key="index">
<q-select
dense
outlined
v-model="item.positionMasterId"
:options="position"
label="ตำแหน่ง"
class="col-xs-9 col-sm-6 col-md-8"
use-input
input-debounce="0"
@filter="filterFn"
hide-bottom-space
option-label="positionPath"
option-value="id"
map-options
emit-value
clearable
:rules="[(val:any) => !!val || `${'กรุณาเลือกตำแหน่ง'}`]"
>
<template v-slot:option="scope">
<q-item v-bind="scope.itemProps">
<q-item-section>
<q-item-label>{{ scope.opt.positionPath }}</q-item-label>
<q-item-label caption>
<q-icon
class="q-mr-sm"
size="15px"
color="primary"
name="mdi-bookmark"
v-if="scope.opt.isDirector"
></q-icon>
{{ scope.opt.positionExecutive }}
{{ scope.opt.positionExecutiveSide }}
{{ scope.opt.positionLevel }}
{{ scope.opt.positionLine }}
{{ scope.opt.positionPathSide }}
{{ scope.opt.positionType }}
</q-item-label>
</q-item-section>
</q-item>
</template>
<template v-slot:selected-item="scope">
<q-chip dense square class="q-my-none q-ml-xs q-mr-none">
{{ scope.opt.positionPath }}
</q-chip>
<q-item-label caption>
<q-icon
class="q-mr-sm"
size="15px"
color="primary"
name="mdi-bookmark"
v-if="scope.opt.isDirector"
></q-icon>
{{ scope.opt.positionExecutive }}
{{ scope.opt.positionExecutiveSide }}
{{ scope.opt.positionLevel }}
{{ scope.opt.positionLine }}
{{ scope.opt.positionPathSide }}
{{ scope.opt.positionType }}
</q-item-label>
</template>
<template v-slot:no-option>
<ddNoResultMsg />
</template>
</q-select>
<div class="col-xs-12 col-sm-12 col-md-12">
<q-input
:class="getClass(true)"
hide-bottom-space
:outlined="true"
dense
lazy-rules
:readonly="false"
:borderless="false"
v-model="item.positionUserNote"
:label="`${'หมายเหตุ'}`"
type="textarea"
/>
<!-- :rules="[(val) => !!val || `${'กรุณากรอกเงื่อนไขตำแหน่ง'}`]" -->
</div>
</div>
</div>
<q-card v-else bordered flat class="q-py-sm">
<q-card
flat
class="bg-grey-2 q-pa-sm q-ma-sm row col-12"
v-for="(item, index) in positions"
:key="index"
>
<div class="col-12 row items-center q-col-gutter-xs">
<div>
<q-avatar
class="q-mr-sm"
size="25px"
color="grey-3"
text-color="grey-9"
>{{ index + 1 }}</q-avatar
>
</div>
<q-btn
flat
round
color="red"
size="10px"
class="q-mr-sm"
icon="mdi-trash-can-outline"
dense
@click="deletePositionItem(item)"
/>
<!-- label="ตำแหน่ง" -->
<q-select
dense
outlined
v-model="item.positionMasterId"
:options="position"
label="ตำแหน่ง"
class="col-xs-9 col-sm-6 col-md-8"
use-input
input-debounce="0"
@filter="filterFn"
hide-bottom-space
option-label="positionPath"
option-value="id"
map-options
emit-value
clearable
:rules="[(val:any) => !!val || `${'กรุณาเลือกตำแหน่ง'}`]"
>
<template v-slot:option="scope">
<q-item v-bind="scope.itemProps">
<q-item-section>
<q-item-label>{{ scope.opt.positionPath }}</q-item-label>
<q-item-label caption>
<q-icon
class="q-mr-sm"
size="15px"
color="primary"
name="mdi-bookmark"
v-if="scope.opt.isDirector"
></q-icon>
{{ scope.opt.positionExecutive }}
{{ scope.opt.positionExecutiveSide }}
{{ scope.opt.positionLevel }}
{{ scope.opt.positionLine }}
{{ scope.opt.positionPathSide }}
{{ scope.opt.positionType }}
</q-item-label>
</q-item-section>
</q-item>
</template>
<template v-slot:selected-item="scope">
<q-chip dense square class="q-my-none q-ml-xs q-mr-none">
{{ scope.opt.positionPath }}
</q-chip>
<q-item-label caption>
<q-icon
class="q-mr-sm"
size="15px"
color="primary"
name="mdi-bookmark"
v-if="scope.opt.isDirector"
></q-icon>
{{ scope.opt.positionPathSide }}
{{ scope.opt.positionExecutive }}
{{ scope.opt.positionLevel }}
{{ scope.opt.positionLine }}
<!-- {{ scope.opt.positionType }}
{{ scope.opt.positionExecutiveSide }} -->
</q-item-label>
</template>
<template v-slot:no-option>
<ddNoResultMsg />
</template>
</q-select>
<q-input
dense
outlined
v-model.number="item.count"
class="col-xs-3 col-sm-2 col-md-2"
type="number"
hide-bottom-space
label="จำนวน"
:rules="[(val:any) => val > 0 || `${'ต้องมากกว่า 0'}`]"
/>
<div class="col-xs-12 col-sm-12 col-md-12">
<q-input
:class="getClass(true)"
hide-bottom-space
:outlined="true"
dense
lazy-rules
:readonly="false"
:borderless="false"
v-model="item.positionUserNote"
:label="`${'หมายเหตุ'}`"
type="textarea"
/>
<!-- :rules="[(val) => !!val || `${'กรุณากรอกเงื่อนไขตำแหน่ง'}`]" -->
</div>
</div>
</q-card>
</q-card>
</q-form>
</template>
<script setup lang="ts">
import { ref, defineAsyncComponent, watch, onMounted } from "vue";
import { useQuasar, QForm } from "quasar";
import type { PropType } from "vue";
import { useDataStore } from "@/stores/data";
import http from "@/plugins/http";
import config from "@/app.config";
import type { DataOption } from "../../interface/index/Main";
const ddNoResultMsg = defineAsyncComponent(
() => import("@/components/DropDownNoResultMsg.vue")
); // Dropdown Filter
const dataStore = useDataStore();
const { loaderPage } = dataStore;
const $q = useQuasar(); // show dialog
const emit = defineEmits(["update:positions", "update:formprops"]);
const props = defineProps({
positions: Array,
formprops: QForm as PropType<QForm | null>,
isAddNew: {
type: Boolean,
required: true,
// default: true,
},
editObj: Object, //FE rowClickTree
});
const myForm = ref<QForm | null>(null);
watch(myForm, (form: QForm | null, prevForm: QForm | null) => {
if (!props.isAddNew) {
positions.value.push(JSON.parse(JSON.stringify(positionSet.value)));
if (!props.editObj != null && !props.editObj != undefined) {
// console.log("position.value", position.value);
// console.log("props.editObj", props.editObj);
positions.value[0].positionMasterId = props.editObj?.positionMasterId;
positions.value[0].positionUserNote = props.editObj?.positionUserNote;
}
}
emit("update:formprops", form);
});
const positions = ref<Array<any>>([]); //Array positionSet Array<object> html
const positionSet = ref<object>({
count: 1, //
positionMasterId: "", // Table PositionMaster ,
positionUserNote: "",
}); // Drop Down key API
emit("update:positions", positions.value);
const positionFilter = ref<Array<any>>([]); //for DropDown
const position = ref<Array<any>>([]); //for DropDown
onMounted(async () => {
loaderPage(false);
await fetchPositionMaster();
});
const fetchPositionMaster = async () => {
loaderPage(true);
await http
// .get(config.API.getPostionMasterDraft(false))
.get(config.API.getPostionMaster(false))
.then((res) => {
// console.log("psMaster:", res.data.result);
res.data.result.map((e: any) => {
positionFilter.value.push({
id: e.id,
isActive: e.isActive,
positionType: e.positionType,
positionLine: e.positionLine,
positionPath: e.positionPath,
positionPathSide: e.positionPathSide,
positionExecutive: e.positionExecutive,
positionExecutiveSide: e.positionExecutiveSide,
positionLevel: e.positionLevel.toString(),
positionStatus: e.positionStatus,
positionTypeId: e.positionTypeId,
positionMasterId: e.positionMasterId,
positionLineId: e.positionLineId,
positionPathId: e.positionPathId,
positionPathSideId: e.positionPathSideId,
positionExecutiveId: e.positionExecutiveId,
positionExecutiveSideId: e.positionExecutiveSideId,
positionLevelId: e.positionLevelId,
positionStatusId: e.positionStatusId,
positionCondition: e.positionCondition,
positionMasterUserNote: e.positionMasterUserNote,
isDirector: e.isDirector,
});
position.value = positionFilter.value;
});
})
.catch((e) => {
console.log(e);
})
.finally(() => {
loaderPage(false);
});
};
/**Fuction Filter DropDown
* q-select งคามาใหเองจาก @filter="filterFn"
* @param val าตวพมพนหา
* @param update กครงทมพ
*/
const filterFn = (val: string, update: any) => {
if (val === "") {
update(() => {
position.value = positionFilter.value;
//
// here you have access to "ref" which
// is the Vue reference of the QSelect
});
return;
}
update(() => {
position.value = positionFilter.value.filter(
(v: any) => v.positionPath != null && v.positionPath.indexOf(val) > -1
);
});
// console.log(positions.value);
};
/**Add new positionSet item into positions
*กรอกขอมลสำคญครบถงเพ ตำแหน ใหมได
*อมลไมครบแสดง Alert เตอนใหเฉยๆ แลวไมใหเพ
*/
const addPositionItem = () => {
// console.log(positions.value);
myForm.value!.validate().then((result) => {
if (result) {
positions.value.push(JSON.parse(JSON.stringify(positionSet.value)));
// positions.value.push(ref<any>(positionSet.value));
emit("update:positions", positions.value);
} else {
// pop-up user
console.log("validation fail");
}
});
};
/**Delete positionSet item from positions
* ลบตำแหนงตวทกดลบ
* @param val data ใน item จะลบ
*/
const deletePositionItem = (val: object) => {
//Check if val is completed before delete
// filter array [val]
if (!isEmptyPosition([val])) {
$q.dialog({
title: "ยืนยันการลบข้อมูล",
message: "มีข้อมูลอยู่ หากต้องการลบกด ตกลง",
cancel: true,
persistent: true,
})
.onOk(() => {
// console.log(">>>> OK");
positions.value = positions.value.filter((x: object) => x !== val); //
// console.log(positions.value);
})
.onCancel(() => {
// console.log(">>>> Cancel");
})
.onDismiss(() => {
// console.log("I am triggered on both OK and Cancel");
});
} else {
positions.value = positions.value.filter((x: object) => x !== val);
}
emit("update:positions", positions.value);
};
/** Check if position is Empty
* -- return true/false
* @param items Array of position
*/
const isEmptyPosition = (items: any[]) => {
console.log("items", items);
const isEmpty = items.map((f: any) => !f.positionMasterId);
// true
// data false
console.log("isEmpty", isEmpty[0]);
return isEmpty[0];
};
/**class
* copy from AddMappingPositions
* @param val อม input สำหรบแกไขหรอไม
*/
const getClass = (val: boolean) => {
return {
"full-width inputgreen cursor-pointer": val,
"full-width cursor-pointer": !val,
};
};
</script>
<style>
.text1 {
color: gray;
font-weight: 400;
padding-right: 2px;
font-size: 13px;
}
.text2 {
font-weight: 400;
padding-right: 10px;
}
</style>

View file

@ -0,0 +1,999 @@
<template>
<div>
<div class="row col-12 items-center q-pt-md">
<div class="bg-white q-px-sm topCard">
<span class="text-weight-medium">เพมหนวยงาน</span>
<q-btn
flat
color="primary"
size="12px"
icon="mdi-plus"
dense
class="q-mx-sm"
@click="addOrganizationItem()"
>
<q-tooltip>เพมหนวยงาน</q-tooltip>
</q-btn>
</div>
</div>
<!-- การดเพมหนวยงาน-->
<q-form ref="myForm">
<q-card bordered flat>
<div class="overScroll q-py-sm">
<q-card
flat
class="bg-grey-2 q-pa-sm q-ma-sm row col-12 items-start"
v-for="(item, index) in organizations"
:key="index"
>
<div>
<q-avatar
class="q-mr-sm"
size="25px"
color="grey-3"
text-color="grey-9"
>{{ index + 1 }}</q-avatar
>
</div>
<q-btn
flat
round
color="red"
size="10px"
class="q-mr-sm"
icon="mdi-trash-can-outline"
dense
@click="deleteOrgItem(item)"
/>
<!-- @update:model-value="updateGoverment" -->
<div class="col-11 row q-col-gutter-xs">
<selector
hide-bottom-space
dense
outlined
v-model="item.organizationOrganizationId"
:options="organizationOri"
label="หน่วยงาน"
class="col-xs-12 col-sm-4 col-md-3"
use-input
input-debounce="0"
@filter="
(inputValue:any, doneFn:Function) =>
filterSelector(inputValue, doneFn, '1')
"
option-label="name"
option-value="id"
map-options
emit-value
clearable
:rules="[(val:any) => !!val || `${'กรุณาเลือกหน่วยงาน'}`]"
/>
<selector
hide-bottom-space
dense
outlined
v-model="item.organizationAgencyCode"
:options="organizationAgencyCode"
label="รหัสหน่วยงาน"
class="col-xs-12 col-sm-4 col-md-3"
use-input
input-debounce="0"
@filter="
(inputValue:any, doneFn:Function) =>
filterCodeSelector(inputValue, doneFn, '2',item)
"
@update:model-value="(value:any) => updateGovernmentCode(value, item)"
option-label="agencyCode"
option-value="agencyCode"
map-options
emit-value
clearable
:rules="[(val:any) => !!val || `${'กรุณาเลือกรหัสหน่วยงาน'}`]"
/>
<selector
hide-bottom-space
dense
outlined
v-model="item.organizationGovernmentCode"
:options="item.organizationGovernmentCodeOption"
label="รหัสส่วนราชการ"
class="col-xs-12 col-sm-4 col-md-3"
use-input
input-debounce="0"
@filter="
(inputValue:any, doneFn:Function) =>
filterCodeSelector(inputValue, doneFn, '3',item)
"
@update:model-value="(value:any) => updateAgencyCode(value, item)"
option-label="governmentCode"
option-value="governmentCode"
map-options
emit-value
clearable
:rules="[(val:any) => !!val || `${'กรุณาเลือกรหัสส่วนราชการ'}`]"
/>
<q-input
hide-bottom-space
dense
readonly
outlined
:modelValue="item.organizationShortName.toString() ?? ''"
label="ชื่อย่อหน่วยงาน"
class="col-xs-12 col-sm-4 col-md-3"
/>
<selector
hide-bottom-space
dense
outlined
v-model="item.organizationAgencyId"
:options="organizationAgency"
label="หน่วยงานต้นสังกัด"
class="col-xs-12 col-sm-4 col-md-3"
use-input
input-debounce="0"
@filter="
(inputValue:any, doneFn:Function) =>
filterSelector(inputValue, doneFn, '1')
"
option-label="name"
option-value="id"
map-options
emit-value
clearable
/>
<selector
hide-bottom-space
dense
outlined
v-model="item.organizationGovernmentAgencyId"
:options="organizationGovernmentAgency"
label="ส่วนราชการต้นสังกัด"
class="col-xs-12 col-sm-4 col-md-3"
use-input
input-debounce="0"
@filter="
(inputValue:any, doneFn:Function) =>
filterSelector(inputValue, doneFn, '1')
"
option-label="name"
option-value="id"
map-options
emit-value
clearable
/>
<selector
hide-bottom-space
dense
outlined
v-model="item.organizationTypeId"
:options="organizationType"
label="ประเภทหน่วยงาน"
class="col-xs-12 col-sm-4 col-md-3"
use-input
input-debounce="0"
@filter="
(inputValue:any, doneFn:Function) =>
filterSelector(inputValue, doneFn, '6')
"
option-label="name"
option-value="id"
map-options
emit-value
clearable
/><!-- :rules="[(val:any) => !!val || `${''}`]" -->
<selector
hide-bottom-space
dense
outlined
v-model="item.organizationLevelId"
:options="organizationLevel"
label="ระดับหน่วยงาน"
class="col-xs-12 col-sm-4 col-md-3"
use-input
input-debounce="0"
@filter="
(inputValue:any, doneFn:Function) =>
filterSelector(inputValue, doneFn, '7')
"
option-label="name"
option-value="id"
map-options
emit-value
clearable
:rules="[(val:any) => !!val || `${'กรุณาเลือกระดับหน่วยงาน'}`]"
/>
<selector
hide-bottom-space
dense
outlined
v-model="item.organizationExternalPhoneId"
:options="organizationTelExternal"
label="หมายเลขโทรศัพท์ติดต่อจากภายนอก"
class="col-xs-12 col-sm-4 col-md-3"
use-input
input-debounce="0"
@filter="
(inputValue:any, doneFn:Function) =>
filterSelector(inputValue, doneFn, '8')
"
option-label="name"
option-value="id"
map-options
emit-value
clearable
/>
<selector
hide-bottom-space
dense
outlined
v-model="item.organizationInternalPhoneId"
:options="organizationTelInternal"
label="หมายเลขโทรศัพท์ติดต่อจากภายใน"
class="col-xs-12 col-sm-4 col-md-3"
use-input
input-debounce="0"
@filter="
(inputValue:any, doneFn:Function) =>
filterSelector(inputValue, doneFn, '9')
"
option-label="name"
option-value="id"
map-options
emit-value
clearable
/>
<selector
hide-bottom-space
dense
outlined
v-model="item.organizationFaxId"
:options="organizationFax"
label="หมายเลขโทรสาร"
class="col-xs-12 col-sm-4 col-md-3"
use-input
input-debounce="0"
@filter="
(inputValue:any, doneFn:Function) =>
filterSelector(inputValue, doneFn, '10')
"
option-label="name"
option-value="id"
map-options
emit-value
clearable
/>
<q-input
dense
outlined
v-model="item.agency"
class="col-xs-12 col-sm-4 col-md-3"
label="หน่วยงาน"
/>
<q-input
dense
outlined
v-model="item.government"
class="col-xs-12 col-sm-4 col-md-3"
label="ส่วนราชการ"
/>
<q-input
dense
outlined
v-model="item.department"
class="col-xs-12 col-sm-4 col-md-3"
label="ฝ่าย/ส่วน"
/>
<q-input
dense
outlined
v-model="item.pile"
class="col-xs-12 col-sm-4 col-md-3"
label="กอง"
/>
<q-input
dense
outlined
:modelValue="Number(item.organizationOrder) ?? 0"
class="col-xs-12 col-sm-4 col-md-3"
type="number"
label="ลำดับผังโครงสร้าง"
/>
<div class="col-xs-12 col-sm-12 col-md-12">
<q-input
:class="getClass(true)"
hide-bottom-space
:outlined="true"
dense
lazy-rules
:readonly="false"
:borderless="false"
v-model="item.organizationUserNote"
:label="`${'หน้าที่รับผิดชอบ'}`"
type="textarea"
/>
<!-- :rules="[(val) => !!val || `${'กรุณากรอกเงื่อนไขตำแหน่ง'}`]" -->
</div>
</div>
</q-card>
</div>
</q-card>
</q-form>
</div>
</template>
<script setup lang="ts">
import { ref, defineAsyncComponent, watch, onMounted } from "vue";
import type { PropType } from "vue";
import { useQuasar, QForm } from "quasar";
import http from "@/plugins/http";
import config from "@/app.config";
import type {
DataOption,
OrganizaOption,
GovermentOption,
} from "../../interface/index/Main";
import { log } from "console";
import { useDataStore } from "@/stores/data";
// import { organizationSet } from "../interface/index/Main";
const props = defineProps({
organizprops: Array as PropType<OrganizaOption[]>,
formprops: QForm as PropType<QForm | null>,
});
const emit = defineEmits(["update:organizprops", "update:formprops"]);
const dataStore = useDataStore();
const { loaderPage } = dataStore;
const $q = useQuasar(); // show dialog
const myForm = ref<QForm | null>(null);
// const organizations = ref<OrganizaOption[]>([]);
const organizations = ref<OrganizaOption[]>([]);
emit("update:organizprops", organizations.value);
// emit("update:formprops", myForm.value);
watch(myForm, (form: QForm | null, prevForm: QForm | null) => {
emit("update:formprops", form);
});
const organizationFax = ref<DataOption[]>([]);
const organizationTelInternal = ref<DataOption[]>([]);
const organizationTelExternal = ref<DataOption[]>([]);
const organizationFaxFilter = ref<DataOption[]>([]);
const organizationTelInternalFilter = ref<DataOption[]>([]);
const organizationTelExternalFilter = ref<DataOption[]>([]);
const organizationGovernmentAgency = ref<DataOption[]>([]);
const organizationGovernmentAgencyFilter = ref<DataOption[]>([]);
const organizationAgency = ref<DataOption[]>([]);
const organizationAgencyFilter = ref<DataOption[]>([]);
const organizationType = ref<DataOption[]>([]);
const organizationTypeFilter = ref<DataOption[]>([]);
const organizationLevel = ref<DataOption[]>([]);
const organizationLevelFilter = ref<DataOption[]>([]);
const organizationOri = ref<DataOption[]>([]);
const organizationOriFilter = ref<DataOption[]>([]);
const organizationGovernmentCode = ref<GovermentOption[]>([]);
const organizationGovernmentCodeFilter = ref<GovermentOption[]>([]);
const organizationAgencyCode = ref<GovermentOption[]>([]);
const organizationAgencyCodeFilter = ref<GovermentOption[]>([]);
onMounted(async () => {
loaderPage(false);
await fetchOrganizationOri();
await fetchOrganizationAgencyCode();
await fetchOrganizationGovernmentCode();
await fetchOrganizationAgency();
await fetchOrganizationGovernmentAgency();
await fetchOrganizationType();
await fetchOrganizationLevel();
await fetchOrganizationFax();
await fetchOrganizationTelExternal();
await fetchOrganizationTelInternal();
});
/**
* หนวยงาน
*/
const fetchOrganizationOri = async () => {
loaderPage(true);
await http
.get(config.API.organization)
.then((res) => {
const data = res.data.result;
let option: DataOption[] = [];
data.map((r: any) => {
option.push({ id: r.id.toString(), name: r.name.toString() });
});
organizationOri.value = option;
organizationOriFilter.value = option;
})
.catch((e) => {
console.log(e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* รหสหนวยงาน
*/
const fetchOrganizationAgencyCode = async () => {
loaderPage(true);
await http
.get(config.API.organizationCode)
.then((res) => {
const data = res.data.result;
// console.log(data);
let option: GovermentOption[] = [];
data.map((r: any) => {
option.push({
id: r.id.toString(),
governmentCode: r.governmentCode.toString(),
agencyCode: r.agencyCode.toString(),
shortName: r.name.toString(),
});
});
organizationAgencyCode.value = option;
organizationAgencyCodeFilter.value = option;
})
.catch((e) => {
console.log(e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* รหสสวนราชการ
*/
const fetchOrganizationGovernmentCode = async () => {
loaderPage(true);
await http
.get(config.API.organizationShortName)
.then((res) => {
const data = res.data.result;
// console.log(data);
let option: GovermentOption[] = [];
data.map((r: any) => {
option.push({
id: r.id.toString(),
governmentCode: r.governmentCode.toString(),
agencyCode: r.agencyCode.toString(),
shortName: r.name.toString(),
});
});
organizationGovernmentCode.value = option;
organizationGovernmentCodeFilter.value = option;
})
.catch((e) => {
console.log(e);
})
.finally(() => {
loaderPage(false);
});
};
// /**
// *
// */
// const fetchOrganizationShortName = async () => {
// loaderPage(true);
// await http
// .get(config.API.organizationShortName)
// .then((res) => {
// const data = res.data.result;
// // console.log(data);
// let option: GovermentOption[] = [];
// data.map((r: any) => {
// option.push({
// id: r.id.toString(),
// name: r.governmentCode.toString(),
// agencyCode: r.agencyCode.toString(),
// shortName: r.name.toString(),
// });
// });
// organizationShortName.value = option;
// organizationShortNameFilter.value = option;
// })
// .catch((e) => {
// console.log(e);
// })
// .finally(() => {
// loaderPage(false);
// });
// };
/**
* หนวยงานตนสงก
*/
const fetchOrganizationAgency = async () => {
loaderPage(true);
await http
.get(config.API.listOrganizationAgency("หน่วยงาน"))
.then((res) => {
const data = res.data.result;
let option: DataOption[] = [];
data.map((r: any) => {
option.push({
id: r.organizationId.toString(),
name: r.organizationName.toString(),
});
});
organizationAgency.value = option;
organizationAgencyFilter.value = option;
})
.catch((e) => {
console.log(e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* วนราชการตนสงก
*/
const fetchOrganizationGovernmentAgency = async () => {
loaderPage(true);
await http
.get(config.API.listOrganizationAgency("ส่วนราชการ"))
.then((res) => {
const data = res.data.result;
let option: DataOption[] = [];
data.map((r: any) => {
option.push({
id: r.organizationId.toString(),
name: r.organizationName.toString(),
});
});
organizationGovernmentAgency.value = option;
organizationGovernmentAgencyFilter.value = option;
})
.catch((e) => {
console.log(e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* ประเภทหนวยงาน
*/
const fetchOrganizationType = async () => {
loaderPage(true);
await http
.get(config.API.organizationType)
.then((res) => {
const data = res.data.result;
let option: DataOption[] = [];
data.map((r: any) => {
option.push({ id: r.id.toString(), name: r.name.toString() });
});
organizationType.value = option;
organizationTypeFilter.value = option;
})
.catch((e) => {
console.log(e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* ระดบหนวยงาน
*/
const fetchOrganizationLevel = async () => {
loaderPage(true);
await http
.get(config.API.organizationLevel)
.then((res) => {
const data = res.data.result;
let option: DataOption[] = [];
data.map((r: any) => {
option.push({ id: r.id.toString(), name: r.name.toString() });
});
organizationLevel.value = option;
organizationLevelFilter.value = option;
})
.catch((e) => {
console.log(e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* เบอรดตอภายใน
*/
const fetchOrganizationTelInternal = async () => {
loaderPage(true);
await http
.get(config.API.organizationTelInternal)
.then((res) => {
const data = res.data.result;
let option: DataOption[] = [];
data.map((r: any) => {
option.push({ id: r.id.toString(), name: r.name.toString() });
});
organizationTelInternal.value = option;
organizationTelInternalFilter.value = option;
})
.catch((e) => {
console.log(e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* เบอรดตอภายนอก
*/
const fetchOrganizationTelExternal = async () => {
loaderPage(true);
await http
.get(config.API.organizationTelExternal)
.then((res) => {
const data = res.data.result;
let option: DataOption[] = [];
data.map((r: any) => {
option.push({ id: r.id.toString(), name: r.name.toString() });
});
organizationTelExternal.value = option;
organizationTelExternalFilter.value = option;
})
.catch((e) => {
console.log(e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* เบอรโทรสาร
*/
const fetchOrganizationFax = async () => {
loaderPage(true);
await http
.get(config.API.organizationFax)
.then((res) => {
const data = res.data.result;
let option: DataOption[] = [];
data.map((r: any) => {
option.push({ id: r.id.toString(), name: r.name.toString() });
});
organizationFax.value = option;
organizationFaxFilter.value = option;
})
.catch((e) => {
console.log(e);
})
.finally(() => {
loaderPage(false);
});
};
/**Delete positionSet item from positions
* ลบตำแหนงตวทกดลบ
* @param val data ใน item จะลบ
*/
const deleteOrgItem = (val: OrganizaOption) => {
//Check if val is completed before delete
// filter array [val]
if (!isEmptyOrganization([val])) {
$q.dialog({
title: "ยืนยันการลบข้อมูล",
message: "มีข้อมูลอยู่ หากต้องการลบกด ตกลง",
cancel: true,
persistent: true,
})
.onOk(() => {
// console.log(">>>> OK");
organizations.value = organizations.value.filter(
(x: object) => x !== val
); //
// console.log(positions.value);
})
.onCancel(() => {
// console.log(">>>> Cancel");
})
.onDismiss(() => {
// console.log("I am triggered on both OK and Cancel");
});
} else {
organizations.value = organizations.value.filter((x: object) => x !== val);
}
emit("update:organizprops", organizations.value);
};
/** Check if organization is Empty
* -- return true/false
* @param items Array of OrganizaOption
*/
const isEmptyOrganization = (items: OrganizaOption[]) => {
const isEmpty = items.map(
(f: OrganizaOption) =>
!f.organizationOrganizationId &&
!f.organizationShortNameId &&
!f.organizationAgencyId &&
!f.organizationGovernmentAgencyId &&
!f.organizationTypeId &&
!f.organizationLevelId &&
!f.organizationExternalPhoneId &&
!f.organizationInternalPhoneId &&
!f.organizationFaxId
);
// true
// data false
return isEmpty[0];
};
/**Add new positionSet item into positions
*กรอกขอมลสำคญครบถงเพ ตำแหน ใหมได
*อมลไมครบแสดง Alert เตอนใหเฉยๆ แลวไมใหเพ
*/
const addOrganizationItem = async () => {
await myForm.value!.validate().then(async (result: boolean) => {
// console.log(result);
if (result) {
// organizations.value.push(JSON.parse(JSON.stringify(organizationSet)));
organizations.value.push({
organizationOrganizationId: "", //
organizationShortNameId: "", // Id
organizationShortName: "", //
organizationAgencyCode: "", //
organizationGovernmentCode: "", //
organizationAgencyId: "", //
organizationGovernmentAgencyId: "", //
organizationTypeId: "", //
organizationLevelId: "", //
organizationInternalPhoneId: "", //
organizationExternalPhoneId: "", //
organizationFaxId: "", //
organizationOrder: 0, //
organizationUserNote: "", // User Note
organizationStatusId: "",
agency: "", //
government: "", //
department: "", // /
pile: "", //
organizationGovernmentCodeOption: organizationGovernmentCode.value,
organizationGovernmentCodeOptionFilter:
organizationGovernmentCodeFilter.value,
});
emit("update:organizprops", organizations.value);
// console.log(organizations);
}
});
};
const fetchAgencyCode = async (val: string, item: OrganizaOption) => {
let option: GovermentOption[] = [];
loaderPage(true);
await http
.get(config.API.organizationGovernmentCode(val))
.then((res) => {
const data = res.data.result;
data.map((r: any) => {
option.push({
id: r.id.toString(),
governmentCode: r.governmentCode.toString(),
agencyCode: r.agencyCode.toString(),
shortName: r.name.toString(),
});
});
// organizationAgencyCode.value = option;
// organizationAgencyCodeFilter.value = option;
})
.catch((e) => {
console.log(e);
})
.finally(() => {
loaderPage(false);
});
return option;
};
const fetchGovernmentCode = async (val: string, item: OrganizaOption) => {
let option: GovermentOption[] = [];
loaderPage(true);
await http
.get(config.API.organizationAgencyCode(val))
.then((res) => {
const data = res.data.result;
data.map((r: any) => {
option.push({
id: r.id.toString(),
governmentCode: r.governmentCode.toString(),
agencyCode: r.agencyCode.toString(),
shortName: r.name.toString(),
});
});
item.organizationGovernmentCodeOption = option;
item.organizationGovernmentCodeOptionFilter = option;
})
.catch((e) => {
console.log(e);
})
.finally(() => {
loaderPage(false);
});
return option;
};
/**
* q-select งคามาใหเองจาก @update:model-value="updateShortName"
* @param val าตวทเลอก
*/
const updateAgencyCode = async (val: string, item: OrganizaOption) => {
let option = await fetchAgencyCode(val, item);
// organizationAgencyCode.value = option;
// organizationAgencyCodeFilter.value = option;
// const find = option.filter((r) => r.governmentCode === val);
// if (find.length == 1) {
item.organizationShortName = option[0].shortName.toString();
item.organizationAgencyCode = option[0].agencyCode.toString();
item.organizationGovernmentCode = option[0].governmentCode.toString();
item.organizationShortNameId = option[0].id;
// } else {
// item.organizationShortName = "";
// item.organizationAgencyCode = "";
// // item.organizationGovernmentCode = "";
// }
await fetchGovernmentCode(item.organizationAgencyCode, item);
};
/**
* q-select งคามาใหเองจาก @update:model-value="updateShortName"
* @param val าตวทเลอก
*/
const updateGovernmentCode = async (val: string, item: OrganizaOption) => {
let option = await fetchGovernmentCode(val, item);
const find = option.filter((r) => r.agencyCode === val);
if (find.length == 1) {
item.organizationShortName = find[0].shortName.toString();
item.organizationAgencyCode = find[0].agencyCode.toString();
item.organizationGovernmentCode = find[0].governmentCode.toString();
item.organizationShortNameId = find[0].id.toString();
} else {
item.organizationShortName = "";
// item.organizationAgencyCode = "";
item.organizationGovernmentCode = "";
}
};
const updateNumber = (item: OrganizaOption, newValue: any) => {
item.organizationOrder = newValue;
};
/**Fuction Filter DropDown
* q-select งคามาใหเองจาก @filter="filterSelector"
* @param val าตวพมพนหา
* @param update กครงทมพ
*/
const filterSelector = (val: any, update: Function, filtername: string) => {
switch (filtername) {
case "1":
update(() => {
organizationOri.value = organizationOriFilter.value.filter(
(v: DataOption) => v.name.indexOf(val) > -1
);
});
break;
// case "2":
// update(() => {
// organizationAgencyCode.value =
// organizationAgencyCodeFilter.value.filter(
// (v: GovermentOption) => v.agencyCode.indexOf(val) > -1
// );
// });
// break;
// case "3":
// update(() => {
// organizationGovernmentCode.value =
// organizationGovernmentCodeFilter.value.filter(
// (v: GovermentOption) => v.governmentCode.indexOf(val) > -1
// );
// });
// break;
case "4":
update(() => {
organizationAgency.value = organizationAgencyFilter.value.filter(
(v: DataOption) => v.name.indexOf(val) > -1
);
});
break;
case "5":
update(() => {
organizationGovernmentAgency.value =
organizationGovernmentAgencyFilter.value.filter(
(v: DataOption) => v.name.indexOf(val) > -1
);
});
break;
case "6":
update(() => {
organizationType.value = organizationTypeFilter.value.filter(
(v: DataOption) => v.name.indexOf(val) > -1
);
});
break;
case "7":
update(() => {
organizationLevel.value = organizationLevelFilter.value.filter(
(v: DataOption) => v.name.indexOf(val) > -1
);
});
break;
case "8":
update(() => {
organizationTelExternal.value =
organizationTelExternalFilter.value.filter(
(v: DataOption) => v.name.indexOf(val) > -1
);
});
break;
case "9":
update(() => {
organizationTelInternal.value =
organizationTelInternalFilter.value.filter(
(v: DataOption) => v.name.indexOf(val) > -1
);
});
break;
case "10":
update(() => {
organizationFax.value = organizationFaxFilter.value.filter(
(v: DataOption) => v.name.indexOf(val) > -1
);
});
break;
default:
break;
}
};
const filterCodeSelector = (
val: any,
update: Function,
filtername: string,
item: OrganizaOption
) => {
switch (filtername) {
case "2":
update(() => {
organizationAgencyCode.value =
organizationAgencyCodeFilter.value.filter(
(v: GovermentOption) => v.agencyCode.indexOf(val) > -1
);
});
break;
case "3":
update(() => {
item.organizationGovernmentCodeOption =
item.organizationGovernmentCodeOptionFilter.filter(
(v: GovermentOption) => v.governmentCode.indexOf(val) > -1
);
});
break;
}
};
/**class
* copy from AddMappingPositions
* @param val อม input สำหรบแกไขหรอไม
*/
const getClass = (val: boolean) => {
return {
"full-width inputgreen cursor-pointer": val,
"full-width cursor-pointer": !val,
};
};
</script>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,232 @@
<!-- =============================== -->
<!-- Component มกด หน TreeList -->
<!-- v-model:editvisible="True/False" -->
<!-- :refreshData="clearLocalStorage Function"
:deleteDraft="clickDeleteDraft Function"
:publishDraft="clickPublish Function"
:publicData="version === 'published'" (True = Disable Buttons) -->
<!-- =============================== -->
<template>
<div>
<q-btn
v-if="!editvisible"
flat
round
:disabled="editvisible"
:color="editvisible ? 'grey-7' : 'primary'"
@click="clickEdit()"
icon="mdi-pencil-outline"
class="q-mr-sm"
>
<q-tooltip>แกไขโครงสราง</q-tooltip>
</q-btn>
<q-btn
flat
round
v-if="editvisible"
:disabled="!editvisible"
:color="!editvisible ? 'grey-7' : 'red'"
@click="clickCancel()"
icon="mdi-undo"
class="q-mr-sm"
>
<q-tooltip>ยกเล</q-tooltip>
</q-btn>
<!-- ลบบนทกราง แสดงเม นทกรางแล -->
<q-btn
flat
round
:disabled="publicData == true || editvisible == false"
:color="
publicData == true || editvisible == false ? 'grey-7' : 'deep-orange'
"
@click="showDeleteModal()"
icon="mdi-file-remove-outline"
class="q-mr-sm"
>
<q-tooltip>ลบบนทกราง</q-tooltip>
</q-btn>
<!-- เผยแพร -->
<q-btn
flat
round
:disabled="
!(publicData == false || updateData == true) || editvisible == false
"
:color="
!(publicData == false || updateData == true) || editvisible == false
? 'grey-7'
: 'public'
"
icon="mdi-cloud-upload-outline"
@click="showPublishModal()"
class="q-mr-sm"
>
<q-tooltip>เผยแพร</q-tooltip>
</q-btn>
<!-- refresh data -->
<q-btn
flat
round
icon="mdi-refresh"
@click="refreshData()"
color="public"
class="q-mr-sm"
>
<q-tooltip>เฟรชขอม</q-tooltip>
</q-btn>
<q-space />
</div>
<!-- อมลการเผยแพรอม -->
<!-- <q-dialog v-model="modalPublish" persistent>
<q-card class="q-pa-sm">
<q-card-section class="row">
<div class="q-pr-md">
<q-avatar
icon="public"
size="lg"
font-size="25px"
color="blue-1"
text-color="public"
/>
</div>
<div class="col text-dark">
<span class="text-bold">องการเผยแพรอมลนหรอไม?</span>
<br />
<span>อมลทกำลงถกเผยแพรจะมผลใชงานทนท</span>
</div>
</q-card-section>
<q-card-actions align="right" class="bg-white text-teal">
<q-btn label="ยกเลิก" flat color="grey-8" v-close-popup />
<q-btn
label="เผยแพร่"
color="public"
@click="publishDraft()"
v-close-popup
/>
</q-card-actions>
</q-card>
</q-dialog> -->
<!-- <notifyPublishDraft v-model:showModal="modalPublish" :ok="publishDraft" /> -->
<!-- อมลการลบเผยแพรอม -->
<!-- <q-dialog v-model="modalDelete" persistent>
<q-card class="q-pa-sm">
<q-card-section class="row">
<div class="q-pr-md">
<q-avatar
icon="mdi-file-remove-outline"
size="lg"
font-size="25px"
color="red-1"
text-color="deep-orange"
/>
</div>
<div class="col text-dark">
<span class="text-bold">องการลบขอมลบนทกรางนหรอไม?</span>
<br />
<span>อมลบนทกรางทกำลงถกลบนจะมผลใชงานทนท</span>
</div>
</q-card-section>
<q-card-actions align="right" class="bg-white text-teal">
<q-btn label="ยกเลิก" flat color="grey-8" v-close-popup />
<q-btn
label="ลบบันทึก"
color="red"
@click="deleteDraft()"
v-close-popup
/>
</q-card-actions>
</q-card>
</q-dialog> -->
<!-- <notifyDeleteDraft v-model:showModal="modalDelete" :ok="deleteDraft" /> -->
</template>
<script setup lang="ts">
// import NotifyDeleteDraft from "@/components/NotifyDeleteDraft.vue";
import { ref } from "vue";
import { useCounterMixin } from "@/stores/mixin";
import { useQuasar } from "quasar";
const $q = useQuasar();
const mixin = useCounterMixin(); //
const { dialogMessage } = mixin;
const modalPublish = ref<boolean>(false);
const modalDelete = ref<boolean>(false);
const emit = defineEmits(["update:editvisible"]);
const props = defineProps({
editvisible: {
type: Boolean,
defualt: false,
},
publicData: {
type: Boolean,
defualt: true,
required: false,
},
updateData: {
type: Boolean,
defualt: true,
required: false,
},
refreshData: {
type: Function,
default: () => console.log("call Parent refreshData"),
},
publishDraft: {
type: Function,
default: () => console.log("call parent publishDraft"),
},
deleteDraft: {
type: Function,
default: () => console.log("call parent deleteDraft"),
},
});
const clickRefresh = () => {
props.refreshData();
};
const clickEdit = () => {
emit("update:editvisible", !props.editvisible);
};
const clickCancel = () => {
emit("update:editvisible", !props.editvisible);
};
const showPublishModal = () => {
// modalPublish.value = true;
dialogMessage(
$q,
"ต้องการเผยแพร่ข้อมูลนี้หรือไม่?",
"ข้อมูลที่กำลังถูกเผยแพร่นี้จะมีผลใช้งานทันที",
"public",
"เผยแพร่",
"public",
props.publishDraft,
undefined
);
};
const showDeleteModal = () => {
// modalDelete.value = true;
dialogMessage(
$q,
"ต้องการลบข้อมูลบันทึกร่างนี้หรือไม่?",
"ข้อมูลบันทึกร่างที่กำลังถูกลบนี้จะมีผลใช้งานทันที",
"mdi-file-remove-outline",
"ลบบันทึก",
"red",
props.deleteDraft,
undefined
);
};
const hideDeleteModal = () => {
props.deleteDraft(); //Call Function DeleteDraft in Parent page
};
const hidePublishModal = () => {
props.publishDraft(); //Call Function DeleteDraft in Parent page
};
</script>
<style lang="scss">
.icon-color {
color: #4154b3;
}
</style>

View file

@ -0,0 +1,89 @@
import { readonly } from "vue";
interface Pagination {
rowsPerPage: number;
}
interface DataOption {
id: string;
name: string;
note?: string;
}
interface GovermentOption {
id: string;
shortName: string;
agencyCode: string;
governmentCode: string;
}
interface OrganizaOption {
organizationOrganizationId: string; // หน่วยงาน
organizationShortNameId: string; // Idย่อหน่วยงาน
organizationShortName: string; // ชื่อย่อหน่วยงาน
organizationAgencyCode: string; // รหัสหน่วยงาน
organizationGovernmentCode: string; // รหัสส่วนราชการ
organizationAgencyId: string; // หน่วยงานต้นสังกัด
organizationGovernmentAgencyId: string; // ส่วนราชการต้นสังกัด
organizationTypeId: string; // ประเภทหน่วยงาน
organizationLevelId: string; //ระดับหน่วยงาน
organizationInternalPhoneId: string; //เบอร์ติดต่อภายใน
organizationExternalPhoneId: string; //เบอร์ติดต่อภายนอก
organizationFaxId: string; //เบอร์โทรสาร
organizationOrder: Number; // ลำดับผังโครงสร้าง
organizationUserNote: string; // User Note
organizationStatusId: string; //status
organizationGovernmentCodeOption: GovermentOption[];
organizationGovernmentCodeOptionFilter: GovermentOption[];
agency: string; // หน่วยงาน
government: string; // ส่วนราชการ
department: string; // ฝ่าย/ส่วน
pile: string; // กอง
// organizationAgencyCodeOption: GovermentOption[];
// organizationAgencyCodeOptionFilter: GovermentOption[];
}
// const organizationSet = readonly<OrganizaOption>({
// organizationOrganizationId: "", // หน่วยงาน
// organizationShortNameId: "", // รหัสส่วนราชการ
// organizationShortName: "", // ชื่อย่อหน่วยงาน
// organizationShortCode: "", // รหัสหน่วยงาน
// organizationAgencyId: "", // หน่วยงานต้นสังกัด
// organizationGovernmentAgencyId: "", // ส่วนราชการต้นสังกัด
// organizationTypeId: "", // ประเภทหน่วยงาน
// organizationLevelId: "", //ระดับหน่วยงาน
// organizationInternalPhoneId: "", //เบอร์ติดต่อภายใน
// organizationExternalPhoneId: "", //เบอร์ติดต่อภายนอก
// organizationFaxId: "", //เบอร์โทรสาร
// organizationOrder: 0, // ลำดับผังโครงสร้าง
// organizationUserNote: "", // User Note
// });
interface UploadType {
id: string;
fileName: string;
fileSize: number;
fileType: string;
detail: string;
}
interface Columns {
[index: number]: {
name: String;
align: String;
label: String;
sortable: Boolean;
field: String;
headerStyle: String;
style: String;
};
}
// export { organizationSet };
export type {
Pagination,
DataOption,
OrganizaOption,
GovermentOption,
UploadType,
Columns,
};

View file

@ -0,0 +1,68 @@
//ข้อมูลประวัติแก้ไข
interface RequestItemsPublishHistoryObject {
id: string;
items: RequestItemsObject[];
publishedDate: string;
}
//ข้อมูล
interface RequestItemsObject {
id: string;
positionMasterId: string; //ประเภท
positionType: string; //ประเภท
positionLine: string; //สายงาน
positionPath: string; //ตำแหน่งในสายงาน
positionPathSide: string; //ด้านของสายงาน
positionExecutive: string; //ตำแหน่งบริหาร
positionExecutiveSide: string; //ด้านบริหาร
positionLevel: any; //ระดับ array text
positionStatus: string; //สถานภาพของตำแหน่ง
positionTypeId: string;
positionLineId: string;
positionPathId: string;
positionPathSideId: string;
positionExecutiveId: string;
positionExecutiveSideId: string;
positionStatusId: string; //สถานภาพของตำแหน่ง ไม่แน่ใจ DB
positionCondition: string; //เงื่อนไขตำแหน่ง
positionMasterUserNote: string; //หมายเหตุ
positionLevelId: any; //ระดับ array id
isDirector: boolean; //หัวหน้า
isActive: boolean;
isPublished?: boolean;
lastUpdateFullName?: String;
lastUpdatedAt?: Date;
}
//columns
interface Columns {
[index: number]: {
name: String;
align: String;
label: String;
sortable: Boolean;
field: String;
headerStyle: String;
style: String;
};
}
interface RequestReport2 {
organizationShortNameId: string;
organizationOrganizationId: string;
positionNumId: string;
positionTypeId: string;
positionExecutiveId: string;
positionExecutiveSideId: string;
positionPathId: string;
positionPathSideId: string;
positionLevelId: string;
status: string | null;
}
export type {
RequestItemsObject,
RequestItemsPublishHistoryObject,
Columns,
RequestReport2,
};

View file

@ -0,0 +1,103 @@
//ข้อมูล
interface ResponseObject {
id: string;
positionType: string;
positionLine: string;
positionPath: string;
positionPathSide: string;
positionExecutive: string;
positionExecutiveSide: string;
positionLevel: any;
positionTypeId: string;
positionLineId: string;
positionPathId: string;
positionPathSideId: string;
positionExecutiveId: string;
positionExecutiveSideId: string;
positionStatus: string;
titleStatus: string;
positionLevelId: any;
owner: boolean;
isActive: boolean;
}
interface ResponseTree {
no: number;
profilePositionId: string | null;
name: string | null;
edu: string | null;
posiNumOld: string | null;
posiNumNew: string | null;
posiOld: string | null;
posiNew: string | null;
levelOld: string | null;
levelNew: string | null;
change: string | null;
statusPosition: Boolean;
report2Id: string | null;
}
interface ResponseDetail {
report2Id: string;
name: string;
edu: string;
salary: number;
salary2: number;
salary3: number;
goverment: string;
agency: string;
posiNum: string;
category: string;
posiManage: string;
sideManage: string;
posiWork: string;
sideWork: string;
level: string;
goverment2: string;
agency2: string;
posiNum2: string;
category2: string;
posiManage2: string;
sideManage2: string;
posiWork2: string;
sideWork2: string;
level2: string;
}
interface ResponseHistoryHead {
historyId: string;
date: Date;
}
interface ResponseHistory {
fullName: string;
education: string;
salary: number;
salaryPosition: number;
salaryMonth: number;
oldOrganizationShortName: string;
oldOrganizationOrganization: string;
oldPositionNum: string;
oldPositionType: string;
oldPositionExecutive: string;
oldPositionExecutiveSide: string;
oldPositionPath: string;
oldPositionPathSide: string;
oldPositionLevel: string;
newOrganizationShortName: string;
newOrganizationOrganization: string;
newPositionNum: string;
newPositionType: string;
newPositionExecutive: string;
newPositionExecutiveSide: string;
newPositionPath: string;
newPositionPathSide: string;
newPositionLevel: string;
}
export type {
ResponseObject,
ResponseTree,
ResponseDetail,
ResponseHistory,
ResponseHistoryHead,
};

View file

@ -0,0 +1,113 @@
/**
* Router (Organizational)
*/
const MainMapping = () =>
import("@/modules/02_organizational/views/MainMapping.vue");
const MainStructChart = () =>
import("@/modules/02_organizational/views/MainStructChart.vue");
const MainOrgChart = () =>
import("@/modules/02_organizational/views/MainOrgChart.vue");
const MainTree = () => import("@/modules/02_organizational/views/MainTree.vue");
const MainReport = () =>
import("@/modules/02_organizational/views/MainReport.vue");
const ManageReport2 = () =>
import("@/modules/02_organizational/views/ManageReport2.vue");
const ManageReport2Add = () =>
import("@/modules/02_organizational/views/ManageReport2Add.vue");
const ManageReport2History = () =>
import("@/modules/02_organizational/views/ManageReport2History.vue");
export default [
{
path: "/organizational/mapping",
name: "organizationalMapping",
component: MainMapping,
meta: {
Auth: true,
Key: [7],
Role: "organization",
},
},
{
path: "/organizational/structchart",
name: "organizationalStructChart",
component: MainStructChart,
meta: {
Auth: true,
Key: [8],
Role: "organization",
},
},
{
path: "/organizational/orgchart",
name: "organizationalOrgChart",
component: MainOrgChart,
meta: {
Auth: true,
key: [14],
Role: "organization",
},
},
{
path: "/organizational/tree",
name: "organizationalTree",
component: MainTree,
meta: {
Auth: true,
Key: [9],
Role: "organization",
},
},
{
path: "/organizational/manage/report",
name: "manageReport2",
component: ManageReport2,
meta: {
Auth: true,
Key: [11],
Role: "organization",
},
},
{
path: "/organizational/manage/report/:id",
name: "ManageReport2Edit",
component: ManageReport2Add,
meta: {
Auth: true,
Key: [7],
Role: "organization",
},
},
{
path: "/organizational/manage/report/add",
name: "ManageReport2Add",
component: ManageReport2Add,
meta: {
Auth: true,
Key: [10],
Role: "organization",
},
},
{
path: "/organizational/manage/report/history/:id",
name: "ManageReport2History",
component: ManageReport2History,
meta: {
Auth: true,
Key: [15],
Role: "organization",
},
},
{
path: "/organizational/report",
name: "organizationalReport",
component: MainReport,
meta: {
Auth: true,
Key: [13],
Role: "organization",
},
},
];

View file

@ -0,0 +1,32 @@
import { ref, computed } from "vue";
import { defineStore } from "pinia";
export const useOrganizationalDataStore = defineStore("organizational", () => {
interface organizational {
mappingPosition: { columns: String[] };
}
const organizationalData = ref<organizational>({
mappingPosition: { columns: [] },
});
const changeOrganizationalColumns = (system: String, val: String[]) => {
if (system == "mappingPosition")
organizationalData.value.mappingPosition.columns = val;
localStorage.setItem(
"organizational",
JSON.stringify(organizationalData.value)
);
};
if (localStorage.getItem("organizational") !== null) {
organizationalData.value = JSON.parse(
localStorage.getItem("organizational") || "{}"
);
}
return {
organizationalData,
changeOrganizationalColumns,
};
});

View file

@ -0,0 +1,22 @@
<!-- =============================== -->
<!-- page:main page ดการตำแหน -->
<!-- =============================== -->
<template>
<div class="toptitle text-dark col-12 row items-center">ดการตำแหน</div>
<q-card flat bordered class="col-12 q-mt-sm q-pt-sm">
<div>
<AddMappingPosition class="q-pa-none" />
</div>
</q-card>
</template>
<script setup lang="ts">
import { defineAsyncComponent } from "@vue/runtime-core";
import { ref } from "vue";
const AddMappingPosition = defineAsyncComponent(
() => import("@/modules/02_organizational/components/AddMappingPositions.vue")
);
</script>
<style></style>

View file

@ -0,0 +1,144 @@
<script setup lang="ts">
import { ref, onMounted } from "vue";
import http from "@/plugins/http";
import config from "@/app.config";
import { OrgChart } from "bma-org-chart";
import "bma-org-chart/org-chart.css";
import chartData from "@/assets/orgChartData";
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); //
onMounted(async () => {
await fetchTreeRoot();
await fetchOrgChart();
});
/**
* าน Root ของขอมลทงหมดกอน
*/
const fetchTreeRoot = async () => {
loader.value = true;
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(() => {
loader.value = false;
});
};
const fetchOrgChart = async () => {
loader.value = true;
let urlRequest = config.API.chartGetOrg(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;
}
})
.catch((e) => {
console.log(e);
})
.finally(() => {
loader.value = false;
});
};
/**
* เมอมการคลกท 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 fetchOrgChart();
if (data.value !== undefined) data.value = 0;
};
</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">
<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>
<q-separator />
<div style="overflow-x: auto; overflow-y: auto" class="q-pt-md">
<OrgChart
style="height: 70vh"
ref="chartRef"
class="org"
:dataSource="dataSource"
@onElementClick="refreshChart"
/>
</div>
</q-card>
</div>
<full-loader :visibility="loader"></full-loader>
</template>
<style>
.org .section-list {
padding: 15px !important;
}
.org .section-list .column-content .header {
font-size: 1rem;
line-height: 1.2rem;
font-weight: 500 !important;
}
.org .section-list .column-content .subheader {
font-weight: 500 !important;
}
.org .section-list .column-content .caption {
font-size: 0.9rem;
line-height: 1.2rem;
font-weight: 400 !important;
}
.org .element-container .column-content p {
padding-top: 3px !important;
}
.org .element-container .column-side .side-button {
background-size: 14px;
}
</style>

View file

@ -0,0 +1,197 @@
<template>
<div class="toptitle text-dark col-12 row items-center">รายงานบญช</div>
<q-card flat bordered class="col-12">
<div class="row col-12">
<q-tabs
v-model="tab"
no-caps
inline-label
align="left"
class="text-primary"
>
<q-tab name="audit1" label="บัญชี 1" />
<q-tab name="audit2" label="บัญชี 2" />
<q-tab name="audit3" label="บัญชี 3" />
</q-tabs>
</div>
<q-separator />
<q-tab-panels
v-model="tab"
transition-prev="jump-up"
transition-next="jump-up"
animated
swipeable
class="row col-12 text-dark"
>
<q-tab-panel name="audit1">
<div class="row col-12 items-center q-gutter-md">
<q-select
class="col-xs-12 col-sm-6"
v-model="goverment"
label="ระบุรหัสส่วนราชการ"
dense
emit-value
map-options
option-label="name"
:options="govermentOP"
option-value="id"
lazy-rules
hide-bottom-space
:readonly="false"
:borderless="false"
:outlined="true"
:hide-dropdown-icon="false"
/>
<q-btn
size="md"
icon="mdi-download"
round
flat
color="primary"
@click="clickAccount1"
>
<q-tooltip>ดาวนโหลด</q-tooltip>
</q-btn>
</div>
</q-tab-panel>
<q-tab-panel name="audit2">
<div class="row col-12 items-center q-gutter-md">
<q-select
class="col-xs-12 col-sm-6"
v-model="goverment"
label="ระบุรหัสส่วนราชการ"
dense
emit-value
map-options
option-label="name"
:options="govermentOP"
option-value="id"
lazy-rules
hide-bottom-space
:readonly="false"
:borderless="false"
:outlined="true"
:hide-dropdown-icon="false"
/>
<q-btn
size="md"
icon="mdi-download"
flat
round
color="primary"
@click="clickAccount2"
>
<q-tooltip>ดาวนโหลด</q-tooltip>
</q-btn>
</div>
</q-tab-panel>
<q-tab-panel name="audit3">
<div class="row col-12 items-center q-gutter-md">
<q-select
class="col-xs-12 col-sm-6"
v-model="goverment"
label="ระบุรหัสส่วนราชการ"
dense
emit-value
map-options
option-label="name"
:options="govermentOP"
option-value="id"
lazy-rules
hide-bottom-space
:readonly="false"
:borderless="false"
:outlined="true"
:hide-dropdown-icon="false"
/>
<q-btn
size="md"
icon="mdi-download"
flat
round
color="primary"
@click="clickAccount3"
>
<q-tooltip>ดาวนโหลด</q-tooltip>
<!-- <viewpdf
:src="pdfSrc"
:currentpage="pdfCurrentPage"
:totalpage="pdfTotalPage" /> -->
</q-btn>
</div>
</q-tab-panel>
</q-tab-panels>
</q-card>
</template>
<script setup lang="ts">
import { onMounted, computed, ref, watch } from "vue";
import { useQuasar } from "quasar";
import { useCounterMixin } from "@/stores/mixin";
import { useRouter, useRoute } from "vue-router";
import { useDataStore } from "@/stores/data";
import TableReport from "@/modules/02_organizational/components/TableReport.vue";
import DialogHeader from "@/modules/02_organizational/components/DialogHeader.vue";
import DialogFooter from "@/modules/02_organizational/components/DialogFooter.vue";
import type { QForm } from "quasar";
import type { DataOption } from "@/modules/02_organizational/interface/index/Main";
import type { ResponseDetail } from "@/modules/02_organizational/interface/response/Mapping";
import type { RequestReport2 } from "@/modules/02_organizational/interface/request/Mapping";
import http from "@/plugins/http";
import config from "@/app.config";
const dataStore = useDataStore();
const { loaderPage } = dataStore;
const $q = useQuasar(); // show dialog
const mixin = useCounterMixin();
const router = useRouter();
const route = useRoute();
const { date2Thai, success, dateToISO } = mixin;
const govermentOP = ref<DataOption[]>([]);
const govermentOPfilter = ref<DataOption[]>([]);
const goverment = ref<string>("");
const tab = ref<string>("audit1");
const clickAccount1 = async () => {
window.open(config.API.getReportAccount1(goverment.value));
};
const clickAccount2 = async () => {
window.open(config.API.getReportAccount2(goverment.value));
};
const clickAccount3 = async () => {
window.open(config.API.getReportAccount3(goverment.value));
};
const fetchOrganizationAgency = async () => {
loaderPage(true);
await http
// .get(config.API.organizationAgency)
.get(config.API.getOCType)
.then((res) => {
const data = res.data.result;
let option: DataOption[] = [];
data.map((r: any) => {
option.push({
id: r.organizationId.toString(),
name: r.organizationName.toString(),
});
});
govermentOP.value = option;
govermentOPfilter.value = option;
})
.catch((e) => {
console.log(e);
})
.finally(() => {
loaderPage(false);
});
};
onMounted(async () => {
loaderPage(false);
await fetchOrganizationAgency();
});
</script>

View file

@ -0,0 +1,225 @@
<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 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 () => {
loader.value = true
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(() => {
loader.value = false
})
};
/**
* านขอม organization id จจนจาก API อมลทไดเอามาสราง Structure Chart
*/
const fetchStructChart = async () => {
loader.value = true
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(() => {
loader.value = false
})
}
/**
* เมอมการคลกท 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>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,622 @@
<!-- =============================== -->
<!-- page:main page ดการบญช 2 -->
<!-- =============================== -->
<template>
<div class="toptitle text-dark col-12 row items-center">ดการบญช 2</div>
<q-card flat bordered class="col-12 q-mt-sm">
<q-layout
view="hHh Lpr lff"
container
class="shadow-2 rounded-borders page-relative"
style="height: 80vh"
>
<q-drawer v-model="isDrawer" class="bg-grey-1" :width="220" :breakpoint="400" bordered>
<q-btn
size="13px"
class="btn-absolute btnShadow"
color="white"
dense
round
unelevated
@click="isDrawer = false"
v-if="isDrawer"
>
<q-tooltip></q-tooltip>
<q-icon name="chevron_left" size="20px" color="grey-7" />
</q-btn>
<q-scroll-area class="fit">
<div class="row col-12 text-dark q-pt-sm">
<div class="col-12 q-pa-sm">
<q-tree
:nodes="nodesTree"
dense
node-key="id"
v-model:selected="selected"
v-model:expanded="expanded"
no-selection-unset
selected-color="primary"
@update:selected="onSelected"
@update:expanded="clickTree"
/>
</div>
</div>
</q-scroll-area>
</q-drawer>
<q-page-container class="q-mx-sm q-pt-md">
<TableReport
:rows="rows"
:columns="columns"
:filter="filter"
:visible-columns="visibleColumns"
v-model:inputfilter="filter"
v-model:inputvisible="visibleColumns"
v-model:isTab="isDrawer"
:delect="true"
:onTab="changeTab"
:onConfirm="onConfirm"
:onHistory="onHistory"
table-style="height: 64vh"
>
<template #columns="props">
<q-tr :props="props" class="cursor-pointer">
<q-td
v-for="col in props.cols"
:key="col.name"
:props="props"
@click="clickTransfer(props.row)"
>
<div v-if="col.name == 'no'">
{{ props.rowIndex + 1 }}
</div>
<div v-else-if="col.name == 'statusPosition'">
{{ col.value ? "ถือครอง" : "ว่าง" }}
</div>
<div v-else>
{{ col.value }}
</div>
</q-td>
<!-- <q-td>
<q-btn
size="14px"
dense
flat
round
color="info"
icon="mdi-history"
>
<q-tooltip>ประว</q-tooltip>
</q-btn>
</q-td> -->
</q-tr>
</template>
</TableReport>
</q-page-container>
</q-layout>
</q-card>
</template>
<script setup lang="ts">
import { onMounted, computed, ref, watch } from "vue";
import { useQuasar, QForm } from "quasar";
import { useCounterMixin } from "@/stores/mixin";
import { useRouter, useRoute } from "vue-router";
import { useDataStore } from "@/stores/data";
import TableReport from "@/modules/02_organizational/components/TableReport.vue";
import type { Columns } from "@/modules/02_organizational/interface/index/Main";
import http from "@/plugins/http";
import config from "@/app.config";
import type { treeTab } from "@/modules/04_registry/interface/index/Main";
import type { ResponseTree } from "@/modules/02_organizational/interface/response/Mapping";
const dataStore = useDataStore();
const { loaderPage } = dataStore;
const $q = useQuasar(); // show dialog
const mixin = useCounterMixin();
const router = useRouter();
const route = useRoute();
const { date2Thai, success, dateToISO, modalError } = mixin;
const filter = ref<string>(""); //search data table
const visibleColumns = ref<String[]>([]);
const profileType = ref<string>("officer");
const isDrawer = ref<boolean>(true);
const expanded = ref<string[]>([]);
const selected = ref<string>("");
const nodesTree = ref<treeTab[]>([]);
const columns = ref<any>([
{
name: "no",
align: "left",
label: "ลำดับ",
sortable: true,
field: "no",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "name",
align: "left",
label: "ชื่อ-สกุล",
sortable: true,
field: "name",
headerStyle: "font-size: 14px; min-width: 200px",
style: "font-size: 14px; ",
},
{
name: "edu",
align: "left",
label: "คุณวุฒิ",
sortable: true,
field: "edu",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "posiNumOld",
align: "left",
label: "ตำแหน่งเลขที่เดิม",
sortable: true,
field: "posiNumOld",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
// sort: (a: string, b: string) => {
// let setA = "";
// let setB = "";
// for (let index = 0; index < a.length; index++) {
// const num = a[index];
// const check = parseInt(num);
// if (!isNaN(check)) {
// setA += num.toString();
// }
// }
// for (let index = 0; index < b.length; index++) {
// const num = b[index];
// const check = parseInt(num);
// if (!isNaN(check)) {
// setB += num.toString();
// }
// }
// return parseInt(setA) - parseInt(setB);
// },
},
{
name: "posiOld",
align: "left",
label: "ตำแหน่งเดิม",
sortable: true,
field: "posiOld",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "levelOld",
align: "left",
label: "ระดับเดิม",
sortable: true,
field: "levelOld",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "posiNumNew",
align: "left",
label: "ตำแหน่งเลขที่ใหม่",
sortable: true,
field: "posiNumNew",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "posiNew",
align: "left",
label: "ตำแหน่งใหม่",
sortable: true,
field: "posiNew",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "levelNew",
align: "left",
label: "ระดับใหม่",
sortable: true,
field: "levelNew",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "change",
align: "left",
label: "การเปลี่ยนแปลง",
sortable: true,
field: "change",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "statusPosition",
align: "left",
label: "สถานะตำแหน่งเลขที่",
sortable: true,
field: "statusPosition",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
]);
const rows = ref<ResponseTree[]>([]);
const mockdata = ref<ResponseTree[]>([
{
no: 1,
report2Id: "1",
profilePositionId: "1",
name: "นายกนก ลายมาก",
edu: "ศศ.บ. (รัฐศาสตร์)",
posiNumOld: "กบห.1",
posiNumNew: "กบห.1",
posiOld: "ผู้อำนวยการ",
posiNew: "ผู้อำนวยการ",
levelOld: "ต้น",
levelNew: "ต้น",
change: "-",
statusPosition: true,
},
{
no: 2,
report2Id: "2",
profilePositionId: "2",
name: "นายกน ลามา",
edu: "ศศ.บ. (การจัดการทั่วไป)",
posiNumOld: "กบห.2",
posiNumNew: "กบห.2",
posiOld: "นักจัดการงานทั่วไป",
posiNew: "นักจัดการงานทั่วไป",
levelOld: "ปฏิบัติการ",
levelNew: "ปฏิบัติการ",
change: "-",
statusPosition: true,
},
{
no: 3,
report2Id: "3",
profilePositionId: "3",
name: "นายกก ลายดี",
edu: "ศศ.บ. (การจัดการทั่วไป)",
posiNumOld: "กบห.3",
posiNumNew: "กบห.3",
posiOld: "นักจัดการงานทั่วไป",
posiNew: "นักจัดการงานทั่วไป",
levelOld: "ปฏิบัติการ",
levelNew: "ปฏิบัติการ",
change: "-",
statusPosition: true,
},
{
no: 4,
report2Id: "4",
profilePositionId: "4",
name: "นายนก มากหลาย",
edu: "ศศ.บ. (การจัดการทั่วไป)",
posiNumOld: "กบห.4",
posiNumNew: "กบห.4",
posiOld: "นักจัดการงานทั่วไป",
posiNew: "นักจัดการงานทั่วไป",
levelOld: "ปฏิบัติการ",
levelNew: "ปฏิบัติการ",
change: "-",
statusPosition: true,
},
{
no: 5,
report2Id: "5",
profilePositionId: "5",
name: "นางสมพร เพชรเหลือ",
edu: "ศศ.บ. (การจัดการทั่วไป)",
posiNumOld: "กบห.5",
posiNumNew: "กบห.5",
posiOld: "นักจัดการงานทั่วไป",
posiNew: "นักจัดการงานทั่วไป",
levelOld: "ชำนาญการ",
levelNew: "ชำนาญการพิเศษ",
change: "เลื่อนระดับ",
statusPosition: true,
},
{
no: 6,
report2Id: "6",
profilePositionId: "6",
name: "นางพร ลายกนก",
edu: "ศศ.บ. (การบริหารการศึกษา)",
posiNumOld: "กบห.6",
posiNumNew: "กบห.6",
posiOld: "นักจัดการงานทั่วไป",
posiNew: "นักจัดการงานทั่วไป",
levelOld: "ปฏิบัติการ",
levelNew: "ชำนาญการ",
change: "เลื่อนระดับ",
statusPosition: true,
},
{
no: 7,
report2Id: "7",
profilePositionId: "7",
name: "นางสาวสวย มากมาย",
edu: "ศศ.บ. (การบริหารการศึกษา)",
posiNumOld: "กบห.7",
posiNumNew: "กบห.7",
posiOld: "นักจัดการงานทั่วไป",
posiNew: "นักจัดการงานทั่วไป",
levelOld: "ปฏิบัติการ",
levelNew: "ปฏิบัติการ",
change: "-",
statusPosition: true,
},
{
no: 8,
report2Id: "8",
profilePositionId: "8",
name: "นายหล่อ ขั้นเทพ",
edu: "ศศ.บ. (การบริหารการศึกษา)",
posiNumOld: "กบห.8",
posiNumNew: "กบห.8",
posiOld: "นักจัดการงานทั่วไป",
posiNew: "นักจัดการงานทั่วไป",
levelOld: "ปฏิบัติการ",
levelNew: "ชำนาญการ",
change: "เลื่อนระดับ",
statusPosition: true,
},
{
no: 9,
report2Id: "9",
profilePositionId: "9",
name: "นางแม้นศรี บางแค",
edu: "ศศ.บ. (การบริหารการศึกษา)",
posiNumOld: "กบห.9",
posiNumNew: "กบห.9",
posiOld: "เจ้าพนักงานธุรการ",
posiNew: "เจ้าพนักงานธุรการ",
levelOld: "ปฏิบัติงาน",
levelNew: "ชำนาญงาน",
change: "เลื่อนระดับ",
statusPosition: true,
},
{
no: 10,
report2Id: "10",
profilePositionId: "10",
name: "นายมั่น มากทอง",
edu: "ศศ.บ. (การบริหารการศึกษา)",
posiNumOld: "กบห.10",
posiNumNew: "กบห.10",
posiOld: "นักวิชาการเงินและบัญชี",
posiNew: "นักวิชาการเงินและบัญชี",
levelOld: "ชำนาญการ",
levelNew: "ชำนาญการพิเศษ",
change: "เลื่อนระดับ",
statusPosition: true,
},
{
no: 11,
report2Id: "11",
profilePositionId: "11",
name: "นายผดุง ทองมาก",
edu: "ศศ.บ. (รัฐศาสตร์)",
posiNumOld: "กบห.11",
posiNumNew: "กบห.11",
posiOld: "นักวิชาการเงินและบัญชี",
posiNew: "นักวิชาการเงินและบัญชี",
levelOld: "ชำนาญการ",
levelNew: "ชำนาญการ",
change: "-",
statusPosition: true,
},
{
no: 12,
report2Id: "12",
profilePositionId: "12",
name: "นางสาวเปรี้ยว เข็ดฟัน",
edu: "ศศ.บ. (รัฐศาสตร์)",
posiNumOld: "กบห.13",
posiNumNew: "กบห.12",
posiOld: "นักวิชาการเงินและบัญชี",
posiNew: "นักวิชาการเงินและบัญชี",
levelOld: "ปฏิบัติการ",
levelNew: "ปฏิบัติการ",
change: "เปลี่ยนตำแหน่งเลขที่",
statusPosition: true,
},
{
no: 13,
report2Id: "13",
profilePositionId: "13",
name: "",
edu: "",
posiNumOld: "กบห.12",
posiNumNew: "กบห.13",
posiOld: "นักวิชาการเงินและบัญชี",
posiNew: "นักวิชาการเงินและบัญชี",
levelOld: "ชำนาญงาน",
levelNew: "ชำนาญงาน",
change: "เปลี่ยนตำแหน่งเลขที่",
statusPosition: false,
},
]);
onMounted(async () => {
let arVisible: string[] = [];
columns.value.map((r: any) => {
arVisible.push(r.name);
});
visibleColumns.value = arVisible;
await nodeTree();
await doSearch();
});
const nodeTree = async () => {
loaderPage(true);
await http
.get(config.API.profileOrganizRoot)
.then((res: any) => {
const data = res.data.result;
nodesTree.value = data;
if (data.length > 0) {
selected.value =
dataStore.selectedReport2 == ""
? data[0].id
: dataStore.selectedReport2;
expanded.value =
dataStore.expandedReport2.length == 0
? [data[0].id]
: dataStore.expandedReport2;
}
})
.catch((e: any) => {})
.finally(() => {
loaderPage(false);
});
};
const onSelected = async (id: string) => {
clickTree();
await doSearch();
};
const clickTree = () => {
dataStore.changeTreeReport2(expanded.value, selected.value);
};
const onHistory = async () => {
loaderPage(true);
await http
.get(config.API.report2HistoryId(selected.value))
.then((res) => {
const data = res.data.result;
if (data.length == 0) {
modalError(
$q,
"ประวัติแก้ไขข้อมูลบัญชี 2",
"ไม่มีข้อมูลประวัติแก้ไขข้อมูลบัญชี 2"
);
} else {
router.push(`/organizational/manage/report/history/${selected.value}`);
}
})
.catch((e) => {
modalError(
$q,
"ประวัติแก้ไขข้อมูลบัญชี 2",
"ไม่มีข้อมูลประวัติแก้ไขข้อมูลบัญชี 2"
);
})
.finally(async () => {
loaderPage(false);
});
};
const doSearch = async () => {
// type
loaderPage(true);
await http
.get(config.API.report2TreeId(selected.value))
.then((res) => {
const data = res.data.result;
if (data.length > 0) {
rows.value = [];
let array: ResponseTree[] = [];
data.map((e: ResponseTree, index: number) => {
array.push({
no: index + 1,
report2Id: e.report2Id,
profilePositionId: e.profilePositionId,
name: e.name ?? "-",
edu: e.edu ?? "-",
posiNumOld: e.posiNumOld ?? "-",
posiNumNew: e.posiNumNew ?? "-",
posiOld: e.posiOld ?? "-",
posiNew: e.posiNew ?? "-",
levelOld: e.levelOld ?? "-",
levelNew: e.levelNew ?? "-",
change: e.change ?? "-",
statusPosition: e.statusPosition,
});
});
rows.value = array;
}
})
.catch((e) => {})
.finally(() => {
loaderPage(false);
});
};
const changeTab = () => {
isDrawer.value = !isDrawer.value;
};
const onConfirm = async () => {
$q.dialog({
title: `ยืนยันเพื่อเอาไปออกคำสั่ง`,
message: `ต้องยืนยันเพื่อเอาไปออกคำสั่งใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
}).onOk(async () => {
loaderPage(true);
await http
.get(config.API.report2DoneId(selected.value))
.then((res) => {
success($q, "ยืนยันเพื่อเอาไปออกคำสั่งสำเร็จ");
})
.catch((e) => {})
.finally(async () => {
loaderPage(false);
await doSearch();
});
});
};
const clickTransfer = async (rows: ResponseTree) => {
if (rows.statusPosition) {
router.push(
`/organizational/manage/report/${rows.profilePositionId ?? "1"}`
);
}
};
</script>
<style lang="scss" scope>
.expan .q-expansion-item--expanded {
border: 1px solid #eaeaea;
border-radius: 2px;
margin: 5px 0px !important;
background: #eaeaea4a !important;
}
.expan .q-expansion-item {
border: 1px solid #eaeaea;
margin-top: -1px;
border-radius: 2px;
background: white;
}
.my-custom-toggle {
border: 1px solid #02a998;
}
.btn-absolute {
z-index: 50;
position: absolute;
left: 200px;
top: 10px;
}
.btnShadow {
box-shadow: 0 1px 2px rgb(0 0 0 / 10%), 3px 3px 7px 1px rgba(95, 95, 95, 0.15) !important;
}
</style>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,478 @@
<template>
<div class="toptitle text-dark col-12 row items-center">
<q-btn
icon="mdi-arrow-left"
unelevated
round
dense
flat
color="primary"
class="q-mr-sm"
@click="clickBack"
/>
<label
>ประวญชดขาราชการกรงเทพมหานครสามญเขาประเภทตำแหน สายงาน
และระดบตำแหน</label
>
<q-card flat bordered class="col-12 q-my-sm q-pt-sm">
<q-btn
flat
round
icon="mdi-menu-left"
@click="clickPreviousNext('next')"
:disable="previous == false"
:color="!previous ? 'grey-7' : 'public'"
/>
<q-btn
flat
round
icon="mdi-menu-right"
@click="clickPreviousNext('previous')"
:disable="next == false"
:color="!next ? 'grey-7' : 'public'"
/>
<label>
{{
`${
historyHead.length > 0 && historyHead[indexRow].date != null
? date2Thai(historyHead[indexRow].date, false, true)
: ""
}`
}}
</label>
<div
class="q-pa-md row col-12 q-col-gutter-sm"
v-for="items in historyData"
:key="items.fullName"
>
<q-input
v-model="items.fullName"
label="ชื่อ-สกุล"
class="col-xs-12 col-sm-6"
hide-bottom-space
:outlined="true"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
<q-input
v-model="items.education"
label="คุณวุฒิ"
class="col-xs-12 col-sm-6"
hide-bottom-space
:outlined="true"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
<q-input
v-model="items.salary"
label="เงินเดือน"
class="col-xs-12 col-sm-4"
hide-bottom-space
:outlined="true"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
<q-input
v-model="items.salaryPosition"
label="เงินประจำตำแหน่ง"
class="col-xs-12 col-sm-4"
hide-bottom-space
:outlined="true"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
<q-input
v-model="items.salaryMonth"
label="เงินตอบแทนรายเดือน"
class="col-xs-12 col-sm-4"
hide-bottom-space
:outlined="true"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
<div class="row col-12 q-col-gutter-x-sm">
<div class="col-xs-12 col-sm-6">
<q-card bordered flat>
<div
class="q-pa-xs bg-grey-2 row items-center q-py-sm q-px-md justify-center text-bold"
>
กำหนดเด
</div>
<q-separator />
<div class="col-12 row q-pa-sm q-col-gutter-xs">
<q-input
v-model="items.oldOrganizationShortName"
label="รหัสส่วนราชการ"
class="col-xs-12 col-sm-6"
hide-bottom-space
:outlined="false"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
<q-input
v-model="items.oldOrganizationOrganization"
label="ชื่อหน่วยงาน"
class="col-xs-12 col-sm-6"
hide-bottom-space
:outlined="false"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
<q-input
v-model="items.oldPositionNum"
label="ตำแหน่งเลขที่"
class="col-xs-12 col-sm-6"
hide-bottom-space
:outlined="false"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
<q-input
v-model="items.oldPositionType"
label="ประเภทตำแหน่ง"
class="col-xs-12 col-sm-6"
hide-bottom-space
:outlined="false"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
<q-input
v-model="items.oldPositionExecutive"
label="ตำแหน่งทางการบริหาร"
class="col-xs-12 col-sm-6"
hide-bottom-space
:outlined="false"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
<q-input
v-model="items.oldPositionExecutiveSide"
label="ด้านทางบริหาร"
class="col-xs-12 col-sm-6"
hide-bottom-space
:outlined="false"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
<q-input
v-model="items.oldPositionPath"
label="ตำแหน่งในสายงาน"
class="col-xs-12 col-sm-6"
hide-bottom-space
:outlined="false"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
<q-input
v-model="items.oldPositionPathSide"
label="ด้าน/สาขา"
class="col-xs-12 col-sm-6"
hide-bottom-space
:outlined="false"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
<q-input
v-model="items.oldPositionLevel"
label="ระดับตำแหน่ง"
class="col-xs-12 col-sm-6"
hide-bottom-space
:outlined="false"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
</div>
</q-card>
</div>
<div class="col-xs-12 col-sm-6">
<q-card bordered flat>
<div
class="q-pa-xs bg-grey-2 row flex items-center justify-center text-bold q-py-sm q-px-md"
>
กำหนดใหม
</div>
<q-separator />
<div class="col-12 row q-pa-sm q-col-gutter-xs">
<q-input
v-model="items.newOrganizationShortName"
label="รหัสส่วนราชการ"
class="col-xs-12 col-sm-6"
hide-bottom-space
:outlined="false"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
<q-input
v-model="items.newOrganizationOrganization"
label="ชื่อหน่วยงาน"
class="col-xs-12 col-sm-6"
hide-bottom-space
:outlined="false"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
<q-input
v-model="items.newPositionNum"
label="ตำแหน่งเลขที่"
class="col-xs-12 col-sm-6"
hide-bottom-space
:outlined="false"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
<q-input
v-model="items.newPositionType"
label="ประเภทตำแหน่ง"
class="col-xs-12 col-sm-6"
hide-bottom-space
:outlined="false"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
<q-input
v-model="items.newPositionExecutive"
label="ตำแหน่งทางการบริหาร"
class="col-xs-12 col-sm-6"
hide-bottom-space
:outlined="false"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
<q-input
v-model="items.newPositionExecutiveSide"
label="ด้านทางบริหาร"
class="col-xs-12 col-sm-6"
hide-bottom-space
:outlined="false"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
<q-input
v-model="items.newPositionPath"
label="ตำแหน่งในสายงาน"
class="col-xs-12 col-sm-6"
hide-bottom-space
:outlined="false"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
<q-input
v-model="items.newPositionPathSide"
label="ด้าน/สาขา"
class="col-xs-12 col-sm-6"
hide-bottom-space
:outlined="false"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
<q-input
v-model="items.newPositionLevel"
label="ระดับตำแหน่ง"
class="col-xs-12 col-sm-6"
hide-bottom-space
:outlined="false"
dense
lazy-rules
:readonly="true"
:borderless="true"
/>
</div>
</q-card>
</div>
</div>
</div>
</q-card>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref } from "vue";
import { useCounterMixin } from "@/stores/mixin";
import { useRouter, useRoute } from "vue-router";
import { useQuasar } from "quasar";
import { useDataStore } from "@/stores/data";
import http from "@/plugins/http";
import config from "@/app.config";
import type {
ResponseHistory,
ResponseHistoryHead,
} from "@/modules/02_organizational/interface/response/Mapping";
const dataStore = useDataStore();
const $q = useQuasar(); // show dia
const mixin = useCounterMixin();
const router = useRouter();
const route = useRoute();
const { loaderPage } = dataStore;
const { date2Thai, success, dateToISO } = mixin;
const id = ref<string>("");
const previous = ref<boolean>(false);
const next = ref<boolean>(false);
const indexRow = ref<number>(0);
const historyHead = ref<ResponseHistoryHead[]>([]);
const historyData = ref<ResponseHistory[]>([]);
onMounted(async () => {
loaderPage(false);
if (route.params.id != undefined) {
id.value = route.params.id.toString();
await fetchHistory();
if (historyHead.value.length > 0) {
await fetchData();
}
}
});
const clickBack = () => {
router.push({ name: "manageReport2" });
};
const clickPreviousNext = async (page: string) => {
const index: number =
page == "next" ? indexRow.value - 1 : indexRow.value + 1;
let length: number = historyHead.value.length;
previous.value = index == 0 ? false : true;
next.value = index == length - 1 ? false : true;
indexRow.value = index;
await fetchData();
};
const fetchHistory = async () => {
loaderPage(true);
await http
.get(config.API.report2HistoryId(id.value))
.then((res) => {
const data = res.data.result;
let header: ResponseHistoryHead[] = [];
data.map((r: any) => {
header.push({
historyId: r.historyId,
date: new Date(r.date),
});
});
historyHead.value = header;
})
.catch((e) => {})
.finally(async () => {
loaderPage(false);
if (historyHead.value.length > 1) {
next.value = true;
previous.value = false;
} else {
next.value = false;
previous.value = false;
}
});
};
const fetchData = async () => {
loaderPage(true);
await http
.get(
config.API.report2HistoryDetailId(
historyHead.value[indexRow.value].historyId
)
)
.then((res) => {
const data = res.data.result;
let responeseData: ResponseHistory[] = [];
data.map((r: any) => {
responeseData.push({
fullName: r.fullName ?? "-",
education: r.fullName ?? "-",
salary: r.salary,
salaryPosition: r.salaryPosition,
salaryMonth: r.salaryMonth,
oldOrganizationShortName: r.oldOrganizationShortName ?? "-",
oldOrganizationOrganization: r.oldOrganizationOrganization ?? "-",
oldPositionNum: r.oldPositionNum ?? "-",
oldPositionType: r.oldPositionType ?? "-",
oldPositionExecutive: r.oldPositionExecutive ?? "-",
oldPositionExecutiveSide: r.oldPositionExecutiveSide ?? "-",
oldPositionPath: r.oldPositionPath ?? "-",
oldPositionPathSide: r.oldPositionPathSide ?? "-",
oldPositionLevel: r.oldPositionLevel ?? "-",
newOrganizationShortName: r.newOrganizationShortName ?? "-",
newOrganizationOrganization: r.newOrganizationOrganization ?? "-",
newPositionNum: r.newPositionNum ?? "-",
newPositionType: r.newPositionType ?? "-",
newPositionExecutive: r.newPositionExecutive ?? "-",
newPositionExecutiveSide: r.newPositionExecutiveSide ?? "-",
newPositionPath: r.newPositionPath ?? "-",
newPositionPathSide: r.newPositionPathSide ?? "-",
newPositionLevel: r.newPositionLevel ?? "-",
});
});
historyData.value = responeseData;
})
.catch((e) => {})
.finally(async () => {
loaderPage(false);
});
};
</script>
<style>
.expan .q-expansion-item--expanded {
border: 1px solid #eaeaea;
border-radius: 2px;
margin: 5px 0px !important;
background: #eaeaea4a !important;
}
.expan .q-expansion-item {
border: 1px solid #eaeaea;
margin-top: -1px;
border-radius: 2px;
background: white;
}
.my-custom-toggle {
border: 1px solid #02a998;
}
</style>

View file

@ -0,0 +1,148 @@
<template>
<div class="toptitle text-dark col-12 row items-center">รายงานบญช</div>
<div class="col-12 row"></div>
<q-card flat bordered class="col-12">
<div class="row col-12">
<q-tabs
v-model="tab"
no-caps
inline-label
align="left"
active-class="text-primary"
class="text-grey-7"
>
<q-tab name="audit1" label="บัญชี 1" />
<q-tab name="audit2" label="บัญชี 2" />
<q-tab name="audit3" label="บัญชี 3" />
</q-tabs>
</div>
<q-separator />
<q-tab-panels
v-model="tab"
transition-prev="jump-up"
transition-next="jump-up"
animated
swipeable
class="row col-12 text-dark"
>
<q-tab-panel name="audit1">
<div class="row col-12 items-center q-gutter-md">
<span class="text-subtitle1 text-weight-medium"
>รายงานบญชฉบบท 1</span
>
<q-select
class="col-xs-12 col-sm-6"
v-model="goverment"
label="รหัสส่วนราชการ"
dense
emit-value
map-options
option-label="name"
:options="govermentOP"
option-value="id"
lazy-rules
hide-bottom-space
:readonly="true"
:borderless="true"
:outlined="false"
:hide-dropdown-icon="true"
/>
<q-btn size="md" icon="mdi-download" round flat color="primary">
<q-tooltip>ดาวนโหลด</q-tooltip>
</q-btn>
<!-- <viewpdf
:src="pdfSrc"
:currentpage="pdfCurrentPage"
:totalpage="pdfTotalPage" /> -->
</div>
</q-tab-panel>
<q-tab-panel name="audit2">
<div class="row col-12 items-center q-gutter-md">
<span class="text-subtitle1 text-weight-medium"
>รายงานบญชฉบบท 2</span
>
<q-btn size="md" icon="mdi-download" flat round color="primary">
<q-tooltip>ดาวนโหลด</q-tooltip>
</q-btn>
<!-- <viewpdf
:src="pdfSrc"
:currentpage="pdfCurrentPage"
:totalpage="pdfTotalPage" /> -->
</div>
</q-tab-panel>
<q-tab-panel name="audit3">
<div class="row col-12 items-center q-gutter-md">
<span class="text-subtitle1 text-weight-medium"
>รายงานบญชฉบบท 3</span
>
<q-btn size="md" icon="mdi-download" flat round color="primary">
<q-tooltip>ดาวนโหลด</q-tooltip>
</q-btn>
<!-- <viewpdf
:src="pdfSrc"
:currentpage="pdfCurrentPage"
:totalpage="pdfTotalPage" /> -->
</div>
</q-tab-panel>
</q-tab-panels>
</q-card>
</template>
<script setup lang="ts">
import { onMounted, computed, ref, watch } from "vue";
import { useQuasar } from "quasar";
import { useCounterMixin } from "@/stores/mixin";
import { useRouter, useRoute } from "vue-router";
import { useDataStore } from "@/stores/data";
import TableReport from "@/modules/02_organizational/components/TableReport.vue";
import DialogHeader from "@/modules/02_organizational/components/DialogHeader.vue";
import DialogFooter from "@/modules/02_organizational/components/DialogFooter.vue";
import type { QForm } from "quasar";
import type { DataOption } from "@/modules/02_organizational/interface/index/Main";
import type { ResponseDetail } from "@/modules/02_organizational/interface/response/Mapping";
import type { RequestReport2 } from "@/modules/02_organizational/interface/request/Mapping";
import http from "@/plugins/http";
import config from "@/app.config";
const dataStore = useDataStore();
const { loaderPage } = dataStore;
const $q = useQuasar(); // show dialog
const mixin = useCounterMixin();
const router = useRouter();
const route = useRoute();
const { date2Thai, success, dateToISO } = mixin;
const govermentOP = ref<DataOption[]>([]);
const govermentOPfilter = ref<DataOption[]>([]);
const goverment = ref<string>("");
const tab = ref<string>("audit1");
const fetchOrganizationAgency = async () => {
loaderPage(true);
await http
// .get(config.API.organizationAgency)
.get(config.API.listOrganizationAgency("หน่วยงาน"))
.then((res) => {
const data = res.data.result;
let option: DataOption[] = [];
data.map((r: any) => {
option.push({
id: r.organizationId.toString(),
name: r.organizationName.toString(),
});
});
govermentOP.value = option;
govermentOPfilter.value = option;
})
.catch((e) => {
console.log(e);
})
.finally(() => {
loaderPage(false);
});
};
onMounted(async () => {
loaderPage(false);
await fetchOrganizationAgency();
});
</script>