Merge branch 'Nice' into develop

This commit is contained in:
DESKTOP-1R2VSQH\Lenovo ThinkPad E490 2025-07-17 14:51:39 +07:00
commit d50f7ddf8e
4 changed files with 171 additions and 34 deletions

View file

@ -21,6 +21,7 @@ interface FormDataSalary {
positionLine: string; // สายงาน positionLine: string; // สายงาน
positionPathSide: string; //ด้าน/สาขา positionPathSide: string; //ด้าน/สาขา
positionExecutive: string; //ตำแหน่งทางการบริหาร positionExecutive: string; //ตำแหน่งทางการบริหาร
positionExecutiveField: string; //ด้านทางการบริหาร
amount: number | null; //เงินเดือน amount: number | null; //เงินเดือน
amountSpecial: number | null; //เงินค่าตอบแทนพิเศษ amountSpecial: number | null; //เงินค่าตอบแทนพิเศษ
positionSalaryAmount: number | null; //เงินประจำตำแหน่ง positionSalaryAmount: number | null; //เงินประจำตำแหน่ง

View file

@ -2,6 +2,7 @@
import { ref, reactive, onMounted, nextTick, watch } from "vue"; import { ref, reactive, onMounted, nextTick, watch } from "vue";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import { useRoute } from "vue-router";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useEditPosDataStore } from "@/modules/04_registryPerson/stores/Edit"; import { useEditPosDataStore } from "@/modules/04_registryPerson/stores/Edit";
import http from "@/plugins/http"; import http from "@/plugins/http";
@ -22,6 +23,7 @@ import DialogHeader from "@/components/DialogHeader.vue";
import FormPosition from "@/modules/04_registryPerson/views/edit/components/FormPosition.vue"; import FormPosition from "@/modules/04_registryPerson/views/edit/components/FormPosition.vue";
const $q = useQuasar(); const $q = useQuasar();
const route = useRoute();
const { const {
dialogConfirm, dialogConfirm,
showLoader, showLoader,
@ -32,10 +34,13 @@ const {
} = useCounterMixin(); } = useCounterMixin();
const store = useEditPosDataStore(); const store = useEditPosDataStore();
const profileId = ref<string>(route.params.id.toString());
const modal = defineModel<boolean>("modal", { required: true }); const modal = defineModel<boolean>("modal", { required: true });
const empType = defineModel<string>("empType", { required: true }); const empType = defineModel<string>("empType", { required: true });
const rowData = defineModel<DataPosition[]>("rowData", { required: true }); const rowData = defineModel<DataPosition[]>("rowData", { required: true });
const rowIndex = defineModel<number>("rowIndex", { required: true }); const rowIndex = defineModel<number>("rowIndex", { required: true });
const isAddPosition = defineModel<boolean>("isAddPosition", { required: true });
const props = defineProps({ const props = defineProps({
fetchData: { type: Function, required: true }, fetchData: { type: Function, required: true },
@ -56,6 +61,7 @@ const formData = reactive<FormDataSalary>({
positionLine: "", // positionLine: "", //
positionPathSide: "", /// positionPathSide: "", ///
positionExecutive: "", // positionExecutive: "", //
positionExecutiveField: "", //
amount: null, // amount: null, //
amountSpecial: null, // amountSpecial: null, //
positionSalaryAmount: null, // positionSalaryAmount: null, //
@ -84,6 +90,7 @@ const formReadonly = reactive<FormDataSalary>({
positionLine: "", // positionLine: "", //
positionPathSide: "", /// positionPathSide: "", ///
positionExecutive: "", // positionExecutive: "", //
positionExecutiveField: "", //
amount: null, // amount: null, //
amountSpecial: null, // amountSpecial: null, //
positionSalaryAmount: null, // positionSalaryAmount: null, //
@ -249,14 +256,10 @@ async function fetchDataOptionExecutive() {
* @param status แกไข , เพ * @param status แกไข , เพ
*/ */
async function updateSelectType(val: string, status: boolean = false) { async function updateSelectType(val: string, status: boolean = false) {
console.log(val);
console.log(dataLevel.value);
const listLevel = val const listLevel = val
? dataLevel.value.find((e: DataPosType) => e.posTypeName === val) ? dataLevel.value.find((e: DataPosType) => e.posTypeName === val)
: null; : null;
console.log("เช็คประเภทตำแหน่งงาน", listLevel);
// //
if (listLevel) { if (listLevel) {
store.posLevelData = listLevel.posLevels.map((e: DataPosLevel) => ({ store.posLevelData = listLevel.posLevels.map((e: DataPosLevel) => ({
@ -308,6 +311,7 @@ async function onDefineData(index: number) {
formData.positionLine = salaryNew.positionLine; formData.positionLine = salaryNew.positionLine;
formData.positionPathSide = salaryNew.positionPathSide; formData.positionPathSide = salaryNew.positionPathSide;
formData.positionExecutive = salaryNew.positionExecutive; formData.positionExecutive = salaryNew.positionExecutive;
formData.positionExecutiveField = salaryNew.positionExecutiveField;
formData.amount = salaryNew.amount; formData.amount = salaryNew.amount;
formData.amountSpecial = salaryNew.amountSpecial; formData.amountSpecial = salaryNew.amountSpecial;
formData.positionSalaryAmount = salaryNew.positionSalaryAmount; formData.positionSalaryAmount = salaryNew.positionSalaryAmount;
@ -335,6 +339,7 @@ async function onDefineData(index: number) {
formReadonly.positionLine = salaryOld.positionLine; formReadonly.positionLine = salaryOld.positionLine;
formReadonly.positionPathSide = salaryOld.positionPathSide; formReadonly.positionPathSide = salaryOld.positionPathSide;
formReadonly.positionExecutive = salaryOld.positionExecutive; formReadonly.positionExecutive = salaryOld.positionExecutive;
formReadonly.positionExecutiveField = salaryOld.positionExecutiveField;
formReadonly.amount = salaryOld.amount; formReadonly.amount = salaryOld.amount;
formReadonly.positionSalaryAmount = salaryOld.positionSalaryAmount; formReadonly.positionSalaryAmount = salaryOld.positionSalaryAmount;
formReadonly.mouthSalaryAmount = salaryOld.mouthSalaryAmount; formReadonly.mouthSalaryAmount = salaryOld.mouthSalaryAmount;
@ -357,31 +362,95 @@ async function onNavigateRow(action: string) {
function onClickCloseDialog() { function onClickCloseDialog() {
modal.value = false; modal.value = false;
formData.commandCode = "";
formData.commandNo = "";
formData.commandYear = null;
formData.commandDateAffect = null;
formData.commandDateSign = null;
formData.posNoAbb = "";
formData.posNo = "";
formData.positionName = "";
formData.positionType = "";
formData.positionLevel = "";
formData.positionCee = "";
formData.positionLine = "";
formData.positionPathSide = "";
formData.positionExecutive = "";
formData.positionExecutiveField = "";
formData.amount = null;
formData.amountSpecial = null;
formData.positionSalaryAmount = null;
formData.mouthSalaryAmount = null;
formData.orgRoot = "";
formData.orgChild1 = "";
formData.orgChild2 = "";
formData.orgChild3 = "";
formData.orgChild4 = "";
formData.remark = "";
formData.posNumCodeSit = "";
formData.posNumCodeSitAbb = "";
formReadonly.commandCode = "";
formReadonly.commandNo = "";
formReadonly.commandYear = null;
formReadonly.commandDateAffect = null;
formReadonly.commandDateSign = null;
formReadonly.posNoAbb = "";
formReadonly.posNo = "";
formReadonly.positionName = "";
formReadonly.positionType = "";
formReadonly.positionLevel = "";
formReadonly.positionCee = "";
formReadonly.positionLine = "";
formReadonly.positionPathSide = "";
formReadonly.positionExecutive = "";
formReadonly.positionExecutiveField = "";
formReadonly.amount = null;
formReadonly.positionSalaryAmount = null;
formReadonly.mouthSalaryAmount = null;
formReadonly.orgRoot = "";
formReadonly.orgChild1 = "";
formReadonly.orgChild2 = "";
formReadonly.orgChild3 = "";
formReadonly.orgChild4 = "";
formReadonly.remark = "";
formReadonly.posNumCodeSit = "";
formReadonly.posNumCodeSitAbb = "";
} }
function onSubmit() { function onSubmit() {
console.log(formData);
dialogConfirm($q, async () => { dialogConfirm($q, async () => {
showLoader(); showLoader();
await http const path = isAddPosition.value
.patch(config.API.salaryTemp + `/${salaryId.value}`, { ? config.API.salaryTemp
...formData, : config.API.salaryTemp + `/${salaryId.value}`;
type: empType.value?.toLocaleUpperCase(), const method = isAddPosition.value ? "post" : "patch";
commandDateAffect: convertDateToAPI(formData.commandDateAffect), await http[method](path, {
commandDateSign: convertDateToAPI(formData.commandDateSign), ...formData,
amount: formData.amount profileId:
? Number(String(formData.amount)?.replace(/,/g, "")) isAddPosition.value && empType.value === "officer"
: null, ? profileId.value
amountSpecial: formData.amountSpecial : undefined,
? Number(String(formData.amountSpecial)?.replace(/,/g, "")) profileEmployeeId:
: null, isAddPosition.value && empType.value !== "officer"
positionSalaryAmount: formData.positionSalaryAmount ? profileId.value
? Number(String(formData.positionSalaryAmount)?.replace(/,/g, "")) : undefined,
: null, type: empType.value?.toLocaleUpperCase(),
mouthSalaryAmount: formData.mouthSalaryAmount commandDateAffect: convertDateToAPI(formData.commandDateAffect),
? Number(String(formData.mouthSalaryAmount)?.replace(/,/g, "")) commandDateSign: convertDateToAPI(formData.commandDateSign),
: null, amount: formData.amount
}) ? Number(String(formData.amount)?.replace(/,/g, ""))
: null,
amountSpecial: formData.amountSpecial
? Number(String(formData.amountSpecial)?.replace(/,/g, ""))
: null,
positionSalaryAmount: formData.positionSalaryAmount
? Number(String(formData.positionSalaryAmount)?.replace(/,/g, ""))
: null,
mouthSalaryAmount: formData.mouthSalaryAmount
? Number(String(formData.mouthSalaryAmount)?.replace(/,/g, ""))
: null,
})
.then(async () => { .then(async () => {
await props.fetchData?.(); await props.fetchData?.();
success($q, "บันทึกข้อมูลสำเร็จ"); success($q, "บันทึกข้อมูลสำเร็จ");
@ -415,7 +484,7 @@ watch(modal, async (val) => {
posLineOptions.value = store.posLineData; posLineOptions.value = store.posLineData;
posPathSideOptions.value = store.posPathSideData; posPathSideOptions.value = store.posPathSideData;
posExecutiveOptions.value = store.posExecutiveData; posExecutiveOptions.value = store.posExecutiveData;
await onDefineData(rowIndex.value); !isAddPosition.value && (await onDefineData(rowIndex.value));
hideLoader(); hideLoader();
} }
}); });
@ -426,17 +495,19 @@ onMounted(async () => {
</script> </script>
<template> <template>
<q-dialog v-model="modal" persistent full-width> <q-dialog v-model="modal" persistent :full-width="!isAddPosition">
<q-card> <q-card style="min-width: 50%">
<q-form greedy @submit.prevent @validation-success="onSubmit"> <q-form greedy @submit.prevent @validation-success="onSubmit">
<DialogHeader <DialogHeader
:tittle="'แก้ไขตำแหน่ง/เงินเดือน'" :tittle="`${
isAddPosition ? 'เพิ่มตำแหน่ง/เงินเดือน' : 'แก้ไขตำแหน่ง/เงินเดือน'
}`"
:close="onClickCloseDialog" :close="onClickCloseDialog"
/> />
<q-separator /> <q-separator />
<q-card-section style="padding: 0px"> <q-card-section style="padding: 0px">
<div class="col-12 row"> <div class="col-12 row" v-if="!isAddPosition">
<div class="col-xs-12 col-md-6 row no-wrap"> <div class="col-xs-12 col-md-6 row no-wrap">
<div class="col-12 q-pa-md"> <div class="col-12 q-pa-md">
<q-card <q-card
@ -504,12 +575,29 @@ onMounted(async () => {
</div> </div>
</div> </div>
</div> </div>
<div class="col-12 q-pa-md" v-else>
<FormPosition
:is-readonly="false"
v-model:form-data="formData"
v-model:command-code-options="commandCodeOptions"
v-model:pos-type-options="posTypeOptions"
v-model:pos-level-options="posLevelOptions"
v-model:pos-line-options="posLineOptions"
v-model:pos-path-side-options="posPathSideOptions"
v-model:pos-executive-options="posExecutiveOptions"
:emp-type="empType"
:update-select-type="updateSelectType"
:is-add-position="isAddPosition"
/>
</div>
</q-card-section> </q-card-section>
<q-separator /> <q-separator />
<q-card-actions align="right"> <q-card-actions align="right">
<q-btn <q-btn
v-if="!isAddPosition"
flat flat
round round
:disable="rowIndex === 0" :disable="rowIndex === 0"
@ -521,6 +609,7 @@ onMounted(async () => {
</q-btn> </q-btn>
<q-btn <q-btn
v-if="!isAddPosition"
flat flat
round round
:disable="rowIndex + 1 === rowData.length" :disable="rowIndex + 1 === rowData.length"

View file

@ -9,6 +9,7 @@ const { date2Thai } = useCounterMixin();
const store = useEditPosDataStore(); const store = useEditPosDataStore();
const isReadonly = defineModel<boolean>("isReadonly", { required: true }); const isReadonly = defineModel<boolean>("isReadonly", { required: true });
const isAddPosition = defineModel<boolean>("isAddPosition", { default: false });
const empType = defineModel<string>("empType", { required: true }); const empType = defineModel<string>("empType", { required: true });
const formData = defineModel<FormDataSalary>("formData", { required: true }); const formData = defineModel<FormDataSalary>("formData", { required: true });
const commandCodeOptions = defineModel<DataOption[]>("commandCodeOptions", { const commandCodeOptions = defineModel<DataOption[]>("commandCodeOptions", {
@ -106,7 +107,6 @@ function classInput(val: boolean) {
<template> <template>
<div class="row col-12 q-col-gutter-sm"> <div class="row col-12 q-col-gutter-sm">
<div class="col-xs-12 col-sm-6 col-md-8"> <div class="col-xs-12 col-sm-6 col-md-8">
<!-- :rules="[(val: string) => !!val || 'กรุณาเลือกประเภทคำสั่ง']" -->
<q-select <q-select
outlined outlined
:class="classInput(isReadonly)" :class="classInput(isReadonly)"
@ -120,6 +120,7 @@ function classInput(val: boolean) {
map-options map-options
option-label="name" option-label="name"
:options="commandCodeOptions" :options="commandCodeOptions"
:rules="isAddPosition ? [(val: string) => !!val || 'กรุณาเลือกประเภทคำสั่ง'] : []"
option-value="id" option-value="id"
hide-bottom-space hide-bottom-space
use-input use-input
@ -140,7 +141,6 @@ function classInput(val: boolean) {
</div> </div>
<div class="col-xs-12 col-sm-6 col-md-4"> <div class="col-xs-12 col-sm-6 col-md-4">
<!-- :rules="[ (val: string) => !!val || `${'กรุณาเลือกวันที่คำสั่งมีผล'}`, ]" -->
<datepicker <datepicker
menu-class-name="modalfix" menu-class-name="modalfix"
:readonly="isReadonly" :readonly="isReadonly"
@ -167,6 +167,7 @@ function classInput(val: boolean) {
: null : null
" "
:label="`${'วันที่คำสั่งมีผล'}`" :label="`${'วันที่คำสั่งมีผล'}`"
:rules="isAddPosition ? [ (val: string) => !!val || `${'กรุณาเลือกวันที่คำสั่งมีผล'}`, ] : []"
hide-bottom-space hide-bottom-space
clearable clearable
@clear="formData.commandDateAffect = null" @clear="formData.commandDateAffect = null"
@ -222,11 +223,11 @@ function classInput(val: boolean) {
v-model="formData.commandNo" v-model="formData.commandNo"
hide-bottom-space hide-bottom-space
:label="`${'เลขที่คำสั่ง'}`" :label="`${'เลขที่คำสั่ง'}`"
:rules="isAddPosition ? [ (val: string) => !!val || `${'กรุณากรอกเลขที่คำสั่ง'}`, ] : []"
/> />
</div> </div>
<label class="col-1 flex justify-center items-center">/</label> <label class="col-1 flex justify-center items-center">/</label>
<div class="col-5"> <div class="col-5">
<!-- :rules="[(val:string) => !!val || `${'กรุณากรอก พ.ศ.'}`]" -->
<datepicker <datepicker
menu-class-name="modalfix" menu-class-name="modalfix"
v-model="formData.commandYear" v-model="formData.commandYear"
@ -253,6 +254,7 @@ function classInput(val: boolean) {
: formData.commandYear + 543 : formData.commandYear + 543
" "
:label="`${'พ.ศ.'}`" :label="`${'พ.ศ.'}`"
:rules="isAddPosition ? [(val:string) => !!val || `${'กรุณากรอก พ.ศ.'}`] : []"
clearable clearable
@clear="formData.commandYear = null" @clear="formData.commandYear = null"
> >
@ -272,7 +274,6 @@ function classInput(val: boolean) {
</div> </div>
<div class="col-xs-6 col-sm-6 col-md-4"> <div class="col-xs-6 col-sm-6 col-md-4">
<!-- :rules="[ (val: string) => !!val || `${'กรุณาเลือก วันที่ลงนาม'}`,]" -->
<datepicker <datepicker
menu-class-name="modalfix" menu-class-name="modalfix"
v-model="formData.commandDateSign" v-model="formData.commandDateSign"
@ -299,6 +300,7 @@ function classInput(val: boolean) {
: null : null
" "
:label="`${'วันที่ลงนาม'}`" :label="`${'วันที่ลงนาม'}`"
:rules="isAddPosition ? [ (val: string) => !!val || `${'กรุณาเลือกวันที่ลงนาม'}`, ] : []"
hide-bottom-space hide-bottom-space
clearable clearable
@clear="formData.commandDateSign = null" @clear="formData.commandDateSign = null"
@ -358,6 +360,7 @@ function classInput(val: boolean) {
borderless borderless
v-model="formData.positionName" v-model="formData.positionName"
:label="empType === 'officer' ? 'ตำแหน่งในสายงาน' : 'ตำแหน่ง'" :label="empType === 'officer' ? 'ตำแหน่งในสายงาน' : 'ตำแหน่ง'"
:rules="isAddPosition ? [(val: string) => !!val || `${empType === 'officer' ? 'ตำแหน่งในสายงาน' : 'ตำแหน่ง'}` ] :[]"
hide-bottom-space hide-bottom-space
/> />
</div> </div>
@ -577,6 +580,20 @@ function classInput(val: boolean) {
</q-select> --> </q-select> -->
</div> </div>
<div class="col-xs-6 col-sm-6 col-md-4" v-if="empType === 'officer'">
<q-input
:class="classInput(isReadonly)"
:readonly="isReadonly"
outlined
dense
lazy-rules
borderless
v-model="formData.positionExecutiveField"
hide-bottom-space
:label="`${'ด้านทางการบริหาร'}`"
/>
</div>
<div class="col-12"> <div class="col-12">
<div class="row q-col-gutter-sm"> <div class="row q-col-gutter-sm">
<div class="col-xs-6 col-sm-6 col-md-4"> <div class="col-xs-6 col-sm-6 col-md-4">

View file

@ -118,6 +118,15 @@ const baseColumns = ref<QTableColumn[]>([
headerStyle: "font-size: 14px", headerStyle: "font-size: 14px",
style: "font-size: 14px", style: "font-size: 14px",
}, },
{
name: "positionExecutiveField",
align: "left",
label: "ด้านทางการบริหาร",
sortable: false,
field: "positionExecutiveField",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{ {
name: "amount", name: "amount",
align: "left", align: "left",
@ -259,6 +268,7 @@ const visibleColumns = ref<string[]>([
"positionType", "positionType",
"positionLevel", "positionLevel",
"positionExecutive", "positionExecutive",
"positionExecutiveField",
"amount", "amount",
"mouthSalaryAmount", "mouthSalaryAmount",
"positionSalaryAmount", "positionSalaryAmount",
@ -276,7 +286,9 @@ const columns = computed<QTableColumn[]>(() => {
return baseColumns.value.filter( return baseColumns.value.filter(
(column) => (column) =>
column.name !== "positionSalaryAmount" && column.name !== "positionSalaryAmount" &&
column.name !== "mouthSalaryAmount" column.name !== "mouthSalaryAmount" &&
column.name !== "positionExecutive" &&
column.name !== "positionExecutivefield"
); );
} }
} }
@ -285,6 +297,7 @@ const columns = computed<QTableColumn[]>(() => {
const modal = ref<boolean>(false); const modal = ref<boolean>(false);
const modalSort = ref<boolean>(false); const modalSort = ref<boolean>(false);
const isAddPosition = ref<boolean>(true); //
/** function fetch ข้อมูลรายการตำแหน่งเงินเดือน*/ /** function fetch ข้อมูลรายการตำแหน่งเงินเดือน*/
async function fetchData() { async function fetchData() {
@ -327,6 +340,8 @@ function serchDataTable() {
function onEditData(index: number) { function onEditData(index: number) {
rowIndex.value = index; rowIndex.value = index;
modal.value = true; modal.value = true;
isAddPosition.value = index === -1; // index -1
console.log(`isAddPosition: ${isAddPosition.value}`);
} }
/** /**
@ -739,6 +754,20 @@ onMounted(async () => {
<div class="row q-col-gutter-sm"> <div class="row q-col-gutter-sm">
<div class="col-12"> <div class="col-12">
<div class="row q-col-gutter-sm items-center"> <div class="row q-col-gutter-sm items-center">
<q-btn
v-if="
tabs === 'PENDING' && statusCheckEdit == 'PENDING' && isConfirmEdit
"
class="q-ml-sm"
round
flat
dense
color="primary"
icon="add"
@click.stop.prevent="onEditData(-1)"
>
<q-tooltip>ดลำดบขอม</q-tooltip></q-btn
>
<q-btn <q-btn
v-if=" v-if="
tabs === 'PENDING' && statusCheckEdit == 'PENDING' && isConfirmEdit tabs === 'PENDING' && statusCheckEdit == 'PENDING' && isConfirmEdit
@ -1393,6 +1422,7 @@ onMounted(async () => {
:emp-type="empType" :emp-type="empType"
:row-data="rows" :row-data="rows"
:fetch-data="fetchData" :fetch-data="fetchData"
:is-add-position="isAddPosition"
/> />
<DialogSort <DialogSort