UI Salary

This commit is contained in:
DESKTOP-1R2VSQH\Lenovo ThinkPad E490 2024-02-16 11:12:16 +07:00
parent d1eab09ee4
commit 18ad7b102e
5 changed files with 612 additions and 8 deletions

View file

@ -1,5 +1,254 @@
<script setup lang="ts"></script>
<script setup lang="ts">
import { computed, ref, reactive, watch } from "vue";
import { useQuasar } from "quasar";
<template>เพ/แกไขอตราเงนเดอน</template>
import type { ObjectSalaryRateRef } from "@/modules/13_salary/interface/index/Main";
import Header from "@/components/DialogHeader.vue";
import { useCounterMixin } from "@/stores/mixin";
const $q = useQuasar();
const {
date2Thai,
dialogConfirm,
showLoader,
hideLoader,
messageError,
success,
} = useCounterMixin();
const modal = defineModel<boolean>("modal", { required: true });
const props = defineProps({
typeAction: {
type: String,
required: true,
},
data: {
type: Object,
defult: [],
},
});
const formData = reactive<any>({
salaryId: "",
salary: null,
salaryHalf: null,
salaryHalfSpecial: null,
salaryFull: null,
salaryFullSpecial: null,
salaryFullHalf: null,
salaryFullHalfSpecial: null,
isNext: false,
});
/** ตัวแปร ref สำหรับแสดง validate */
const salaryRef = ref<Object | null>(null);
const salaryHalfRef = ref<Object | null>(null);
const salaryHalfSpecialRef = ref<Object | null>(null);
const salaryFullRef = ref<Object | null>(null);
const salaryFullSpecialRef = ref<Object | null>(null);
const salaryFullHalfRef = ref<Object | null>(null);
const salaryFullHalfSpecialRef = ref<Object | null>(null);
const ObjectRef: ObjectSalaryRateRef = {
salary: salaryRef,
salaryHalf: salaryHalfRef,
salaryHalfSpecial: salaryHalfSpecialRef,
salaryFull: salaryFullRef,
salaryFullSpecial: salaryFullSpecialRef,
salaryFullHalf: salaryFullHalfRef,
salaryFullHalfSpecial: salaryFullHalfSpecialRef,
};
const title = computed(() => {
const name =
props.typeAction === "add"
? "เพิ่มอัตราเงินเดือน"
: props.typeAction === "edit"
? "แก้ไขอัตราเงินเดือน"
: "อัตราเงินเดือน";
return name;
});
function closeDialog() {
modal.value = !modal.value;
}
function onClickSubmit() {
// console.log(Number(formData.salary.replace(/,/g, "")));
const hasError = [];
for (const key in ObjectRef) {
if (Object.prototype.hasOwnProperty.call(ObjectRef, key)) {
const property = ObjectRef[key];
if (property.value && typeof property.value.validate === "function") {
const isValid = property.value.validate();
hasError.push(isValid);
}
}
}
if (hasError.every((result) => result === true)) {
createSalaryRate();
}
}
function createSalaryRate() {
dialogConfirm($q, () => {
if (props.typeAction === "add") {
success($q, "add");
} else {
success($q, "edit");
}
closeDialog();
});
}
watch(
() => modal.value,
() => {
if (modal.value && props.typeAction === "edit") {
if (props.data) {
console.log(props.data);
const data = props.data;
// formData.salaryId = data.id;
formData.salary = data.salary;
formData.salaryHalf = data.salaryHalf;
formData.salaryHalfSpecial = data.salaryHalfSpecial;
formData.salaryFull = data.salaryFull;
formData.salaryFullSpecial = data.salaryFullSpecial;
formData.salaryFullHalf = data.salaryFullHalf;
formData.salaryFullHalfSpecial = data.salaryFullHalfSpecial;
formData.isNext = data.isNext;
}
}
}
);
</script>
<template>
<q-dialog v-model="modal" persistent>
<q-card style="width: 700px; max-width: 80vw">
<Header :tittle="title" :close="closeDialog" />
<q-separator />
<q-card-section class="q-pt-none">
<div class="row q-gutter-sm q-pa-md">
<div class="row col-xs-12 col-md-12 q-col-gutter-sm">
<div class="col-6">
<q-input
ref="salaryRef"
dense
outlined
v-model="formData.salary"
label="เงินเดือนฐาน"
mask="###,###,###,###"
reverse-fill-mask
:rules="[(val) => !!val || `${'กรุณากรอกเงินเดือนฐาน'}`]"
lazy-rules
hide-bottom-space
/>
</div>
<div class="col-6 row items-center">
<q-checkbox dense v-model="formData.isNext" label="ทำลุขั้น" />
</div>
<div class="col-6">
<q-input
ref="salaryHalfRef"
dense
outlined
v-model="formData.salaryHalf"
label="เลื่อน 0.5 ขั้น"
mask="###,###,###,###"
reverse-fill-mask
:rules="[(val) => !!val || `${'กรุณากรอกเลื่อน 0.5 ขั้น'}`]"
lazy-rules
hide-bottom-space
/>
</div>
<div class="col-6">
<q-input
ref="salaryHalfSpecialRef"
dense
outlined
v-model="formData.salaryHalfSpecial"
label="เงินพิเศษ"
mask="###,###,###,###"
reverse-fill-mask
:rules="[(val) => !!val || `${'เงินพิเศษ'}`]"
lazy-rules
hide-bottom-space
/>
</div>
<div class="col-6">
<q-input
ref="salaryFullRef"
dense
outlined
v-model="formData.salaryFull"
label="เลื่อน 1 ขั้น"
mask="###,###,###,###"
reverse-fill-mask
:rules="[(val) => !!val || `${'กรุณากรอกเลื่อน 1 ขั้น'}`]"
lazy-rules
hide-bottom-space
/>
</div>
<div class="col-6">
<q-input
ref="salaryFullSpecialRef"
dense
outlined
v-model="formData.salaryFullSpecial"
label="เงินพิเศษ"
mask="###,###,###,###"
reverse-fill-mask
:rules="[(val) => !!val || `${'เงินพิเศษ'}`]"
lazy-rules
hide-bottom-space
/>
</div>
<div class="col-6">
<q-input
ref="salaryFullHalfRef"
dense
outlined
v-model="formData.salaryFullHalf"
label="เลื่อน 1.5 ขั้น"
mask="###,###,###,###"
reverse-fill-mask
:rules="[(val) => !!val || `${'กรุณากรอกเลื่อน 1.5 ขั้น'}`]"
lazy-rules
hide-bottom-space
/>
</div>
<div class="col-6">
<q-input
ref="salaryFullHalfSpecialRef"
dense
outlined
v-model="formData.salaryFullHalfSpecial"
label="เงินพิเศษ"
mask="###,###,###,###"
reverse-fill-mask
:rules="[(val) => !!val || `${'เงินพิเศษ'}`]"
lazy-rules
hide-bottom-space
/>
</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>
<style lang="scss" scoped></style>

View file

@ -27,4 +27,22 @@ interface ObjectSalaryRef {
[key: string]: any;
}
export type { DataOption, NewPagination, ItemsMenu, ObjectSalaryRef };
interface ObjectSalaryRateRef {
salary: object | null;
salaryHalf: object | null;
salaryHalfSpecial: object | null;
salaryFull: object | null;
salaryFullSpecial: object | null;
salaryFullHalf: object | null;
salaryFullHalfSpecial: object | null;
[key: string]: any;
}
export type {
DataOption,
NewPagination,
ItemsMenu,
ObjectSalaryRef,
ObjectSalaryRateRef,
};

View file

@ -14,4 +14,16 @@ interface Salary {
detail: string;
}
export type { Salary };
interface SalaryRate {
id: string;
salary: number;
salaryHalf: number;
salaryHalfSpecial: number;
salaryFull: number;
salaryFullSpecial: number;
salaryFullHalf: number;
salaryFullHalfSpecial: number;
isNext: boolean;
}
export type { Salary, SalaryRate };

View file

@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, onMounted, reactive } from "vue";
import { ref, onMounted, reactive, watch } from "vue";
import { useQuasar } from "quasar";
import { useRouter } from "vue-router";
@ -122,8 +122,8 @@ const totalRow = ref<number>(1);
* @param newPagination อม Pagination ใหม
*/
function updatePagination(newPagination: NewPagination) {
// reqMaster.value.pageSize = newPagination.rowsPerPage;
// reqMaster.value.page = 1;
formQuery.page = 1;
formQuery.pageSize = newPagination.rowsPerPage;
}
async function fetchListSalaly() {
@ -178,6 +178,10 @@ async function onClickDelete() {
onMounted(async () => {
await fetchListSalaly();
});
watch([() => formQuery.page, () => formQuery.pageSize], () => {
console.log(formQuery.page, formQuery.pageSize);
});
</script>
<template>

View file

@ -1,12 +1,333 @@
<script setup lang="ts">
import { ref, onMounted, reactive, watch } from "vue";
import { useQuasar } from "quasar";
import { useRouter } from "vue-router";
/** importType*/
import type { QTableProps } from "quasar";
import type {
NewPagination,
ItemsMenu,
} from "@/modules/13_salary/interface/index/Main";
import type { SalaryRate } from "@/modules/13_salary/interface/response/Main";
import type { FormQuerySalary } from "@/modules/13_salary/interface/request/Main";
/** importComponents*/
import DialogFormRate from "@/modules/13_salary/components/SalaryChart/DialogFormRate.vue";
/** importStore*/
import { useCounterMixin } from "@/stores/mixin";
/** use*/
const $q = useQuasar();
const router = useRouter();
const { date2Thai, dialogRemove, success } = useCounterMixin();
/** modalDialog*/
const modalDialogFormRate = ref<boolean>(false);
/** Table*/
const rows = ref<SalaryRate[]>([]);
const columns = ref<QTableProps["columns"]>([
{
name: "no",
align: "left",
label: "ลำดับ",
sortable: false,
field: "no",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "salary",
align: "left",
label: "เงินเดือนฐาน",
sortable: true,
field: "salary",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "salaryHalf",
align: "left",
label: "เลื่อน 0.5 ขั้น/(พิเศษ)",
field: "salaryHalf",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "salaryFull",
align: "left",
label: "เลื่อน 1 ขั้น/(พิเศษ)",
sortable: true,
field: "salaryFull",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "salaryFullHalf",
align: "left",
label: "เลื่อน 1.5 ขั้น/(พิเศษ)",
sortable: true,
field: "salaryFullHalf",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
]);
/** List Mune*/
const itemMenu = ref<ItemsMenu[]>([
{
label: "แก้ไข",
icon: "edit",
color: "edit",
type: "edit",
},
{
label: "ลบ",
icon: "delete",
color: "red",
type: "delete",
},
]);
/** queryString*/
const formQuery = reactive<FormQuerySalary>({
page: 1, //*
pageSize: 10, //*
keyword: "", //keyword
});
const totalRow = ref<number>(1);
function fetchListSalalyRate() {
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;
}
/**
* function updatePagination
* @param newPagination อม Pagination ใหม
*/
function updatePagination(newPagination: NewPagination) {
formQuery.page = 1;
formQuery.pageSize = newPagination.rowsPerPage;
}
const typeAction = ref<string>("");
const dataRow = ref<SalaryRate>();
function onClickSalaryRate(type: string, data: SalaryRate | null) {
modalDialogFormRate.value = !modalDialogFormRate.value;
typeAction.value = type;
if (data) {
dataRow.value = data;
}
}
function onClickDelete() {
dialogRemove($q, () => {
success($q, "ลบข้อมูลสำเร็จ");
});
}
onMounted(async () => {
await fetchListSalalyRate();
});
</script>
<template>หนารายการผงบญชเงนเดอน</template>
<template>
<div class="row items-center">
<div class="toptitle text-dark row items-center q-py-xs">
<q-btn
icon="mdi-arrow-left"
unelevated
round
dense
flat
color="primary"
class="q-mr-sm"
@click="router.go(-1)"
/>
รายการผงบญชเงนเดอน
</div>
</div>
<q-card flat bordered class="q-pa-md">
<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">
<q-toolbar class="text-primary q-gutter-sm" style="padding: 0px">
<q-btn
flat
round
dense
icon="add"
color="primary"
@click="onClickSalaryRate('add', null)"
>
<q-tooltip>เพมอตราเงนเดอน </q-tooltip>
</q-btn>
<q-space />
<q-btn outline label="พิมพ์เอกสาร" icon="print" color="green" />
<q-btn outline label="ดาว์นโหลด" icon="download" color="blue" />
</q-toolbar>
</div>
<div class="col-12"><q-separator /></div>
<div class="col-12 q-pa-md">
<d-table
ref="table"
:columns="columns"
:rows="rows"
row-key="id"
flat
bordered
:paging="true"
dense
:rows-per-page-options="[10, 25, 50, 100]"
@update:pagination="updatePagination"
>
<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-th auto-width></q-th>
</q-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props" class="cursor-pointer">
<q-td v-for="col in props.cols" :key="col.name" :props="props">
<div v-if="col.name == 'no'">
{{
(formQuery.page - 1) * formQuery.pageSize +
props.rowIndex +
1
}}
</div>
<div v-else-if="col.name === 'salaryHalf'">
{{
props.row.salaryHalfSpecial
? col.value + " " + `(${props.row.salaryHalfSpecial})`
: col.value
}}
</div>
<div v-else-if="col.name === 'salaryFull'">
{{
props.row.salaryFullSpecial
? col.value + " " + `(${props.row.salaryFullSpecial})`
: col.value
}}
</div>
<div v-else-if="col.name === 'salaryFullHalf'">
{{
props.row.salaryFullHalfSpecial
? col.value + " " + `(${props.row.salaryFullHalfSpecial})`
: col.value
}}
</div>
<div v-else>
{{ col.value ? col.value : "-" }}
</div>
</q-td>
<q-td>
<q-btn
flat
dense
icon="mdi-dots-vertical"
class="q-pa-none q-ml-xs"
color="grey-13"
size="12px"
>
<q-menu>
<q-list dense style="min-width: 150px">
<q-item
v-for="(item, index) in itemMenu"
:key="index"
clickable
v-close-popup
@click.stop="
item.type === 'edit'
? onClickSalaryRate('edit', props.row)
: item.type === 'delete'
? onClickDelete()
: null
"
>
<q-item-section>
<div class="row items-center">
<q-icon
:color="item.color"
size="17px"
:name="item.icon"
/>
<div class="q-pl-md">{{ item.label }}</div>
</div>
</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
</q-td>
</q-tr>
</template>
<template v-slot:pagination="scope">
<q-pagination
v-model="formQuery.page"
active-color="primary"
color="dark"
:max="totalRow"
size="sm"
boundary-links
direction-links
></q-pagination>
</template>
</d-table>
</div>
</q-card>
</q-card>
<DialogFormRate
v-model:modal="modalDialogFormRate"
:typeAction="typeAction"
:data="dataRow"
/>
</template>
<style scoped></style>