hrms-mgt/src/modules/18_command/components/DialogEditSalary.vue
DESKTOP-1R2VSQH\Lenovo ThinkPad E490 d215283163 fix(command): edit-salary
2025-12-15 11:50:33 +07:00

484 lines
14 KiB
Vue

<script setup lang="ts">
import { ref, computed, watch } from "vue";
import { useQuasar, type QTableProps } from "quasar";
import http from "@/plugins/http";
import config from "@/app.config";
import { useRouter } from "vue-router";
import { useCounterMixin } from "@/stores/mixin";
import DialogHeader from "@/components/DialogHeader.vue";
const $q = useQuasar();
const router = useRouter();
const {
dialogConfirm,
messageError,
showLoader,
hideLoader,
success,
onSearchDataTable,
} = useCounterMixin();
const modal = defineModel<boolean>("modal", {
type: Boolean,
required: true,
});
const props = defineProps({
commandCode: {
type: String,
required: true,
},
commandId: {
type: String,
required: true,
},
fetchData: {
type: Function,
default: () => {},
},
});
const baseColumns = ref<QTableProps["columns"]>([
{
name: "no",
align: "left",
label: "ลำดับ",
field: (row) => rows.value.indexOf(row) + 1,
sortable: false,
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "posNo",
align: "left",
label: "รักษาการ (เลขที่ตำแหน่ง)",
field: "posNo",
sortable: false,
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "citizenId",
align: "left",
label: "เลขประจำตัวประชาชน",
field: "citizenId",
sortable: false,
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "fullName",
align: "left",
label: "ชื่อ-นามสกุล",
field: "fullName",
sortable: false,
headerStyle: "font-size: 14px",
style: "font-size: 14px",
format(val, row) {
return `${row.prefix ?? ""}${row.firstName ?? ""} ${row.lastName ?? ""}`;
},
},
{
name: "position",
align: "left",
label: "ตำแหน่ง",
field: "position",
sortable: false,
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "positionType",
align: "left",
label: "ประเภทตำแหน่ง",
field: "positionType",
sortable: false,
headerStyle: "font-size: 14px",
style: "font-size: 14px",
format(val, row) {
return row.posType
? `${row.posType} ${row.posLevel ? `(${row.posLevel})` : ""}`
: "-";
},
},
{
name: "amount",
align: "left",
label: "เงินเดือน",
field: "amount",
format(val) {
return val ? val.toLocaleString() : "-";
},
sortable: false,
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "amountSpecial",
align: "left",
label: "เงินค่าตอบแทนพิเศษ",
field: "amountSpecial",
format(val) {
return val ? val.toLocaleString() : "-";
},
sortable: false,
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "positionSalaryAmount",
align: "left",
label: "เงินประจำตำแหน่ง",
field: "positionSalaryAmount",
format(val) {
return val ? val.toLocaleString() : "-";
},
sortable: false,
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "mouthSalaryAmount",
align: "left",
label: "เงินค่าตอบแทนรายเดือน",
field: "mouthSalaryAmount",
format(val) {
return val ? val.toLocaleString() : "-";
},
sortable: false,
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "remarkHorizontal",
align: "left",
label: "หมายเหตุแนวนอน",
field: "remarkHorizontal",
format(val) {
return val ? val.toLocaleString() : "-";
},
sortable: false,
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "remarkVertical",
align: "left",
label: "หมายเหตุแนวตั้ง",
field: "remarkVertical",
format(val) {
return val ? val.toLocaleString() : "-";
},
sortable: false,
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
]);
const columns = computed<QTableProps["columns"]>(() => {
if (
props.commandCode === "C-PM-01" ||
props.commandCode === "C-PM-02" ||
props.commandCode === "C-PM-03" ||
props.commandCode === "C-PM-04"
) {
return baseColumns.value;
} else if (props.commandCode == "C-PM-40") {
return baseColumns.value?.filter(
(e) => e.name !== "position" && e.name !== "positionType"
);
} else {
return baseColumns.value?.filter(
(e) =>
e.name !== "position" && e.name !== "positionType" && e.name !== "posNo"
);
}
});
const visibleColumns = ref<String[]>([
"no",
"posNo",
"citizenId",
"fullName",
"amount",
"position",
"positionType",
"amountSpecial",
"positionSalaryAmount",
"mouthSalaryAmount",
"remarkHorizontal",
"remarkVertical",
]);
const filter = ref<string>("");
const rowsMain = ref<Array<any>>([]);
const rows = ref<Array<any>>([]);
const isNext = ref<boolean>(false);
// Functions for number formatting
function formatNumber(value: any): string {
if (!value || isNaN(value)) return "";
return Number(value).toLocaleString();
}
function unformatNumber(value: string): number | null {
if (!value) return null;
const numStr = value.replace(/,/g, "");
const num = parseFloat(numStr);
return isNaN(num) ? null : num;
}
function onSearchData() {
rows.value = onSearchDataTable(
filter.value,
rowsMain.value,
columns.value ? columns.value : []
);
}
function closeModal() {
modal.value = false;
rows.value = [];
rowsMain.value = [];
filter.value = "";
}
/** ดึงข้อมูล บุคคล */
async function getPersonList() {
await http
.get(config.API.commandAction(props.commandId, "tab2"))
.then(async (res) => {
const data = await res.data.result;
rows.value = data.commandRecives;
rowsMain.value = data.commandRecives;
onSearchData();
})
.catch((e) => {
messageError($q, e);
});
}
function onSubmit() {
dialogConfirm($q, async () => {
showLoader();
try {
const payload = rows.value.map((item) => ({
id: item.id,
mouthSalaryAmount: Number(item.mouthSalaryAmount) || null,
positionSalaryAmount: Number(item.positionSalaryAmount) || null,
amount: Number(item.amount) || null,
amountSpecial: Number(item.amountSpecial) || null,
remarkVertical: item.remarkVertical,
remarkHorizontal: item.remarkHorizontal,
}));
await http.post(config.API.commandEditSalary, payload);
success($q, "บันทึกข้อมูลาสำเร็จ");
if (isNext.value) {
router.push(`/command/edit/${props.commandId}`);
} else {
closeModal();
props.fetchData(); // เรียกฟังก์ชัน fetchData ที่ส่งมาจาก props เพื่อรีเฟรชข้อมูล
}
} catch (error) {
messageError($q, error);
} finally {
hideLoader();
}
});
}
watch(
() => modal.value,
(newVal) => {
if (newVal) {
getPersonList();
}
}
);
</script>
<template>
<q-dialog v-model="modal" persistent full-width>
<q-card>
<DialogHeader :tittle="'แก้ไขเงินเดือน'" :close="closeModal" />
<q-form greedy @submit.prevent @validation-success="onSubmit">
<q-separator />
<q-card-section>
<div class="row q-col-gutter-sm">
<div class="col-12 row q-pb-sm items-center">
<q-space />
<div class="items-center" style="display: flex">
<!-- ค้นหาข้อความใน table -->
<q-input
standout
dense
v-model="filter"
ref="filterRef"
outlined
placeholder="ค้นหา"
@keydown.enter.prevent="onSearchData()"
>
<template v-slot:append>
<q-icon name="search" />
</template>
</q-input>
<!-- แสดงคอลัมน์ใน table -->
<q-select
v-model="visibleColumns"
:display-value="$q.lang.table.columns"
multiple
outlined
dense
:options="columns"
options-dense
option-value="name"
map-options
emit-value
style="min-width: 140px"
class="gt-xs q-ml-sm"
/>
</div>
</div>
<div class="col-12">
<d-table
:rows="rows"
:columns="columns"
:visible-columns="visibleColumns"
row-key="name"
>
<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-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props">
<q-td
v-for="col in props.cols"
:key="col.name"
:props="props"
>
<div v-if="col.name == 'amount'">
<q-input
:model-value="formatNumber(props.row.amount)"
@update:model-value="(val:string) => props.row.amount = unformatNumber(val)"
type="number"
dense
borderless
outlined
:rules="[(val:string) => !!unformatNumber(val) || 'กรุณากรอกเงินเดือน']"
hide-bottom-space
/>
</div>
<div v-else-if="col.name == 'amountSpecial'">
<q-input
:model-value="formatNumber(props.row.amountSpecial)"
@update:model-value="(val:string) => props.row.amountSpecial = unformatNumber(val)"
type="text"
dense
borderless
outlined
/>
<!-- :rules="[(val:string) => !!val || 'กรุณากรอกเงินค่าตอบแทนพิเศษ']" -->
</div>
<div v-else-if="col.name == 'positionSalaryAmount'">
<q-input
:model-value="
formatNumber(props.row.positionSalaryAmount)
"
@update:model-value="(val:string) => props.row.positionSalaryAmount = unformatNumber(val)"
type="text"
dense
borderless
outlined
/>
<!-- :rules="[(val:string) => !!val || 'กรุณากรอกเงินประจำตำแหน่ง']" -->
</div>
<div v-else-if="col.name == 'mouthSalaryAmount'">
<q-input
:model-value="
formatNumber(props.row.mouthSalaryAmount)
"
@update:model-value="
(val:string) =>
(props.row.mouthSalaryAmount =
unformatNumber(val))
"
type="text"
dense
borderless
outlined
/>
<!-- :rules="[(val:string) => !!val || 'กรุณากรอกเงินค่าตอบแทนรายเดือน']" -->
</div>
<div v-else-if="col.name == 'remarkHorizontal'">
<q-input
v-model="props.row.remarkHorizontal"
type="textarea"
autorows
dense
borderless
outlined
rows="1"
/>
</div>
<div v-else-if="col.name == 'remarkVertical'">
<q-input
v-model="props.row.remarkVertical"
type="textarea"
autorows
dense
borderless
outlined
rows="1"
/>
</div>
<div v-else>
{{ col.value ?? "-" }}
</div>
</q-td>
</q-tr>
</template>
</d-table>
</div>
</div>
</q-card-section>
<q-separator />
<q-card-actions align="right">
<q-btn
label="นทกและเลอกรายชอต"
color="blue"
@click="() => (isNext = false)"
type="submit"
>
<q-tooltip>บันทึกและเลือกรายชื่อต่อ</q-tooltip>
</q-btn>
<q-btn
label="นทกและไปยงหนาคำส"
@click="() => (isNext = true)"
color="public"
type="submit"
>
<q-tooltip>นทกและไปยงหนาคำส</q-tooltip>
</q-btn>
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
</template>
<style scoped></style>