api ระบบ รอบการปฏิบัติงาน

This commit is contained in:
DESKTOP-1R2VSQH\Lenovo ThinkPad E490 2023-11-10 13:28:42 +07:00
parent aeaa8c8df2
commit 48e8037099
7 changed files with 383 additions and 235 deletions

View file

@ -1,9 +1,9 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>ระบบทรัพยากรบุคคล</title>
</head>
<body>

View file

@ -0,0 +1,6 @@
import env from "../index";
const leave = `${env.API_URI}/leave`;
export default {
roundDutytime: () => `${leave}/duty-time`,
roundDutytimeByid: (id: string) => `${leave}/duty-time/${id}`,
};

View file

@ -43,6 +43,9 @@ import message from "./api/00_dashboard/api.message";
/** API reports */
import reports from "./api/reports/api.report";
/** API ระบบลงเวลา */
import leave from "./api/09_leave/api.leave";
// environment variables
export const compettitivePanel = import.meta.env.VITE_COMPETITIVE_EXAM_PANEL;
export const qualifyDisableExamPanel = import.meta.env
@ -86,6 +89,9 @@ const API = {
//reports
...reports,
/**leave */
...leave,
};
export default {

View file

@ -1,39 +1,71 @@
<script setup lang="ts">
import { ref, reactive, watchEffect, watch } from "vue";
import { ref, reactive, watch } from "vue";
import http from "@/plugins/http";
import config from "@/app.config";
/** ImportType */
import type {
dataRowRound,
FormData,
MyObjectRoundRef,
} from "@/modules/09_leave/interface/response/round";
/** ImportComponents */
import DialogHeader from "@/components/DialogHeader.vue";
import { useCounterMixin } from "@/stores/mixin";
import { useQuasar } from "quasar";
const $q = useQuasar();
const mixin = useCounterMixin();
const { dialogConfirm } = mixin;
const { showLoader, dialogConfirm, success, messageError } = mixin;
/** propsData จาก RoundMain */
const props = defineProps({
modal: {
type: Boolean,
require: true,
},
editCheck: {
type: String,
require: true,
},
fetchData: {
type: Function,
require: true,
},
closeDialog: {
type: Function,
require: true,
},
detailData: {
type: Object,
require: false,
},
});
/** Ref INPUT เวลา*/
const amRef = ref<Object | null>(null);
const amOutRef = ref<Object | null>(null);
const pmRef = ref<Object | null>(null);
const pmOutRef = ref<Object | null>(null);
const formData = reactive<dataRowRound>({
am: "",
amOut: "",
pm: "",
pmOut: "",
note: "",
status: false,
isDefault: false,
});
const objectRound: MyObjectRoundRef = {
am: amRef,
amOut: amOutRef,
pm: pmRef,
pmOut: pmOutRef,
startTimeMorning: amRef,
endTimeMorning: amOutRef,
startTimeAfternoon: pmRef,
endTimeAfternoon: pmOutRef,
};
/** Form ข้อมูล */
const formData = reactive<FormData>({
startTimeMorning: "",
endTimeMorning: "",
startTimeAfternoon: "",
endTimeAfternoon: "",
description: "",
isDefault: false,
isActive: false,
});
/** Function validateForm*/
function validateForm() {
const hasError = [];
for (const key in objectRound) {
@ -51,48 +83,82 @@ function validateForm() {
console.log(hasError);
}
}
/** Function ยืนยันการบันทึกข้อมูล*/
function onSubmit() {
dialogConfirm(
$q,
async () => {
props.closeDialog?.();
const dataId = props.detailData?.id;
props.editCheck === "add" ? postRoundDuty() : putRoundDuty(dataId);
},
"ยืนยันการบันทึกข้อมูล",
"ต้องการยืนยันการบันทึกข้อมูลนี้หรือไม่ ?"
);
}
const props = defineProps({
modal: Boolean,
editCheck: String,
closeDialog: Function,
detailData: Object,
});
/** Function สร้างรอบการปฏิบัติงาน*/
async function postRoundDuty() {
await http
.post(config.API.roundDutytime(), formData)
.then(() => {
success($q, "บันทึกข้อมูล");
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
props.fetchData?.();
props.closeDialog?.();
});
}
/** Functiom แก้ไข้รอบการปฏิบัติงาน*/
async function putRoundDuty(id: string) {
const data = {
description: formData.description,
isDefault: formData.isDefault,
isActive: formData.isActive,
};
await http
.put(config.API.roundDutytimeByid(id), data)
.then(() => {
success($q, "บันทึกข้อมูล");
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
props.fetchData?.();
props.closeDialog?.();
});
}
function close() {
if (props.closeDialog) {
props.closeDialog();
}
props.closeDialog?.();
}
/***/
watch(
() => props.modal,
(newDetailData, oldDetailData) => {
if (props.editCheck === "add") {
formData.am = "";
formData.amOut = "";
formData.pm = "";
formData.pmOut = "";
formData.note = "";
formData.startTimeMorning = "";
formData.endTimeMorning = "";
formData.startTimeAfternoon = "";
formData.endTimeAfternoon = "";
formData.description = "";
formData.isDefault = false;
formData.status = false;
} else if(props.editCheck === "edit"){
formData.isActive = false;
} else if (props.editCheck === "edit") {
if (props.detailData) {
formData.am = props.detailData.am;
formData.amOut = props.detailData.amOut;
formData.pm = props.detailData.pm;
formData.pmOut = props.detailData.pmOut;
formData.note = props.detailData.note;
formData.startTimeMorning = props.detailData.startTimeMorning;
formData.endTimeMorning = props.detailData.endTimeMorning;
formData.startTimeAfternoon = props.detailData.startTimeAfternoon;
formData.endTimeAfternoon = props.detailData.endTimeAfternoon;
formData.description = props.detailData.description;
formData.isDefault = props.detailData.isDefault;
formData.status = props.detailData.status;
formData.isActive = props.detailData.isActive;
}
}
}
@ -129,21 +195,23 @@ watch(
dense
lazy-rules
borderless
v-model="formData.am"
v-model="formData.startTimeMorning"
:rules="[
(val) => !!val || 'กรุณากรอกเวลาเข้างาน',
(val) => {
if (val && formData.amOut) {
if (val > formData.amOut) {
if (val && formData.endTimeMorning) {
if (val > formData.endTimeMorning) {
return 'ต้องน้อยกว่าเวลาออกงาน';
}
if (val >= formData.pm && val <= formData.pmOut) {
if (
val >= formData.startTimeAfternoon &&
val <= formData.endTimeAfternoon
) {
return 'ช่วงเวลาทับซ้อนกับช่วงบ่าย';
}
if(val === formData.amOut){
return 'เวลาเข้างานช่วงเช้าต้องไม่ซ้ำกับออกงานเช้า'
if (val === formData.endTimeAfternoon) {
return 'เวลาเข้างานช่วงเช้าต้องไม่ซ้ำกับออกงานเช้า';
}
}
return true;
},
@ -162,21 +230,24 @@ watch(
:readonly="props.editCheck === 'edit'"
:outlined="props.editCheck === 'add'"
dense
v-model="formData.amOut"
v-model="formData.endTimeMorning"
lazy-rules
borderless
:rules="[
(val) => !!val || 'กรุณากรอกเวลาออกงาน',
(val) => {
if (val && formData.am) {
if (val < formData.am) {
if (val && formData.startTimeMorning) {
if (val < formData.startTimeMorning) {
return 'ต้องมากกว่าเวลาเข้างาน';
}
if (val >= formData.pm && val <= formData.pmOut) {
if (
val >= formData.startTimeAfternoon &&
val <= formData.endTimeAfternoon
) {
return 'ช่วงเวลาทับซ้อนกับช่วงบ่าย';
}
if(val === formData.am){
return 'เวลาออกงานช่วงเช้าต้องไม่ซ้ำกับเข้างานเช้า'
if (val === formData.startTimeMorning) {
return 'เวลาออกงานช่วงเช้าต้องไม่ซ้ำกับเข้างานเช้า';
}
}
return true;
@ -199,15 +270,18 @@ watch(
:rules="[
(val) => !!val || 'กรุณากรอกเวลาเข้างาน',
(val) => {
if (val && formData.pmOut) {
if (val > formData.pmOut) {
if (val && formData.endTimeAfternoon) {
if (val > formData.endTimeAfternoon) {
return 'ต้องน้อยกว่าเวลาออกงาน';
}
if (val >= formData.am && val <= formData.amOut) {
if (
val >= formData.startTimeMorning &&
val <= formData.endTimeMorning
) {
return 'ช่วงเวลาทับซ้อนกับช่วงเช้า';
}
if(val === formData.pmOut){
return 'เวลาเข้างานช่วงบ่ายต้องไม่ซ้ำกับออกงานช่วงบ่าย'
if (val === formData.endTimeAfternoon) {
return 'เวลาเข้างานช่วงบ่ายต้องไม่ซ้ำกับออกงานช่วงบ่าย';
}
}
return true;
@ -219,7 +293,7 @@ watch(
dense
lazy-rules
borderless
v-model="formData.pm"
v-model="formData.startTimeAfternoon"
hide-bottom-space
type="time"
style="width: 140px"
@ -233,15 +307,18 @@ watch(
:rules="[
(val) => !!val || 'กรุณากรอกเวลาออกงาน',
(val) => {
if (val && formData.pm) {
if (val < formData.pm) {
if (val && formData.startTimeAfternoon) {
if (val < formData.startTimeAfternoon) {
return 'ต้องมากกว่าเวลาเข้างาน';
}
if (val >= formData.am && val <= formData.amOut) {
if (
val >= formData.startTimeMorning &&
val <= formData.endTimeMorning
) {
return 'ช่วงเวลาทับซ้อนกับช่วงเช้า';
}
if(val === formData.pm){
return 'เวลาออกงานช่วงบ่ายต้องไม่ซ้ำกับเข้างานช่วงบ่าย'
if (val === formData.startTimeAfternoon) {
return 'เวลาออกงานช่วงบ่ายต้องไม่ซ้ำกับเข้างานช่วงบ่าย';
}
}
return true;
@ -251,7 +328,7 @@ watch(
:readonly="props.editCheck === 'edit'"
:outlined="props.editCheck === 'add'"
dense
v-model="formData.pmOut"
v-model="formData.endTimeAfternoon"
lazy-rules
borderless
hide-bottom-space
@ -264,7 +341,7 @@ watch(
class="col-12 bg-white q-ma-md"
outlined
stack-label
v-model="formData.note"
v-model="formData.description"
label="คำอธิบาย"
hide-bottom-space
type="textarea"
@ -286,7 +363,7 @@ watch(
<div class="row items-center q-my-sm justify-between">
<p class="q-ma-none">สถานะการใชงาน</p>
<label class="toggle-control">
<input type="checkbox" v-model="formData.status" />
<input type="checkbox" v-model="formData.isActive" />
<span class="control"></span>
</label>
</div>

View file

@ -1,40 +1,59 @@
interface RoundRows {
name: string;
position: string;
responsibilities: string;
email: string;
phone: string;
name: string;
position: string;
responsibilities: string;
email: string;
phone: string;
}
interface dataRowRound {
am: string
amOut: string
pm: string
note:string
pmOut: string
status: boolean
isDefault: boolean
id: string;
createdAt: string;
createdFullName: string;
createdUserId: string;
description: string;
endTimeAfternoon: string;
endTimeMorning: string;
startTimeMorning: string;
startTimeAfternoon: string;
lastUpdateFullName: string;
lastUpdateUserId: string;
lastUpdatedAt: string;
isActive: boolean;
isDefault: boolean;
}
interface FormData {
startTimeMorning: string;
endTimeMorning: string;
startTimeAfternoon: string;
endTimeAfternoon: string;
description: string;
isDefault: boolean;
isActive: boolean;
}
interface roundShow {
round: string;
am: string;
amOut: string;
pm: string;
pmOut: string;
amRound: string;
pmRound: string;
status: boolean;
isDefault: boolean;
}
interface MyObjectRoundRef {
am: object | null,
amOut: object | null,
pm: object | null,
pmOut: object | null,
[key: string]: any;
id: string;
round: string;
morningRound: string;
afternoonRound: string;
createdAt: string;
createdFullName: string;
createdUserId: string;
description: string;
endTimeAfternoon: string;
endTimeMorning: string;
startTimeMorning: string;
startTimeAfternoon: string;
lastUpdateFullName: string;
lastUpdateUserId: string;
lastUpdatedAt: string;
isActive: boolean;
isDefault: boolean;
}
export type {
RoundRows,
dataRowRound,
MyObjectRoundRef,
roundShow
};
interface MyObjectRoundRef {
startTimeMorning: object | null;
endTimeMorning: object | null;
startTimeAfternoon: object | null;
endTimeAfternoon: object | null;
[key: string]: any;
}
export type { RoundRows, dataRowRound, FormData, MyObjectRoundRef, roundShow };

View file

@ -1,85 +1,96 @@
import { defineStore } from "pinia";
import { ref } from "vue";
import type { dataRowRound,roundShow } from "@/modules/09_leave/interface/response/round.ts";
import type {
dataRowRound,
roundShow,
} from "@/modules/09_leave/interface/response/round.ts";
import type { QTableProps } from "quasar";
// store ลา >> รอบการปฏิบัติงาน
export const useRoundDataStore = defineStore(
"roundWorkStore",
() => {
//ค้นหา คอลัมน์ คอลัมน์ที่แสดง
const visibleColumns = ref<string[]>([
"round",
"amRound",
"pmRound",
"note",
"status"
]);
export const useRoundDataStore = defineStore("roundWorkStore", () => {
/** ค้นหา คอลัมน์ คอลัมน์ที่แสดง */
const visibleColumns = ref<string[]>([
"round",
"morningRound",
"afternoonRound",
"isActive",
]);
// หัวตาราง
const columns = ref<QTableProps["columns"]>([
{
name: "round",
align: "left",
label: "รอบ",
sortable: true,
field: "round",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "amRound",
align: "left",
label: "ช่วงเช้า",
sortable: true,
field: "amRound",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "pmRound",
align: "left",
label: "ช่วงบ่าย",
sortable: true,
field: "pmRound",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "status",
align: "center",
label: "สถานะการใช้งาน",
sortable: true,
field: "status",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
]);
/** หัวตาราง */
const columns = ref<QTableProps["columns"]>([
{
name: "round",
align: "left",
label: "รอบ",
sortable: true,
field: "round",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "morningRound",
align: "left",
label: "ช่วงเช้า",
sortable: true,
field: "morningRound",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "afternoonRound",
align: "left",
label: "ช่วงบ่าย",
sortable: true,
field: "afternoonRound",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "isActive",
align: "center",
label: "สถานะการใช้งาน",
sortable: true,
field: "isActive",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
]);
// ข้อมูลในตาราง
const rows = ref<dataRowRound[]>([]);
function fetchData(data: dataRowRound[]) {
let datalist: roundShow[] = data.map((e: dataRowRound) => {
return {
round:`${e.am}-${e.pmOut}`,
am: e.am,
amOut: e.amOut,
pm: e.pm,
pmOut: e.pmOut,
amRound:`${e.am}-${e.amOut}`,
pmRound:`${e.pm}-${e.pmOut}`,
status: e.status,
isDefault: e.isDefault,
};
/** ข้อมูลในตาราง */
const rows = ref<dataRowRound[]>([]);
/**
* Function API map
* @param data API
*/
function fetchData(data: dataRowRound[]) {
let datalist: roundShow[] = data.map((e: dataRowRound) => {
return {
id: e.id,
round: `${e.startTimeMorning}-${e.endTimeAfternoon}`,
morningRound: `${e.startTimeMorning}-${e.endTimeMorning}`,
afternoonRound: `${e.startTimeAfternoon}-${e.endTimeAfternoon}`,
createdAt: e.createdAt,
createdFullName: e.createdFullName,
createdUserId: e.createdUserId,
description: e.description,
endTimeAfternoon: e.endTimeAfternoon,
endTimeMorning: e.endTimeMorning,
startTimeMorning: e.startTimeMorning,
startTimeAfternoon: e.startTimeAfternoon,
lastUpdateFullName: e.lastUpdateFullName,
lastUpdateUserId: e.lastUpdateUserId,
lastUpdatedAt: e.lastUpdatedAt,
isActive: e.isActive,
isDefault: e.isDefault,
};
});
rows.value = datalist;
}
return {
visibleColumns,
columns,
rows,
fetchData
};
}
);
return {
visibleColumns,
columns,
rows,
fetchData,
};
});

View file

@ -1,18 +1,29 @@
<script setup lang="ts">
import { ref, useAttrs, onMounted } from "vue";
import router from "@/router";
import { useQuasar } from "quasar";
import DialogForm from "@/modules/09_leave/components/3_WorkTime/DialogForm.vue";
import http from "@/plugins/http";
import config from "@/app.config";
/** ImportStores*/
import { useRoundDataStore } from "@/modules/09_leave/stores/RoundStores";
import { useCounterMixin } from "@/stores/mixin";
/** ImportComponents*/
import DialogForm from "@/modules/09_leave/components/3_WorkTime/DialogForm.vue";
const mixin = useCounterMixin();
const dataStore = useRoundDataStore();
const { fetchData } = dataStore;
const { showLoader, hideLoader, messageError, dialogRemove, success } = mixin;
const $q = useQuasar(); // noti quasar
const attrs = ref<any>(useAttrs());
const modal = ref<boolean>(false);
const detailData = ref<any>();
const editCheck = ref<string>("");
//
/** ค้นหาข้อมูลใน Table */
const filterKeyword = ref<string>("");
const filterRef = ref<HTMLInputElement | null>(null);
const resetFilter = () => {
@ -22,19 +33,52 @@ const resetFilter = () => {
}
};
const attrs = ref<any>(useAttrs());
const paging = ref<boolean>(true);
const pagination = ref({
// sortBy: "desc",
descending: false,
page: 1,
rowsPerPage: 10,
onMounted(() => {
fetchListRoind();
});
const paginationLabel = (start: string, end: string, total: string) => {
if (paging.value == true) return " " + start + "-" + end + " ใน " + total;
else return start + "-" + end + " ใน " + total;
};
/** Function get ข้อมูลรายการรอบการปฏิบัติงาน */
async function fetchListRoind() {
showLoader();
await http
.get(config.API.roundDutytime())
.then((res) => {
const data = res.data.result;
fetchData(data);
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
/**
* Function delete รายการรอบการปฏงาน
* @param id ID ของ rows
*/
function onClickDelete(id: string) {
dialogRemove($q, async () => {
await http
.delete(config.API.roundDutytimeByid(id))
.then(() => {
success($q, "ลบข้อมูลสำเร็จ");
})
.catch((err) => {
messageError($q, err);
})
.finally(async () => {
await fetchListRoind();
});
});
}
/**
*
* @param data อมลรอบการปฏงาน
* @param check action แกไข,เพ
*/
function openModal(data: any, check: string) {
modal.value = true;
editCheck.value = check;
@ -43,45 +87,18 @@ function openModal(data: any, check: string) {
}
}
/** Function ปิด popup รายละเอียดและการเพิ่ม*/
function closeDialog() {
modal.value = false;
editCheck.value = "add";
}
onMounted(() => {
dataStore.fetchData([
{
am: "07:30",
amOut: "12:00",
pm: "13:00",
pmOut: "15:30",
status: true,
isDefault: true,
},
{
am: "08:30",
amOut: "12:00",
pm: "13:00",
pmOut: "15:30",
status: false,
isDefault: false,
},
{
am: "09:30",
amOut: "12:00",
pm: "13:00",
pmOut: "15:30",
status: true,
isDefault: false,
},
{
am: "10:30",
amOut: "12:00",
pm: "13:00",
pmOut: "15:30",
status: true,
isDefault: false,
},
]);
/** pagination */
const pagination = ref({
// sortBy: "desc",
descending: false,
page: 1,
rowsPerPage: 10,
});
</script>
<template>
@ -158,7 +175,6 @@ onMounted(() => {
class="custom-header-table"
v-bind="attrs"
:visible-columns="dataStore.visibleColumns"
:pagination-label="paginationLabel"
v-model:pagination="pagination"
>
<template v-slot:header="props">
@ -172,6 +188,7 @@ onMounted(() => {
>
<span class="text-weight-medium">{{ col.label }}</span>
</q-th>
<q-th auto-width></q-th>
</q-tr>
</template>
<template v-slot:body="props">
@ -192,15 +209,15 @@ onMounted(() => {
:props="props"
@click.prevent="openModal(props.row, 'edit')"
>
<div v-if="col.name === 'status'" class="text-center">
<div v-if="col.name === 'isActive'" class="text-center">
<q-icon
v-if="props.row.status === true"
v-if="props.row.isActive === true"
name="mdi-check"
size="sm"
color="positive"
/>
<q-icon
v-if="props.row.status === false"
v-if="props.row.isActive === false"
name="mdi-close"
size="sm"
color="grey"
@ -210,6 +227,17 @@ onMounted(() => {
{{ col.value }}
</div>
</q-td>
<q-td>
<q-btn
v-if="props.row.isActive === false"
dense
flat
round
color="red"
icon="delete"
@click="onClickDelete(props.row.id)"
/>
</q-td>
</q-tr>
</template>
</d-table>
@ -220,6 +248,7 @@ onMounted(() => {
:closeDialog="closeDialog"
:editCheck="editCheck"
:detailData="detailData"
:fetchData="fetchListRoind"
/>
</template>
<style scoped lang="scss">