Merge branch 'develop' of github.com:Frappet/bma-ehr-frontend into develop

This commit is contained in:
Warunee Tamkoo 2024-01-31 18:06:35 +07:00
commit 764078488c
11 changed files with 795 additions and 194 deletions

View file

@ -1,6 +1,7 @@
import env from "../index";
const organization = `${env.API_URI}/org`;
const orgPos = `${env.API_URI}/org/pos`;
export default {
/** โครงสร้างอัตรากำลัง*/
@ -10,6 +11,16 @@ export default {
createOrgLevel: (type: string) => `${organization}/${type}`,
orgLevelByid: (type: string, id: string) => `${organization}/${type}/${id}`,
orgSetDateTime:(id:string) => `${organization}/set/publish/${id}`,
orgSetDateTime: (id: string) => `${organization}/set/publish/${id}`,
organizationHistoryNew: `${organization}/history`,
organizationHistoryPostNew: `${organization}/history/publish`,
/** position*/
orgPosPosition: `${orgPos}/position`,
orgPosPositionById: (id: string) => `${orgPos}/position/${id}`,
orgPosExecutive: `${orgPos}/executive`,
orgPosType: `${orgPos}/type`,
orgPosLevel: `${orgPos}/level`,
orgPosMaster: `${orgPos}/master`,
organizationShortName: `${organization}/sort`,
};

View file

@ -10,22 +10,43 @@ import type {
DataOption,
FormPositionSelect,
RowDetailPositions,
FormPositionSelectRef,
ListMenu,
} from "@/modules/02_organizationalNew/interface/index/Main";
import type {
OptionType,
OptionLevel,
OptionExecutive,
DataPosition,
} from "@/modules/02_organizationalNew/interface/response/organizational";
import http from "@/plugins/http";
import config from "@/app.config";
const props = defineProps({
modal: Boolean,
close: Function,
orgLevel: Number,
treeId: String,
actionType: String,
});
const isReadonly = ref<boolean>(false); //
const isDisValidate = ref<boolean>(false);
const $q = useQuasar();
const mixin = useCounterMixin();
const { dialogConfirm } = mixin;
const {
dialogConfirm,
showLoader,
hideLoader,
messageError,
success,
dialogRemove,
} = mixin;
const selected = ref<any>([]);
const search = ref<string>("");
const type = ref<string>("positionName");
const typeOps = ref<DataOption[]>([
const optionFilter = ref<DataOption[]>([
{ id: "positionName", name: "ตำแหน่งในสายงาน" },
{ id: "positionField", name: "สายงาน" },
{ id: "positionType", name: "ประเภทตำแหน่ง" },
@ -35,6 +56,13 @@ const typeOps = ref<DataOption[]>([
{ id: "positionArea", name: "ด้าน/สาขา" },
]);
const typeOpsMain = ref<DataOption[]>([]);
const levelOpsMain = ref<DataOption[]>([]);
const executiveOpsMain = ref<DataOption[]>([]);
const typeOps = ref<DataOption[]>([]);
const levelOps = ref<DataOption[]>([]);
const executiveOps = ref<DataOption[]>([]);
const listMenu = ref<ListMenu[]>([
{
label: "คัดลอก",
@ -57,12 +85,19 @@ const ocLevelOp = ref<DataOption[]>([]);
const prefixNoRef = ref<Object | null>(null);
const positionNoRef = ref<Object | null>(null);
const positionNameRef = ref<Object | null>(null);
const positionFieldRef = ref<Object | null>(null);
const positionTypeRef = ref<Object | null>(null);
const positionLevelRef = ref<Object | null>(null);
const positionExecutiveRef = ref<Object | null>(null);
const positionExecutiveFieldRef = ref<Object | null>(null);
const positionAreaRef = ref<Object | null>(null);
const formData = reactive<FormDataPosition>({
shortName: "สกจ.",
prefixNo: "",
positionNo: "",
suffixNo: "",
confirm: false,
});
const formPositionSelect = reactive<FormPositionSelect>({
@ -81,6 +116,16 @@ const objectPositionRef: FormPositionRef = {
positionNo: positionNoRef,
};
const objectPositionSelectRef: FormPositionSelectRef = {
positionName: positionNameRef,
positionField: positionFieldRef,
positionType: positionTypeRef,
positionLevel: positionLevelRef,
positionExecutive: positionExecutiveRef,
positionExecutiveField: positionExecutiveFieldRef,
positionArea: positionAreaRef,
};
const columns = ref<QTableProps["columns"]>([
{
name: "no",
@ -110,29 +155,29 @@ const columns = ref<QTableProps["columns"]>([
style: "font-size: 14px",
},
{
name: "positionType",
name: "posTypeName",
align: "left",
label: "ประเภทตำเเหน่ง",
sortable: true,
field: "positionType",
field: "posTypeName",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "positionLevel",
name: "posLevelName",
align: "left",
label: "ระดับตำแหน่ง",
sortable: true,
field: "positionLevel",
field: "posLevelName",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "positionExecutive",
name: "posExecutiveName",
align: "left",
label: "ตำแหน่งทางการบริหาร",
sortable: true,
field: "positionExecutive",
field: "posExecutiveName",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
@ -159,13 +204,88 @@ const visibleColumns = ref<string[]>([
"no",
"positionName",
"positionField",
"positionType",
"positionLevel",
"positionExecutive",
"posTypeName",
"posLevelName",
"posExecutiveName",
"positionExecutiveField",
"positionArea",
]);
async function fetchPosition(id: string) {
showLoader();
await http
.get(config.API.orgPosPositionById(id))
.then((res) => {
console.log(res);
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
/** function เรียกรายการประเภทตำแหน่ง */
async function fetchType() {
showLoader();
await http
.get(config.API.orgPosType)
.then((res) => {
typeOpsMain.value = res.data.result.map((e: OptionType) => ({
id: e.id,
name: e.posTypeName,
}));
typeOps.value = typeOpsMain.value;
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
/** function เรียกรายการระดับตำแหน่ง */
async function fetchLevel() {
showLoader();
await http
.get(config.API.orgPosLevel)
.then((res) => {
levelOpsMain.value = res.data.result.map((e: OptionLevel) => ({
id: e.id,
name: e.posLevelName,
}));
levelOps.value = levelOpsMain.value;
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
/** function เรียกรายการตำแหน่งทางการบริหาร */
async function fetchExecutive() {
showLoader();
await http
.get(config.API.orgPosExecutive)
.then((res) => {
executiveOpsMain.value = res.data.result.map((e: OptionExecutive) => ({
id: e.id,
name: e.posExecutiveName,
}));
executiveOps.value = executiveOpsMain.value;
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
/** ฟังก์ชั่นตรวจสอบความถูกต้องของข้อมูลในฟอร์ม */
function validateForm() {
const hasError = [];
@ -186,31 +306,33 @@ function validateForm() {
/** ฟังก์ชั่นตรวจสอบความถูกต้องของข้อมูลในฟอร์ม */
function validateFormPositionEdit() {
// const hasError = [];
// for (const key in objectPositionRef) {
// if (Object.prototype.hasOwnProperty.call(objectPositionRef, key)) {
// const property = objectPositionRef[key];
// if (property.value && typeof property.value.validate === "function") {
// const isValid = property.value.validate();
// hasError.push(isValid);
// }
// }
// }
// if (hasError.every((result) => result === true)) {
onSubmitSelectEdit();
// } else {
// }
isDisValidate.value = false;
const hasError = [];
for (const key in objectPositionSelectRef) {
if (Object.prototype.hasOwnProperty.call(objectPositionSelectRef, key)) {
const property = objectPositionSelectRef[key];
if (property.value && typeof property.value.validate === "function") {
const isValid = property.value.validate();
hasError.push(isValid);
}
}
}
if (hasError.every((result) => result === true)) {
onSubmitSelectEdit();
}
}
/** ฟังชั่น บันทึก */
function onSubmit() {
dialogConfirm($q, () => {
console.log(props.orgLevel);
dialogConfirm($q, async () => {
const positionsData = rows.value.map((e) => ({
posDictName: e.positionName, // ()
posDictField: e.positionField, //
posTypeId: e.positionName, //*
posLevelId: e.positionName, //*
posExecutiveId: e.positionName, //
posTypeId: e.posTypeId, //*
posLevelId: e.posLevelId, //*
posExecutiveId: e.posExecutiveId, //
posDictExecutiveField: e.positionName, //
posDictArea: e.positionArea, ///
}));
@ -218,22 +340,56 @@ function onSubmit() {
posMasterNoPrefix: formData.prefixNo, //*Prefix Optional (/)
posMasterNo: Number(formData.positionNo), //*
posMasterNoSuffix: formData.suffixNo, //Suffix .
// orgRootId: Guid, //Id
// orgChild1Id: Guid, //Id 1
// orgChild2Id: Guid, //Id 2
// orgChild3Id: Guid, //Id 3
// orgChild4Id: Guid, //Id 4
positions: [positionsData],
orgRootId: props.orgLevel === 0 ? props.treeId : null, //Id
orgChild1Id: props.orgLevel === 1 ? props.treeId : null,
orgChild2Id: props.orgLevel === 2 ? props.treeId : null,
orgChild3Id: props.orgLevel === 3 ? props.treeId : null,
orgChild4Id: props.orgLevel === 4 ? props.treeId : null,
positions: positionsData,
};
console.log(body);
showLoader();
await http
.post(config.API.orgPosMaster, body)
.then((res) => {
success($q, "เพิ่มข้อมูลสำเร็จ");
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
props.close?.();
hideLoader();
});
});
}
/** ฟังชั่น บันทึก */
function onSubmitSelectEdit() {
dialogConfirm(
$q,
() => {
console.log(formPositionSelect);
async () => {
showLoader();
const body = {
posDictName: formPositionSelect.positionName,
posDictField: formPositionSelect.positionField, //
posTypeId: formPositionSelect.positionType, //*
posLevelId: formPositionSelect.positionLevel, //*
posExecutiveId: formPositionSelect.positionExecutive, //
posDictExecutiveField: formPositionSelect.positionExecutiveField, //
posDictArea: formPositionSelect.positionArea, ///
};
await http
.post(config.API.orgPosPosition, body)
.then(() => {
success($q, "เพิ่มข้อมูลสำเร็จ");
clearFormPositionSelect();
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
},
"ยืนยันการเพิ่มตำแหน่ง",
"ต้องการยืนยันการเพิ่มตำแหน่งนี้ใช่หรือไม่?"
@ -250,40 +406,22 @@ const searchRef = ref<any>(null);
async function searchInput() {
searchRef.value.validate();
if (!searchRef.value.hasError) {
//
const dataList = [
{
positionId: "x1",
positionName: "นักกายภาพบำบัด",
positionField: "จัดการงานทั่วไป",
positionType: "วิชาการ",
positionLevel: "ชำนาญการ",
positionExecutive: "การพยาบาลทั่วไป",
positionExecutiveField: "การพยาบาลทั่วไป",
positionArea: "การพยาบาลทั่วไป",
},
{
positionId: "x2",
positionName: "นักทรัพยากรบุคคล",
positionField: "จัดการงานทั่วไป",
positionType: "ทั่วไป",
positionLevel: "ชำนาญการ",
positionExecutive: "-",
positionExecutiveField: "-",
positionArea: "-",
},
{
positionId: "x3",
positionName: "นักทรัพยากรบุคคล",
positionField: "จัดการงานทั่วไป",
positionType: "วิชาการ",
positionLevel: "ชำนาญการพิเศษ",
positionExecutive: "-",
positionExecutiveField: "-",
positionArea: "-",
},
];
rowsPositionSelect.value = dataList;
showLoader();
await http
.get(
config.API.orgPosPosition +
`?keyword=${search.value}&type=${type.value}`
)
.then((res) => {
console.log(res);
rowsPositionSelect.value = res.data.result;
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
}
@ -295,9 +433,9 @@ function copyDetiail(data: RowDetailPositions) {
formPositionSelect.positionId = data.positionId;
formPositionSelect.positionName = data.positionName;
formPositionSelect.positionField = data.positionField;
formPositionSelect.positionType = data.positionType;
formPositionSelect.positionLevel = data.positionLevel;
formPositionSelect.positionExecutive = data.positionExecutive;
formPositionSelect.positionType = data.posTypeId;
formPositionSelect.positionLevel = data.posLevelId;
formPositionSelect.positionExecutive = data.posExecutiveId;
formPositionSelect.positionExecutiveField = data.positionExecutiveField;
formPositionSelect.positionArea = data.positionArea;
}
@ -317,14 +455,23 @@ watch(
() => props.modal,
() => {
if (props.modal === true) {
fetchType();
fetchLevel();
fetchExecutive();
if (props.actionType === "ADD") {
rowsPositionSelect.value = [];
search.value = "";
rows.value = [];
clearFormPositionSelect();
} else {
// props.treeId && fetchPosition(props.treeId);
}
}
}
);
function addPosition(data: RowDetailPositions) {
const isIdExist = rows.value.some(
(item) => item.positionId === data.positionId
);
const isIdExist = rows.value.some((item) => item.id === data.id);
if (!isIdExist) {
rows.value = [data, ...rows.value];
@ -333,15 +480,48 @@ function addPosition(data: RowDetailPositions) {
function deleteData(id: string) {
const dataRow = rows.value;
const updatedRows = dataRow.filter((item: any) => item.positionId !== id);
const updatedRows = dataRow.filter((item: any) => item.id !== id);
rows.value = updatedRows;
}
function deletePos(id: string) {
dialogRemove($q, () => {
showLoader();
http
.delete(config.API.orgPosPositionById(id))
.then((res) => {
success($q, "ลบข้อมูลสำเร็จ");
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
searchInput();
hideLoader();
});
});
}
async function clearFormPositionSelect() {
isDisValidate.value = await true;
formPositionSelect.positionId = "";
formPositionSelect.positionName = "";
formPositionSelect.positionField = "";
formPositionSelect.positionType = "";
formPositionSelect.positionLevel = "";
formPositionSelect.positionExecutive = "";
formPositionSelect.positionExecutiveField = "";
formPositionSelect.positionArea = "";
setTimeout(async () => {
isDisValidate.value = await false;
}, 1000);
}
</script>
<template>
<template>
<q-dialog v-model="props.modal" persistent>
<q-card style="min-width: 96vw">
<DialogHeader tittle="เพิ่มอัตรากำลัง" :close="props.close" />
<DialogHeader :tittle="props.actionType === 'ADD' ? 'เพิ่มอัตรากำลัง':'แก้ไขอัตรากำลัง'" :close="props.close" />
<q-separator />
<q-card-section class="q-pa-sm">
@ -456,7 +636,7 @@ function deleteData(id: string) {
icon="mdi-delete"
class="q-pa-none q-ml-xs"
color="red"
@click="deleteData(props.row.positionId)"
@click="deleteData(props.row.id)"
>
<q-tooltip>ลบขอม</q-tooltip>
</q-btn>
@ -465,14 +645,6 @@ function deleteData(id: string) {
</template>
</d-table>
</div>
<div class="col-12 q-mt-sm">
<q-checkbox
dense
v-model="formData.confirm"
label="ไม่ผูกกับตำแหน่งก่อนหน้า"
color="teal"
/>
</div>
</div>
<q-separator />
<q-card-actions
@ -501,7 +673,7 @@ function deleteData(id: string) {
<q-select
label="ค้นหาจาก"
v-model="type"
:options="typeOps"
:options="optionFilter"
emit-value
dense
@update:model-value="updateSelect"
@ -544,7 +716,7 @@ function deleteData(id: string) {
ref="table"
:columns="columns"
:rows="rowsPositionSelect"
row-key="positionId"
row-key="id"
flat
bordered
:paging="true"
@ -602,7 +774,7 @@ function deleteData(id: string) {
@click="
item.type === 'copy'
? copyDetiail(props.row)
: ''
: deletePos(props.row.id)
"
>
<q-item-section avatar>
@ -644,26 +816,46 @@ function deleteData(id: string) {
<div class="row q-col-gutter-sm col-12 q-pa-sm">
<div class="col-6">
<q-input
ref="positionNameRef"
v-model="formPositionSelect.positionName"
:class="inputEdit(isReadonly)"
dense
outlined
for="#positionName"
label="ตำแหน่งในสายงาน"
lazy-rules
hide-bottom-space
:rules="
!isDisValidate
? [
(val) =>
!!val || `${'กรุณากรอกตำแหน่งในสายงาน'}`,
]
: []
"
/>
</div>
<div class="col-6">
<q-input
ref="positionFieldRef"
v-model="formPositionSelect.positionField"
:class="inputEdit(isReadonly)"
dense
outlined
for="#positionField"
label="สายงาน"
lazy-rules
hide-bottom-space
:rules="
!isDisValidate
? [(val) => !!val || `${'กรุณากรอกสายงาน'}`]
: []
"
/>
</div>
<div class="col-6">
<q-select
ref="positionTypeRef"
:class="inputEdit(isReadonly)"
label="ประเภทตำแหน่ง"
v-model="formPositionSelect.positionType"
@ -675,14 +867,22 @@ function deleteData(id: string) {
outlined
option-label="name"
option-value="id"
lazy-rules
hide-bottom-space
:rules="
!isDisValidate
? [(val) => !!val || `${'กรุณาเลือกประเภทตำแหน่ง'}`]
: []
"
/>
</div>
<div class="col-6">
<q-select
ref="positionLevelRef"
:class="inputEdit(isReadonly)"
label="ระดับตำแหน่ง"
v-model="formPositionSelect.positionLevel"
:options="typeOps"
:options="levelOps"
emit-value
dense
@update:model-value="updateSelect"
@ -690,14 +890,22 @@ function deleteData(id: string) {
outlined
option-label="name"
option-value="id"
lazy-rules
hide-bottom-space
:rules="
!isDisValidate
? [(val) => !!val || `${'กรุณาเลือกระดับตำแหน่ง'}`]
: []
"
/>
</div>
<div class="col-6">
<q-select
ref="positionExecutiveRef"
:class="inputEdit(isReadonly)"
label="ตำแหน่งทางการบริหาร"
v-model="formPositionSelect.positionExecutive"
:options="typeOps"
:options="executiveOps"
emit-value
dense
@update:model-value="updateSelect"
@ -705,26 +913,55 @@ function deleteData(id: string) {
outlined
option-label="name"
option-value="id"
lazy-rules
hide-bottom-space
:rules="
!isDisValidate
? [
(val) =>
!!val || `${'กรุณาเลือกตำแหน่งทางการบริหาร'}`,
]
: []
"
/>
</div>
<div class="col-6">
<q-input
ref="positionExecutiveFieldRef"
v-model="formPositionSelect.positionExecutiveField"
:class="inputEdit(isReadonly)"
dense
outlined
for="#positionExecutiveField"
label="ด้านทางการบริหาร"
lazy-rules
hide-bottom-space
:rules="
!isDisValidate
? [
(val) =>
!!val || `${'กรุณากรอกด้านทางการบริหาร'}`,
]
: []
"
/>
</div>
<div class="col-6">
<q-input
ref="positionAreaRef"
v-model="formPositionSelect.positionArea"
:class="inputEdit(isReadonly)"
dense
outlined
for="#positionArea"
label="ด้าน/สาขา"
lazy-rules
hide-bottom-space
:rules="
!isDisValidate
? [(val) => !!val || `${'กรุณากรอกด้าน/สาขา'}`]
: []
"
/>
</div>
</div>

View file

@ -3,7 +3,7 @@ import { ref, reactive, watch } from "vue";
import { useQuasar } from "quasar";
import { useCounterMixin } from "@/stores/mixin";
import type { QTableProps } from "quasar";
import type { HistoryType } from "@/modules/02_organizationalNew/interface/index/Main";
import type { HistoryPostType } from "@/modules/02_organizationalNew/interface/index/Main";
import DialogHeader from "@/components/DialogHeader.vue";
import Modal from "@/modules/05_placement/components/AppointEmployee/Modal.vue";
@ -12,15 +12,14 @@ import { getDateMeta } from "@fullcalendar/core/internal";
import http from "@/plugins/http";
import config from "@/app.config";
const props = defineProps({
modal: Boolean,
close: Function,
});
const modal = defineModel<boolean>("history", { required: true });
const type = defineModel<number>("type", { required: true });
const orgId = defineModel<string>("orgId", { required: true });
const $q = useQuasar();
const mixin = useCounterMixin();
const { showLoader, hideLoader, messageError, date2Thai } = mixin;
const rows = ref<HistoryType[]>([]);
const rows = ref<HistoryPostType[]>([]);
const columns = ref<QTableProps["columns"]>([
{
@ -41,6 +40,16 @@ const columns = ref<QTableProps["columns"]>([
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "name",
align: "left",
label: "",
sortable: true,
field: "name",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "lastUpdatedAt",
align: "left",
@ -50,79 +59,55 @@ const columns = ref<QTableProps["columns"]>([
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "orgRevisionIsCurrent",
align: "center",
label: "โครงสร้างที่ใช้อยู่",
sortable: false,
field: "orgRevisionIsCurrent",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "orgRevisionIsDraft",
align: "center",
label: "โครงสร้างแบบร่าง",
sortable: false,
field: "orgRevisionIsDraft",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "orgRevisionCreatedAt",
align: "left",
label: "วันเริ่มใช้โครงสร้าง",
sortable: true,
field: "orgRevisionCreatedAt",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
]);
const visibleColumns = ref<string[]>([
"no",
"name",
"orgRevisionName",
"orgRevisionIsCurrent",
"orgRevisionIsDraft",
"orgRevisionCreatedAt",
"lastUpdatedAt",
]);
function getDate() {
showLoader()
function postData() {
showLoader();
http
.get(config.API.organizationHistoryNew)
.then((res)=>{
const dataList = res.data.result
dataList.map((item:HistoryType)=>(
{
orgRevisionId:item.orgRevisionId ? item.orgRevisionId:'-',
orgRevisionName:item.orgRevisionName ? item.orgRevisionName:'-',
orgRevisionIsCurrent:item.orgRevisionIsCurrent ? item.orgRevisionIsCurrent:'-',
orgRevisionIsDraft:item.orgRevisionIsDraft ? item.orgRevisionIsDraft:'-',
orgRevisionCreatedAt:item.orgRevisionCreatedAt ? date2Thai(item.orgRevisionCreatedAt as Date):'-',
}
))
rows.value = dataList
}).catch((e)=>{
messageError($q,e)
})
.finally(()=>{
hideLoader()
})
.post(config.API.organizationHistoryPostNew, {
id: orgId.value,
type: type.value,
})
.then((res) => {
const dataList = res.data.result;
const dataMap = dataList.map((item: HistoryPostType) => ({
id: item.id ? item.id : "-",
name: item.name ? item.name : "-",
lastUpdatedAt: item.lastUpdatedAt ? date2Thai(item.lastUpdatedAt as Date,false,true) : "-",
orgRevisionName: item.orgRevisionName ? item.orgRevisionName : "-",
}));
rows.value = dataMap;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
watch(
() => props.modal,
() => modal.value,
() => {
if (props.modal == true) {
getDate();
if (modal.value == true) {
postData();
}
}
);
</script>
<template>
<template>
<q-dialog v-model="props.modal" persistent>
<q-dialog v-model="modal" persistent>
<q-card style="min-width: 40vw">
<DialogHeader :tittle="`ประวัติโครงสร้าง`" :close="props.close" />
<DialogHeader
:tittle="type == 0 ? `ประวัติหน่วยงาน` : `ประวัติส่วนราชการ`"
:close="() => (modal = false)"
/>
<q-separator />
<q-card-section>
@ -148,6 +133,13 @@ watch(
:props="props"
style="color: #000000; font-weight: 500"
>
<span
v-if="col.name === 'name'"
class="text-weight-medium"
>
{{ type === 0 ? "ชื่อหน่วยงาน" : "ส่วนราชการ" }}
</span>
<span class="text-weight-medium">{{ col.label }}</span>
</q-th>
</q-tr>
@ -165,15 +157,31 @@ watch(
<div v-else-if="col.name == 'orgRevisionIsCurrent'">
<q-icon
:name="props.row.orgRevisionIsCurrent == true ? 'mdi-check':''"
:color="props.row.orgRevisionIsCurrent == true ? 'positive':''"
:name="
props.row.orgRevisionIsCurrent == true
? 'mdi-check'
: ''
"
:color="
props.row.orgRevisionIsCurrent == true
? 'positive'
: ''
"
class="text-h5"
/>
</div>
<div v-else-if="col.name == 'orgRevisionIsDraft'">
<q-icon
:name="props.row.orgRevisionIsDraft == true ? 'mdi-check':''"
:color="props.row.orgRevisionIsDraft == true ? 'positive':''"
:name="
props.row.orgRevisionIsDraft == true
? 'mdi-check'
: ''
"
:color="
props.row.orgRevisionIsDraft == true
? 'positive'
: ''
"
class="text-h5"
/>
</div>

View file

@ -0,0 +1,127 @@
<script setup lang="ts">
import { ref, reactive, watch } from "vue";
import { useQuasar } from "quasar";
import http from "@/plugins/http";
import config from "@/app.config";
import type { QTableProps } from "quasar";
import DialogHeader from "@/components/DialogHeader.vue";
import type {
FormDataNewStructure,
FormNewStructureRef,
DataOption,
HistoryType,
} from "@/modules/02_organizationalNew/interface/index/Main";
import { useCounterMixin } from "@/stores/mixin";
import { useOrganizational } from "@/modules/02_organizationalNew/store/organizational";
const $q = useQuasar();
const store = useOrganizational();
const { dialogConfirm, showLoader, success, hideLoader, messageError } =
useCounterMixin();
const modal = defineModel<boolean>("sortAgency", { required: true });
const modalSort = defineModel<Array<any>>("data", { required: true });
const rows = ref<any>([]);
const columns = ref<QTableProps["columns"]>([
{
name: "name",
required: true,
label: "ชื่อ",
align: "left",
field: "name",
sortable: true,
},
]);
function onDrop(from: any, to: any) {
onDropRow(from, to);
}
function onDropRow(from: any, to: any) {
rows.value.splice(to, 0, rows.value.splice(from, 1)[0]);
}
function save() {
dialogConfirm($q, () => {
const data = rows.value;
const dataId = data.map((item: any) => item.orgTreeId);
http
.post(config.API.organizationShortName, {
id: data[0].orgLevel === 0 ? data[0].orgRevisionId : data[0].orgRootId,
type: data[0].orgLevel,
sortId: dataId,
})
.then((res) => {
modal.value = false;
success($q, "บันทึกข้อมูลสำเร็จ");
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {});
});
}
watch(
() => modal.value,
() => {
if (modal.value == true) {
rows.value = [];
const dataStandant = modalSort.value;
const mappedData = dataStandant.map((item: any) => ({
name: `${item.orgTreeName} (${item.orgTreeShortName})`,
orgRootId: item.orgRootId,
orgTreeId: item.orgTreeId,
orgLevel: item.orgLevel,
orgTreeName: item.orgTreeName,
orgTreeShortName: item.orgTreeShortName,
orgRevisionId: item.orgRevisionId,
}));
rows.value = mappedData;
}
}
);
</script>
<template>
<template>
<q-dialog v-model="modal" persistent>
<q-card style="min-width: 50vw">
<!-- <form @submit.prevent="validateForm"> -->
<DialogHeader
:tittle="`จัดลำดับการแสดงผล`"
:close="() => (modal = false)"
/>
<q-separator />
<q-card-section>
<q-table
v-draggable-table="{
options: {
mode: 'row',
onlyBody: true,
dragHandler: 'th,td',
},
onDrop,
}"
flat
bordered
:rows="rows"
:columns="columns"
:rows-per-page-options="[100]"
row-key="orgTreeId"
hide-bottom
hide-pagination
hide-header
/>
</q-card-section>
<q-separator />
<q-card-actions align="right" class="bg-white text-teal">
<q-btn type="submit" :label="`บันทึก`" color="public" @click="save" />
</q-card-actions>
<!-- </form> -->
</q-card>
</q-dialog>
</template>
</template>

View file

@ -4,8 +4,6 @@ import { useQuasar } from "quasar";
import http from "@/plugins/http";
import config from "@/app.config";
import type { HistoryType } from "@/modules/02_organizationalNew/interface/index/Main";
import DialogHeader from "@/components/DialogHeader.vue";
import { useCounterMixin } from "@/stores/mixin";

View file

@ -17,10 +17,13 @@ const store = useOrganizational();
const $q = useQuasar();
const { showLoader, hideLoader, messageError } = useCounterMixin();
const showData = ref<boolean>(false);
const nodeTree = ref<OrgTree[]>();
const historyId = defineModel<string>("historyId", { required: true });
const count = defineModel<number>("count", { required: true });
const nodeId = ref<string>("");
const orgLevel = ref<number>(0);
const isLoad = ref<boolean>(false);
const nodeData = ref<any>();
// defineProps<{ dataActive: DataActive }>();
@ -44,6 +47,22 @@ async function fetchDataTree(id: string) {
// console.log(nodeTree.value);
}
async function fetchDataTable(id: string, level: namber) {
orgLevel.value = level;
// isLoad.value = true;
// await http
// .get(config.API.orgPosPositionById(id))
// .then((res) => {
// console.log(res);
// })
// .catch((err) => {
// messageError($q, err);
// })
// .finally(() => {
// isLoad.value = false;
// });
}
onMounted(async () => {
const id =
store.typeOrganizational === "current" ? store.activeId : store.draftId;
@ -63,6 +82,7 @@ watch(
const id =
store.typeOrganizational === "current" ? store.activeId : store.draftId;
id && store.typeOrganizational !== "old" && fetchDataTree(id);
nodeId.value = "";
}
);
</script>
@ -73,7 +93,10 @@ watch(
<div class="col-12 row no-wrap bg-grey-1">
<TreeView
v-model:nodeTree="nodeTree"
v-model:nodeId="nodeId"
v-model:isLoad="isLoad"
:fetchDataTree="fetchDataTree"
:fetchDataTable="fetchDataTable"
/>
<div class="col-12 row">
@ -84,7 +107,27 @@ watch(
<div class="col-xs-12 col-sm-9 q-pa-md">
<div class="col-12 row items-center">
<TableView v-model:showData="showData" />
<div
class="row col-12 justify-center items-center"
v-if="isLoad"
style="height: 550px"
>
<div class="col-2">
<q-spinner color="primary" size="3em" />
</div>
</div>
<div v-else class="col-12 row items-center">
<TableView
v-if="nodeId !== ''"
v-model:orgLevel="orgLevel"
v-model:treeId="nodeId"
/>
<q-banner v-else class="bg-warning text-white col-12 text-center">
เลอกรายการ {{ nodeId }}
</q-banner>
</div>
</div>
</div>
</q-card>

View file

@ -10,7 +10,8 @@ import type { OrgTree } from "@/modules/02_organizationalNew/interface/response/
/** importComponents*/
import DialogAgency from "@/modules/02_organizationalNew/components/DialogFormAgency.vue";
import DialogStructureDetail from "@/modules/02_organizationalNew/components/StructureDetail.vue";
import DialogSortAgency from "@/modules/02_organizationalNew/components/DialogSortAgency.vue";
import DialogHistory from "@/modules/02_organizationalNew/components/DialogHistory.vue";
/** importStore*/
import { useOrganizational } from "@/modules/02_organizationalNew/store/organizational";
import { useCounterMixin } from "@/stores/mixin";
@ -25,6 +26,10 @@ const props = defineProps({
type: Function,
require: true,
},
fetchDataTable: {
type: Function,
require: true,
},
});
const listAdd = ref<ListMenu[]>([
@ -79,17 +84,28 @@ const listAdd = ref<ListMenu[]>([
]);
const nodeTEST = defineModel<OrgTree[]>("nodeTree", { default: [] });
const nodeId = defineModel<string>("nodeId", { require: true });
const isLoad = defineModel<boolean>("isLoad", { require: true });
const filter = ref<string>("");
const nodes = ref<Array<OrgTree>>([]);
const dataSort = ref<Array<any>>([]);
const lazy = ref(nodes);
const expanded = ref<Array<any>>([]);
const notFound = ref<string>("ไม่พบข้อมูลที่ค้นหา");
const noData = ref<string>("ไม่มีข้อมูล");
const selected = ref("");
const orgLevel = ref<number>(0);
const type = ref<number>(0);
const orgId = ref<string>("");
const updateSelected = (target: any) => {
console.log("updateSelected===>", target);
const updateSelected = (id: string, level: number) => {
if (id === nodeId.value) {
nodeId.value = "";
} else {
nodeId.value = id ? id : "";
id && props.fetchDataTable?.(id, level);
}
};
const breakLoop = ref<boolean>(false);
@ -165,6 +181,8 @@ function deleteNode(treeNode: any, organizationId: any): boolean {
return false;
}
const modalHistory = ref<boolean>(false);
const modalSortAgency = ref<boolean>(false);
const dialogAgency = ref<boolean>(false);
const actionType = ref<string>("");
const dataNode = ref<any>();
@ -208,12 +226,55 @@ async function onClickDel(type: number, id: string) {
messageError($q, err);
})
.finally(async () => {
props.fetchDataTree?.();
hideLoader();
props.fetchDataTree?.();
hideLoader();
});
});
}
async function onClickSort(id: string) {
modalSortAgency.value = true;
if (id) {
breakLoop.value = false;
const orgId = id;
for (let index = 0; index < nodes.value.length; index++) {
const data = nodes.value[index];
searchAndReplace(data, orgId);
if (breakLoop.value) break;
}
} else {
const dataList = nodes.value;
const dataMap = dataList.map((item: any) => ({
orgTreeId: item.orgTreeId,
orgLevel: item.orgLevel,
orgTreeName: item.orgTreeName,
orgTreeShortName: item.orgTreeShortName,
orgRevisionId: item.orgRevisionId,
}));
dataSort.value = dataMap;
}
function searchAndReplace(data: any, id: string) {
if (data.orgTreeId === id) {
dataSort.value = data.children;
breakLoop.value = true;
} else if (data.children) {
for (const child of data.children) {
searchAndReplace(child, id);
}
}
}
}
function onClickHistory(level: number, id: string) {
type.value = level;
orgId.value = id;
modalHistory.value = true;
}
watch(
() => nodeTEST.value,
() => {
@ -277,12 +338,14 @@ onMounted(async () => {});
:no-nodes-label="noData"
v-model:expanded="expanded"
v-model:selected="selected"
@update:selected="updateSelected"
>
<template v-slot:default-header="prop">
<!-- {{ prop.node.orgTreeName }} -->
<div class="row items-center q-px-xs q-pt-xs q-gutter-sm">
<div
class="row items-center q-px-xs q-pt-xs q-gutter-sm"
@click="updateSelected(prop.node.orgTreeId, prop.node.orgLevel)"
>
<!--แสดงชอแผนก มพวหนา คลกแลวกาง/ Tree-->
<div>
<div class="text-weight-medium">
@ -328,6 +391,13 @@ onMounted(async () => {});
? onClickDetail(prop.node.orgTreeId, prop.node.orgLevel)
: item.type === 'DEL'
? onClickDel(prop.node.orgLevel, prop.node.orgTreeId)
: item.type === 'SORT'
? onClickSort(prop.node.orgRootId)
: item.type === 'HISTORY'
? onClickHistory(
prop.node.orgLevel,
prop.node.orgTreeId
)
: null
"
>
@ -451,6 +521,16 @@ onMounted(async () => {});
v-model:treeId="treeId"
v-model:orgLevel="orgLevel"
/>
<DialogSortAgency
v-model:sort-agency="modalSortAgency"
v-model:data="dataSort"
/>
<DialogHistory
v-model:history="modalHistory"
v-model:type="type"
v-model:org-id="orgId"
/>
</template>
<style scoped></style>

View file

@ -12,9 +12,12 @@ import DialogPositionDetail from "@/modules/02_organizationalNew/components/Posi
/** importStore*/
import { useOrganizational } from "@/modules/02_organizationalNew/store/organizational";
const showData = defineModel<boolean>("showData", { required: true });
const showAllData = ref<boolean>(false);
const orgLevel = defineModel<number>("orgLevel", { require: true });
const treeId = defineModel<string>("treeId", { require: true });
const stroe = useOrganizational();
const filter = ref<string>("");
const actionType = ref<string>("");
const listMenu = ref<ListMenu[]>([
{
label: "ดูรายละเอียด",
@ -22,6 +25,12 @@ const listMenu = ref<ListMenu[]>([
type: "VIEWDETIAL",
color: "primary",
},
{
label: "แก้ไข",
icon: "edit",
type: "EDIT",
color: "primary",
},
]);
const document = ref<any>([
{
@ -111,7 +120,8 @@ const rows = ref<any>([
]);
const dialogPosition = ref<boolean>(false);
function onClickPosition() {
function onClickPosition(type: string) {
actionType.value = type;
dialogPosition.value = !dialogPosition.value;
}
@ -131,7 +141,7 @@ function onClickViewDetail() {
dense
color="primary"
icon="add"
@click="onClickPosition"
@click="onClickPosition('ADD')"
>
<q-tooltip>เพมตำแหน</q-tooltip></q-btn
>
@ -160,7 +170,7 @@ function onClickViewDetail() {
<div>
<q-checkbox
keep-color
v-model="showData"
v-model="showAllData"
label="แสดงตำแหน่งทั้งหมด"
color="primary"
>
@ -238,7 +248,11 @@ function onClickViewDetail() {
clickable
v-close-popup
@click="
item.type === 'VIEWDETIAL' ? onClickViewDetail() : null
item.type === 'VIEWDETIAL'
? onClickViewDetail()
: item.type === 'EDIT'
? onClickPosition('EDIT')
: null
"
>
<q-item-section avatar>
@ -252,7 +266,7 @@ function onClickViewDetail() {
</q-td>
</q-tr>
<q-tr v-show="props.expand" :props="props" >
<q-tr v-show="props.expand" :props="props">
<q-td colspan="100%">
<div class="text-left q-pa-md">
<div class="col-12">
@ -356,7 +370,13 @@ function onClickViewDetail() {
</d-table>
</div>
<DialogFormPosotion :modal="dialogPosition" :close="onClickPosition" />
<DialogFormPosotion
:modal="dialogPosition"
:close="onClickPosition"
:orgLevel="orgLevel"
:treeId="treeId"
:actionType="actionType"
/>
<!-- รายละเอยดตำแหน -->
<DialogPositionDetail v-model:position-detail="dialogDetail" />

View file

@ -29,7 +29,6 @@ interface FormDataPosition {
prefixNo: string;
positionNo: string;
suffixNo: string;
confirm: boolean;
}
interface FormDataNewStructure {
@ -74,9 +73,15 @@ interface HistoryType {
orgRevisionIsDraft: boolean;
orgRevisionCreatedAt: Date | string;
}
interface HistoryPostType {
id: string;
name: string;
lastUpdatedAt: Date;
orgRevisionName: string;
}
interface FormPositionSelect {
positionId: string,
positionId: string;
positionName: string;
positionField: string;
positionType: string;
@ -86,16 +91,28 @@ interface FormPositionSelect {
positionArea: string;
}
interface RowDetailPositions {
positionId: string,
positionName: string
positionField: string
positionType: string
positionLevel: string
positionExecutive: string
positionExecutiveField: string
positionArea: string
interface FormPositionSelectRef {
positionName: object | null;
positionField: object | null;
positionType: object | null;
positionLevel: object | null;
positionExecutive: object | null;
positionExecutiveField: object | null;
positionArea: object | null;
[key: string]: any;
}
interface RowDetailPositions {
positionId: string;
positionName: string;
positionField: string;
positionType: string;
positionLevel: string;
positionExecutive: string;
positionExecutiveField: string;
positionArea: string;
}
export type {
Pagination,
DataOption,
@ -109,5 +126,7 @@ export type {
HistoryType,
ListMenu,
FormPositionSelect,
RowDetailPositions
RowDetailPositions,
HistoryPostType,
FormPositionSelectRef,
};

View file

@ -31,4 +31,42 @@ interface OrgRevision {
orgRevisionName: string;
}
export type { DataActive, OrgTree, OrgRevision };
interface OptionType {
id: string;
posTypeName: string;
}
interface OptionLevel {
id: string;
posLevelName: string;
}
interface OptionExecutive {
id: string;
posExecutiveName: string;
}
interface DataPosition {
id: string;
posExecutiveId: string;
posExecutiveName: string;
posLevelId: string;
posLevelName: string;
posTypeId: string;
posTypeName: string;
positionArea: string;
positionExecutiveField: string;
positionField: string;
positionIsSelected: boolean;
positionName: string;
}
export type {
DataActive,
OrgTree,
OrgRevision,
OptionType,
OptionLevel,
OptionExecutive,
DataPosition,
};

View file

@ -17,6 +17,7 @@ import type {
import type { QTableProps } from "quasar";
import PopupPersonal from "@/components/Dialogs/PopupPersonal.vue";
const avatar = ref<string>('')
const modalPersonal = ref<boolean>(false);
const personId = ref<string>("");
/** Use */
@ -179,6 +180,7 @@ const fetchData = async (id: string) => {
location.value = data.location ?? "";
status.value = data.status ?? "";
remarkHorizontal.value = data.remarkHorizontal ?? "-";
getAvatar(data.profileId)
})
.catch((e) => {
messageError($q, e);
@ -187,6 +189,23 @@ const fetchData = async (id: string) => {
hideLoader();
});
};
function getAvatar(id:string){
if(id){
http
.get(config.API.profileAvaId(id))
.then((res)=>{
console.log(res)
const dataList = res.data.result
avatar.value = dataList.avatar
}).catch((e)=>{
}).finally(()=>{
})
}
}
// const downloadFile = (response: any, filename: string) => {
// const link = document.createElement("a");
// var fileName = filename;
@ -435,7 +454,8 @@ function updatemodalPersonal(modal: boolean) {
<div class="row col-12 q-pa-md">
<div class="col-12 row bg-white q-col-gutter-md">
<div class="col-xs-3 col-sm-2 col-md-1 row">
<q-img src="@/assets/avatar_user.jpg" />
<q-img :src="avatar" v-if="avatar !== '' && avatar !== null" />
<q-img src="@/assets/avatar_user.jpg" v-else />
</div>
<div class="col-xs-6 col-sm-3 row items-center">
<div class="col-12 q-pl-md">