hrms-mgt/src/modules/02_organizational/components/Tree/MappingPositions.vue
2023-06-01 12:54:58 +07:00

444 lines
16 KiB
Vue

<!-- =============================== -->
<!-- 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>