ปรับ บัญชีเงินเดือน

This commit is contained in:
DESKTOP-1R2VSQH\Lenovo ThinkPad E490 2024-02-19 10:53:52 +07:00
parent 7891c16a6c
commit c32c56bc10
5 changed files with 374 additions and 362 deletions

View file

@ -79,6 +79,7 @@ const salaryTypeOption = ref<DataOption[]>([
{ id: "EMPLOYEE", name: "ลูกจ้างประจำกรุงเทพมหานคร" },
]);
const posType = ref<SalaryPosType[]>([]);
const salaryPosTypeOption = ref<DataOption[]>([]);
const salaryPosLevelOption = ref<DataOption[]>([]);
@ -100,6 +101,7 @@ async function fetchPosType() {
await http
.get(config.API.salaryPosType)
.then((res) => {
posType.value = res.data.result;
const listOption = res.data.result.map((e: SalaryPosType) => ({
id: e.id,
name: e.posTypeName,
@ -111,19 +113,18 @@ async function fetchPosType() {
});
}
async function fetchPosLevel() {
await http
.get(config.API.salaryPosLevel)
.then((res) => {
const listOption = res.data.result.map((e: SalaryPosLevel) => ({
id: e.id,
name: e.posLevelName,
}));
salaryPosLevelOption.value = listOption;
})
.catch((err) => {
messageError($q, err);
});
async function fetchPosLevel(id: string) {
const filterLevel = posType.value.find((e: SalaryPosType) => e.id === id);
const listOption =
filterLevel?.posLevels.map((e: SalaryPosLevel) => ({
id: e.id,
name: e.posLevelName,
})) || [];
salaryPosLevelOption.value = listOption;
if (!listOption.some((e: DataOption) => e.id === formData.posLevelId)) {
formData.posLevelId = "";
}
}
async function fetchSalaryDetail(id: string) {
@ -132,7 +133,6 @@ async function fetchSalaryDetail(id: string) {
.get(config.API.salaryChartByid(id))
.then((res) => {
const data = res.data.result;
console.log(data);
formData.salaryType = data.salaryType;
formData.posTypeId = data.posTypeId;
formData.posLevelId = data.posLevelId;
@ -167,9 +167,6 @@ watch(
if (salaryPosTypeOption.value.length === 0) {
await fetchPosType();
}
if (salaryPosLevelOption.value.length === 0) {
await fetchPosLevel();
}
if (props.typeAction === "edit") {
await showLoader();
@ -177,6 +174,7 @@ watch(
salaryId.value = props.data.id;
await fetchDocumentFile(props.data.id);
await fetchSalaryDetail(props.data.id);
await fetchPosLevel(props.data.posTypeId);
}
}
}
@ -293,7 +291,7 @@ function onClickDeleteFile(fileName: string) {
showLoader();
await http
.delete(config.API.salaryChartDelFile(salaryId.value, fileName))
.then((res) => {
.then(() => {
setTimeout(() => {
fetchDocumentFile(salaryId.value);
success($q, "ลบไฟล์สำเร็จ");
@ -371,319 +369,336 @@ async function downloadFile(url: string, type: string, fileName: string) {
<q-separator />
<q-card-section class="q-pt-none">
<div class="row col-12 q-gutter-sm q-pa-md">
<div class="row col-sm-12 col-md-9 q-col-gutter-sm">
<div class="col-xs-12 col-md-3">
<q-select
ref="salaryTypeRef"
dense
hide-bottom-space
outlined
option-label="name"
option-value="id"
emit-value
map-options
v-model="formData.salaryType"
:options="salaryTypeOption"
label="ประเภทผังบัญชีเงินเดือน"
:rules="[(val) => !!val || 'กรุณาเลือกประเภทผังบัญชีเงินเดือน']"
lazy-rules
/>
</div>
<div class="row col-12 q-col-gutter-sm q-pa-md">
<div class="col-xs-12 col-md-9">
<div class="row col-12 q-col-gutter-sm">
<div class="col-xs-12 col-md-3">
<q-select
ref="salaryTypeRef"
dense
hide-bottom-space
outlined
option-label="name"
option-value="id"
emit-value
map-options
v-model="formData.salaryType"
:options="salaryTypeOption"
label="ประเภทผังบัญชีเงินเดือน"
:rules="[
(val) => !!val || 'กรุณาเลือกประเภทผังบัญชีเงินเดือน',
]"
lazy-rules
/>
</div>
<div class="col-xs-12 col-md-3">
<q-select
ref="posTypeRef"
dense
hide-bottom-space
outlined
option-label="name"
option-value="id"
emit-value
map-options
v-model="formData.posTypeId"
:options="salaryPosTypeOption"
label="ประเภทตำแหน่ง/กลุ่ม"
:rules="[(val) => !!val || 'กรุณาเลือกประเภทตำแหน่ง/กลุ่ม']"
lazy-rules
/>
</div>
<div class="col-xs-12 col-md-3">
<q-select
ref="posTypeRef"
dense
hide-bottom-space
outlined
option-label="name"
option-value="id"
emit-value
map-options
v-model="formData.posTypeId"
:options="salaryPosTypeOption"
label="ประเภทตำแหน่ง/กลุ่ม"
:rules="[(val) => !!val || 'กรุณาเลือกประเภทตำแหน่ง/กลุ่ม']"
lazy-rules
@update:model-value="fetchPosLevel"
/>
</div>
<div class="col-xs-12 col-md-3">
<q-select
ref="posLevelRef"
dense
hide-bottom-space
outlined
option-label="name"
option-value="id"
emit-value
map-options
v-model="formData.posLevelId"
:options="salaryPosLevelOption"
label="ระดับ"
:rules="[(val) => !!val || 'กรุณาเลือกระดับ']"
lazy-rules
/>
</div>
<div class="col-xs-12 col-md-3">
<q-select
ref="posLevelRef"
dense
hide-bottom-space
outlined
option-label="name"
option-value="id"
emit-value
map-options
v-model="formData.posLevelId"
:options="salaryPosLevelOption"
label="ระดับ"
:rules="[(val) => !!val || 'กรุณาเลือกระดับ']"
lazy-rules
:disable="formData.posTypeId === ''"
/>
</div>
<div
class="col-xs-12 col-md-3"
style="display: flex; justify-content: flex-end"
>
<q-toggle
color="primary"
label="สถานะการใช้งาน"
v-model="formData.isActive"
/>
</div>
<div class="col-xs-12 col-md-4">
<datepicker
menu-class-name="modalfix"
v-model="formData.date"
:locale="'th'"
autoApply
borderless
:enableTimePicker="false"
week-start="0"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
ref="dateRef"
outlined
dense
hide-bottom-space
:model-value="
formData.date != null ? date2Thai(formData.date) : null
"
label="ให้ไว ณ วันที่"
:rules="[
(val) =>
!!val || `${'กรุณาเลือกวันที่ ให้ไว ณ วันที่'}`,
]"
lazy-rules
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-xs-12 col-md-4">
<datepicker
menu-class-name="modalfix"
v-model="formData.startDate"
:locale="'th'"
autoApply
borderless
:enableTimePicker="false"
week-start="0"
@update:model-value="checkEndDate"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
ref="startDateRef"
outlined
dense
hide-bottom-space
:model-value="
formData.startDate != null
? date2Thai(formData.startDate)
: null
"
label="วันที่มีผลบังคับใช้"
:rules="[
(val) => !!val || `${'กรุณาเลือกวันที่มีผลบังคับใช้'}`,
]"
lazy-rules
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-xs-12 col-md-4">
<datepicker
menu-class-name="modalfix"
v-model="formData.endDate"
:locale="'th'"
autoApply
borderless
:enableTimePicker="false"
week-start="0"
:min-date="formData.startDate"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
ref="endDateRef"
outlined
dense
hide-bottom-space
:model-value="
formData.endDate != null
? date2Thai(formData.endDate)
: null
"
label="วันที่สิ้นสุดบังคับใช้"
:rules="[
(val) =>
!!val || `${'กรุณาเลือกวันที่สิ้นสุดบังคับใช้'}`,
]"
lazy-rules
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-12">
<q-input
v-model="formData.details"
outlined
dense
type="textarea"
label="คำอธิบาย"
/>
</div>
</div>
<div
class="col-xs-12 col-md-3"
class="col-xs-12 col-md-3 q-mt-sm"
style="display: flex; justify-content: flex-end"
>
<q-toggle
color="primary"
label="สถานะการใช้งาน"
v-model="formData.isActive"
/>
</div>
<div class="col-xs-12 col-md-4">
<datepicker
menu-class-name="modalfix"
v-model="formData.date"
:locale="'th'"
autoApply
borderless
:enableTimePicker="false"
week-start="0"
<q-btn label="บันทึก" color="secondary" @click="onClickSubmit"
><q-tooltip>นทกขอม</q-tooltip></q-btn
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
ref="dateRef"
outlined
dense
hide-bottom-space
:model-value="
formData.date != null ? date2Thai(formData.date) : null
"
label="ให้ไว ณ วันที่"
:rules="[
(val) => !!val || `${'กรุณาเลือกวันที่ ให้ไว ณ วันที่'}`,
]"
lazy-rules
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-xs-12 col-md-4">
<datepicker
menu-class-name="modalfix"
v-model="formData.startDate"
:locale="'th'"
autoApply
borderless
:enableTimePicker="false"
week-start="0"
@update:model-value="checkEndDate"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
ref="startDateRef"
outlined
dense
hide-bottom-space
:model-value="
formData.startDate != null
? date2Thai(formData.startDate)
: null
"
label="วันที่มีผลบังคับใช้"
:rules="[
(val) => !!val || `${'กรุณาเลือกวันที่มีผลบังคับใช้'}`,
]"
lazy-rules
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-xs-12 col-md-4">
<datepicker
menu-class-name="modalfix"
v-model="formData.endDate"
:locale="'th'"
autoApply
borderless
:enableTimePicker="false"
week-start="0"
:min-date="formData.startDate"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
ref="endDateRef"
outlined
dense
hide-bottom-space
:model-value="
formData.endDate != null
? date2Thai(formData.endDate)
: null
"
label="วันที่สิ้นสุดบังคับใช้"
:rules="[
(val) => !!val || `${'กรุณาเลือกวันที่สิ้นสุดบังคับใช้'}`,
]"
lazy-rules
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
style="color: var(--q-primary)"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-12">
<q-input
v-model="formData.details"
outlined
dense
type="textarea"
label="คำอธิบาย"
/>
</div>
</div>
<div class="col-sm-12 col-md-3">
<q-card
bordered
class="row col-12"
style="border: 1px solid #d6dee1"
>
<div class="col-12 text-weight-medium bg-grey-1 q-py-sm q-px-md">
ปโหลดเอกสารอางอ
</div>
<div class="col-12"><q-separator /></div>
<div class="row col-12 q-col-gutter-y-sm q-pa-sm">
<div class="col-12 row">
<q-file
v-if="props.typeAction === 'edit'"
class="col-12"
outlined
dense
v-model="documentFile"
label="เอกสารอ้างอิง"
hide-bottom-space
<div class="col-xs-12 col-md-3">
<div class="row col-12 q-col-gutter-sm">
<div class="col-xs-12 col-md-12">
<q-card bordered style="border: 1px solid #d6dee1">
<div
class="col-12 text-weight-medium bg-grey-1 q-py-sm q-px-md"
>
<template v-slot:prepend>
<q-icon name="attach_file" color="primary" />
</template>
<template v-slot:after>
<q-btn
v-if="documentFile"
size="14px"
flat
round
ปโหลดเอกสารอางอ
</div>
<div class="col-12"><q-separator /></div>
<div class="row col-12 q-col-gutter-y-sm q-pa-sm">
<div class="col-12 row">
<q-file
v-if="props.typeAction === 'edit'"
class="col-12"
outlined
dense
color="add"
icon="mdi-upload"
@click="uploadDocumentFile"
><q-tooltip>ปโหลดเอกสาร</q-tooltip></q-btn
v-model="documentFile"
label="เอกสารอ้างอิง"
hide-bottom-space
>
</template>
</q-file>
</div>
<template v-slot:prepend>
<q-icon name="attach_file" color="primary" />
</template>
<template v-slot:after>
<q-btn
v-if="documentFile"
size="14px"
flat
round
dense
color="add"
icon="mdi-upload"
@click="uploadDocumentFile"
><q-tooltip>ปโหลดเอกสาร</q-tooltip></q-btn
>
</template>
</q-file>
</div>
<div v-if="itemsDocument.length > 0" class="col-xs-12 row">
<q-list class="full-width rounded-borders" bordered separator>
<q-item
v-for="file in itemsDocument"
:key="file.id"
clickable
v-ripple
>
<q-item-section>{{ file.name }}</q-item-section>
<q-item-section avatar>
<div class="row">
<div>
<q-btn
dense
flat
round
size="12px"
color="blue"
icon="mdi-download-outline"
@click="onClickDonwload(file.name)"
>
<q-tooltip>ดาวนโหลดไฟล</q-tooltip>
</q-btn>
</div>
<div>
<q-btn
dense
flat
round
size="12px"
color="red"
icon="mdi-delete-outline"
@click="onClickDeleteFile(file.name)"
><q-tooltip>ลบไฟล</q-tooltip></q-btn
>
</div>
</div>
</q-item-section>
</q-item>
</q-list>
</div>
<div v-if="itemsDocument.length > 0" class="col-xs-12 row">
<q-list
class="full-width rounded-borders"
bordered
separator
>
<q-item
v-for="file in itemsDocument"
:key="file.id"
clickable
v-ripple
>
<q-item-section>{{ file.name }}</q-item-section>
<q-item-section avatar>
<div class="row">
<div>
<q-btn
dense
flat
round
size="12px"
color="blue"
icon="mdi-download-outline"
@click="onClickDonwload(file.name)"
>
<q-tooltip>ดาวนโหลดไฟล</q-tooltip>
</q-btn>
</div>
<div>
<q-btn
dense
flat
round
size="12px"
color="red"
icon="mdi-delete-outline"
@click="onClickDeleteFile(file.name)"
><q-tooltip>ลบไฟล</q-tooltip></q-btn
>
</div>
</div>
</q-item-section>
</q-item>
</q-list>
</div>
<div class="col-12" v-else>
<q-card class="q-pa-md" bordered> ไมรายการเอกสาร </q-card>
</div>
<div class="col-12" v-else>
<q-card class="q-pa-md" bordered>
ไมรายการเอกสาร
</q-card>
</div>
</div>
</q-card>
</div>
</q-card>
</div>
</div>
</div>
</q-card-section>
<q-separator />
<q-card-actions align="right" class="bg-white text-teal">
<q-btn label="บันทึก" color="secondary" @click="onClickSubmit"
><q-tooltip>นทกขอม</q-tooltip></q-btn
>
</q-card-actions>
</q-card>
</q-dialog>
</template>

View file

@ -23,7 +23,6 @@ const {
} = useCounterMixin();
const salaryId = ref<string>(route.params.id.toString());
const salaryRateId = ref<string>("");
const modal = defineModel<boolean>("modal", { required: true });
const props = defineProps({
@ -85,9 +84,23 @@ const title = computed(() => {
function closeDialog() {
modal.value = !modal.value;
clearFormData();
}
function clearFormData() {
formData.salaryId = "";
formData.salary = null;
formData.salaryHalf = null;
formData.salaryHalfSpecial = null;
formData.salaryFull = null;
formData.salaryFullSpecial = null;
formData.salaryFullHalf = null;
formData.salaryFullHalfSpecial = null;
formData.isNext = false;
}
function onClickSubmit() {
console.log(formData.salaryHalfSpecial);
const hasError = [];
for (const key in ObjectRef) {
if (Object.prototype.hasOwnProperty.call(ObjectRef, key)) {
@ -118,7 +131,9 @@ function createSalaryRate() {
: Number(formData.salaryHalf.replace(/,/g, "")), //0.5
salaryHalfSpecial:
typeof formData.salaryHalfSpecial === "number"
formData.salaryHalfSpecial === "" || formData.salaryHalfSpecial === null
? null
: typeof formData.salaryHalfSpecial === "number"
? formData.salaryHalfSpecial
: Number(formData.salaryHalfSpecial.replace(/,/g, "")), //0.5 ()
@ -128,7 +143,9 @@ function createSalaryRate() {
: Number(formData.salaryFull.replace(/,/g, "")), //1
salaryFullSpecial:
typeof formData.salaryFullSpecial === "number"
formData.salaryFullSpecial === "" || formData.salaryFullSpecial === null
? null
: typeof formData.salaryFullSpecial === "number"
? formData.salaryFullSpecial
: Number(formData.salaryFullSpecial.replace(/,/g, "")), //1 ()
@ -138,7 +155,10 @@ function createSalaryRate() {
: Number(formData.salaryFullHalf.replace(/,/g, "")), //1.formData5
salaryFullHalfSpecial:
typeof formData.salaryFullHalfSpecial === "number"
formData.salaryFullHalfSpecial === "" ||
formData.salaryFullHalfSpecial === null
? null
: typeof formData.salaryFullHalfSpecial === "number"
? formData.salaryFullHalfSpecial
: Number(formData.salaryFullHalfSpecial.replace(/,/g, "")), //1.5 ()
isNext: formData.isNext, //*
@ -233,7 +253,6 @@ watch(
label="เงินพิเศษ"
mask="###,###,###,###"
reverse-fill-mask
:rules="[(val) => !!val || `${'เงินพิเศษ'}`]"
lazy-rules
hide-bottom-space
/>
@ -261,7 +280,6 @@ watch(
label="เงินพิเศษ"
mask="###,###,###,###"
reverse-fill-mask
:rules="[(val) => !!val || `${'เงินพิเศษ'}`]"
lazy-rules
hide-bottom-space
/>
@ -289,7 +307,6 @@ watch(
label="เงินพิเศษ"
mask="###,###,###,###"
reverse-fill-mask
:rules="[(val) => !!val || `${'เงินพิเศษ'}`]"
lazy-rules
hide-bottom-space
/>

View file

@ -30,6 +30,7 @@ interface SalaryPosType {
id: string;
posTypeName: string;
posTypeRank: string;
posLevels: SalaryPosLevel[];
}
interface SalaryPosLevel {

View file

@ -41,7 +41,7 @@ const columns = ref<QTableProps["columns"]>([
name: "salaryType",
align: "left",
label: "ประเภทผัง",
sortable: false,
sortable: true,
field: "salaryType",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
@ -49,7 +49,7 @@ const columns = ref<QTableProps["columns"]>([
{
name: "posType",
align: "left",
label: "เลขที่ตำแหน่ง",
label: "ประเภทตำแหน่ง",
sortable: true,
field: "posType",
headerStyle: "font-size: 14px",
@ -60,6 +60,7 @@ const columns = ref<QTableProps["columns"]>([
align: "left",
label: "ระดับ",
field: "posLevel",
sortable: true,
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
@ -121,7 +122,7 @@ const itemMenu = ref<ItemsMenu[]>([
/** queryString*/
const formQuery = reactive<FormQuerySalary>({
page: 1, //*
pageSize: 2, //*
pageSize: 10, //*
keyword: "", //keyword
});
const maxPage = ref<number>(1);

View file

@ -85,6 +85,15 @@ const columns = ref<QTableProps["columns"]>([
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "isNext",
align: "left",
label: "ทะลุขั้น",
sortable: true,
field: "isNext",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
]);
/** List Mune*/
@ -123,52 +132,14 @@ async function fetchListSalalyRate() {
`?page=${page}&pageSize=${pageSize}&keyword=${keyword}`
)
.then((res) => {
console.log(res);
rows.value = res.data.result.data;
})
.catch((err) => {
// messageError($q, err);
messageError($q, err);
})
.finally(() => {
hideLoader();
});
// const data = [
// {
// id: "0bc687ad-4273-4aa1-8d8a-65f45e743644",
// salary: 100,
// salaryHalf: 100,
// salaryHalfSpecial: 100,
// salaryFull: 100,
// salaryFullSpecial: 100,
// salaryFullHalf: 100,
// salaryFullHalfSpecial: 100,
// isNext: false,
// },
// {
// id: "0bc687ad-4273-4aa1-8d8a-65f45e743666",
// salary: 200,
// salaryHalf: 200,
// salaryHalfSpecial: 200,
// salaryFull: 200,
// salaryFullSpecial: 200,
// salaryFullHalf: 200,
// salaryFullHalfSpecial: 200,
// isNext: false,
// },
// {
// id: "0bc687ad-4273-4aa1-8d8a-65f45e743677",
// salary: 300,
// salaryHalf: 300,
// salaryHalfSpecial: 300,
// salaryFull: 300,
// salaryFullSpecial: 300,
// salaryFullHalf: 300,
// salaryFullHalfSpecial: 300,
// isNext: false,
// },
// ];
// rows.value = data;
}
/**
@ -229,7 +200,7 @@ watch([() => formQuery.page, () => formQuery.pageSize], async () => {
class="q-mr-sm"
@click="router.go(-1)"
/>
รายการผงบญชเงนเดอน
ราเงนเดอน
</div>
</div>
<q-card flat bordered class="q-pa-md">
@ -313,6 +284,13 @@ watch([() => formQuery.page, () => formQuery.pageSize], async () => {
: col.value.toLocaleString()
}}
</div>
<div v-else-if="col.name === 'isNext'">
<q-icon
:name="col.value ? 'done' : 'close'"
:color="col.value ? 'primary' : 'grey'"
size="24px"
/>
</div>
<div v-else>
{{ col.value ? col.value.toLocaleString() : "-" }}